我正在使用一些长方程但不是很复杂,我想使用 sympy 来简化和“分解”它们。但我遇到了一些问题。以下是一些最小例子的列表:
问题1:对称性
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
。
问题
有没有办法解决这些问题?或许我应该使用另一个象征性的数学工具?欢迎任何建议。
答案 0 :(得分:5)
SymPy中存在一个主要问题,即由于Python的工作方式,number/number
给出了一个浮点(如果使用Python 2并且不是{{1},则会进行整数除法}})。
在第一种情况和原始表达式中,Python从左到右评估from __future__ import division
。 Python会对1/12*b
进行评估,以提供1/12
,然后乘以0.08333333333333333
。在第二种情况下,b
被评估为b*1
。然后由SymPy评估b
(因为b/12
是SymPy对象),以提供b
。
由于浮点数的不精确性,SymPy看不到浮点Rational(1, 12)*b
等于理性0.08333333333333333
。
有关此问题的更多讨论here。作为一种解决方法,你应该避免直接1/12
而不以某种方式包装它,以便SymPy可以创建一个理性的。以下都将创造一个理性:
integer/integer
对于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
中。 SymPy通常只替换它看到的东西。
您似乎不介意添加和减去x**2 + x + 1
以进行替换工作。所以我建议改为x
。通过仅替换单个术语((((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x)
),替换将始终有效,并且x**2
将取消以留下任何2*x
个术语(在这种情况下,x
)。
答案 1 :(得分:1)
这是解决问题的可能方法:
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))
答案 2 :(得分:1)
关于问题1,请注意clickThing
和1/12*b
不同样的事情。第一个是由符号多次浮动的浮点数,而第二个是精确的符号表达式(您可以通过简单的print语句检查它)。由于b*1/12
包含expr
,因此第二个1/12*b
不起作用就不足为奇了。
关于问题2,您提供的subs
规则不明确。特别是替换规则意味着等式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
规则中明确提供,即
subs
(((x+1)**2-x).expand()).subs(x**2, -2*x + y + 1)