How can I evaluate an array of lambda functions - python

I am trying to write a function that will create a list of lambda functions and then passing an array to this list.
I figured out how to hard code this function list, however, I cannot seem to figure out how to use a for loop to create the list.
For example, let's take a very simple function where we multiply every element of A by 1, then 2, then 3, ... and so on so that each row corresponds to the element of A and each column corresponds to the number at which A is multiplied by.
import numpy as np
A = np.array([1,2,3,4])
def f():
F3 = lambda x: 3*x
F2 = lambda x: 2*x
F1 = lambda x: 1*x
F0 = lambda x: 0*x
return lambda x: np.stack((F3(x),F2(x),F1(x),F0(x)),axis=1)
F = f()
F(A)
My output is then.
array([[ 3, 2, 1, 0],
[ 6, 4, 2, 0],
[ 9, 6, 3, 0],
[12, 8, 4, 0]])
The code above only goes to 3*x. What would I do if I want to follow the pattern to n*x? My basic idea would be as follows (however, this does not work):
import numpy as np
A = np.array([1,2,3,4])
def _f():
return lambda x: n*x
def f(N):
F = []
for n in range(N):
F.append(lambda x: _f(n))
return np.array(F)
F = f(5)
F(A)
In real life, my function _f() is far more complicated. The motivation behind this is that I would rather have my program iterate through each _f only once and then perform the calculation F(A) in one shot.
The desired output of can be achieved by the following code, however, this will iterate through the loop each time F is called.
import numpy as np
A = np.array([1,2,3,4])
def _f(n,x):
return n*x
def f(N,x):
F = []
for n in range(N):
F.append(_f(n,x))
return np.array(F)
F = f(5,A)
print(F.T)
This would return:
[[ 0 1 2 3 4]
[ 0 2 4 6 8]
[ 0 3 6 9 12]
[ 0 4 8 12 16]]

This loop is broken:
for n in range(N):
F.append(lambda x: _f(n))
because n is lazily read in the body of the function (so all the functions stored read the final value of n from the loop).
The easiest fix is to bind n as a default argument; default arguments are bound eagerly at definition time:
for n in range(N):
F.append(lambda x, n=n: _f(n))
^^^^^ Changed part
If you want to avoid the default argument, make your factory function do the eager binding for you:
def _f(n): # Now receives n as an argument to outer function
return lambda x: n*x # While inner function uses n from closure and x passed when called
then use it with:
for n in range(N):
F.append(_f(n))

_f (properly defined; it should take n as an argument rather than treating n as a global variable) is already the function which, when called, returns your desired function.
# Or _f = lambda n: lambda x: n * x
def _f(n):
return lambda x: n * x
F = [_f(n) for n in range(N)]
That said, you can avoid lambda expressions and their scoping issues altogether by using functools.partial:
from functools import partial
from operator import mul
F = [partial(mul, n) for n in range(N)]

Related

How to pass multiple variables to a function in Python (used in packages such as PSO and GA)

some packages in Python use functions (def) as a objective function or fitness function for optimization problems, such as https://pypi.org/project/pyswarms/ and https://pypi.org/project/geneticalgorithm/
For example
def f(X):
return np.sum(X)
This is the default setup for the package and I cannot define:
def f(X, Y):
return np.sum(X) + np.sum(Y)
These functions have only X as input and I wonder how could I use more than one variable as input (x and y for example), or even variables with multiple indexes.
I was able to solve some problems converting multiple variables in a single array; however, that is a hard work in my point of view.
Can someone, please, provide any tip in this subject?
Thank you
I suggest to take a look into map().
https://docs.python.org/3/library/functions.html#map
The map() function applies a given function to each item of an iterable (list, tuple etc.) and returns an iterator.
def func(a):
return a*a
cluster = [5,10,15,20]
list(map(func, cluster))
[25, 100, 225, 400]
or also, with lambda functions:
numbers = [1, 2, 3, 4, 5]
squared = map(lambda num: num ** 2, numbers)
list(squared)
[1, 4, 9, 16, 25]
According to the geneticalalgorithm's documentation:
Notice that we define the function f so that its output is the objective function we want to minimize where the input is the set of X (decision variables).
Example from the documentation (chapter 'Optimization problems with constraints'):
def f(X):
pen = 0
if X[0] + X[1] < 2:
pen = 500 + 1000 * (2 - X[0] - X[1])
return np.sum(X) + pen
varbound = np.array([[0, 10]] * 3)
model = ga(function=f, dimension=3, variable_type='real', variable_boundaries=varbound)
model.run()
Solution for your example:
def f(X):
return np.sum(X[0]) + np.sum(X[1])

