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.].
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.
Related
def square(x):
return lambda x: x**2
object = (1,2,3)
print (object[0])
print (square(object[0]))
output =
1,
<function square.. at 0x03494F10>
Why did the square not work for the tuple element?
Square is returning a pointer to a function, if you want to actually execute the function, you should write:
print (square(object[0])())
lambda is the syntax to create an anonymous function.
square = lambda x: x**2
is equivalent to...
def square(x):
return x**2
The latter is preferred for clarity and is how your code ought to have looked. You aren't usually supposed to assign your lambda expressions to names like square - they are a convenience for those times when you're supposed to pass a function as an input to something else and want to define one in-place - but nothing actually prevents you from doing so.
If you check the printed output you'll see that it is in fact telling you that it's returned a function.
I have come across this example from Python hitchhikers guide:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
The example above is the solution to some issues caused with late binding, where variables used in closures are looked up at the time the inner function is called.
What does the i=i mean and why is it making such difference?
It's actually not just for lambdas; any function that takes default parameters will use the same syntax. For example
def my_range(start, end, increment=1):
ans = []
while start < end:
ans.append(start)
start += increment
return ans
(This is not actually how range works, I just thought it would be a simple example to understand). In this case, you can call my_range(5,10) and you will get [5,6,7,8,9]. But you can also call my_range(5,10,increment=2), which will give you [5, 7, 9].
You can get some surprising results with default arguments. As this excellent post describes, the argument is bound at function definition, not at function invocation as you might expect. That causes some strange behavior, but it actually helps us here. Consider the incorrect code provided in your link:
def create_multipliers():
return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
print multiplier(2)
When you call multiplier(2), what is it actually doing? It's taking your input parameter, 2, and returning i * 2. But what is i? The function doesn't have any variable called i in its own scope, so it checks the surrounding scope. In the surrounding scope, the value of i is just whatever value you left it -- in this case 4. So every function gives you 8.
On the other hand, if you provide a default parameter, the function has a variable called i in its own scope. What's the value of i? Well, you didn't provide one, so it uses its default value, which was bound when the function was defined. And when the function was defined, i had a different value for each of the functions in your list!
It is a bit confusing that they've used the same name for the parameter variable as they did for the iterating variable. I suspect you could get the same result with greater readability with
def create_multipliers():
return [(lambda x, y=i: y*x) for i in range(5)]
In that case, each number in the range, will be assigned to the optional parameters of each lambda function:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
lambda x, i=0
lambda x, i=1
lambda x, i=2
lambda x, i=3
lambda x, i=4
So, you can call the functions now with one parameter (because they already have the default)
for f in create_multipliers():
print(f(3))
0
3
6
9
12
Or you can call the function and give the parameter you want, that's why is optional
for f in create_multipliers():
print(f(3,2))
6
6
6
6
6
There are examples where optional parameter are needed, such as recursion
For example, square in terms of square:
square = lambda n, m=0: 0 if n==m else n+square(n,m+1)
Look that the optional parameter there is used as accumulator
I'm trying to write a function in Python for a polynomial p that is a linear combination of n basis functions phi_i. How can I define a function that is itself a sum of n other functions?
I know that this works:
phi1 = lambda x: x**2
phi2 = lambda x: x
p = lambda x: phi1(x) + phi2(x)
But if I try a loop like this:
p = lambda x: 0
for i in range(0,n):
p = lambda x: p(x)+phi[i](x)
where phi is a list of my basis functions, I create an infinite loop.
I checked Writing a function that is sum of functions, but unfortunately that's not in Python.
You can do this by passing a simple generator expression to sum:
def sigma(funcs, x):
return sum(f(x) for f in funcs)
phi = [lambda x: x**2, lambda x: x]
y = sigma(phi, x)
BTW, it's considered bad style to use lambda for named functions, it's supposed to be for anonymous functions.
If you want a function that doesn't need phi to be passed in each time you call it, there are a couple of ways to do that. The easiest way is to simply use phi in the function. Eg,
def sigma(x):
return sum(f(x) for f in phi)
However, that has a couple of downsides. It won't work if phi isn't in the scope where you call sigma; you can get around that by making phi global, but that may not be convenient, and it's best to avoid globals when they aren't necessary. The other downside is that it uses the current contents of phi, not the contents it had when sigma was defined, so if you modify the contents of phi those changes will be reflected in sigma, which may or may not be desirable.
Another option is to use a closure to create the function. Then we won't be affected by the scope issue: you can call the resulting summing function inside a scope where the original function list isn't visible. We can also create a copy of the function list, so it won't be affected by changes to the passed-in function list.
def make_adder(funcs):
# Copy the function list
funcs = funcs[:]
def sigma(x):
return sum(f(x) for f in funcs)
return sigma
phi = [lambda x: x**2, lambda x: x]
sigma = make_adder(phi)
y = sigma(x)
Yet another option is to use my original sigma and pass it and the phi functions to functools.partial, eg
from functools import partial
sig = partial(sigma, phi)
y = sig(x)
Straight answer to OP
Store your phis in a list:
phis = [
lambda x: x**2,
lambda x: x,
]
p = lambda x: sum(phi(x) for phi in phis)
Further considerations
If you want to achieve a polynomial, I would suggest something similar to this:
def poly(c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
poly function accepts a sequence as the only argument, where its elements need to be int or float. The first element is assigned as the coeficient of x^0, the second to x^1 and so on. So your example (p(x) = x + x^2) would end up being constructed like this: p = poly([0, 1, 1])
Another option is to accept any number of arguments where each of them needs to be a int or float instead of the first being a sequence. This would only require to add one * to the function declaration.
def poly(*c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
To construct your example with this function you would not require the list: p = poly(0, 1, 1).
Any of those methods would create a polynomic function that can be called as you would expect: p(1) would return 2, p(2) would return 6 and so on.
Function explained
def poly(c):
# Create a list where we are gonna store the functions for every term in the polynomial
terms = []
# Create as many terms as the arguments length
for i in range(len(c)):
# Each term is the product of the nth coefficient from c and x to the power of n
terms.append(lambda x, n=i: c[n]*x**n)
# The second parameter n is needed because if we pass i directly
# inside the function algorithm, Python wouldn't check its value
# inmediately, but when it gets executed, and by then the loop will
# be finished and i would be constant for every term. This argument
# is not exposed to the polynomial function as the next lambda only
# has one argument, so there is no way to wrongly call this function
# We return a function that adds the result of every term
return lambda x: sum(f(x) for f in terms)
I should probably start by saying that I am relatively new to python, but I have coded in java and Matlab before.
In python, the code
def func(f):
return f
g = func(cos)
print(g(0))
gives the result
>1.0
as g now is defined as the cosine function.
I want to write a function that calculates the derivative of any provided function using a finite difference approach. The function is defined as
def derivator(f, h = 1e-8):
and would like to achieve the follwing:
g = derivator(cos)
print(g(0)) # should be about 0
print(g(pi/2)) # should be about -1
At the moment my derivator function looks like this
def derivator(f, h = 1e-8):
return (f(x+h/2)-f(x-h/2))/h
which definitely is wrong, but I am not sure how I should fix it. Any thoughts?
Your current derivator() function (which should probably be called differentiator()) uses an undefined variable x and would return a single value, if x were defined--the value of f'(x). You want to return a function that takes an x value. You can define an inner function and return it:
def fprime(x):
return (f(x+h/2)-f(x-h/2))/h
return fprime
Because you don't use that function anywhere else, though, you can use lambda instead, which is also shorter:
return lambda x: (f(x+h/2)-f(x-h/2))/h
The only thing PEP 8 says about lambdas is that you should not assign the result of the lambda to a variable, then return it:
fprime = lambda x: (f(x+h/2)-f(x-h/2))/h # Don't do this!
return fprime
Make an inner function inside your derivator function and return it:
from math import cos, pi
def derivator(f, h = 1e-8):
def g(x):
return (f(x+h/2)-f(x-h/2))/h
return g
g = derivator(cos)
print(g(0)) # 0.0
print(g(pi/2)) # -0.999999993923
f and h will be part of the closure of the returned function.
You can also return a lambda expression to make it one line:
return lambda x: (f(x+h/2)-f(x-h/2))/h
I'm trying to return from a function a list of functions, each of which uses variables from the outside scope. This isn't working. Here's an example which demonstrates what's happening:
a = []
for i in range(10):
a.append(lambda x: x+i)
a[1](1) # returns 10, where it seems it should return 2
Why is this happening, and how can I get around it in python 2.7 ?
The i refers to the same variable each time, so i is 9 in all of the lambdas because that's the value of i at the end of the loop. Simplest workaround involves a default argument:
lambda x, i=i: x+i
This binds the value of the loop's i to a local variable i at the lambda's definition time.
Another workaround is to define a lambda that defines another lambda, and call the first lambda:
(lambda i: lambda x: x+i)(i)
This behavior makes a little more sense if you consider this:
def outerfunc():
def innerfunc():
return x+i
a = []
for i in range(10):
a.append(innerfunc)
return a
Here, innerfunc is defined once, so it makes intuitive sense that you are only working with a single function object, and you would not expect the loop to create ten different closures. With a lambda it doesn't look like the function is defined only once, it looks like you're defining it fresh each time through the loop, but in fact it is functionally the same as the the long version.
Because i isn't getting evaluated when you define the anonymous function (lambda expression) but when it's called. You can see this by adding del i before a[1](1): you'll get NameError: global name 'i' is not defined on the a[1](1) line.
You need to fix the value of i into the lambda expression every time, like so:
a = [lambda x, i=i: x+i for i in range(10)]
a[1](1) # returns 2
Another, more general solution - also without lambdas:
import operator
from functools import partial
a = []
for i in range(10):
a.append(partial(operator.add, i))
a[1][(1) # returns 2
The key aspect here is functools.partial.