有没有办法为函数f编写一个替换规则,其中包含任意数量的参数,使其在所有参数中都是线性的? f有三个参数的例子:
使用“Wild”部分工作:
from sympy import *
f=Function('f')
var("x1:5")
a=Wild("a")
b=Wild("b")
A=Wild('A', exclude=[0])
B=Wild('B', exclude=[0])
expr=f(x1,x2+x4,x3);
print("This one works")
print expr , '->' , expr.replace(f(a,Add(A,B),b),f(a,A,b)+f(a,B,b))
# f(x1, x2 + x4, x3) -> f(x1, x2, x3) + f(x1, x4, x3)
print("This one doesn't on the last entry")
expr=f(x1,x2,x3+x4);
print f(x1,x2,x3+x4) , '->' , expr.replace(f(a,Add(A,B),b),f(a,A,b)+f(a,B,b))
# f(x1, x2, x3 + x4) -> f(x1, x2, x3 + x4)
我知道我可以通过各种方式迭代函数的参数,同时改变替换,但我希望功能已经内置到“Wild”或“replace”中。例如,Mathematica有“通配符”,如“a ___,b ___,A ___,B ___”,这意味着“a ___”可以是空序列,也可以是单个参数,也可以是多个参数的序列。例如,在Mathematica中,
expr /. f[a__,A_Plus,b__] :> f[a,A[[1]],b]+f[a,A[[2;;]],b]
会正确地简化两个测试用例,并且f
包含任意数量的参数。
是否有类似的东西,或者这是否接近,因为有同情心?
或者,这可能与从def f(*args):
开始的递归定义上的参数解包有关吗?
答案 0 :(得分:0)
而不是Wild匹配,我会检测f的哪些参数是Add,并使用itertools.product
扩展它们
import itertools
term_groups = [term.args if term.func is Add else (term,) for term in expr.args]
expanded = Add(*[expr.func(*args) for args in itertools.product(*term_groups)])
例如,如果expr
为f(x1+x2+x4, x2+x4, x3*x1)
,则term_groups
为[(x1, x2, x4), (x2, x4), (x1*x3,)]
,其中最后一个参数产生1个元素元组,因为它不是Add。 expanded
是
f(x1, x2, x1*x3) + f(x1, x4, x1*x3) + f(x2, x2, x1*x3) + f(x2, x4, x1*x3) + f(x4, x2, x1*x3) + f(x4, x4, x1*x3)