我有一個物件串列,每個物件都是一個數學函式,這些函式可能相互依賴,例如:
[
Formula("G", ["y"], "1 - y"),
Formula("V", ["x", "y"], "G(y) * x / 3"),
Formula("U", ["x", "y"],"(G(y)**2) / (9 * V(x, y)) V(x, y)")
]
其中第一個引數是函式名,第二個是使用的變數串列,第三個是字串 - 函式的運算式。
有沒有一種簡單的方法來評估函式U(x, y)在給定點的值,例如,在 [2, 3] 并遞回呼叫G(3)和V(2, 3),并得到最終結果?
我曾嘗試在 Sympy 中執行此操作,但無法在函式V(x,y)中呼叫例如函式G(y )
uj5u.com熱心網友回復:
感謝您的所有建議。在我給出的示例中,Formulas 是按拓撲順序排列的,但實際上并不總是如此。
我可以使用@Stef 的解決方案,但我必須先格式化公式eval()運算式
x,y = sympy.symbols('x y'); G = 1-y;V = G * x / 3;U = G**2 / (9*V V)
然后@OscarBenjamin 建議使用 sympy parse_expr,它作業得很好,直到我意識到公式并不總是按拓撲順序給出。所以我發現,試圖把它放在拓撲順序然后決議它,會花費太多的執行時間。
最終,我決定制作自己的決議器,它看起來像這樣(測驗類和變數):
import re
import copy
class Formula():
function_name = ""
variables = []
expression = ""
__expr__ = ""
other_func_calls = 0
def __init__(self, function_name:str, variables:list, fun:str) -> None:
self.function_name = function_name
self.variables = variables
self.expression = fun
other_func = []
for i in fun:
if ord(i) in range(ord("A"), ord("Z") 1):
self.other_func_calls = 1
other_func.append(i)
self.__expr__ = re.sub('[A-Z]?\((\w|, )*\)','_TBR_', fun) # _TBR_ is being replaced later
self.other_func = other_func # list of other functions in chronological order
class Pyramid():
name:str
functions:dict[str:Formula]
def __init__(self, name:str, funs:dict[str:Formula]) -> None:
self.name = name
self.functions = funs
def get_result(self, fun:str, values:dict[str:int]):
if (self.functions[fun].other_func_calls == 0): # Function does not call other functions
return eval(self.functions[fun].expression, values)
other_funcs = copy.deepcopy(self.functions[fun].other_func)
s = self.functions[fun].__expr__
for i in range(len(other_funcs)):
other_funcs[i] = self.get_result(other_funcs[i], values)
s = re.sub("_TBR_", f"({str(other_funcs[i])})", s, count=1)
return eval(s, values)
a = {
"V": Formula("V", ["x", "y"], "G(y) * x / 3"),
"U": Formula("U", ["x", "y"], "G(y)**2 / (9 * V(x, y)) V(x, y)"),
"G": Formula("G", ["y"], "1 - y")
}
p = Pyramid("Testing", a)
print(p.get_result("U", {"x":2,"y":3}))
uj5u.com熱心網友回復:
也許是這樣的?
>>> def Formula(*args):
... return parse_expr('{%s(*%s): %s}' % args)
...
>>> f =[
... Formula("G", ["y"], "1 - y"),
... Formula("V", ["x", "y"], "G(y) * x / 3"),
... Formula("U", ["x", "y"],"(G(y)**2) / (9 * V(x, y)) V(x, y)")
... ]
>>> f
[{G(y): 1 - y}, {V(x, y): x*G(y)/3}, {U(x, y): G(y)**2/(9*V(x, y)) V(x, y)}]
f已經是拓撲排序的,所以回替代
>>> from sympy import Dict
>>> e=Dict(f[-1])
>>> e=e.subs(f[-2])
>>> e=e.subs(f[-3])
>>> a,b=dict(e).popitem()
>>> U = Lambda(a.args,b)
>>> U(2,3)
-5/3
如果它沒有排序,你可以使用topological_sort, 也許通過repsort 這里這樣做:
>>> repsort(*[tuple(i.items()) for i in f])
[(U(x, y), G(y)**2/(9*V(x, y)) V(x, y)), (V(x, y), x*G(y)/3), (G(y), 1 - y)]
>>> s = _
>>> expr = s[0][0]
>>> for i in s:
... expr = expr.subs(*i)
...
>>> expr
x*(1 - y)/3 (1 - y)/(3*x)
>>> U = Lambda(tuple(ordered(expr.free_symbols)), _)
>>> U(2,3)
-5/3
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/431630.html
