使用 sympy 解析字符串时的意外行为

Unexpected behaviour when parsing string with sympy

我正在尝试使用 sympy 执行方程式的导数,但是,如果我手写方程式,则导数是正确的;当我将等式作为字符串传递时,输出是错误的。谁能解释我如何解决这个问题?我正在使用 python 3.6 和 sympy 1.5.1.

>>>from sympy import *

>>>from operator import *

>>> x1 = symbols('x1')

>>> f = add(sin(x1), mul(x1, x1))

>>> diff(f, x1)

2*x1 + cos(x1)   ## Correct output

>>>> f = 'add(sin(x1), mul(x1, x1))'  ## Equation provided as string

>>>> diff(f, x1)

(Subs(Derivative(mul(_xi_1, x1), _xi_1), _xi_1, x1) + Subs(Derivative(mul(x1, _xi_2), _xi_2), _xi_2, x1))*Subs(Derivative(add(sin(x1), _xi_2), _xi_2), _xi_2, mul(x1, x1)) + cos(x1)*Subs(Derivative(add(_xi_1, mul(x1, x1)), _xi_1), _xi_1, sin(x1))  ## Wrong output

发生这种情况是因为 f = 'add(sin(x1), mul(x1, x1))' 不是 parse_expr 可以解析的有效数学方程式。此函数旨在解析以数学语法编写的方程式,而不是 Sympy 函数。要特别正确地解析此函数,您需要使用,例如:

>>> f = 'sin(x1) +  x1^2'
>>> diff(f, x1)
2*x1 + cos(x1)

如果你真的需要使用那个特定的字符串,你可以使用 eval():

>>> f = 'add(sin(x1), mul(x1, x1))'
>>> diff(eval(f), x1)
2*x1 + cos(x1)

如果您想以这种方式编写它,请务必使用实际的 SymPy 对象名称(大写)。我使用 S(...) 来解释表达式,这与任何函数都会做的事情一样:

>>> S('Add(sin(x1), Mul(x1, x1))')
x1**2 + sin(x1)

但您也可以使用数学运算符 +*:

>>> S('sin(x1) + x1*x1')
x1**2 + sin(x1)

您不应将字符串直接传递给 SymPy 函数。相反,首先用 sympify 解析它们(与 S 相同)。如果您希望 add 等非标准名称映射到现有的 SymPy 名称,例如

,则可以将名称字典作为第二个参数传递给 sympify
sympify('add(x, y)', {'add': Add}) # Gives x + y

否则 sympify 将假设任何未知函数都是未定义的函数,如 f(x)。

Sympy 提供了将字符串转换为 sympy 对象的解析器函数,请参阅文档 parse_expr

对于自定义函数翻译,您可以使用 sympy 提供的映射映射,并将其作为参数 local_dict 传递给解析器。

from sympy import Add, Mul, sin
from sympy.parsing.sympy_parser import parse_expr

f = parse_expr('add(sin(x1), mul(x1, x1))', local_dict={'add': Add, 'mul': Mul})
f.diff('x1')

输出

2x1 + cos(x1)