Есть ли способ написать правило замены для функции f с произвольным числом аргументов, которое делает ее линейной по всем аргументам?
Пример, когда f имеет три аргумента:
- f (x1 + x4, x2, x3) = f (x4, x2, x3) + f (x1, x2, x3)
- f (x1, x2 + x4, x3) = f (x1, x2, x3) + f (x1, x4, x3)
- f (x1, x2, x3 + x4) = f (x1, x2, x3) + f (x1, x2, x4)
Использование «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):
?