Iteration over multiple maps

I have a question about how Python(3) internally loops when computing multiple maps. Here's a nonsense example:
from random import randint
A = [randint(0,20) for _ in range(100)]
map1 = map(lambda a: a+1, A)
map2 = map(lambda a: a-1, map1)
B = list(map2)
Because map() produces a lazy expression, nothing is actually computed until list(map2) is called, correct?
When it does finally do this computation, which of these methods is it more akin to?
Loop method 1:
A = [randint(0,20) for _ in range(100)]
temp1 = []
for a in A:
temp1.append(a+1)
B = []
for t in temp1:
B.append(t-1)
Loop method 2:
A = [randint(0,20) for _ in range(100)]
B = []
for a in A:
temp = a+1
B.append(temp-1)
Or does it compute in some entirely different manner?
In general, the map() function produces a generator, which in turn doesn't produce any output or calculate anything until it's explicitly asked to. Converting a generator to a list is essentially akin to asking it for the next element until there is no next element.
We can do some experiments on the command line in order to find out more:
>>> B = [i for i in range(5)]
>>> map2 = map(lambda b:2*b, B)
>>> B[2] = 50
>>> list(map2)
[0, 2, 100, 6, 8]
We can see that, even though we modify B after creating the generator, our change is still reflected in the generator's output. Thus, it seems that map holds onto a reference to the original iterable from which it was created, and calculates one value at a time only when it's asked to.
In your example, that means the process goes something like this:
A = [2, 4, 6, 8, 10]
b = list(map2)
b[0] --> next(map2) = (lambda a: a-1)(next(map1))
--> next(map1) = (lambda a: a+1)(next(A))
--> next(A) = A[0] = 2
--> next(map1) = 2+1 = 3
--> next(map2) = 3-1 = 2
...
In human terms, the next value of map2 is calculated by asking for the next value of map1. That, in turn, is calculated from A that you originally set.
This can be investigated by using map on functions with side-effects. Generally speaking, you shouldn't do this for real code, but it's fine for investigating the behaviour.
def f1(x):
print('f1 called on', x)
return x
def f2(x):
print('f2 called on', x)
return x
nums = [1, 2, 3]
map1 = map(f1, nums)
map2 = map(f2, map1)
for x in map2:
print('printing', x)
Output:
f1 called on 1
f2 called on 1
printing 1
f1 called on 2
f2 called on 2
printing 2
f1 called on 3
f2 called on 3
printing 3
So, each function is called at the latest time it could possibly be called; f1(2) isn't called until the loop is finished with the number 1. Nothing needs to be done with the number 2 until the loop needs the second value from the map.

Apply function taking one argument to a value in Python

I don't really get how that works, why is 10 not an variable of the function? I never saw a case where you would apply a function to an item outside of that function. I don't want the answer to the problem, just want to understand it.
Thanks guys
Write a function called general_poly, that meets the specifications below.
For example, general_poly([1, 2, 3, 4])(10) should evaluate to 1234 because 1∗103+2∗102+3∗101+4∗100
So in the example the function only takes one argument with general_poly([1, 2, 3, 4]) and it returns a function that you can apply to a value, in this case x = 10 with general_poly([1, 2, 3, 4])(10).
It's asking you for general_poly to return a function, e.g.:
def general_poly(L):
def inner(x):
return sum(x+e for e in L)
return inner
general_poly([1,2,3,4])(10)
# 11+12+13+14 = 50
This should give you enough to be able to work through your homework.
def general_poly (L):
""" L, a list of numbers (n0, n1, n2, ... nk)
Returns a function, which when applied to a value x, returns the value
n0 * x^k + n1 * x^(k-1) + ... nk * x^0 """
def inner(x):
L.reverse()
return sum(e*x**L.index(e) for e in L)
return inner

