Search code examples
pythonpython-2.7lambdalambdify

Lambda of a lambdified function whose argument is a function


I am currently trying to create a lambda function that will pass a variable to both a function that is a input to a lambdified function and to the lambdified function itself. My Python version is 2.7, and my sympy version is 1.3.

I am able to have the lambdify function (f) work correctly when passed the correct argument (Y). I then attempt to create a lambda function that will pass a variable (z) to a function (controlFunc) which will both then be inputted into my lambdify function (f).

The problem seems to be that the lambda function will use the latest lambdify function each iteration (which it should) AND update all the PREVIOUS lambda functions to use the latest lambdify function as well. I believe this isn't an error in my code, but I could easily be wrong.

I have tried setting the lambdify function to a vasriable, and then making a lambda function from that. I have tried using the whole lambdify function in the lambda function. I even attempted to use list comprehension (I believe this is the right term) to evaluate each lambda of a lambdify in a list.

import sympy as sy
import numpy as np
r,s,t,v,w,x,y = sy.symbols('r,s,t,v,w,x,y')

variables = [[t,v,w,x,y]]
inputs = [[r,s]]
L = [[]]
controlledSim = True
ctrl_input = [[10., 10.]]
def controlFunc(x,controlDict):
    return ctrl_input[0]

control = [controlFunc for i in range(10)]
controlDict = []
func = [sy.Matrix([[1.*r*s*t*v*w*x*y],
                   [2.*r*s*t*v*w*x*y],
                   [3.*r*s*t*v*w*x*y],
                   [4.*r*s*t*v*w*x*y],
                   [5.*r*s*t*v*w*x*y]])]

X = [1.,1.,1.,1.,1.]
Y = [1.,1.,1.,1.,1.,10.,10.]

for j in range(len(L)):
    if controlledSim == True:
                    func[j] = list(func[j])
                    temp = [[] for i in range(len(func[j]))]
                    f = [[] for i in range(len(func[j]))]
                    for i in range(len(func[j])):
                        f[i] = sy.lambdify([np.append(variables[j],inputs[j])], func[j][i])
                        temp[i] = lambda z: f[i](np.append(z,control[i](z,controlDict)))
                    func_lambda = lambda z: np.array([lamb(z) for lamb in temp]).T

I know the output of func_lambda(X) should be an array of [100.,200.,300.,400.,500.].

My current results are an array of [500.,500.,500.,500.,500.].


Solution

  • It is pretty common problem with lambda functions inside loops. Lambda expressions are resolved at call-time (not during looping but after). Consider the following slight correction:

    temp[i] = lambda z, i=i: f[i](np.append(z,control[i](z,controlDict)))
    

    i=i is a default argument value so it is resolved at function definition. With this modification func_lambda(X) gives me [100. 200. 300. 400. 500.].

    I use python 3. However this way should work in python 2 too. Try it.