Search code examples
pythonsympylambdify

sympy lambdify with function arguments in tuple?


Suppose you have computed fu as a result of a sympy calculation:

fu= sy.cos(x)+sy.sin(y)+1

where

x,y = sy.symbols("x y")

are symbols. Now you want to turn fu to a numpy function of (obviously) two variables. You can do this by:

fun= sy.lambdify((x,y), fu, "numpy")

and you produce fun(x,y). Is there a way that lambdify can produce fun(z) with x,y=z, i.e produce the following function:

def fun(z):
   x,y=z
   return np.cos(x)+np.sin(y)+1   

Solution

  • According to the documentation of lambdify you can nest the symbols in the first argument to denote unpacking in the signature:

    import sympy as sym
    
    x,y = sym.symbols('x y')
    fu = sym.cos(x) + sym.sin(y) + 1
    
    # original: signature f1(x, y)
    f1 = sym.lambdify((x,y), fu)
    f1(1, 2)  # returns 2.4495997326938213
    
    # nested: signature f2(z) where x,y = z
    f2 = sym.lambdify([(x,y)], fu)
    f2((1, 2))  # returns 2.4495997326938213
    

    Even if this weren't possible to do within lambdify, we could define a thin wrapper that unpacks the arguments to the lambdified function (although this would be one function call slower on each call, so for fast functions that get called a lot of times this might lead to measurable impact on the runtime):

    f = sym.lambdify((x,y), fu)  # signature f(x,y)
    def unpacking_f(z):  # signature f(z) where x,y = z
        return f(*z)
    

    Of course if the function is not for a single, throw-away use in a numerical solver (such as curve fitting or minimization), it's good practice to use functools.wraps for wrappers. This would preserve the docstring automatically generated by lambdify.