function making

Hi I am new to functional programming. What i did is
>>> g=lambda x:x*2
>>> f=g
>>> g=lambda x:f(f(x))
>>> g(9)
36
Now, it is not creating g as a nonterminating recursive function - g(x) is transformed to a new function which gives the result g(g(x)).
>>> f=g
>>> g=lambda x:f(f(x))
>>> f(8)
RuntimeError: maximum recursion depth exceeded
I expected g to be transformed into a function which gives the result g(g(g(x))), according to the first definition of g(x). Why does it not? Is it possible to make a new function which results in g(g(g(...(g(x))....))) for a certain number of iterations in this way?
When you do f = g for the second time, f becomes lambda x: f(x). Closures are created by name, not by value.
This becomes easy with a helper function:
def compose(f, g):
return lambda x: f(g(x))
square = lambda x:x*2
g = square
for i in xrange(4):
g = compose(g, square)
In python, variables are names mapped to values, not values themselves (everything is a reference). Also, you can think of lambda as storing text that can be evaluated. The following will illustrate
a = 2
f = lambda x: a*x
f(2) # This gives 4
a = 3
f(2) # This gives 6
This should clear up why you are getting infinite recursion.
In answer to your question about recursing, here is a little hack that might do
g = lambda x, n: n > 0 and g(x, n-1)**2 or x
Then g(2,3) would be (((2)^2)^2)^2 = 256.
This
g=lambda x:x*2
f=g
g=lambda x:f(x)
is equivalent to:
f=lambda x:x*2
g=lambda x:f(x)
When you call g, you get whatever f happens to be defined in the global (or enclosing) scope.
what you're expecting is something like:
f=lambda x:x*2
g=lambda x, f=f:f(x)
That captures the value of f in the outer scope at the time the lambda expression is evaluated.

Repeated Function Application

I'm having trouble with a question which follows: Write a recursive function repeatedlyApply that takes as arguments a function
f of one argument and a positive integer n. The result of repeatedlyApply is a function of one argument that applies f to that argument n times.
So, for example, we would have
repeatedlyApply(lambda x: x+1,10)(100) ==> 110
You may assume that the following function has been defined. You don't have to use it, but it can contribute to a pretty solution.
def compose(f,g):
return lambda x: f(g(x))
So far i've written this
def compose(f,g):
return lambda x: f(g(x))
def recApply(f,n):
for i in range(n):
return recApply(compose(f,f), n-1)
return f
I'm going wrong somewhere because using the above example recApply(lambda x: x+1,10)(100) i get 1124.
Help much appreciated
Correct answer is:
def recApply(func, n):
if n > 1:
rec_func = recApply(func, n - 1)
return lambda x: func(rec_func(x))
return func
And the output:
>>>> print recApply(lambda x: x+1,10)(100)
110
Your function needs some work:
You have a return inside your for loop, so you return immediately instead of running the loop.
You have a recursive call inside your for loop, so you are doing a bit too much iteration. Choose one or the other.
Be careful when you stack function compositions on top of each other, you are doing power composition rather than linear composition.
Can you tell us what precisely you are trying to do?
EDIT: Since everybody else is posting an answer:
recApply = lambda f, n: lambda x: x if n == 0 else recApply(f, n-1)(f(x))
I have a solution based on lambdas:
>>> f = lambda x: x + 10
>>> iterate = lambda f, n, x : reduce(lambda x, y: f(x), range(n), x)
>>> iterate(f, 10, 3)
103
>>> iterate(f, 4, 4)
44
>>> f10 = lambda x: iterate(f, 10, x)
>>> f10(5)
105
I assume this is an exercise of some sort. There are a few ways you could do it, here's a short one:
>>> repeatedlyApply = lambda f, n: reduce(lambda f1, f2: compose(f1, f2), [f]*n)
>>> repeatedlyApply(lambda x: x+1,10)(100)
110

Categories