Game Theory¶
Exercise 11.1¶
Let \(y\) and \(x\) denote the strategy for players A and B respectively. The strategy consists of two choices \(\{a, b\}_{> 0}\). The corresponding payoff matrix is
Player B seeks a strategy \(x^*\) that attains optimality in the following LP:
Converting to standard form yields
The initial feasible dictionary is
Since \(v\) is a free variable, choose \(v\) and \(x_4\) as the entering and leaving variable respectively where
Pivot dictionary to
where \(v = \epsilon\).
Choose \(x_1\) and \(x_3\) as the entering and leaving variable respectively where
Pivot dictionary to
The optimal strategy for player B is a uniform random strategy. By the strong duality theorem, optimal strategy for player A is \(y_1^* = \frac{b}{a + b}\) and \(y_2^* = \frac{a}{a + b}\).
The value of the game is \(v^* = \epsilon^* = 0\), which indicates that the game is fair for arbitrary denominations.
Exercise 11.2¶
Let \(y\) and \(x\) denote the strategy for players A and B respectively. The corresponding payoff matrix is a skew-symmetric matrix
Since \(-A^\top = A\), the game is symmetric and hence fair. This means both players have the same set of pure strategies and the same optimal mixed strategies.
Player B seeks a strategy \(x^*\) that attains optimality in the following LP:
Converting to standard form gives
The initial feasible dictionary is
\(n = 1\)¶
There is only one trivial strategy available.
\(n = 2\)¶
Choose \(v\) and \(x_4\) as the entering and leaving variable respectively where
Pivot dictionary to
where \(v = \epsilon\). The already optimal dictionary implies that the optimal strategy is \(x^* = (0, 1) = y^*\).
\(n = 3\)¶
Choose \(v\) and \(x_4\) as the entering and leaving variable respectively where
Pivot dictionary to
where \(v = \epsilon\).
The final dictionary
implies that the optimal strategy is \(x^* = \left( \frac{1}{3}, \frac{1}{3}, \frac{1}{3} \right) = y^*\).
\(n \geq 4\)¶
Choose \(v\) and \(x_5\) as the entering and leaving variable respectively where
Pivot dictionary to
where \(v = \epsilon\).
The final dictionary
implies that the optimal strategy is \(x^* = \left( \frac{1}{3}, \frac{1}{3}, \frac{1}{3}, 0 \right) = y^*\).
By induction, the optimal strategy for \(n > 4\) is
because there is no incentive to choose a larger number.
Exercise 11.3¶
Applying (a) and (b) to the payoff matrix gives
(a)¶
Suppose a new row \(r\) is added to \(A\) such that \(r\) dominates row \(s\) and \(y_r^* \neq 0\). By inspection,
Furthermore,
contradicts the definition of a minimum. Therefore, \(y_r^* = 0\) and dominate rows can be removed without affecting the value of the game.
(b)¶
Suppose a new column \(c\) is added to \(A\) such that \(c\) dominates column \(s\) and \(x_s^* \neq 0\). By inspection,
Furthermore,
contradicts the definition of a maximum. Therefore, \(x_s^* = 0\) and dominated columns can be removed without affecting the value of the game.
Exercise 11.4¶
[1]:
from enum import Enum
class Action(Enum):
BET = 1
PASS = 0
class StrategyA:
def __init__(self, pure_strategies):
lines = [
StrategyA.__line1, StrategyA.__line2, StrategyA.__line3
]
self.action_plans = []
for ps in pure_strategies:
self.action_plans.append(lines[ps - 1])
def invoke(self, card_dealt):
return self.action_plans[card_dealt - 1]()
@staticmethod
def __line1():
return Action.PASS,\
lambda _: Action.PASS
@staticmethod
def __line2():
return Action.PASS,\
lambda action: Action.BET if action == Action.BET else Action.PASS
@staticmethod
def __line3():
return Action.BET,\
lambda _: Action.BET
class StrategyB:
def __init__(self, pure_strategies):
lines = [
StrategyB.__line1, StrategyB.__line2,
StrategyB.__line3, StrategyB.__line4
]
self.action_plans = []
for ps in pure_strategies:
self.action_plans.append(lines[ps - 1])
def invoke(self, card_dealt, other_action):
return self.action_plans[card_dealt - 1](other_action)
@staticmethod
def __line1(_):
return Action.PASS
@staticmethod
def __line2(action):
return Action.PASS if action == Action.PASS else Action.BET
@staticmethod
def __line3(action):
return Action.BET if action == Action.PASS else Action.PASS
@staticmethod
def __line4(_):
return Action.BET
[2]:
import itertools
import numpy
def paymentA2B(pure_strategies_A, pure_strategies_B, ante=1, bet=1):
A = StrategyA(pure_strategies_A)
B = StrategyB(pure_strategies_B)
total_payment = 0
count = 0
for cards_dealt in itertools.product([1, 2, 3], [1, 2, 3]):
a, b = cards_dealt
if a == b:
#card game is without replacement
continue
A_action, A_response = A.invoke(a)
B_action = B.invoke(b, A_action)
end_turn = A_response(B_action)
pot = 0
if A_action == Action.PASS and B_action == Action.PASS:
if a > b:
pot = -ante
elif a < b:
pot = ante
elif A_action == Action.PASS and B_action == Action.BET and end_turn == Action.PASS:
pot = ante
elif A_action == Action.PASS and B_action == Action.BET and end_turn == Action.BET:
if a > b:
pot = -ante - bet
elif a < b:
pot = ante + bet
elif A_action == Action.BET and B_action == Action.PASS:
pot = -ante
elif A_action == Action.BET and B_action == Action.BET:
if a > b:
pot = -ante - bet
elif a < b:
pot = ante + bet
count += 1
total_payment += pot
return total_payment / count
a_strategies = [
(1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3),
(3, 1, 2), (3, 1, 3), (3, 2, 2), (3, 2, 3)
]
b_strategies = [
(1, 1, 4), (1, 2, 4), (3, 1, 4), (3, 2, 4)
]
payoff_matrix = []
for psa in a_strategies:
payoffs = []
for psb in b_strategies:
payoffs.append(paymentA2B(psa, psb, ante=2))
payoff_matrix.append(payoffs)
A = numpy.asarray(payoff_matrix)
print(A)
[[ 0. 0. 0.5 0.5 ]
[ 0. -0.16666667 0.66666667 0.5 ]
[ 0.16666667 0.16666667 -0.16666667 -0.16666667]
[ 0.16666667 0. 0. -0.16666667]
[-0.5 0.33333333 0. 0.83333333]
[-0.5 0.16666667 0.16666667 0.83333333]
[-0.33333333 0.5 -0.66666667 0.16666667]
[-0.33333333 0.33333333 -0.5 0.16666667]]
[3]:
def solveDualMatrixGame(A):
P = numpy.column_stack((-A.T, numpy.ones(A.T.shape[0])))
n = A.T.shape[1] + 1
c = numpy.zeros(n)
c[-1] = 1
from pymprog import model
lp = model('LP')
#lp.verbose(True)
y = lp.var('y', n, bounds=(None, None))
for j in range(n - 1):
lp.st(y[j] >= 0)
lp.minimize(sum(c[j] * y[j] for j in range(n)))
for row in range(P.shape[0]):
sum(P[row, col] * y[col] for col in range(n)) >= 0
sum(y[j] for j in range(n - 1)) == 1
lp.solve()
lp.sensitivity()
lp.end()
solveDualMatrixGame(A)
PyMathProg 1.0 Sensitivity Report Created: 2020/04/05 Sun 03:20AM
================================================================================
Variable Activity Dual.Value Obj.Coef Range.From Range.Till
--------------------------------------------------------------------------------
y[0] 0 0.0666667 0 -0.0666667 inf
*y[1] 0.2 0 0 -0.333333 0
y[2] 0 0.0666667 0 -0.0666667 inf
*y[3] 0.6 0 0 0 0.0666667
y[4] 0 0.0666667 0 -0.0666667 inf
y[5] 0 0 0 0 inf
y[6] 0 0.0666667 0 -0.0666667 inf
*y[7] 0.2 0 0 -0.333333 0
*y[8] 0.0333333 0 1 0 1.79769e+308
================================================================================
================================================================================
Constraint Activity Dual.Value Lower.Bnd Upper.Bnd RangeLower RangeUpper
--------------------------------------------------------------------------------
R1 0 0.4 0 inf 0 0.5
R2 0 0.4 0 inf -0.166667 0
*R3 0 0 0 inf 0 0
R4 0 0.2 0 inf 0 0.166667
R5 1 0.0333333 1 1 0 1.79769e+308
================================================================================
[4]:
def solvePrimalMatrixGame(A):
P = numpy.column_stack((-A, numpy.ones(A.shape[0])))
n = A.shape[1] + 1
c = numpy.zeros(n)
c[-1] = 1
from pymprog import model
lp = model('LP')
#lp.verbose(True)
x = lp.var('x', n, bounds=(None, None))
for i in range(n - 1):
lp.st(x[i] >= 0)
lp.maximize(sum(c[i] * x[i] for i in range(n)))
for row in range(P.shape[0]):
sum(P[row, col] * x[col] for col in range(n)) <= 0
sum(x[i] for i in range(n - 1)) == 1
lp.solve()
lp.sensitivity()
lp.end()
solvePrimalMatrixGame(A)
PyMathProg 1.0 Sensitivity Report Created: 2020/04/05 Sun 03:20AM
================================================================================
Variable Activity Dual.Value Obj.Coef Range.From Range.Till
--------------------------------------------------------------------------------
*x[0] 0.4 0 0 0 0
*x[1] 0.4 0 0 0 0
x[2] 0 0 0 -inf 0
*x[3] 0.2 0 0 0 0
*x[4] 0.0333333 0 1 0 1.79769e+308
================================================================================
================================================================================
Constraint Activity Dual.Value Lower.Bnd Upper.Bnd RangeLower RangeUpper
--------------------------------------------------------------------------------
*R1 -0.0666667 0 -inf 0 -0.0666667 -0.0666667
R2 0 0 -inf 0 0 0.111111
*R3 -0.0666667 0 -inf 0 -0.0666667 -0.0666667
R4 0 0.8 -inf 0 -0.166667 0
*R5 -0.0666667 0 -inf 0 -0.0666667 -0.0666667
R6 0 0.2 -inf 0 -0.333333 0
*R7 -0.0666667 0 -inf 0 -0.0666667 -0.0666667
*R8 0 0 -inf 0 0 0
R9 1 0.0333333 1 1 0 1.79769e+308
================================================================================
Exercise 11.5¶
The simultaneously optimality of the \(r\text{th}\) pure strategy of the row and the \(s\text{th}\) pure strategy of the column player requires \(y^*, x^*\) to be indicator vectors. This means \(r\) is dominated by all the other rows and \(s\) dominates all the other columns.
Exercise 11.6¶
Suppose \(x^*\) and \(y^*\) are the optimal strategies. The Minimax Theorem guarantees that
By the Strong Duality Theorem,
and
for all \(x, y\). Thus
Exercise 11.7¶
Given a matrix \(M \in \mathbb{R}^{n \times n}\) and a vector \(q \in \mathbb{R}^n\), the linear complementarity problem (LCP) is to find vectors \(u, v \in \mathbb{R}^n\) satisfying the relations [Cha]:
The reason for the term “complementarity” in the name of the problem is due to
The stochastic vectors \(x^*\) and \(y^*\) form a Nash equilibrium pair if they satisfy
where \(A, B \in \mathbb{R}^{m \times n}\) are loss matrices of the row and column players respectively. Since \(e^\top x^* = \sum_j x^*_j = 1\) and \(e^\top y^* = \sum_i y^*_i = 1\), the preceding relations are equivalent to
The equivalent LCP formulation is
and
(a)¶
Let \(C = A + kJ\) and \(D = B + kJ\) where \(k\) is the smallest scalar such that the all-ones matrix \(J\) forces \(C\) and \(D\) to be positive matrices. Any equilibrium pair of strategies for \((A, B)\) is also an equilibrium pair of strategies for \((C, D)\):
The proof is the same for \(B\) and \(D\).
(b)¶
Suppose \((x^*, y^*)\) is a Nash equilibrium and \(A, B\) are positive matrices such that
and
The remaining LCP relations are also satisfied because
The proof is the same for \({x'}^\top z\). Therefore, \((x', y')\) solves the LCP.
(c)¶
Suppose \((x', y')\) solves the LCP such that
The conditions for \((x^*, y^*)\) to form a Nash equilibrium is satisfied because
The proof is the same for \(z \geq 0\). Therefore, \((x^*, y^*)\) is a Nash equilibrium.
Exercise 11.8¶
Since players A and B can only throw out one or two fingers, the total sum of the outstretched fingers are:
Player B 1 |
Player B 2 |
|
Player A 1 |
2 |
3 |
Player A 2 |
3 |
4 |
(a)¶
The players’ pure strategies can be denoted by \((g_1, g_2)\) where \(g_i \in \{ 2, 3, 4 \}\) is the player’s guess when throwing out \(i \in \{ 1, 2 \}\) fingers. Each player has a total of \(3 \times 3 = 9\) pure strategies. Thus there are \(9 \times 9 = 81\) pairs.
(b)¶
The following observations reveal that certain strategies are nonsensical:
A player throwing out one finger should never guess four.
A player throwing out two fingers should never guess two.
After eliminating these strategies from consideration, each player has \(2 \times 2 = 4\) pure strategies.
(c)¶
The formulation is given by (11.4).
(d)¶
This is a symmetric fair game; hence, the value of the game is zero.
(e)¶
The optimal randomized strategy is to uniformly throw one or two finger while using the pure strategy \((g_1 = 3, g_2 = 4)\).
[5]:
def paymentA2B(psa, psb):
total_payment = 0
count = 0
for fingers_thrown in itertools.product([1, 2], [1, 2]):
a_fingers, b_fingers = fingers_thrown
total_fingers = a_fingers + b_fingers
a_guess = psa[a_fingers - 1]
b_guess = psb[b_fingers - 1]
if a_guess == total_fingers and b_guess != total_fingers:
total_payment -= total_fingers
elif a_guess != total_fingers and b_guess == total_fingers:
total_payment += total_fingers
count += 1
return total_payment / count
a_strategies = [
(2, 3), (2, 4), (3, 3), (3, 4)
]
b_strategies = [
(2, 3), (2, 4), (3, 3), (3, 4)
]
payoff_matrix = []
for psa in a_strategies:
payoffs = []
for psb in b_strategies:
payoffs.append(paymentA2B(psa, psb))
payoff_matrix.append(payoffs)
A = numpy.asarray(payoff_matrix)
print(A)
solveDualMatrixGame(A)
[[ 0. 0.25 0.25 0.5 ]
[-0.25 0. 0. 0.25]
[-0.25 0. 0. 0.25]
[-0.5 -0.25 -0.25 0. ]]
PyMathProg 1.0 Sensitivity Report Created: 2020/04/05 Sun 03:20AM
================================================================================
Variable Activity Dual.Value Obj.Coef Range.From Range.Till
--------------------------------------------------------------------------------
y[0] 0 0.5 0 -0.5 inf
y[1] 0 0.25 0 -0.25 inf
y[2] 0 0.25 0 -0.25 inf
*y[3] 1 0 0 -1.79769e+308 0.25
*y[4] 0 0 1 0 1.79769e+308
================================================================================
================================================================================
Constraint Activity Dual.Value Lower.Bnd Upper.Bnd RangeLower RangeUpper
--------------------------------------------------------------------------------
*R1 0.5 0 0 inf 0.5 0.5
*R2 0.25 0 0 inf 0.25 0.25
*R3 0.25 0 0 inf 0.25 0.25
R4 0 1 0 inf -0.25 1.79769e+308
R5 1 0 1 1 0 1.79769e+308
================================================================================
Exercise 11.9¶
There are three possible betting scenarios:
Player A leaves: $1 goes to player B.
Player A stays and player B leaves: $1 goes to player A.
Player A stays and player B stays: $2 goes to player A if the fair coin flip resulted in heads, otherwise $2 goes to player B.
(a)¶
Player A’s pure strategy can be denoted by \((y_1, y_2)\) where \(y_i \in \{ \text{leave}, \text{stay} \}\) is player A’s action when the observed outcome is \(i \in \{ \text{heads}, \text{tails} \}\).
Player B’s pure strategy \((x_1)\) is dependent on A’s declared action. \(x_1 \in \{ \text{leave}, \text{stay} \}\) is player B’s decision when player A decides to stay. Note that player B wins when player A leaves.
Therefore there are \((2 \times 2) \times (2) = 8\) pairs.
(b)¶
The accompanying code prints out the reduced payoff matrix.
(c)¶
Player A should never leave the game when the outcome is heads.
When the outcome is tails, leaving will guarantee a loss of $1, but staying will on average result in \(\alpha (2) + (1 - \alpha) (-1)\) where \(\alpha\) is the probability of player B staying. This strategy should be ruled out when
(d)¶
The formulation is given by (11.4).
(e)¶
Player A’s optimal strategy is as follows:
When heads is observed, always stay.
When tails is observed, leave \(2/3\) of the time and stay \(1/3\) of the time.
Player B’s optimal strategy is to leave \(1/3\) of the time and stay \(2/3\) of the time.
(f)¶
This game is neither symmetric nor fair, and it is in player A’s favor. This game is interesting in the sense that there is no way to make the game fair.
[6]:
def paymentA2B(psa, psb):
total_payment = 0
count = 0
for coin in range(2):
a_action = psa[coin]
b_action = psb
if a_action == LEAVE:
total_payment += 1
else:
if b_action == LEAVE:
total_payment -= 1
else:
if coin == HEADS:
total_payment -= 2
else:
total_payment += 2
count += 1
return total_payment / count
LEAVE, STAY = range(2)
HEADS, TAILS = range(2)
a_strategies = [
(STAY, LEAVE), (STAY, STAY)
]
b_strategies = [
(LEAVE), (STAY)
]
payoff_matrix = []
for psa in a_strategies:
payoffs = []
for psb in b_strategies:
payoffs.append(paymentA2B(psa, psb))
payoff_matrix.append(payoffs)
A = numpy.asarray(payoff_matrix)
print(A)
solveDualMatrixGame(A)
[[ 0. -0.5]
[-1. 0. ]]
PyMathProg 1.0 Sensitivity Report Created: 2020/04/05 Sun 03:20AM
================================================================================
Variable Activity Dual.Value Obj.Coef Range.From Range.Till
--------------------------------------------------------------------------------
*y[0] 0.666667 0 0 -1 0.5
*y[1] 0.333333 0 0 -0.5 1
*y[2] -0.333333 0 1 0 1.79769e+308
================================================================================
================================================================================
Constraint Activity Dual.Value Lower.Bnd Upper.Bnd RangeLower RangeUpper
--------------------------------------------------------------------------------
R1 0 0.333333 0 inf -0.5 1
R2 0 0.666667 0 inf -1 0.5
R3 1 -0.333333 1 1 0 1.79769e+308
================================================================================
References
- Cha
R. Chandrasekaran. Bimatrix games. http://www.utdallas.edu/ chandra/documents/6311/bimatrix.pdf. Accessed on 2017-08-06.