evolutionary-game-dynamics 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- evolutionary_game_dynamics-0.1.0/LICENSE +21 -0
- evolutionary_game_dynamics-0.1.0/PKG-INFO +408 -0
- evolutionary_game_dynamics-0.1.0/README.md +353 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics/__init__.py +26 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics/analysis.py +140 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics/plotting.py +622 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics/response_functions.py +154 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics/simulation.py +847 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics/utils.py +303 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics.egg-info/PKG-INFO +408 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics.egg-info/SOURCES.txt +14 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics.egg-info/dependency_links.txt +1 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics.egg-info/requires.txt +9 -0
- evolutionary_game_dynamics-0.1.0/evolutionary_game_dynamics.egg-info/top_level.txt +1 -0
- evolutionary_game_dynamics-0.1.0/pyproject.toml +58 -0
- evolutionary_game_dynamics-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ankur-tutlani
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: evolutionary-game-dynamics
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python library for simulating two-player strategic interactions with memory-based decision-making, exogenous shocks, and recovery dynamics.
|
|
5
|
+
Author-email: Ankur Tutlani <ankur.tutlani@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 ankur-tutlani
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/ankur-tutlani/evolutionary-game-dynamics
|
|
29
|
+
Project-URL: Documentation, https://github.com/ankur-tutlani/evolutionary-game-dynamics#readme
|
|
30
|
+
Project-URL: Repository, https://github.com/ankur-tutlani/evolutionary-game-dynamics.git
|
|
31
|
+
Project-URL: Issues, https://github.com/ankur-tutlani/evolutionary-game-dynamics/issues
|
|
32
|
+
Keywords: game-theory,evolutionary-dynamics,agent-based-simulation,monte-carlo,agent-based-modeling
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: Topic :: Scientific/Engineering
|
|
37
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
38
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
39
|
+
Classifier: Programming Language :: Python :: 3
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Requires-Python: >=3.11
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
License-File: LICENSE
|
|
46
|
+
Requires-Dist: numpy>=2.0
|
|
47
|
+
Requires-Dist: pandas>=2.0
|
|
48
|
+
Requires-Dist: matplotlib>=3.5
|
|
49
|
+
Requires-Dist: seaborn>=0.12
|
|
50
|
+
Requires-Dist: openpyxl>=3.0
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
53
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
# Game Theory Simulation Library
|
|
57
|
+
|
|
58
|
+
## Overview
|
|
59
|
+
|
|
60
|
+
This Python library simulates two-player strategic interactions with memory-based decision-making, exogenous shocks, and recovery dynamics. It is designed for research on **norm formation, stability, and recovery** following temporary disruptions to the payoff environment.
|
|
61
|
+
|
|
62
|
+
The project enables researchers to conduct large-scale Monte Carlo simulations across parameter spaces, analyze how agents' behavioral patterns respond to shocks, and measure recovery times to equilibrium. It is particularly useful for studying the robustness of social conventions and norms in dynamic game-theoretic settings.
|
|
63
|
+
|
|
64
|
+
## Key Features
|
|
65
|
+
|
|
66
|
+
- **Two-Player Game Engine**: Configurable N×M games with arbitrary payoff matrices for both players
|
|
67
|
+
- **Memory-Based Behavior**: Agents remember past joint actions and base decisions on that history
|
|
68
|
+
- **Multiple Response Rules**:
|
|
69
|
+
- Exhaustive best responses (condition on distinct actions observed in history)
|
|
70
|
+
- Expected payoff maximization (empirical frequency-based expectations)
|
|
71
|
+
- Epsilon-greedy stochastic actions for bounded rationality
|
|
72
|
+
- **Shock Analysis**:
|
|
73
|
+
- Temporary payoff matrix changes to represent exogenous disruptions
|
|
74
|
+
- Track pre-shock, post-shock, and recovery-phase frequencies
|
|
75
|
+
- Measure time-to-recovery for each action pair
|
|
76
|
+
- **Initial State Modes**:
|
|
77
|
+
- Random initial histories
|
|
78
|
+
- Balanced distributions
|
|
79
|
+
- Canonical (exhaustive enumeration) distributions
|
|
80
|
+
- **Comprehensive Analysis & Visualization**:
|
|
81
|
+
- Pre/post-shock frequency comparisons
|
|
82
|
+
- Recovery time distributions
|
|
83
|
+
- Heatmaps across memory length and noise parameters
|
|
84
|
+
- Recovery rate statistics
|
|
85
|
+
- Individual trajectory plotting
|
|
86
|
+
- **Monte Carlo Sensitivity Analysis**: Systematic parameter sweeps with parallel Monte Carlo runs
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
### Prerequisites
|
|
91
|
+
- Python 3.11+
|
|
92
|
+
- Conda (recommended) or pip
|
|
93
|
+
|
|
94
|
+
### Using Conda (Recommended)
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
conda env create -f environment.yml
|
|
98
|
+
conda activate game-sim-env
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Using pip
|
|
102
|
+
|
|
103
|
+
If you prefer pip, install the required packages:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pip install numpy pandas matplotlib seaborn openpyxl
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Project Structure
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
.
|
|
113
|
+
├── README.md # This file
|
|
114
|
+
├── environment.yml # Conda environment specification
|
|
115
|
+
│
|
|
116
|
+
├── simulation.py # Core simulation engine
|
|
117
|
+
│ ├── simulate_two_player_game() # Basic game simulation
|
|
118
|
+
│ ├── simulate_with_shock() # Game simulation with payoff shocks
|
|
119
|
+
│ ├── run_sensitivity_with_shock() # Monte Carlo sensitivity analysis
|
|
120
|
+
│ └── compute_*_frequencies() # Recovery time calculations
|
|
121
|
+
│
|
|
122
|
+
├── response_functions.py # Decision-making strategies
|
|
123
|
+
│ ├── exhaustive_epsilon_policy_*() # Exhaustive best response policies
|
|
124
|
+
│ ├── expected_payoff_policy_*() # Expected payoff maximization policies
|
|
125
|
+
│ └── unified_response() # Policy selector wrapper
|
|
126
|
+
│
|
|
127
|
+
├── analysis.py # Result aggregation & reporting
|
|
128
|
+
│ ├── build_table_norm_epsilon_memory() # Master results table
|
|
129
|
+
│ ├── build_table_norm_shock_pair() # Shock outcome analysis
|
|
130
|
+
│ └── build_table_norm_initial_state_bin()# Initial state sensitivity
|
|
131
|
+
│
|
|
132
|
+
├── plotting.py # Visualization functions
|
|
133
|
+
│ ├── plot_pre_post_frequency_overall() # Summary bar chart
|
|
134
|
+
│ ├── plot_recovery_*_allpairs() # Recovery vs parameters
|
|
135
|
+
│ ├── plot_pre_shock_heatmap_grid() # Heatmaps (2×2 subplots)
|
|
136
|
+
│ ├── plot_individual_run() # Trajectory visualization
|
|
137
|
+
│ ├── heatmap_standard_deviation_grid() # Variability analysis
|
|
138
|
+
│ └── generate_all_outputs() # Full report generation
|
|
139
|
+
│
|
|
140
|
+
├── utils.py # Utility functions
|
|
141
|
+
│ ├── get_distinct_actions_from_history() # Extract observation set
|
|
142
|
+
│ ├── best_responses_*() # Best response calculation
|
|
143
|
+
│ ├── epsilon_greedy_choice() # Stochastic action selection
|
|
144
|
+
│ ├── generate_initial_history() # History initialization
|
|
145
|
+
│ ├── generate_all_distributions() # Canonical distribution enumeration
|
|
146
|
+
│ └── compute_initial_distribution() # Distribution parsing
|
|
147
|
+
│
|
|
148
|
+
└── examples.py # Example usage & parameter templates
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Usage
|
|
152
|
+
|
|
153
|
+
### Basic Example: Single Simulation
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from simulation import simulate_two_player_game
|
|
157
|
+
|
|
158
|
+
# Define a 2×2 game (Prisoner's Dilemma)
|
|
159
|
+
row_player_payoffs = [2, 0, 0, 1] # (C,C), (C,D), (D,C), (D,D)
|
|
160
|
+
col_player_payoffs = [1, 0, 0, 2]
|
|
161
|
+
|
|
162
|
+
# Run one trajectory
|
|
163
|
+
traj_df, freq_df = simulate_two_player_game(
|
|
164
|
+
num_rows=2,
|
|
165
|
+
num_cols=2,
|
|
166
|
+
memory_length=3,
|
|
167
|
+
timeperiod=100,
|
|
168
|
+
row_player_payoffs=row_player_payoffs,
|
|
169
|
+
column_player_payoffs=col_player_payoffs,
|
|
170
|
+
epsilon_row=0.05,
|
|
171
|
+
epsilon_col=0.05,
|
|
172
|
+
response_rule='exhaustive',
|
|
173
|
+
random_seed=42
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
print(traj_df.head()) # Time series of actions
|
|
177
|
+
print(freq_df) # Frequency of each joint action
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Shock Simulation
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from simulation import simulate_with_shock
|
|
184
|
+
|
|
185
|
+
# Same setup, but with a temporary payoff shock
|
|
186
|
+
shock_payoffs_row = [2, 1, 1, 1]
|
|
187
|
+
shock_payoffs_col = [1, 1, 1, 2]
|
|
188
|
+
|
|
189
|
+
traj_df, freq_df = simulate_with_shock(
|
|
190
|
+
num_rows=2,
|
|
191
|
+
num_cols=2,
|
|
192
|
+
memory_length=3,
|
|
193
|
+
timeperiod=100,
|
|
194
|
+
row_player_payoffs=row_player_payoffs,
|
|
195
|
+
column_player_payoffs=col_player_payoffs,
|
|
196
|
+
shock_payoff_row=shock_payoffs_row,
|
|
197
|
+
shock_payoff_col=shock_payoffs_col,
|
|
198
|
+
epsilon_row=0.05,
|
|
199
|
+
epsilon_col=0.05,
|
|
200
|
+
shock_time=48, # Shock starts at t=48
|
|
201
|
+
shock_duration=4, # Lasts 4 periods
|
|
202
|
+
response_rule='exhaustive',
|
|
203
|
+
random_seed=42
|
|
204
|
+
)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Full Monte Carlo Sensitivity Analysis
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from simulation import run_sensitivity, generate_all_outputs
|
|
211
|
+
from utils import generate_all_distributions
|
|
212
|
+
import pandas as pd
|
|
213
|
+
|
|
214
|
+
# Parameters
|
|
215
|
+
num_rows, num_cols = 2, 2
|
|
216
|
+
row_payoffs = [2, 0, 0, 1]
|
|
217
|
+
col_payoffs = [1, 0, 0, 2]
|
|
218
|
+
shock_payoffs_row = [2, 1, 1, 1]
|
|
219
|
+
shock_payoffs_col = [1, 1, 1, 2]
|
|
220
|
+
|
|
221
|
+
# Sensitivity ranges
|
|
222
|
+
memory_lengths = [1, 2, 3, 4, 5]
|
|
223
|
+
epsilons = [0, 0.01, 0.05, 0.1, 0.15]
|
|
224
|
+
timeperiods = [100]
|
|
225
|
+
shock_times = [48]
|
|
226
|
+
shock_durations = [4]
|
|
227
|
+
|
|
228
|
+
# Precompute canonical distributions
|
|
229
|
+
canonical_sets = {}
|
|
230
|
+
for mem in memory_lengths:
|
|
231
|
+
canonical_sets[mem] = generate_all_distributions(num_rows, num_cols, mem)
|
|
232
|
+
|
|
233
|
+
# Run main analysis
|
|
234
|
+
results_df = run_sensitivity(
|
|
235
|
+
initial_state_mode='canonical', # or 'random', 'balanced'
|
|
236
|
+
num_rows=num_rows,
|
|
237
|
+
num_cols=num_cols,
|
|
238
|
+
row_player_payoffs=row_payoffs,
|
|
239
|
+
column_player_payoffs=col_payoffs,
|
|
240
|
+
shock_payoff_row=shock_payoffs_row,
|
|
241
|
+
shock_payoff_col=shock_payoffs_col,
|
|
242
|
+
memory_lengths=memory_lengths,
|
|
243
|
+
epsilons=epsilons,
|
|
244
|
+
timeperiods=timeperiods,
|
|
245
|
+
shock_times=shock_times,
|
|
246
|
+
shock_durations=shock_durations,
|
|
247
|
+
canonical_sets=canonical_sets,
|
|
248
|
+
n_runs_per_setting=10, # Monte Carlo runs per setting
|
|
249
|
+
export_dir='outputs/analysis',
|
|
250
|
+
iter_name='test_run_1',
|
|
251
|
+
random_seed=123,
|
|
252
|
+
response_rule='exhaustive'
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Generate all outputs (tables + visualizations)
|
|
256
|
+
outputs = generate_all_outputs(
|
|
257
|
+
results_df,
|
|
258
|
+
output_dir='outputs/figures'
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# Access generated tables
|
|
262
|
+
table1 = outputs['table1'] # Master results table
|
|
263
|
+
table2 = outputs['table2'] # Initial state binned analysis
|
|
264
|
+
table3 = outputs['table3'] # Shock pair comparison
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Customizing Decision Rules
|
|
268
|
+
|
|
269
|
+
**Exhaustive Best Response Rule** (Default)
|
|
270
|
+
```python
|
|
271
|
+
# Agents choose an action from the set of best responses to any distinct
|
|
272
|
+
# opponent action observed in history, plus epsilon-greedy exploration
|
|
273
|
+
response_rule = 'exhaustive'
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Expected Payoff Rule**
|
|
277
|
+
```python
|
|
278
|
+
# Agents estimate empirical frequency distribution of opponent actions,
|
|
279
|
+
# compute expected payoffs for each own action, then pick best responses
|
|
280
|
+
# plus epsilon-greedy exploration
|
|
281
|
+
response_rule = 'expected'
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Output Files
|
|
285
|
+
|
|
286
|
+
The library generates two types of outputs:
|
|
287
|
+
|
|
288
|
+
**1. Data Files** (`export_dir`)
|
|
289
|
+
- `monte_carlo_results_[iter_name].xlsx` — Main results table (one row per setting, run, and pair)
|
|
290
|
+
- `traj_mem*.xlsx` — Individual trajectory files for each run
|
|
291
|
+
|
|
292
|
+
**2. Analysis Files** (`output_dir`)
|
|
293
|
+
- `table_norm_epsilon_memory.xlsx` — Summary statistics by memory length and epsilon
|
|
294
|
+
- `table_norm_initial_state_bin.xlsx` — Recovery by initial state distribution
|
|
295
|
+
- `table_norm_shock_pair.xlsx` — Results by shock joint action
|
|
296
|
+
- PNG visualizations — Heatmaps and line plots
|
|
297
|
+
|
|
298
|
+
## Configuration Parameters
|
|
299
|
+
|
|
300
|
+
### Game Setup
|
|
301
|
+
| Parameter | Type | Description |
|
|
302
|
+
|-----------|------|-------------|
|
|
303
|
+
| `num_rows`, `num_cols` | int | Game dimensions (rows = row player actions, cols = column player actions) |
|
|
304
|
+
| `row_player_payoffs` | list | Payoff vector for row player (length = rows × cols) |
|
|
305
|
+
| `column_player_payoffs` | list | Payoff vector for column player (length = rows × cols) |
|
|
306
|
+
| `shock_payoff_row` | list | Payoff vector during shock period for row player |
|
|
307
|
+
| `shock_payoff_col` | list | Payoff vector during shock period for column player |
|
|
308
|
+
|
|
309
|
+
### Behavioral Parameters
|
|
310
|
+
| Parameter | Type | Default | Description |
|
|
311
|
+
|-----------|------|---------|-------------|
|
|
312
|
+
| `memory_length` | int | — | Number of past joint actions agents remember |
|
|
313
|
+
| `epsilon_row`, `epsilon_col` | float | 0.1 | Probability of random action (per player) |
|
|
314
|
+
| `response_rule` | str | 'exhaustive' | Decision rule: 'exhaustive' or 'expected' |
|
|
315
|
+
| `initial_state_mode` | str | — | How to initialize: 'random', 'balanced', or 'canonical' |
|
|
316
|
+
|
|
317
|
+
### Simulation Parameters
|
|
318
|
+
| Parameter | Type | Description |
|
|
319
|
+
|-----------|------|-------------|
|
|
320
|
+
| `timeperiod` | int | Number of periods to simulate |
|
|
321
|
+
| `shock_time` | int | Period when shock begins (or None for no shock) |
|
|
322
|
+
| `shock_duration` | int | Number of periods shock lasts |
|
|
323
|
+
| `n_runs_per_setting` | int | Monte Carlo replications per parameter combination |
|
|
324
|
+
| `random_seed` | int | Seed for reproducibility |
|
|
325
|
+
|
|
326
|
+
## Key Functions Reference
|
|
327
|
+
|
|
328
|
+
### Core Simulation
|
|
329
|
+
- `simulate_two_player_game()` — Run a single game trajectory
|
|
330
|
+
- `simulate_with_shock()` — Single trajectory with payoff shock
|
|
331
|
+
- `run_sensitivity()` — Full Monte Carlo analysis across parameter grid
|
|
332
|
+
|
|
333
|
+
### Analysis
|
|
334
|
+
- `build_table_norm_epsilon_memory()` — Aggregate by memory and epsilon
|
|
335
|
+
- `build_table_norm_shock_pair()` — Compare shock outcomes
|
|
336
|
+
- `build_table_norm_initial_state_bin()` — Bin by initial state and compare
|
|
337
|
+
|
|
338
|
+
### Visualization
|
|
339
|
+
- `generate_all_outputs()` — Produces all tables and plots automatically
|
|
340
|
+
- `plot_recovery_heatmap_grid()` — 2×2 grid of recovery time heatmaps
|
|
341
|
+
- `plot_pre_shock_heatmap_grid()` — 2×2 grid of pre-shock frequency heatmaps
|
|
342
|
+
- `plot_individual_run()` — Trajectory visualization with shock window
|
|
343
|
+
|
|
344
|
+
## Theory Background
|
|
345
|
+
|
|
346
|
+
This library implements a **memory-based best-response model** of strategic interaction:
|
|
347
|
+
|
|
348
|
+
1. **History**: Each agent maintains a list of recent joint actions (payoff pairs played)
|
|
349
|
+
2. **Play**: At each time step:
|
|
350
|
+
- Extract distinct opponent actions from history
|
|
351
|
+
- Compute best responses (or expected payoffs)
|
|
352
|
+
- Apply epsilon-greedy action selection
|
|
353
|
+
3. **Update**: Add the joint action to history (remove oldest if memory exceeded)
|
|
354
|
+
4. **Shock**: Optionally change payoff matrices temporarily
|
|
355
|
+
5. **Recovery**: Track time until behavior returns to pre-shock norm
|
|
356
|
+
|
|
357
|
+
**Key metric**: *Recovery time* = periods until a norm's frequency returns to pre-shock level.
|
|
358
|
+
|
|
359
|
+
## Dependencies
|
|
360
|
+
|
|
361
|
+
- `numpy` — Numerical computing
|
|
362
|
+
- `pandas` — Data manipulation and analysis
|
|
363
|
+
- `matplotlib` — Plotting library
|
|
364
|
+
- `seaborn` — Statistical visualization
|
|
365
|
+
- `openpyxl` — Excel file I/O
|
|
366
|
+
|
|
367
|
+
All included in `environment.yml`.
|
|
368
|
+
|
|
369
|
+
## Example Workflow
|
|
370
|
+
|
|
371
|
+
See [examples.py](examples.py) for a complete working example showing:
|
|
372
|
+
1. Parameter setup
|
|
373
|
+
2. Canonical distribution precomputation
|
|
374
|
+
3. Sensitivity analysis execution
|
|
375
|
+
4. Output generation
|
|
376
|
+
5. Result visualization
|
|
377
|
+
|
|
378
|
+
To run the example:
|
|
379
|
+
```bash
|
|
380
|
+
python examples.py
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Output Interpretation
|
|
384
|
+
|
|
385
|
+
### Pre/Post Shock Frequencies
|
|
386
|
+
Shows how frequently each joint action is played before / after the shock. Used to identify which norms are disrupted and which persist.
|
|
387
|
+
|
|
388
|
+
### Recovery Time
|
|
389
|
+
Number of periods until a norm's frequency returns to at least its pre-shock level. Longer recovery = less resilient norms.
|
|
390
|
+
|
|
391
|
+
### Heatmaps
|
|
392
|
+
Visualize how recovery time (or pre-shock frequency) varies across memory length and epsilon parameters. Identify which parameter combinations produce robust vs. fragile norms.
|
|
393
|
+
|
|
394
|
+
## Notes for Users
|
|
395
|
+
|
|
396
|
+
- **Random Seed**: Set `random_seed` for reproducibility
|
|
397
|
+
- **Memory Length**: Larger memory captures more history but increases state space
|
|
398
|
+
- **Epsilon**: Higher epsilon = more randomness = less stable norms
|
|
399
|
+
- **Initial State**: 'canonical' requires precomputation but covers the full distribution space
|
|
400
|
+
- **Export Path**: Create parent directories in advance if needed; the library will handle subdirectory creation
|
|
401
|
+
|
|
402
|
+
## License
|
|
403
|
+
|
|
404
|
+
MIT License
|
|
405
|
+
|
|
406
|
+
## Citation
|
|
407
|
+
|
|
408
|
+
If you use this library in your research, please cite it appropriately. Citation format to be added upon publication.
|