SymPy自动处理表达式

4 投票
3 回答
1679 浏览
提问于 2025-04-16 20:06

我一直在用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 个回答

-1

>>> 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',这是一种常用的数学排版格式。

1

其实,当你调用 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 类中的方法,比如 addmul,可以参考下面的内容。

def __add__(self, other):
        #simplifychange:
        evaluate_expr=self.get_evaluate()
        return Add(self, other,evaluate=evaluate_expr)

不过我建议最好不要使用 evaluate=False。这样会导致 sympy 的行为发生很大变化。你可能会遇到我在这个 帖子 中提到的问题。

6

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评论的回复,这可能并不是你想要的结果。

撰写回答