Reputation: 13
I have the following code:
import numpy as np
from scipy.optimize import minimize
def U(contributions, sizes, l):
return sizes*l*np.log(np.sum(contributions)) - contributions**2/sizes
def min_Ui(vars, sizes,l, number):
return -U(vars, sizes, l)[number]
sizes = np.array([1,1/4])
l = 4
number = 1 # 1 refers to nation 2
m_N = sizes**2 * np.sqrt(l/(2*np.sum(sizes**2)))
U_N = U(m_N, sizes, l)
constr = []
for i in range(len(sizes)):
if i != number:
constr.append({'type':'eq', 'fun': lambda x, sizes,l, U_N: U(x,sizes,l)[i] - U_N[i], 'args': (sizes,l, U_N)})
res = minimize(min_Ui, m_N, method='SLSQP', constraints=constr, args=(sizes,l, number))
print(res)
In this code, several nations make a contribution to a public good. They each have a utility function (calculated by U) which depends positively on the total contribution made and negatively on their own contribution. Each nation has their specific size (described in sizes), the parameter l is common for all nations. I now want to maximimize the utility of one of the nations (referred to with 'number') while keeping the utility of the other nations constant at their initial value (U_N). This means that one nation gets to choose the contributions of all other nations to maximize its own utility, subject to that they are not worse of than in the starting point.
In the code shown, I do this for 2 nations with sizes 1 and 1/4, the parameter l takes the value 4 and nation 2 maximizes its utility (I use these values because I know the solution for this case: the contributions should be 1.70297443 and 0.17713154). The code should however work for n nations and any positive parameter values.
However, the minimize function does not give the correct result. The utility of nation 2 in the result is typically its initial utility while the utility of nation 1 changes depending on the initial guess I give. In this problem however, the constraint says that the utility of nation 1 should be its initial value and the utility of nation 2 is maximized.
Can someone explain what I did wrong or why it's not working?
Upvotes: 1
Views: 539
Reputation: 7157
You need to capture the loop variable i
when defining constraints via lambda expressions inside a loop, see here for more details. Defining the constraints as follows
constr = []
for i in range(len(sizes)):
if i != number:
constr.append({'type':'eq', 'fun': lambda x, sizes,l, U_N, i=i: U(x,sizes,l)[i] - U_N[i], 'args': (sizes,l, U_N)})
yields the solution you are expecting.
Upvotes: 1