1

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.].

  • "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." No, it's just that Python (and most languages nowadays) use lexically scoped closures, so your `temp` variable in all the lambdas you create is always referring to the same `temp` – juanpa.arrivillaga Jul 11 '19 at 23:26
  • @juanpa.arrivillaga Since I am storing each 'f' and 'temp' function externally of the loop where they are created, how would the 'temp' function refer to the same 'f' function and updated the other 'temp' functions with each iteration? – James Faunda Jul 11 '19 at 23:50
  • *they are all referring to the same variable* – juanpa.arrivillaga Jul 12 '19 at 00:10

1 Answers1

1

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.