SymPy自动处理表达式
我一直在用SymPy把数学表达式转换成latex格式,然后再用Matplotlib来显示。例如:
from sympy import latex, sympify
from sympy.abc import x
str = '2*x + 3*x'
TeX = latex(sympify(str))
问题是它会自动处理这些表达式,比如2*x + 3*x会自动变成5*x等等;这不是我想要的(别问我为什么!)。
3 个回答
>>> import re
>>> re.sub("(^|[\(\[\{\+\-\*/ ,\:=])(\-?[0-9]*\.?[0-9]+)", "\\1Dummy('\\2')", '2*x + 3*x')
"Dummy('2')*x + Dummy('3')*x"
>>> eval(_)
2⋅x + 3⋅x
>>> latex(_)
'2 x + 3 x'
首先,我们导入了一个叫做re的模块,这个模块主要用来处理字符串中的模式匹配。
接着,我们用re.sub这个函数来替换字符串中的某些部分。这里的字符串是'2*x + 3*x',我们想要找到数字并把它们包裹在一个叫做Dummy的函数里。具体来说,我们在寻找那些数字前面是特定符号的情况,比如加号、减号、乘号等。
替换后,原来的'2*x + 3*x'变成了"Dummy('2')*x + Dummy('3')*x",也就是把数字2和3都放进了Dummy函数里。
然后,我们用eval这个函数来计算这个新的表达式。eval会执行字符串中的代码,所以它把"Dummy('2')*x + Dummy('3')*x"计算成了2⋅x + 3⋅x。
最后,我们用latex这个函数把结果转换成LaTeX格式,得到的结果是'2 x + 3 x',这是一种常用的数学排版格式。
其实,当你调用 sympify(str)
时,它会尝试解析表达式并将其转换为默认的类。在这个例子中,Add(2*x,2*x)
会被调用(默认参数是 evaluate=True
),所以它变成了 5*x
。如果你想避免这种情况,你要么可以调用 Add(2*x,3*x,evaluate=False)
,要么使用一些全局变量,并在 init 方法中检查 AssocOp 类,位置在 core-> operation.py。
我正在这样做。
try:
import __builtin__
evaluate_expr=__builtin__.evaluate_expr
except AttributeError ,ex:
pass
if ((not options.pop('evaluate', True)) or (evaluate_expr==False)) :
**注意 - sympy 对函数使用了缓存,所以如果你两次调用同一个函数(比如:sympy("2*x+3*x")
),第一次使用全局变量 evaluate=True
,第二次使用 evaluate=False
。在这两种情况下,由于缓存的原因,你会得到相同的结果。所以你需要更新 core->expr 类中的方法,比如 add 和 mul,可以参考下面的内容。
def __add__(self, other):
#simplifychange:
evaluate_expr=self.get_evaluate()
return Add(self, other,evaluate=evaluate_expr)
不过我建议最好不要使用 evaluate=False
。这样会导致 sympy 的行为发生很大变化。你可能会遇到我在这个 帖子 中提到的问题。
Sympy的 Add
类用于处理符号的加法。你可以提供一个关键词参数来停止自动收集项。
from sympy import Add
from sympy.abc import x
eq = Add(2*x, 3*x, evaluate=False)
# this will print: 2*x + 3*x
print eq
根据你对phimuemue评论的回复,这可能并不是你想要的结果。