简体   繁体   English

解析的SymPy表达式的导数始终为0

[英]Derivative of a parsed SymPy expression is always 0

I am writing a program that requires the user to enter an expression. 我正在编写一个要求用户输入表达式的程序。 This expression is entered as a string and converted to a Sympy expression using parse_expr . 该表达式作为字符串输入,并使用parse_expr转换为Sympy表达式。 I then need to take the partial derivative of that expression that the user entered. 然后,我需要采用用户输入的表达式的偏导数。 However, diff is returning 0 with every expression I am testing. 但是, diff正在测试的每个表达式都返回0。

For example if the user enters a*exp(-b*(xc)**(2)) , using the following code, diff returns 0 when it should (as far as I know about diff ) return 2*a*b*(c - x)*exp(-b*(x - c)**2) when taking the partial derivative with respect to x : 例如,如果用户输入a*exp(-b*(xc)**(2)) ,则使用以下代码,当diff应该返回2*a*b*(c - x)*exp(-b*(x - c)**2)时(据我所知diff ), diff返回0 2*a*b*(c - x)*exp(-b*(x - c)**2)相对于x取偏导数时2*a*b*(c - x)*exp(-b*(x - c)**2)

a, b, c, x = symbols('a b c x', real=True)
str_expr = "a*exp(-b*(x-c)**(2))"
parsed_expr = parse_expr(str_expr)
result = diff(parsed_expr, x)
print(result) # prints 0

What am I doing wrong? 我究竟做错了什么?

Bottom line: use parse_expr(str_expr,locals()) . 底线:使用parse_expr(str_expr,locals())

Add global_dict=<dict of allowed entities to use> , too, if the expression may use any entities not imported into the local namespace and not accessible with the default from sympy import * . 如果表达式可以使用未导入到本地名称空间中且无法使用from sympy import *的默认值访问的任何实体,则也添加global_dict=<dict of allowed entities to use>


According to Calculus — SymPy Tutorial - SymPy 1.0.1.dev documentation , you type the symbolic expression into the diff() argument as-is. 根据微积分-SymPy教程-SymPy 1.0.1.dev文档 ,您可以按原样diff()参数中键入符号表达式。 Due to the fact that the letters are Symbol objects (with overridden operators), Python is tricked into constructing the SymPy object corresponding to the expression as it evaluates the argument! 由于字母是Symbol对象(带有重写的运算符),因此Python在计算参数时被欺骗构造与表达式相对应的SymPy对象!

Thus, if you have it as a string, you eval it to trigger the same behaviour: 因此,如果将其作为字符串,则可以eval它以触发相同的行为:

<...>
>>> s="a*exp(-b*(x-c)**(2))"
>>> diff(eval(s), x)
−ab(−2c+2x)e−b(−c+x)2

But eval is a security hazard if used with untrusted input because it accepts arbitrary Python code. 但是,如果eval与不受信任的输入一起使用,则会造成安全隐患,因为它接受任意Python代码。

This is where replacements like parse_expr come into play. 这是诸如parse_expr替代品发挥作用的地方。 However, due to the way expressions are parsed, described above, it needs access to the external entities used in the expression - like the Symbol objects for variables and function objects for the named functions used - through the local_dict and global_dict arguments. 但是,由于如上所述解析表达式的方式,它需要通过local_dictglobal_dict参数访问表达式中使用的外部实体,例如变量的Symbol对象和所使用的命名函数的function对象。

Otherwise, it creates the Symbol objects on the fly. 否则,它将动态创建Symbol对象。 Which means, the Symbol object it has created for x in the expression is different from the variable x ! 这意味着,它为表达式中的x创建的Symbol对象与变量x不同! No wonder that the derivative over it is 0! 难怪它的导数是0!

<...>
>>> ps=parse_expr(s)
>>> ps.free_symbols
{a,b,c,x}
>>> x in _
False
>>> diff(ps,x)
0

>>> ps=parse_expr(s,locals())
>>> x in ps.free_symbols
True
>>> diff(ps,x)
-ab(−2c+2x)e−b(−c+x)2

Work is ongoing to make sympify safer than eval . 使sympifyeval更安全的工作正在进行中。 Better to use something like the following: 最好使用如下所示的内容:

from sympy import *

var ('a b c x')

str_expr = "a*exp(-b*(x-c)**(2))"
parsed_expr = sympify(str_expr)
result = diff(parsed_expr, x)
print(result) 

Result: 结果:

-a*b*(-2*c + 2*x)*exp(-b*(-c + x)**2)

Replace a, b, c, x = symbols('abc x', real=True) with: a, b, c, x = symbols('abc x', real=True)替换为:

a = Symbol('a')
b = Symbol('b')
c = Symbol('c')
x = Symbol('x')

Symbols with different assumptions compare unequal: 具有不同假设的符号比较不相等:

>>> Symbol('x') == Symbol('x', real=True)
False

When you use sympify or parse_expr , it parses unknown variables as symbols without assumptions. 当您使用sympifyparse_expr ,它将在不假设的情况下将未知变量解析为符号。 In your case, this creates Symbol('x') , which is considered distinct from the Symbol('x', real=True) you already created. 在您的情况下,这将创建Symbol('x') ,这被认为与您已经创建的Symbol('x', real=True)

The solution is to either remove the assumptions, or include the locals() dictionary when you parse, so that it recognizes the name x as being the Symbol('x', real=True) that you already defined, like 解决方案是删除假设,或者在解析时包括locals()字典,以便它将名称x识别为您已经定义的Symbol('x', real=True) ,例如

parse_expr(str_expr,locals())

or 要么

sympify(str_expr, locals())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM