Professional Documents
Culture Documents
1 Prisoners’ Dilemma
The Prisoners’ Dilemma is a famous model for illustrating the conflict between social cooperation
and self-interested behavior. Consider a two player Prisoners’ Dilemma in which the cooperative
payoff possibilities are mathematically described by a polytope which is defined as the convex hull
of the payoff vectors (4,4), (6,0), (0,6) and (0,0). Suppose we think of the Prisoners’ Dilemma as
a bargaining situation where the disagreement point is d = (𝑑1 , 𝑑2 ). The notion of a disagreement
point introduces a constraint that player 𝑖 cannot get a payoff below her disagreement point payoff
𝑑𝑖 .
Whether or not you want to invest in understanding this model, you can always start your work
taking as given that the feasible set ℱ of payoff vectors (𝑢1 , 𝑢2 ) for the bargaining problem is
mathematically described as
𝑢1 + 2𝑢2 ≤ 12
2𝑢1 + 𝑢2 ≤ 12
𝑢1 ≥ 𝑑1 , 𝑢2 ≥ 𝑑2
Plot player 1’s utilitarian optimum 𝑢1 (𝜃) as the weight 𝜃 varies in [0, 1].
[1]: #Compute the weighted utilitarian optimum of Prisoners Dilemma as a solution to␣
↪a linear optimization problem
import numpy as np
import cvxpy as cp
import matplotlib.pyplot as plt
from matplotlib import rc
np.set_printoptions(precision=4, suppress=True)
font_properties = {'family': 'monospace', 'size': 10}
rc('font', **font_properties)
1
#Vector variable with shape (2,).
x = cp.Variable(2)
#Form objective.
obj = cp.Maximize(theta * (x[0] - d[0]) + (1-theta) * (x[1] - d[1]))
#Form problem.
prob = cp.Problem(obj, constraints)
2
ax.set_xlim(0,1)
ax.set_ylim(3,5.5)
ax.legend()
#activate when a pdf is needed; needs to be called before plt.show() lest it␣
↪give a blank output
plt.savefig('comparative_statics_utilopt.png')
/opt/anaconda3/lib/python3.8/site-
packages/cvxpy/reductions/solvers/solving_chain.py:163: UserWarning: You are
solving a parameterized problem that is not DPP. Because the problem is not DPP,
subsequent solves will not be faster than the first one. For more information,
see the documentation on Discplined Parametrized Programming, at
https://www.cvxpy.org/tutorial/advanced/index.html#disciplined-
parametrized-programming
warnings.warn(dpp_error_msg)
3
3 Problem 2. (8 points). (Convex optimization using CVXPY).
Suppose the disagreement point is given by d = (3.5, 2). A Nash welfare criterion is defined as
(a) (4 points). In addition to displaying the Nash bargaining solution, display the primal optimal
value and the optimal dual variables for the constraints as well.
4
import numpy as np
import cvxpy as cp
# Form objective.
obj = cp.Maximize(cp.sum(cp.log(x - d)))
# Form problem.
prob = cp.Problem(obj, constraints)
#Solve problem.
prob.solve()
#print solver status, primal optimal value and primal optimal variables.
print(f'status: {prob.status}')
print(f'primal optimal value: {prob.value:.4f}')
print(f'The Nash solution is the primal optimal solution: {x.value}')
status: optimal
primal optimal value: 0.1178
The Nash solution is the primal optimal solution: [4.25 3.5 ]
optimal (x >= 2) dual variable is: 0.0000
optimal (y >= 1) dual variable is: 0.0000
optimal (x + 2y <= 12) dual variable is: 0.0000
5
optimal (2x + y <= 12) dual variable is: 0.6667
4 Comparative statics
(b) (4 points). Now fix the disagreement payoff of player 2 at 𝑑2 = 2. In the same figure, plot
how both players’ payoffs in the Nash bargaining solution vary as the disagreement payoff 𝑑1
of player 1 varies over the interval [2, 5].
# Form objective.
obj = cp.Maximize(cp.sum(cp.log(x - d)))
6
prob.solve()
nbs_1.append(x[0].value)
nbs_2.append(x[1].value)
nash_prod.append(prob.value)
ax.plot(grid, nbs_2, label = 'Nash bargain for player 2', color = 'b',␣
↪linestyle = '--', linewidth = 3, alpha = overlapping)
ax.legend()
#activate when a pdf is needed; needs to be called before plt.show() lest it␣
↪give a blank output
plt.savefig('comparative_statics_nbs.png')
7
5 Problem 3. (7 points). (Convex optimization using interior
point algorithm).
You cannot use the CVXPY package here. Please implement the algorithm.
Suppose the disagreement point is given by d = (2, 1). Solve Problem 2(a) by implementing the
interior point algorithm that uses log barrier for inequality constraints. Display the following
(i) initial t and final t (ii) Nash bargaining solution (iii) primal optimal value (Maximized Nash
welfare) (iv) dual optimal variables for constraints (v) inequality constraint function values
at the optimum
import numpy as np
8
import numdifftools as nd
from scipy.optimize import minimize_scalar
from scipy.linalg import cholesky
#option precision tells NumPy the number of digits after decimal point
#for printing; option suppress tells NumPy not to use exponential
#notation for very small numbers. This only affects printing not
#calculations
np.set_printoptions(precision=4, suppress=True)
######################################################################################
######################parameters of the optimization␣
↪problem###########################
#diagreement point
d = np.array([2, 1])
######################parameters of the␣
↪algorithm######################################
#set the values of acceptable descent parameter alpha in (0,0.5) and reduction␣
↪factor beta in (0,1)
def f(x):
"""return inequality constraint function values as a flat 1D array"""
return np.array([- x[0] + d[0], - x[1] + d[1], x[0] + 2 * x[1] - 12, 2 *␣
↪x[0] + x[1] - 12])
def log_barrier(x):
"""logarithmic barrier for inequality constraints"""
return - np.sum(np.log(-f(x)))
9
"""return the gradient vector of objective fn as a flat 1D array"""
epsilon = nd.MaxStepGenerator(base_step=2.0, num_steps=10, offset=0)
return nd.Gradient(obj, method = 'forward', step = epsilon)(x, t)
t_0 = 10
10
dual = - np.reciprocal(t*f(nbs))
The initial t is 10
The final t is 97656250
Nash bargaining solution with respect to disagreement point [2 1] is [3.9931
3.9859]
Maximized Nash product is 1.7836
The dual optimal variables are [0. 0. 0. 0.]
Inequality constraint function values are [-1.9931 -2.9859 -0.0351 -0.0278]
/opt/anaconda3/lib/python3.8/site-packages/numpy/lib/nanfunctions.py:1395:
RuntimeWarning: All-NaN slice encountered
result = np.apply_along_axis(_nanquantile_1d, axis, a, q,
/opt/anaconda3/lib/python3.8/site-packages/numdifftools/limits.py:150:
UserWarning: All-NaN slice encountered
warnings.warn(str(msg))
/opt/anaconda3/lib/python3.8/site-packages/numpy/lib/nanfunctions.py:1395:
RuntimeWarning: All-NaN slice encountered
result = np.apply_along_axis(_nanquantile_1d, axis, a, q,
/opt/anaconda3/lib/python3.8/site-packages/numdifftools/limits.py:150:
UserWarning: All-NaN slice encountered
warnings.warn(str(msg))
/opt/anaconda3/lib/python3.8/site-packages/numpy/lib/nanfunctions.py:1395:
RuntimeWarning: All-NaN slice encountered
result = np.apply_along_axis(_nanquantile_1d, axis, a, q,
/opt/anaconda3/lib/python3.8/site-packages/numdifftools/limits.py:150:
UserWarning: All-NaN slice encountered
warnings.warn(str(msg))
/opt/anaconda3/lib/python3.8/site-packages/numpy/lib/nanfunctions.py:1395:
RuntimeWarning: All-NaN slice encountered
result = np.apply_along_axis(_nanquantile_1d, axis, a, q,
/opt/anaconda3/lib/python3.8/site-packages/numdifftools/limits.py:150:
UserWarning: All-NaN slice encountered
warnings.warn(str(msg))
/opt/anaconda3/lib/python3.8/site-packages/numpy/lib/nanfunctions.py:1395:
RuntimeWarning: All-NaN slice encountered
result = np.apply_along_axis(_nanquantile_1d, axis, a, q,
/opt/anaconda3/lib/python3.8/site-packages/numdifftools/limits.py:150:
UserWarning: All-NaN slice encountered
warnings.warn(str(msg))
11