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*b
和 b*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*b
。 1/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
).
我正在处理一些长方程但并不复杂,我想使用 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*b
和 b*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*b
。 1/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
).