【问题标题】:Collecting like term of an expression in Sympy在 Sympy 中收集一个表达式的类似术语
【发布时间】:2016-06-09 05:44:02
【问题描述】:

我目前正在处理多个变量的函数,并且需要收集类似的术语以尝试简化表达式。

假设表达式写成如下:

x = sympy.Symbol('x')
y = sympy.Symbol('y')
k = sympy.Symbol('k')
a = sympy.Symbol('a')

z = k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
zEx = z.expand()
print type(z)
print type(zEx)

编辑:格式化以增加清晰度并更改表达式 z 以使问题更易于理解。

假设z 包含这么多术语,可以通过肉眼筛选它们。并选择适当的条款,将花费不令人满意的时间。

我想收集所有是 a**1 倍数的术语。我不关心 a 的二次或更高次幂,也不关心不包含 a 的项。

zzEx 的类型返回以下内容:

print type(z)
print type(zEx)
>>>
<class 'sympy.core.add.Add'>
<class 'sympy.core.mul.Mul'>

有谁知道我如何收集 a 的倍数而不是 a^0 或 a^2 的术语?

tl'dr

其中 z(x,y) 和常数 a 和 k 由 zzEx 及其 type() 描述:如何从 z 中删除所有非 a 项并删除所有二次或表达式中a 的更高术语?这样剩下的就是包含a的统一力量的术语。

【问题讨论】:

    标签: python python-2.7 math sympy polynomials


    【解决方案1】:

    最后它只是一条线。 @asmeurer 让我走上了正轨(查看这篇文章下方的 cmets)。这是代码;解释如下:

    from sympy import *
    from sympy.parsing.sympy_parser import parse_expr
    import sys
    
    x, y, k, a = symbols('x y k a')
    
    # modified string: I added a few terms
    z = x*(k*a**9) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*(k*a**1) - k*a**3 + y*a**5
    
    zmod = Add(*[argi for argi in z.args if argi.has(a)])
    

    那么zmod就是

    a**9*k*x - a**8*k + a**5*y - a**3*k + a*k*x
    

    让我们更仔细地看一下:

    z.args
    

    只是表达式中所有单个术语的集合(请注意,符号也被解析,这使事情变得更容易):

    (k*x**2, a**5*y, -a**3*k, -a**8*k, a*k*x, a**9*k*x, k**2*x*y, k**3*x**2*y)
    

    然后,在列表理解中,您可以使用函数has 选择包含a 的所有术语。然后可以使用Add 将所有这些术语重新组合在一起,从而为您提供所需的输出。

    编辑

    上面返回所有包含a 的表达式。如果只想用统一幂过滤掉包含a的表达式,可以使用collectMul

    from sympy import *
    from sympy.parsing.sympy_parser import parse_expr
    import sys
    
    x, y, k, a = symbols('x y k a')
    
    z2 = x**2*(k*a**1) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*k*a - k*a**3 + y*a**1
    
    zc = collect(z2, a, evaluate=False)
    zmod2 = Mul(zc[a], a)
    

    那么zmod2就是

    a*(k*x**2 + k*x + y)
    

    zmod2.expand()

    a*k*x**2 + a*k*x + a*y
    

    这是正确的。

    使用您提供的更新后的z 我运行:

    z3 =  k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
    zc3 = collect(z3.expand(), a, evaluate=False)
    zmod3 = Mul(zc3[a], a)
    

    然后获取zmod3.expand():

    a*k*x**2 + a*k*y**2
    

    这是您要寻找的结果吗?

    PS:感谢 @asmeurer 提供所有这些有用的 cmets!

    【讨论】:

    • 如果你使用字符串来操作 sympy 表达式,那你就错了。
    • @asmeurer:据我理解的问题,OP 希望过滤 z 中包含参数 a 的所有术语。首先将其转换为字符串是我可以完成此操作的唯一方法,因为迭代 z.args 不允许(?)检查 a 是否在元素中。 collect 似乎也不适合,但也许我以错误的方式使用它。也许您可以像我定义的那样使用z 来扩展您的答案,并尝试在不先将其转换为字符串的情况下获得与我相同的结果!?我总是很高兴扩大我的知识:)
    • 感谢分享!当表达式全部为正时,将其拆分为字符串似乎效果很好。但是如果表达式中有否定项怎么办?我认为它不会正确地拆分条款。如果其他术语都是负面的,我怎么能这样做?
    • 如果他们都是否定的,你必须做zstr.split('-')' - '.join(res)。如果同时存在+-,那就有点棘手了。我可以稍后尝试更新帖子。但根据@asmeurer 和至少另一个人的说法,这不是要走的路——尽管它完成了这项工作,但它甚至被否决了。
    • @Cleb 我删除了反对票。不过,我只想删除旧答案。它仍会在编辑历史记录中可见。
    【解决方案2】:

    要遍历表达式的术语,请使用expr.args

    我不清楚a 应该是什么,但collect function 可以做你想做的事。

    【讨论】:

    • 对不起。 a 应该被定义为另一个变量: a = sympy.Symbol('a')
    【解决方案3】:

    除了给出的其他答案,您还可以将collect 用作字典。

    print(collect(zEx,a,evaluate=False)[a])
    

    产生表达式

    k*x**2 + k*y**2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多