Sympy 的订阅限制

Sympy's subs limitations

我正在处理一些长方程但并不复杂,我想使用 sympy 来简化和 "factorize" 它们。但是我遇到了一些问题。以下是一些最小示例的列表:

问题一:对称性

from sympy import *
from __future__ import division
a = symbols('a')
b = symbols('b')
expr = 1/12*b + 1
expr.subs(1/12*b, a)
expr.subs(b*1/12, a)

第一行给出了预期的结果(即a+1),而第二行没有替换。

问题2:因式分解

表达式的某些部分被分解了,当我展开表达式时,它们会被简化,因此无法进行替换。例如

(((x+1)**2-x).expand()).subs(x**2+2*x, y+1)

会给出 x^2+x+1 而我要找的是 y+2-x.

问题

有没有办法解决这些问题?或者也许我应该使用另一种符号数学工具?欢迎任何建议。

以下是您的问题的可能解决方案:

from sympy import *

a = symbols('a')
b = symbols('b')
expr = 1 / 12 * b + 1
print(expr.subs((1 / 12) * b, a))
print(expr.subs(b * (1 / 12), a))

x = symbols('x')
y = symbols('y')
expr = ((x + 1)**2 - x).expand()
print(expr.subs(x**2 + x, y - x + 1))

关于问题 1,请注意 1/12*bb*1/12 在 sympy 中 不是 同一件事。第一个是一个浮点数乘以一个符号,而第二个是一个精确的符号表达式(你可以通过一个简单的打印语句来检查它)。由于expr包含1/12*b,所以第二个subs不起作用也就不足为奇了。

关于问题2,您提供的subs规则不明确。特别是替换规则意味着等式 x**2+2*x==y+1。但是,这个等式有很多解释,例如

x**2 == y + 1 - 2*x(这是你考虑的那个),

x**2 + x == y + 1 - x

x == (y + 1 - x**2)/2,

因此,我认为 sympy 拒绝执行替换实际上是一种正确的做法。

如果这是你想要的第一个解释,最好在subs规则中明确提供,即

(((x+1)**2-x).expand()).subs(x**2, -2*x + y + 1)

-x + y + 2

SymPy 中有一个主要问题,那就是,由于 Python 的工作方式,number/number 给出了一个浮点数(或者如果您使用 Python 则进行整数除法) 2 而不是 from __future__ import division)。

在第一种情况下,在您的原始表达式中,Python 从左到右计算 1/12*b1/12 由 Python 计算得出 0.08333333333333333,然后乘以 b。在第二种情况下,b*1 被评估为 b。然后 b/12 被 SymPy 求值(因为 b 是一个 SymPy 对象),得到 Rational(1, 12)*b

由于浮点数的不精确性,SymPy 不会将浮点数 0.08333333333333333 视为等于有理数 1/12

这个问题还有一些讨论here。作为一种解决方法,您应该避免直接 integer/integer 而不以某种方式包装它,以便 SymPy 可以创建一个有理数。以下都将创建一个有理数:

b/12
Rational(1, 12)*b
S(1)/12*b

对于 (((x+1)**2-x).expand()).subs(x**2+2*x, y+1),问题是 x**2 + 2*x 没有准确出现在表达式中,即 x**2 + x + 1。 SymPy 通常只替换它准确看到的东西。

看来您不介意加减一个 x 来进行替换。所以我建议改为 (((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x)。通过仅替换单个术语 (x**2),替换将始终有效,并且 2*x 将抵消以留下任何 x 术语(在这种情况下,-x ).