2017-04-22 86 views
1

我正在編寫一個程序,要求用戶輸入表達式。此表達式作爲字符串輸入,並使用parse_expr轉換爲Sympy表達式。然後我需要獲取用戶輸入的表達式的偏導數。但是,diff在我測試的每個表達式都返回0。解析的SymPy表達式的衍生值始終爲0

例如,如果用戶輸入a*exp(-b*(x-c)**(2)),使用下面的代碼,diff返回0當它應該(據我知道diff)取偏導數時相對於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 

我在做什麼錯?

回答

1

底線:使用parse_expr(str_expr,locals())

加上global_dict=<dict of allowed entities to use>如果該表達式可能使用任何未導入到本地名稱空間且不可訪問的實體with the default from sympy import *


根據Calculus — SymPy Tutorial - SymPy 1.0.1.dev documentation,鍵入符號表達式入diff()參數原樣。由於這些字母是Symbol對象(帶有重載操作符),因此在評估參數時,Python被誘騙構建與該表達式相對應的SymPy對象!

因此,如果你有它作爲一個字符串,你eval它來觸發相同的行爲:

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

eval是一個安全隱患,如果有不可信的輸入使用,因爲它接受任意Python代碼。

這就是parse_expr這樣的替代品發揮作用。但是,由於表達式被解析的方式(如上所述),它需要訪問表達式中使用的外部實體 - 例如通過參數local_dictglobal_dict來訪問所使用的命名函數的變量和函數對象的Symbol對象。

否則,它會即時創建Symbol對象。也就是說,表達式中爲x創建的Symbol對象與變量x不同!難怪它的衍生物是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 
0

替換a, b, c, x = symbols('a b c x', real=True)有:

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

它不是代替'symbol'->'Symbol'使它工作的替代品。這是「真實=真」的省略。 'Symbol('x')'恰好等於'x'的'Symbol'對象,當'parse_expr'沒有在參數中傳遞時隱式創建',如[我的答案]中所述(http://stackoverflow.com /一個/648265分之43554892)。 –

+1

所以,你只是幸運,這不是正確的做法。 –

1

工作正在進行使sympifyeval安全。最好使用類似以下內容:

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) 

結果:

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

'sympify'和'parse_expr'有什麼區別?他們似乎也在做同樣的事情。 'sympify'甚至似乎不太安全,因爲它似乎只是試圖清理字符串,而'parse_expr'是一個完整的專用解析器。 –

+0

我在評論你答案的第一個版本,比較'sympify'和'eval'。另外,請注意,我寫道,這項工作*正在進行*。我問Sympy聊天sympify是否可以變得更安全,並且做了一些努力來實現這一點。 –

0

符號與不同的假設比較不平等:

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

當您使用sympifyparse_expr,它解析未知變量沒有假設的符號。在你的情況下,這會創建Symbol('x'),這與您已創建的Symbol('x', real=True)不同。

解決方法是要麼刪除的假設,或包括locals()字典,當你解析,以便它能夠識別的名稱x爲您已經定義的Symbol('x', real=True),像

parse_expr(str_expr,locals()) 

sympify(str_expr, locals())