在SymPy中选择不同的表达式因式分解

8 投票
2 回答
960 浏览
提问于 2025-04-16 22:33

假设我有一个这样的表达式:

a*b*c + b*c + a*d

我们可以把它分解成:

b*(a*c + c) + (a*d)

或者可以分解成

c*(a*b + b) + (a*d)

或者可以分解成

a*d + b*c*(a + 1)

还有其他的可能性。

对于其他表达式,可能的分解方式会更多。

我想问的是,SymPy这个工具有没有什么功能,可以让用户选择显示哪种分解方式?有没有办法在分解或组合表达式中的项时,指定要使用的公因子?

编辑:正如@user772649下面提到的,我可以使用collect来实现这个功能。不过,collect的输出似乎会根据数学表达式的初始分解不同而有所不同,例如:

a,b,c,d = symbols("a,b,c,d")

# These two equations are mathematically equivalent:
eq1 = a*b*c + b*c + a*d
eq2 = a*d + b*c*(a + 1)

print collect(eq1, a)
print collect(eq2, a)

输出:

a*(b*c + d) + b*c
a*d + b*c*(a + 1)

方程eq1eq2在数学上是等价的,但collect对它们的分解输出却不同,尽管对这两个方程调用collect的方式是一样的。这让我产生了以下两个问题:

  1. 有没有办法在调用collect之前“展开”一个表达式?
  2. 有没有一种“收集”(分解一个表达式)的方法,可以在不先展开表达式的情况下,对初始分解保持不变?

2 个回答

0

有一点可能会比较好,就是如果给多个符号的话,collect 可以在之前分组的子表达式上进行收集。不过,像 @HYRY 展示的那样,给一个乘积进行收集,或者像下面这样做也是可以的:

def separatevars_additively(expr, symbols=[]):
    from sympy import factor_terms
    free = set(symbols) or expr.free_symbols
    d = {}
    while free:
        f = free.pop()
        expr, dep = expr.as_independent(f, as_Add=True)
        if dep.has(*free):
            return None
        d[f] = factor_terms(dep)
    if expr:
        d[0] = expr
    return d

var('a:d')
eq = a*b*c + b*c + a*d
def do(i):
    return sum(separatevars_additively(eq,[i]).values())
for i in eq.free_symbols:
    print('%s: %s' % (i, do(i)))

结果是

b: a*d + b*c*(a + 1)
a: a*(b*c + d) + b*c
c: a*d + b*c*(a + 1)
d: a*b*c + a*d + b*c
5

使用 collect() 方法:

from sympy import *

a,b,c,d = symbols("a,b,c,d")
eq = a * b * c + b * c + a * d
print collect(eq, b)
print collect(eq, c)
print collect(eq, b*c)

输出结果是:

a*d + b*(c + a*c)
a*d + c*(b + a*b)
a*d + b*c*(1 + a)

撰写回答