Reputation: 37
Here is the piece of code that I'm currently running:
def fun_test(x):
return 3*x[0]**2 + x[1] + 4*x[2]
con = [{"type" : "ineq", "fun" : lambda x: fun_test(x)},
{"type" : "ineq", "fun" : lambda x: x[0]-x[1]},
{"type" : "ineq", "fun" : lambda x: x[1]-x[2]},]
res = minimize(fun_test, method='COBYLA', x0=[3, 3, 3], constraints=con)
print("Resulting factors:",res.x)
So here, I'm optimizing the factors of fun_test with the conditions that x[0] >= x[1], and x[1] >= x[2]. So far so good, and the result is:
Resulting factors: [ 0.84965894 -0.31342016 -0.46308519]
Now, my goal is to be able to set the last two conditions dynamically, for example deciding that x[2] >= x[1] and x[1] >= x[0], with a list stating the superiority of each factor to the others. For example, the list [2, 1, 0] would mean that x[2]>=x[1] and x[1]>=x[0].
What I'm doing right now is this:
def fun_test(x):
return 3*x[0]**2 + x[1] + 4*x[2]
Lorder = [2,1,0]
con = [{"type" : "ineq", "fun" : lambda x: fun_test(x)}]
for i in range(np.shape(Lorder)[0]-1):
con.append({"type" : "ineq", "fun" : lambda x: x[Lorder[i]]-x[Lorder[i+1]]})
res = minimize(fun_test, method='COBYLA', x0=[3, 3, 3], constraints=con)
print("Resulting factors:",res.x)
But it doesn't work, and it gives me this result:
Resulting factors: [-0.22910497 2.05130651 -0.55219344]
Would you have an idea about why it doesn't work and how to make it work?
Upvotes: 1
Views: 129
Reputation: 7157
You need to capture the loop variable i
when creating lambda expressions in a loop, see here for more details:
con = [{"type" : "ineq", "fun" : lambda x: fun_test(x)}]
for i in range(np.shape(Lorder)[0]-1):
con.append({"type" : "ineq", "fun" : lambda x, i=i: x[Lorder[i]]-x[Lorder[i+1]]})
However, note also that
( -x[0] + x[1] ) >= 0
( -x[1] + x[2] ) >= 0
can be written as a matrix-vector product
( -1 1 0) (x[0])
D @ x = ( 0 -1 1) @ (x[1]) >= 0
( 0 0 0) (x[2])
So you could add all constraints at once:
n = 3
D = np.zeros((n, n))
for i in range(len(Lorder)-1):
k = Lorder[i]
r = Lorder[i+1]
D[-i+1, [k, r]] = [1.0, -1.0]
con = [{"type" : "ineq", "fun" : lambda x: fun_test(x)},
{"type" : "ineq", "fun" : lambda x: D @ x}]
Upvotes: 1