2

Using fmin_slsqp, I have to provide

ieqcons : list, optional

A list of functions of length n such that ieqcons[j](x,*args) >= 0.0 in a successfully optimized problem.

Since my problem is quite large, the simple option of writing them explicitly does not work.

def f1(x,arg1,arg2):
     ...
def f2(x,arg1,arg2):
     ...
...

list_func = [f1,f2,...]

There is this question which addresses dynamic and anonymous functions in Python and most of the answer go around parsing the code as a string, which seems totally unnecessary and complicates passing of arguments to the function.

The nature of the constrains list is that a single parameter (the index e.g.) can uniquely identify the function, but all the functions in the list receive the same arguments and it is impossible to make a distinction based on passed arguments.

A construction of this form would be sufficient and painless

def f(x,arg1,arg2,i):
   # return value based on i
   # e.g. # for constrain of form x[i]>=arg1[i] the funct is:
   #        return x[i]-arg1[i]

i = 1
f1 = lambda x,arg1,arg2 : f(x,arg1,arg2,i)
i = 2
f2 = lambda x,arg1,arg2 : f(x,arg1,arg2,i)

Calling f1 and f2 returns the same functions for i=2

However I can not find a solution to make i final in the function definition or restrict its scope, visibility to a particular lambda function.

As a remark, i has to remain a variable since the final solution would look like

list_f =[]
for i in range(0,num_cons):
    list_f.append(lambda x,arg1,arg2 : f(x,arg1,arg2,i))

How can I solve this issue or is there a more simpler and clever way of achieving my goal?

3 Answers 3

2

From what I understand, you can solve it using functools.partial:

from functools import partial

list_f = [partial(f, i=i) for i in range(0, num_cons)]

You can find more information on lambda vs partial here:

Sign up to request clarification or add additional context in comments.

Comments

1

The reason its not working as expected is when you write a lambda expression, it does not call the function; it is called when you evaluate the expression.

So, when you evaluate it, the value of i is 2, hence the same results.

I believe what you need is functools.partial, like this:

from functools import partial

func_call_map = {i: partial(f, i=i) for i in [some range]}

# Get result for i = 4
ret_value = func_call_map[4](other, args, here)

1 Comment

Thank you. It totally makes sense the behaviour now and partial does the job
1

Following @alecxe link on Python: Why is functools.partial necessary? and the explanation provided in the comments of one of the answers, to avoid the late binding (lazy evaluation) explained by @BurhanKhalid, the code would need to be changed as follows

i = 1
f1 = lambda x,arg1,arg2,n_i=i : f(x,arg1,arg2,n_i)
i = 2
f2 = lambda x,arg1,arg2,n_i=i : f(x,arg1,arg2,n_i)

But using functions.partial provides a more elegant solution.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.