Is there a way to write a replacement rule for a function f with an arbitrary number of arguments that makes it linear in all its arguments? An example for when f has three arguments:
- 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)
Using "Wild" works partially:
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)
I know I could iterate in a variety of ways over the arguments of the function while altering the replacement, but I was hoping the functionality was built into "Wild" or "replace" already. Mathematica, for example, has "wildcards" like "a___,b___,A___,B___" which mean that "a___" could be an empty sequence, or a single argument, or a sequence of multiple arguments. For example, in Mathematica,
expr /. f[a__,A_Plus,b__] :> f[a,A[[1]],b]+f[a,A[[2;;]],b]
would correctly simplify both test cases, and for f's with any number of arguments.
Is there something similar, or is this is close as sympy gets?
Alternatively, might this be possible to do with argument unpacking on a recursive definition starting from something like def f(*args):?