Search code examples
pythonscipyscipy-optimize-minimize

How to keep certain parameters unchanged in lambda expression


Situation: I am using the scipy for an optimization problem. For many constraints are needed, the coefficients are in a pandas.dataframe object. I am trying to input all these constraints using cycles. the problem is in the next cycle, the parameters have been changed, so there is only on constraints remained actually.

to express the problem more clearly, I give an example(in this example, just a few parameters is given. But in the actual situation, maybe there are more than 50 paramters). Step1: the code I used is something as follows: the constraints is w1 + w2 * 2 >= 0; w1 * 3 + w2 * 5 >= 0

cons = []
d = {
        'type': 'ineq', 
        'fun': ''}
a = np.array([1,2])
d['fun'] = lambda w: a.dot(w)
cons.append(d.copy())
a = np.array([3,5])
d['fun'] = lambda w: a.dot(w)
cons.append(d.copy())
cons

Step2: test the cons using the code shown as follows: just using w as [1, 1], I expect the fun stored in cons will output 3 and 8, but actually 8 and 8.

w = np.array([1,1])
for each in cons:
    fun = each['fun']
    print(fun(w))

Can anyone give some help on how to solve this problem? Or it's just something wrong.


Solution

  • The problem is you redefine a.

    This code renames your second definition of a to b and gives the result you expect:

    import numpy as np
    
    cons = []
    d = {
            'type': 'ineq', 
            'fun': ''}
    a = np.array([1, 2])
    d['fun'] = lambda w: a.dot(w)
    cons.append(d.copy())
    b = np.array([3, 5])
    d['fun'] = lambda w: b.dot(w)
    cons.append(d.copy())
    print(cons)
    
    c = np.array([1, 1])
    for each in cons:
        fun = each['fun']
        print(fun(c))
    

    Note that this solves your immediate problem, but it doesn't mean this is an optimal or very robust solution to the problem you're trying to solve.

    I think what you're looking for here is functools.partial. Here's your code, but rewritten to use partial:

    import numpy as np
    from functools import partial
    
    
    def get_dot(a, w):
        return a.dot(w)
    
    
    cons = []
    d = {
        'type': 'ineq',
        'fun': None
    }
    
    d['fun'] = partial(get_dot, np.array([1, 2]))
    cons.append(d.copy())
    
    d['fun'] = partial(get_dot, np.array([3, 5]))
    cons.append(d.copy())
    
    print(cons)
    
    g = np.array([1, 1])
    for each in cons:
        fun = each['fun']
        print(fun(g))