Define the Lemke-Howson algorithm
Bookwork: https://vknight.org/gt/chapters/07/#The-Lemke-Howson-algorithm
Draw the best response polytopes and use the Lemke-Howson algorithm (with all possible starting labels) for the following games:
From the previous exercise sheet https://vknight.org/gt/exercises/06/ we have the vertices of the row player best response polytope $\mathcal{P}$ (with labels):
The vertices for the column player best response polytope $\mathcal{Q}$ (with labels):
Here is the plot of these:
In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import scipy.spatial
V = [np.array([0, 0]), np.array([0, 1 / 8]), np.array([1 / 8, 0]), np.array([7 / 60, 1 / 15])]
P = scipy.spatial.ConvexHull(V)
plt.figure()
scipy.spatial.convex_hull_plot_2d(P);
plt.title("$\mathcal{P}$")
plt.text(0.001, .06, "Label: 0")
plt.text(0.05, .002, "Label: 1")
plt.text(0.07, .09, "Label: 2")
plt.text(0.1, .015, "Label: 3")
for v, s in zip(V, "abcd"):
plt.text(v[0] + 0.001, v[1] + 0.001, s)
;
V = [np.array([0, 0]), np.array([0, 1 / 9]), np.array([1 / 5, 0]), np.array([8 / 41, 1 / 41])]
Q = scipy.spatial.ConvexHull(V)
plt.figure()
scipy.spatial.convex_hull_plot_2d(Q);
plt.title("$\mathcal{Q}$")
plt.text(0.001, .03, "Label: 2")
plt.text(0.04, .002, "Label: 3")
plt.text(0.04, .07, "Label: 1")
plt.text(0.17, .005, "Label: 0")
for v, s in zip(V, "wxyz"):
plt.text(v[0] + 0.001, v[1] + 0.001, s)
;
Out[1]:
Using the plot we can carry out the Lemke-Howson algorithm:
Dropping label 0:
Dropping label 1:
Dropping label 2:
Dropping label 3:
For all of these dropped labels the only fully labeled vertex pair is:
$$((7/60, 1/15), (8/41, 1/41))$$which gives the normalised Nash equilibrium:
$$((7/11, 4/11), (8/9, 1/9))$$
In [2]:
import numpy as np
import nashpy as nash
A = np.array([[3, -1], [2, 7]])
B = np.array([[-3, 1], [1, -6]])
game = nash.Game(A, B)
list(game.lemke_howson_enumeration())
Out[2]:
In [3]:
(7 / 11, 4 / 11), (8 / 9, 1 / 9)
Out[3]:
2
. $
A =
\begin{pmatrix}
2 & -1\\
1 & 3\end{pmatrix}
\qquad
B =
\begin{pmatrix}
-2 & 2\\
1 & -2\end{pmatrix}
$
From the previous exercise sheet https://vknight.org/gt/exercises/06/ we have the vertices of the row player best response polytope $\mathcal{P}$ (with labels):
$d=(3/19, 4/19)$: $\{2, 3\}$
The vertices for the column player best response polytope $\mathcal{Q}$ (with labels):
$w=(0, 0)$: $\{2, 3\}$
$z=(4/17, 1/17)$: $\{0, 1\}$
Here is the plot of these:
In [4]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import scipy.spatial
V = [np.array([0, 0]), np.array([0, 1 / 4]), np.array([1 / 5, 0]), np.array([3/19, 4/19])]
P = scipy.spatial.ConvexHull(V)
plt.figure()
scipy.spatial.convex_hull_plot_2d(P);
plt.title("$\mathcal{P}$")
plt.text(0.001, .12, "Label: 0")
plt.text(0.08, .004, "Label: 1")
plt.text(0.06, .24, "Label: 2")
plt.text(0.18, .12, "Label: 3")
for v, s in zip(V, "abcd"):
plt.text(v[0] + 0.001, v[1] + 0.001, s)
;
V = [np.array([0, 0]), np.array([0, 1 / 5]), np.array([1 / 4, 0]), np.array([4 / 17, 1 / 17])]
Q = scipy.spatial.ConvexHull(V)
plt.figure()
scipy.spatial.convex_hull_plot_2d(Q);
plt.title("$\mathcal{Q}$")
plt.text(0.001, .075, "Label: 2")
plt.text(0.08, .002, "Label: 3")
plt.text(0.08, .125, "Label: 1")
plt.text(0.20, .015, "Label: 0")
for v, s in zip(V, "wxyz"):
plt.text(v[0] + 0.001, v[1] + 0.001, s)
;
Out[4]:
Using the plot we can carry out the Lemke-Howson algorithm:
Dropping label 0:
Dropping label 1:
Dropping label 2:
Dropping label 3:
For all of these dropped labels the only fully labeled vertex pair is:
$$(d, z) = ((3/19, 4/19), (4/17, 1/17))$$which gives the normalised Nash equilibrium:
$$((3/7,4/7),(4/5,1/5))$$
In [5]:
A = np.array([[2, -1], [1, 3]])
B = np.array([[-2, 2], [1, -2]])
game = nash.Game(A, B)
list(game.lemke_howson_enumeration())
Out[5]:
In [6]:
(3 / 7, 4 / 7), (4 / 5, 1 / 5)
Out[6]:
3
. Use the tableaux representation to execute the Lemke-Howson algorithm (with all possible starting labels) on the games of question 2.
We start by ensuring our payoff matrices are positive:
The tableaux are:
$$ T_r = \begin{pmatrix} B^T&I &1\\ \end{pmatrix} = \begin{pmatrix} 4 & 8 & 1 & 0 & 1\\ 8 & 1 & 0 & 1 & 1 \end{pmatrix} $$$$ T_c = \begin{pmatrix} I&A &1\\ \end{pmatrix} = \begin{pmatrix} 1 & 0 & 5 & 1 & 1\\ 0 & 1 & 4 & 9 & 1 \end{pmatrix} $$Dropping label 0: corresonds to first column of $T_r$ (non basic variables correspond to labels). Looking at the ratios in the first column (to the values in the last column): $1/4$ and $1/8$. So we pivot on the second row, giving:
$$ T_r = \begin{pmatrix} 0 & 60 & 8 & -4 & 4\\ 8 & 1 & 0 & 1 & 1 \end{pmatrix} $$This now has labels (non basic variables) $\{1, 3\}$. So we need to pivot column 3 in $T_c$. Looking at the fourth column ratios: $1/1$ and $1/9$, thus we pivot on the second row:
$$ T_c = \begin{pmatrix} 9 & -1 & 41 & 0 & 8\\ 0 & 1 & 4 & 9 & 1 \end{pmatrix} $$This now has labels (non basic variables) $\{1, 2\}$. So we need to pivot column 1 in $T_r$. Looking at the second column ratios: $4/60$ and $1/1$, thus we pivot on the first row:
$$ T_r = \begin{pmatrix} 0 & 60 & 8 & -4 & 4\\ 480 & 0 & -8 & 64 & 56 \end{pmatrix} $$This now has labels (non basic variables) $\{2, 3\}$ we wee need to pivot column 2 in $T_c$. Looking at the third column ratios: $8/41$ and $1/4$, thus we pivot on the first row:
$$ T_c = \begin{pmatrix} 9 & -1 & 41 & 0 & 8\\ -36 & 45 & 0 & 369 & 9 \end{pmatrix} $$This now has labels $\{0, 1\}$ so we have a fully labeled vertex pair. Setting the non basic variables to 0 in each tableaux gives:
$$((56/480, 4/60), (8/41, 9/369)) = ((7/60, 1/15), (8/41, 1/41))$$which gives the normalised Nash equilibrium:
$$((7/11, 4/11), (8/9, 1/9))$$Here is some code to carry out the above:
In [7]:
import numpy as np
row_tableau = np.array([[4, 8, 1, 0, 1],
[8, 1, 0, 1, 1]])
col_tableau = np.array([[1, 0, 5, 1, 1],
[0, 1, 4, 9, 1]])
In [8]:
# Dropping label 0 from row tableau
dropped_label = nash.integer_pivoting.pivot_tableau(row_tableau,
column_index=0)
row_tableau
Out[8]:
In [9]:
# Dropping label 3 from col tableau
dropped_label = nash.integer_pivoting.pivot_tableau(col_tableau,
column_index=3)
col_tableau
Out[9]:
In [10]:
# Dropping label 1 from row tableau
dropped_label = nash.integer_pivoting.pivot_tableau(row_tableau,
column_index=1)
row_tableau
Out[10]:
In [11]:
# Dropping label 2 from col tableau
dropped_label = nash.integer_pivoting.pivot_tableau(col_tableau,
column_index=2)
col_tableau
Out[11]:
2
. $
A \to A + 2 =
\begin{pmatrix}
4 & 1\\
3 & 5\end{pmatrix}
\qquad
B \to B + 3 =
\begin{pmatrix}
1 & 5\\
4 & 1\end{pmatrix}
$
The tableaux are:
$$ T_r = \begin{pmatrix} B^T&I &1\\ \end{pmatrix} = \begin{pmatrix} 1 & 4 & 1 & 0 & 1\\ 5 & 1 & 0 & 1 & 1 \end{pmatrix} $$$$ T_c = \begin{pmatrix} I&A &1\\ \end{pmatrix} = \begin{pmatrix} 1 & 0 & 4 & 1 & 1\\ 0 & 1 & 3 & 5 & 1 \end{pmatrix} $$Dropping label 0: corresonds to first column of $T_r$ (non basic variables correspond to labels). Looking at the ratios in the first column (to the values in the last column): $1/4$ and $1/5$. So we pivot on the second row, giving:
$$ T_r = \begin{pmatrix} 0 & 19 & 5 & -1 & 4\\ 5 & 1 & 0 & 1 & 1 \end{pmatrix} $$This now has labels (non basic variables) $\{1, 3\}$. So we need to pivot column 3 in $T_c$. Looking at the fourth column ratios: $1/1$ and $1/5$, thus we pivot on the second row:
$$ T_c = \begin{pmatrix} 5 & -1 & 17 & 0 & 4\\ 0 & 1 & 3 & 5 & 1 \end{pmatrix} $$This now has labels (non basic variables) $\{1, 2\}$. So we need to pivot column 1 in $T_r$. Looking at the second column ratios: $1/19$ and $1/1$, thus we pivot on the first row:
$$ T_r = \begin{pmatrix} 0 & 19 & 5 & -1 & 4\\ 95 & 0 & -5 & 20 & 15 \end{pmatrix} $$This now has labels (non basic variables) $\{2, 3\}$ we wee need to pivot column 2 in $T_c$. Looking at the third column ratios: $4/17$ and $1/3$, thus we pivot on the first row:
$$ T_c = \begin{pmatrix} 5 & -1 & 17 & 0 & 4\\ -15 & 20 & 0 & 85 & 5 \end{pmatrix} $$This now has labels $\{0, 1\}$ so we have a fully labeled vertex pair. Setting the non basic variables to 0 in each tableaux gives:
$$((15/95, 4/19), (4/17, 5/85)) = ((3/19, 4/19), (4/17, 1/17))$$which gives the normalised Nash equilibrium:
$$((3/7, 4/7), (4/5, 1/5))$$Here is some code to carry out the above:
In [12]:
row_tableau = np.array([[1, 4, 1, 0, 1],
[5, 1, 0, 1, 1]])
col_tableau = np.array([[1, 0, 4, 1, 1],
[0, 1, 3, 5, 1]])
In [13]:
# Dropping label 0 from row tableau
dropped_label = nash.integer_pivoting.pivot_tableau(row_tableau,
column_index=0)
row_tableau
Out[13]:
In [14]:
# Dropping label 3 from col tableau
dropped_label = nash.integer_pivoting.pivot_tableau(col_tableau,
column_index=3)
col_tableau
Out[14]:
In [15]:
# Dropping label 1 from row tableau
dropped_label = nash.integer_pivoting.pivot_tableau(row_tableau,
column_index=1)
row_tableau
Out[15]:
In [16]:
# Dropping label 2 from col tableau
dropped_label = nash.integer_pivoting.pivot_tableau(col_tableau,
column_index=2)
col_tableau
Out[16]: