删除SymPy系列扩展中的混合变量术语

时间:2017-08-29 14:54:06

标签: python big-o sympy polynomial-approximations

考虑SymPy符号ei的两个函数:

from sympy import Symbol, expand, Order
i = Symbol('i')
e = Symbol('e')
f = (i**3 + i**2 + i + 1)
g = (e**3 + e**2 + e + 1)
z = expand(f*g)

这将产生

z = e**3*i**3 + e**3*i**2 + e**3*i + e**3 + e**2*i**3 + e**2*i**2 + e**2*i + e**2 + e*i**3 + e*i**2 + e*i + e + i**3 + i**2 + i + 1

但是,假设ei都很小,我们可以忽略三阶或更高阶的术语。使用Sympy的系列工具或只是添加O-notation Order类可以解决这个问题:

In : z = expand(f*g + Order(i**3) + Order(e**3))
Out: 1 + i + i**2 + e + e*i + e*i**2 + e**2 + e**2*i + e**2*i**2 + O(i**3) + O(e**3)

看起来很棒。但是,我仍然使用混合术语e**2 * i**2。这些术语中的个体变量小于期望的截止值,因此SymPy保留它们。但是,数学上小²·小²=小⁴。同样,e·i²= small·small²=small³。

至少就我的目的而言,我希望删除这些混合术语。添加混合Order不会产生所需的结果(它似乎忽略了前两个订单)。

In : expand(f*g + Order(i**3) + Order(e**3) + Order((i**2)*(e**2)))
Out: 1 + i + i**2 + i**3 + e + e*i + e*i**2 + e*i**3 + e**2 + e**2*i + e**3 + e**3*i + O(e**2*i**2, e, i)

问题:SymPy是否有一个简单的系统来快速删除第n个条款,以及(e ^ a)·(i ^ b)其中a + b> ; N'

凌乱的解决方案:我找到了解决这个问题的方法,但它很麻烦,而且可能不一般。

z = expand(f*g + Order((e**2)*i) + Order(e*(i**2)))
zz = expand(z.removeO() + Order(e**3) + Order(i**3))

产生

zz = 1 + i + i**2 + e + e*i + e**2 + O(i**3) + O(e**3)

这正是我想要的。所以要指定我的问题:有没有办法在一个步骤中执行此操作可以推广到任何n?此外,我的解决方案丢失了表示混合术语丢失的大O符号。这不是必需的,但会很好。

2 个答案:

答案 0 :(得分:1)

由于您有双重限制,您必须在所有e个对象中指定无穷小变量(iOrder),即使它们没有出现在第一个参数中。

原因是Order(expr)仅自动选择那些实际出现在expr中的无穷小符号,因此,例如O(e)仅用于限制e→0。 现在,具有不同限制的Order个对象不能很好地混合,例如:

O(e*i)+O(e) == O(e*i) != O(e)+O(e*i) == O(e) # True

这会导致混乱,结果取决于添加的顺序,这是一个很好的指标,这是要避免的。 这可以通过明确指定无穷小符号(作为Order的加法参数)来避免,例如:

O(e*i)+O(e,e,i) == O(e,e,i)+O(e*i) == O(e,e,i) # True

我还没有办法避免手动遍历ei的所有组合,但这可以通过简单的迭代来完成:

orders = sum( Order(e**a*i**(n-a),e,i) for a in range(n+1) )
expand(f*g+orders)
# 1 + i + i**2 + e + e*i + e**2 + O(e**2*i, e, i) + O(e*i**2, e, i) + O(i**3, e, i) + O(e**3, e, i)

答案 1 :(得分:1)

如果不使用Order,您可以尝试这样简单的事情:

>>> eq = expand(f*g)  # as you defined
>>> def total_degree(e):
...     x = Dummy()
...     free = e.free_symbols
...     if not free: return S.Zero
...     for f in free:
...         e = e.subs(f, x)
...     return degree(e)
>>> eq.replace(lambda x: total_degree(x) > 2, lambda x: S.Zero)
e**2 + e*i + e + i**2 + i + 1