Search code examples
pythonpattern-matchingsympysymbolic-math

Using sympy.replace and Wild symbols to match and substitute arbitrary functions


Is it possible with sympy Wild symbols and replace to match arbitrary function applications?

What I would ideally like to do is the following:

x = Symbol('x')
expr1 = sin(x)
expr2 = exp(x)
F = Wild('F') #or maybe WildFunction('F')?
result1 = expr1.replace(F(x), lambda F: F(tan(x)))    #expected: sin(tan(x))
result2 = expr2.replace(F(x), lambda F: F(tan(x)))    #expected: exp(tan(x))

Unfortunately this does not work: it throws a TypeError since Wild symbols are not callable. So is there a way to make this work? Note that I really don't want to match and replace specific functions, nor do I want to match and replace symbolic functions like Function('f'). I want to match and replace arbitrary (sympy?) functions like sin, exp, im, tan, re, conjguate and so on.

What does work is

F = WildFunction('F')
result1 = expr1.replace(F, lambda F: F.func(*F.args))

But it feels a little unnatural and fragile.

Thank you!


Solution

  • Yes, but you're looking for Wild's properties argument and can use the type() of the match to nest a function call

    >>> F = Wild("F", properties=[lambda F: F.is_Function])
    >>> expr1.replace(F, lambda F: type(F)(tan(x)))
    sin(tan(x))
    

    Or to be more picky about which functions are replaced

    >>> F = Wild("F", properties=[lambda F: type(F) in [sin,tan,cos]])
    >>> (sin(x) + cosh(x) + cos(x)).replace(F, lambda F: type(F)(csc(x)))
    sin(csc(x)) + cos(csc(x)) + cosh(x)
    

    A somewhat shameless plug, but check out my other Answer about how .replace et al. behave (also links to more on Wild)!