Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/economics/game_theory.tex
51 views
unlisted
1
\documentclass[a4paper, 11pt]{report}
2
\usepackage[utf8]{inputenc}
3
\usepackage[T1]{fontenc}
4
\usepackage{amsmath, amssymb}
5
\usepackage{graphicx}
6
\usepackage{siunitx}
7
\usepackage{booktabs}
8
\usepackage{xcolor}
9
\usepackage[makestderr]{pythontex}
10
11
\definecolor{nash}{RGB}{46, 204, 113}
12
\definecolor{player1}{RGB}{52, 152, 219}
13
\definecolor{player2}{RGB}{231, 76, 60}
14
15
\title{Game Theory:\\
16
Nash Equilibrium, Mixed Strategies, and Payoff Analysis}
17
\author{Department of Economics\\Technical Report EC-2024-001}
18
\date{\today}
19
20
\begin{document}
21
\maketitle
22
23
\begin{abstract}
24
This report presents a computational analysis of game theory concepts. We implement Nash equilibrium finding for 2-player games, analyze mixed strategies in zero-sum and non-zero-sum games, visualize payoff matrices, and explore classic games including Prisoner's Dilemma, Battle of the Sexes, and Matching Pennies.
25
\end{abstract}
26
27
\tableofcontents
28
29
\chapter{Introduction}
30
31
Game theory studies strategic interactions where outcomes depend on choices of multiple decision-makers (players).
32
33
\section{Key Concepts}
34
\begin{itemize}
35
\item \textbf{Nash Equilibrium}: No player can improve by unilaterally changing strategy
36
\item \textbf{Dominant Strategy}: Optimal regardless of opponent's choice
37
\item \textbf{Mixed Strategy}: Randomizing over pure strategies
38
\end{itemize}
39
40
\chapter{Two-Player Normal Form Games}
41
42
\section{Payoff Matrix Representation}
43
For players 1 and 2 with strategies $S_1 = \{s_1^1, ..., s_1^m\}$ and $S_2 = \{s_2^1, ..., s_2^n\}$:
44
\begin{equation}
45
\text{Payoffs: } (u_1(s_1^i, s_2^j), u_2(s_1^i, s_2^j))
46
\end{equation}
47
48
\begin{pycode}
49
import numpy as np
50
import matplotlib.pyplot as plt
51
from scipy.optimize import linprog
52
plt.rc('text', usetex=True)
53
plt.rc('font', family='serif')
54
55
np.random.seed(42)
56
57
def find_pure_nash(payoff1, payoff2):
58
m, n = payoff1.shape
59
nash = []
60
for i in range(m):
61
for j in range(n):
62
best_resp_1 = np.argmax(payoff1[:, j]) == i
63
best_resp_2 = np.argmax(payoff2[i, :]) == j
64
if best_resp_1 and best_resp_2:
65
nash.append((i, j))
66
return nash
67
68
def find_mixed_nash_2x2(payoff1, payoff2):
69
# For 2x2 games
70
# Player 2's mix makes Player 1 indifferent
71
a, b = payoff1[0, 0], payoff1[0, 1]
72
c, d = payoff1[1, 0], payoff1[1, 1]
73
if (a - b - c + d) != 0:
74
q = (d - b) / (a - b - c + d)
75
else:
76
q = 0.5
77
78
# Player 1's mix makes Player 2 indifferent
79
a, b = payoff2[0, 0], payoff2[1, 0]
80
c, d = payoff2[0, 1], payoff2[1, 1]
81
if (a - b - c + d) != 0:
82
p = (d - c) / (a - b - c + d)
83
else:
84
p = 0.5
85
86
p = np.clip(p, 0, 1)
87
q = np.clip(q, 0, 1)
88
return p, q
89
90
def expected_payoff(p, q, payoff):
91
return p * q * payoff[0, 0] + p * (1-q) * payoff[0, 1] + \
92
(1-p) * q * payoff[1, 0] + (1-p) * (1-q) * payoff[1, 1]
93
94
# Classic games
95
games = {
96
"Prisoner's Dilemma": {
97
'payoff1': np.array([[-1, -3], [0, -2]]),
98
'payoff2': np.array([[-1, 0], [-3, -2]]),
99
'strategies': ['Cooperate', 'Defect']
100
},
101
'Battle of Sexes': {
102
'payoff1': np.array([[3, 0], [0, 2]]),
103
'payoff2': np.array([[2, 0], [0, 3]]),
104
'strategies': ['Opera', 'Football']
105
},
106
'Matching Pennies': {
107
'payoff1': np.array([[1, -1], [-1, 1]]),
108
'payoff2': np.array([[-1, 1], [1, -1]]),
109
'strategies': ['Heads', 'Tails']
110
}
111
}
112
\end{pycode}
113
114
\chapter{Classic Games Analysis}
115
116
\section{Prisoner's Dilemma}
117
118
\begin{pycode}
119
fig, axes = plt.subplots(2, 3, figsize=(14, 8))
120
121
for idx, (name, game) in enumerate(games.items()):
122
ax = axes[0, idx]
123
payoff1 = game['payoff1']
124
payoff2 = game['payoff2']
125
126
# Plot payoff matrix
127
im = ax.imshow(payoff1, cmap='RdYlGn', aspect='auto')
128
129
# Annotate cells
130
for i in range(2):
131
for j in range(2):
132
text = f'({payoff1[i,j]}, {payoff2[i,j]})'
133
ax.text(j, i, text, ha='center', va='center', fontsize=10)
134
135
ax.set_xticks([0, 1])
136
ax.set_yticks([0, 1])
137
ax.set_xticklabels(game['strategies'])
138
ax.set_yticklabels(game['strategies'])
139
ax.set_xlabel('Player 2')
140
ax.set_ylabel('Player 1')
141
ax.set_title(name)
142
143
# Find equilibria
144
pure_nash = find_pure_nash(payoff1, payoff2)
145
for eq in pure_nash:
146
rect = plt.Rectangle((eq[1]-0.5, eq[0]-0.5), 1, 1,
147
fill=False, edgecolor='green', linewidth=3)
148
ax.add_patch(rect)
149
150
# Best response analysis for Prisoner's Dilemma
151
pd_payoff1 = games["Prisoner's Dilemma"]['payoff1']
152
pd_payoff2 = games["Prisoner's Dilemma"]['payoff2']
153
154
ax = axes[1, 0]
155
p_range = np.linspace(0, 1, 100)
156
# Player 1's expected payoff vs strategy
157
for j, s2 in enumerate(['Cooperate', 'Defect']):
158
eu = p_range * pd_payoff1[0, j] + (1 - p_range) * pd_payoff1[1, j]
159
ax.plot(p_range, eu, label=f'P2 plays {s2}')
160
ax.set_xlabel('P1 probability of Cooperate')
161
ax.set_ylabel('P1 Expected Payoff')
162
ax.set_title("Prisoner's Dilemma: P1 Payoffs")
163
ax.legend()
164
ax.grid(True, alpha=0.3)
165
166
# Battle of Sexes mixed equilibrium
167
bos_payoff1 = games['Battle of Sexes']['payoff1']
168
bos_payoff2 = games['Battle of Sexes']['payoff2']
169
p_mix, q_mix = find_mixed_nash_2x2(bos_payoff1, bos_payoff2)
170
171
ax = axes[1, 1]
172
p_range = np.linspace(0, 1, 100)
173
q_range = np.linspace(0, 1, 100)
174
P, Q = np.meshgrid(p_range, q_range)
175
EU1 = expected_payoff(P, Q, bos_payoff1)
176
cs = ax.contourf(P, Q, EU1, levels=20, cmap='viridis')
177
ax.plot(p_mix, q_mix, 'ro', markersize=10, label='Mixed NE')
178
ax.scatter([1, 0], [1, 0], color='green', s=100, marker='s', label='Pure NE')
179
ax.set_xlabel('P1: prob(Opera)')
180
ax.set_ylabel('P2: prob(Opera)')
181
ax.set_title('Battle of Sexes: P1 Payoff')
182
ax.legend()
183
plt.colorbar(cs, ax=ax)
184
185
# Matching Pennies
186
mp_payoff1 = games['Matching Pennies']['payoff1']
187
mp_payoff2 = games['Matching Pennies']['payoff2']
188
p_mp, q_mp = find_mixed_nash_2x2(mp_payoff1, mp_payoff2)
189
190
ax = axes[1, 2]
191
EU1 = expected_payoff(P, Q, mp_payoff1)
192
cs = ax.contourf(P, Q, EU1, levels=20, cmap='RdBu')
193
ax.plot(p_mp, q_mp, 'ko', markersize=10, label=f'Mixed NE ({p_mp:.1f}, {q_mp:.1f})')
194
ax.set_xlabel('P1: prob(Heads)')
195
ax.set_ylabel('P2: prob(Heads)')
196
ax.set_title('Matching Pennies: P1 Payoff')
197
ax.legend()
198
plt.colorbar(cs, ax=ax)
199
200
plt.tight_layout()
201
plt.savefig('game_theory_analysis.pdf', dpi=150, bbox_inches='tight')
202
plt.close()
203
\end{pycode}
204
205
\begin{figure}[htbp]
206
\centering
207
\includegraphics[width=0.95\textwidth]{game_theory_analysis.pdf}
208
\caption{Game theory analysis: payoff matrices (top), equilibrium analysis (bottom).}
209
\end{figure}
210
211
\chapter{Mixed Strategy Equilibria}
212
213
\section{Computing Mixed Nash Equilibrium}
214
For a 2x2 game, player 1 mixes to make player 2 indifferent:
215
\begin{equation}
216
p \cdot u_2(s_1^1, s_2^1) + (1-p) \cdot u_2(s_1^2, s_2^1) = p \cdot u_2(s_1^1, s_2^2) + (1-p) \cdot u_2(s_1^2, s_2^2)
217
\end{equation}
218
219
\begin{pycode}
220
# Compute all equilibria
221
results = []
222
for name, game in games.items():
223
pure = find_pure_nash(game['payoff1'], game['payoff2'])
224
p, q = find_mixed_nash_2x2(game['payoff1'], game['payoff2'])
225
226
# Expected payoffs at mixed equilibrium
227
eu1 = expected_payoff(p, q, game['payoff1'])
228
eu2 = expected_payoff(p, q, game['payoff2'])
229
230
results.append({
231
'name': name,
232
'pure': pure,
233
'mixed_p': p,
234
'mixed_q': q,
235
'eu1': eu1,
236
'eu2': eu2
237
})
238
239
# Visualize dynamics
240
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
241
242
# Replicator dynamics for Matching Pennies
243
ax = axes[0]
244
dt = 0.01
245
T = 100
246
p_hist = [0.6]
247
q_hist = [0.4]
248
249
for _ in range(int(T/dt)):
250
p, q = p_hist[-1], q_hist[-1]
251
252
# Fitness calculations
253
f1_H = q * mp_payoff1[0, 0] + (1-q) * mp_payoff1[0, 1]
254
f1_T = q * mp_payoff1[1, 0] + (1-q) * mp_payoff1[1, 1]
255
f1_avg = p * f1_H + (1-p) * f1_T
256
257
f2_H = p * mp_payoff2[0, 0] + (1-p) * mp_payoff2[1, 0]
258
f2_T = p * mp_payoff2[0, 1] + (1-p) * mp_payoff2[1, 1]
259
f2_avg = q * f2_H + (1-q) * f2_T
260
261
dp = p * (f1_H - f1_avg) * dt
262
dq = q * (f2_H - f2_avg) * dt
263
264
p_new = np.clip(p + dp, 0.01, 0.99)
265
q_new = np.clip(q + dq, 0.01, 0.99)
266
267
p_hist.append(p_new)
268
q_hist.append(q_new)
269
270
ax.plot(p_hist, q_hist, 'b-', alpha=0.7)
271
ax.plot(p_hist[0], q_hist[0], 'go', markersize=10, label='Start')
272
ax.plot(0.5, 0.5, 'ro', markersize=10, label='NE')
273
ax.set_xlabel('P1: prob(Heads)')
274
ax.set_ylabel('P2: prob(Heads)')
275
ax.set_title('Replicator Dynamics: Matching Pennies')
276
ax.legend()
277
ax.grid(True, alpha=0.3)
278
279
# Iterated elimination
280
ax = axes[1]
281
# Show Cournot duopoly convergence
282
q1_hist = [10]
283
q2_hist = [10]
284
a, b, c = 100, 1, 10 # Demand: P = a - b*Q, cost = c
285
286
for _ in range(20):
287
# Best response functions
288
q1_br = (a - c - b * q2_hist[-1]) / (2 * b)
289
q2_br = (a - c - b * q1_hist[-1]) / (2 * b)
290
q1_hist.append(max(0, q1_br))
291
q2_hist.append(max(0, q2_br))
292
293
ax.plot(q1_hist, 'b-o', label='Firm 1')
294
ax.plot(q2_hist, 'r-s', label='Firm 2')
295
ax.axhline((a - c) / (3 * b), color='green', linestyle='--', label='NE')
296
ax.set_xlabel('Iteration')
297
ax.set_ylabel('Quantity')
298
ax.set_title('Cournot Duopoly Convergence')
299
ax.legend()
300
ax.grid(True, alpha=0.3)
301
302
plt.tight_layout()
303
plt.savefig('game_dynamics.pdf', dpi=150, bbox_inches='tight')
304
plt.close()
305
\end{pycode}
306
307
\begin{figure}[htbp]
308
\centering
309
\includegraphics[width=0.95\textwidth]{game_dynamics.pdf}
310
\caption{Game dynamics: replicator dynamics cycling (left), Cournot convergence (right).}
311
\end{figure}
312
313
\chapter{Numerical Results}
314
315
\begin{table}[htbp]
316
\centering
317
\caption{Nash equilibria for classic games}
318
\begin{tabular}{@{}lccc@{}}
319
\toprule
320
Game & Pure NE & Mixed $(p, q)$ & Expected Payoffs \\
321
\midrule
322
\py{results[0]['name']} & \py{str(results[0]['pure'])} & (\py{f"{results[0]['mixed_p']:.2f}"}, \py{f"{results[0]['mixed_q']:.2f}"}) & (\py{f"{results[0]['eu1']:.2f}"}, \py{f"{results[0]['eu2']:.2f}"}) \\
323
\py{results[1]['name']} & \py{str(results[1]['pure'])} & (\py{f"{results[1]['mixed_p']:.2f}"}, \py{f"{results[1]['mixed_q']:.2f}"}) & (\py{f"{results[1]['eu1']:.2f}"}, \py{f"{results[1]['eu2']:.2f}"}) \\
324
\py{results[2]['name']} & \py{str(results[2]['pure'])} & (\py{f"{results[2]['mixed_p']:.2f}"}, \py{f"{results[2]['mixed_q']:.2f}"}) & (\py{f"{results[2]['eu1']:.2f}"}, \py{f"{results[2]['eu2']:.2f}"}) \\
325
\bottomrule
326
\end{tabular}
327
\end{table}
328
329
\chapter{Conclusions}
330
331
\begin{enumerate}
332
\item Prisoner's Dilemma: Dominant strategy leads to Pareto-inferior outcome
333
\item Battle of Sexes: Multiple equilibria require coordination
334
\item Matching Pennies: Only mixed strategy equilibrium exists
335
\item Replicator dynamics may cycle rather than converge
336
\item Nash equilibrium provides predictions for strategic behavior
337
\end{enumerate}
338
339
\end{document}
340
341