pynamo-egt 0.3.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pyNamo contributors
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,436 @@
1
+ Metadata-Version: 2.4
2
+ Name: pynamo-egt
3
+ Version: 0.3.1
4
+ Summary: pyNamo-EGT: plotting and analysis tools for replicator dynamics in evolutionary games.
5
+ Author: Slimane Dridi, Benjamin Giraudon
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 pyNamo contributors
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: Repository, https://github.com/SlimaneD/pynamo
29
+ Project-URL: Issues, https://github.com/SlimaneD/pynamo/issues
30
+ Classifier: Development Status :: 3 - Alpha
31
+ Classifier: Intended Audience :: Science/Research
32
+ Classifier: Intended Audience :: Education
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.12
36
+ Classifier: Topic :: Scientific/Engineering
37
+ Classifier: Topic :: Scientific/Engineering :: Visualization
38
+ Requires-Python: >=3.12
39
+ Description-Content-Type: text/markdown
40
+ License-File: LICENSE
41
+ Requires-Dist: matplotlib
42
+ Requires-Dist: numpy
43
+ Requires-Dist: pandas
44
+ Requires-Dist: scipy
45
+ Requires-Dist: sympy
46
+ Provides-Extra: notebook
47
+ Requires-Dist: ipykernel; extra == "notebook"
48
+ Requires-Dist: ipympl; extra == "notebook"
49
+ Requires-Dist: ipywidgets; extra == "notebook"
50
+ Requires-Dist: jupyter; extra == "notebook"
51
+ Provides-Extra: dev
52
+ Requires-Dist: pytest; extra == "dev"
53
+ Dynamic: license-file
54
+
55
+ # pyNamo-EGT
56
+
57
+ [![Launch Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/SlimaneD/pynamo/master?filepath=tutorial.ipynb)
58
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SlimaneD/pynamo/blob/master/tutorial_colab.ipynb)
59
+
60
+ pyNamo-EGT is a Python package for plotting and analyzing replicator dynamics
61
+ in evolutionary games. It focuses on game classes whose state spaces can be
62
+ visualized directly, producing phase portraits on simplices with trajectories,
63
+ speed fields, vector fields, equilibria, and stability information.
64
+
65
+ The package is designed for researchers, teachers, and students who want clear,
66
+ publication-quality diagrams of theoretical phase portraits. Its high-level
67
+ interface is built for Jupyter notebooks and produces informative figures with
68
+ minimal code, while still exposing fine-grained controls for plotting details.
69
+
70
+ ## Start Here
71
+
72
+ There are three main ways to try pyNamo-EGT.
73
+
74
+ **1. Full interactive tutorial in Binder**
75
+
76
+ Use Binder if you want the closest experience to a local Jupyter notebook,
77
+ including the interactive widget and rotatable 3D Matplotlib figures:
78
+
79
+ [Launch the Binder tutorial](https://mybinder.org/v2/gh/SlimaneD/pynamo/master?filepath=tutorial.ipynb)
80
+
81
+ Binder runs in the browser and does not require a local installation. First launch
82
+ can take a few minutes while Binder builds the environment.
83
+
84
+ Interactive 3D plots may occasionally appear blank in Binder. Try rerunning the
85
+ plotting cell. If the issue persists, replace `%matplotlib widget` with
86
+ `%matplotlib inline` in that plotting cell for a static preview without rotation.
87
+ SVG/PDF export quality is unaffected.
88
+
89
+ **2. Faster static tutorial in Google Colab**
90
+
91
+ Use Colab if you want a faster browser-based preview of the tutorial:
92
+
93
+ [Open the Colab tutorial](https://colab.research.google.com/github/SlimaneD/pynamo/blob/master/tutorial_colab.ipynb)
94
+
95
+ The Colab notebook supports ordinary plotting cells, but not the interactive
96
+ widget or rotatable 3D Matplotlib figures.
97
+
98
+ **3. Local installation from GitHub**
99
+
100
+ Use a local installation if you want to use pyNamo-EGT in your own notebooks or
101
+ modify the code:
102
+
103
+ ```bash
104
+ git clone https://github.com/SlimaneD/pynamo.git
105
+ cd pynamo
106
+ pip install ".[notebook]"
107
+ ```
108
+
109
+ ## Features
110
+
111
+ - One-population symmetric 2×2 phase lines and one-parameter bifurcation diagrams, with customizable phase-line labels and curve styles.
112
+ - Replicator dynamics for asymmetric 2-player / 2-strategy games (`2Pop2S`), symmetric 2-player / 3-strategy games (`1Pop3S`), symmetric 2-player / 4-strategy games (`1Pop4S`), and asymmetric 3-player / 2-strategy games (`3Pop2S`).
113
+ - A curated catalogue of built-in example games with descriptions, references, parameter notes, and explanations of what each example illustrates.
114
+ - Matplotlib phase portraits with trajectories, equilibria, speed fields, vector fields, and optional colored faces for 3D state spaces.
115
+ - Reproducible grid-based default trajectories, with automatic one-dimensional flow arrows on triangle and square boundaries.
116
+ - Equilibrium analysis with linear stability classification, Nash equilibria, strict Nash equilibria, and ESS checks where applicable.
117
+ - A Jupyter widget for quick exploration of built-in example games.
118
+
119
+ ## Requirements
120
+
121
+ - Python 3.12+
122
+ - `numpy`, `scipy`, `matplotlib`, `sympy`, `pandas`
123
+ - Optional for notebooks/widgets: `jupyter`, `ipykernel`, `ipywidgets`, `ipympl`
124
+
125
+ Install dependencies in a virtual environment:
126
+
127
+ ```bash
128
+ python -m venv .venv
129
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
130
+ pip install numpy scipy matplotlib sympy pandas ipywidgets ipympl
131
+ ```
132
+
133
+ ## Installation
134
+
135
+ pyNamo-EGT is currently distributed from GitHub. For ordinary notebook use, install with:
136
+
137
+ ```bash
138
+ pip install ".[notebook]"
139
+ ```
140
+
141
+ For core functionality only, without notebook/widget dependencies:
142
+
143
+ ```bash
144
+ pip install .
145
+ ```
146
+
147
+ For development tests:
148
+
149
+ ```bash
150
+ pip install ".[dev]"
151
+ python -m pytest -q
152
+ ```
153
+
154
+ ## First use
155
+
156
+ ```python
157
+ import matplotlib.pyplot as plt
158
+
159
+ import pynamo_egt as pn
160
+
161
+ fig, ax = pn.phase_portrait(pn.examples.games.good_rps)
162
+ plt.show()
163
+ ```
164
+
165
+ `pn.phase_portrait` returns ordinary Matplotlib objects, so figures can be
166
+ modified or saved with standard Matplotlib commands:
167
+
168
+ ```python
169
+ fig.savefig("good_rps.svg", bbox_inches="tight")
170
+ fig.savefig("good_rps.pdf", bbox_inches="tight")
171
+ ```
172
+
173
+ ## Built-In Examples
174
+
175
+ Built-in games are available through `pn.examples.games`:
176
+
177
+ ```python
178
+ g = pn.examples.games.battle_of_the_sexes
179
+ same_game = pn.examples.games("battle_of_the_sexes")
180
+ pn.examples.games.by_class("2Pop2S")
181
+ ```
182
+
183
+ Each catalogue game carries metadata:
184
+
185
+ ```python
186
+ g = pn.examples.games.chaotic_four_strategy_game
187
+ g.describe()
188
+ ```
189
+
190
+ You can also use the module-level helper:
191
+
192
+ ```python
193
+ pn.examples.describe(g)
194
+ ```
195
+
196
+ The metadata include the game description, reference, parameter values, and the
197
+ main mathematical point illustrated by the example.
198
+
199
+ ## Game Classes
200
+
201
+ Game-class identifiers use population counts (`Pop`) and strategies per population
202
+ (`S`), rather than the number of players in an interaction. A symmetric two-player
203
+ interaction can be modeled in one population or in two separate populations.
204
+
205
+ pyNamo currently supports five game classes:
206
+
207
+ - `1Pop2S`: symmetric 2-player / 2-strategy games in one population, represented by one `2 x 2` payoff matrix.
208
+ - `2Pop2S`: 2-player / 2-strategy games, represented by one payoff matrix per player. In each matrix, rows are that player's own strategies and columns are the opponent's strategies.
209
+ - `1Pop3S`: symmetric 2-player / 3-strategy games, represented by one `3 x 3` payoff matrix.
210
+ - `1Pop4S`: symmetric 2-player / 4-strategy games, represented by one `4 x 4` payoff matrix.
211
+ - `3Pop2S`: 3-player / 2-strategy games, represented by one `2 x 2 x 2` payoff tensor per player.
212
+
213
+ For asymmetric 2-strategy games, each coordinate in a reduced state is the
214
+ probability that the corresponding player uses their first listed strategy.
215
+
216
+ For symmetric 3-strategy games, initial conditions use two coordinates and the
217
+ third strategy frequency is inferred. For symmetric 4-strategy games, initial
218
+ conditions use three coordinates and the fourth strategy frequency is inferred.
219
+
220
+ ## Defining Games
221
+
222
+ A symmetric 3-strategy game:
223
+
224
+ ```python
225
+ import numpy as np
226
+ import pynamo_egt as pn
227
+ my_game = pn.Game(
228
+ name="My RPS Variant",
229
+ payoffs=np.array([
230
+ [0, -1, 2],
231
+ [2, 0, -1],
232
+ [-1, 2, 0],
233
+ ], dtype=float),
234
+ strategy_labels=["R", "P", "S"],
235
+ )
236
+ ```
237
+
238
+ An asymmetric 2-player / 2-strategy game:
239
+
240
+ Each payoff matrix uses its recipient as the focal player. The first matrix has
241
+ player 1's strategies as rows and player 2's as columns; the second has player
242
+ 2's strategies as rows and player 1's as columns.
243
+
244
+ ```python
245
+ my_asymmetric_game = pn.Game(
246
+ name="My Asymmetric Game",
247
+ payoffs=(
248
+ # Player 1 rows; player 2 columns.
249
+ np.array([[3, 0], [1, 2]], dtype=float),
250
+ # Player 2 rows; player 1 columns.
251
+ np.array([[2, 1], [0, 3]], dtype=float),
252
+ ),
253
+ player_strategy_labels=[["A", "B"], ["C", "D"]],
254
+ player_labels=["Player 1", "Player 2"],
255
+ symmetric=False,
256
+ )
257
+ ```
258
+
259
+ ## Plot Customization
260
+
261
+ Most common plotting options are parameters of `pn.phase_portrait`:
262
+
263
+ ```python
264
+ fig, ax = pn.phase_portrait(
265
+ pn.examples.games.matching_pennies,
266
+ starts=[[0.2, 0.7], [0.7, 0.5], [0.9, 0.9]],
267
+ tmax=40,
268
+ speed_cmap=plt.cm.cividis,
269
+ speed_levels=20,
270
+ show_vector_field=True,
271
+ vector_grid=18,
272
+ trajectory_color="black",
273
+ trajectory_linewidth=1.2,
274
+ trajectory_arrows=[0.001],
275
+ )
276
+ ```
277
+
278
+ When `starts` is omitted, pyNamo uses deterministically spaced starts. For `1Pop3S` and
279
+ `2Pop2S`, it also treats every invariant edge as a one-dimensional phase line
280
+ and places arrows halfway between consecutive edge equilibria. Control the exact
281
+ number of generated trajectories with `trajectory_number`; explicit `starts` override it. Use
282
+ `show_edge_flow=True` to combine explicit starts with boundary flow, or
283
+ `show_edge_flow=False` to hide boundary flow. Boundary-arrow positions are
284
+ determined by edge equilibria rather than the time-based `trajectory_arrows`
285
+ values; `trajectory_arrows=[]` hides all arrowheads.
286
+
287
+ Use one color per trajectory by passing a list:
288
+
289
+ ```python
290
+ fig, ax = pn.phase_portrait(
291
+ pn.examples.games.cyclic_mismatching_pennies,
292
+ starts=[[0.52, 0.50, 0.48], [0.70, 0.45, 0.35]],
293
+ trajectory_color=["tab:blue", "tab:orange"],
294
+ trajectory_arrows=[],
295
+ tmax=1000,
296
+ )
297
+ ```
298
+
299
+ Colored faces are available for 3D state spaces:
300
+
301
+ ```python
302
+ fig, ax = pn.phase_portrait(
303
+ pn.examples.games.ownership_game,
304
+ show_faces=True,
305
+ face_alpha=0.15,
306
+ )
307
+ ```
308
+
309
+ Vector fields are available for both 2D and 3D game classes. Sparse 3D vector
310
+ fields can be useful for exploration, but trajectories are usually clearer in
311
+ static publication figures.
312
+
313
+ Labels are Matplotlib text labels and can include simple LaTeX-style math
314
+ notation such as `"$S_1$"` or `"$x = P(A)$"`. pyNamo-EGT does not require a
315
+ full LaTeX installation by default; users who want full LaTeX rendering can
316
+ enable Matplotlib's `text.usetex` option manually.
317
+
318
+ For the full parameter documentation:
319
+
320
+ ```python
321
+ help(pn.phase_portrait)
322
+ ```
323
+
324
+ ## Equilibrium Analysis
325
+
326
+ For notebooks, use `pn.equilibrium_table`:
327
+
328
+ ```python
329
+ import pynamo_egt as pn
330
+
331
+ pn.equilibrium_table(pn.examples.games.good_rps)
332
+ ```
333
+
334
+ For programmatic use:
335
+
336
+ ```python
337
+ result = pn.analyze_equilibria(pn.examples.games.good_rps)
338
+ rows = result.to_rows()
339
+ ```
340
+
341
+ For quick access to static equilibrium concepts:
342
+
343
+ ```python
344
+ pn.rest_points_nash(game=pn.examples.games.good_rps)
345
+ pn.rest_points_strict_nash(game=pn.examples.games.good_rps)
346
+ pn.rest_points_ess(game=pn.examples.games.good_rps)
347
+ ```
348
+
349
+ These helpers filter the replicator rest points detected by pyNamo; they do not
350
+ claim to enumerate additional or non-isolated Nash-equilibrium families.
351
+ `rest_points_ess` returns ESS only for symmetric games.
352
+
353
+ ## Stability Caveats
354
+
355
+ Stability is classified from the linearization restricted to admissible directions
356
+ in the state space. This is important at boundaries because outward perturbations
357
+ are not valid evolutionary deviations.
358
+
359
+ Some equilibria are non-hyperbolic or belong to degenerate equilibrium sets. In
360
+ these cases pyNamo emits warnings rather than forcing a classification. For higher-dimensional games, non-isolated
361
+ equilibrium manifolds are not plotted automatically; isolated equilibria are still
362
+ shown when they can be identified.
363
+
364
+ The category `unstable` means that linearization proves the equilibrium is not
365
+ stable, but does not always distinguish source from saddle. In plots, unstable
366
+ equilibria are drawn with the source color for visual compatibility.
367
+
368
+ ## Interactive Widget
369
+
370
+ In a notebook, use:
371
+
372
+ ```python
373
+ %matplotlib widget
374
+
375
+ import pynamo_egt as pn
376
+ pn.interactive.launch_replicator_widget()
377
+ ```
378
+
379
+ The widget lets users choose a game class and example, adjust trajectories, toggle
380
+ speed/vector fields, and inspect payoff data and equilibrium analysis.
381
+
382
+ If 3D rotation does not work, make sure the notebook kernel has `ipympl` installed
383
+ and that `%matplotlib widget` has been evaluated.
384
+
385
+ ## Repository Structure
386
+
387
+ - `pynamo_egt/game.py`: core `Game` class and game-class inference.
388
+ - `pynamo_egt/examples.py`: curated catalogue of predefined games.
389
+ - `pynamo_egt/dynamics.py`: replicator vector fields and rest-point computation.
390
+ - `pynamo_egt/analysis.py`: equilibrium and stability analysis.
391
+ - `pynamo_egt/drawer.py`: plotting helpers and `phase_portrait`.
392
+ - `pynamo_egt/interactive.py`: Jupyter widget front-end.
393
+ - `tutorial.ipynb`: notebook tutorial.
394
+ - `tests/`: pytest test suite.
395
+
396
+ ## One-population phase lines and bifurcation diagrams
397
+
398
+ ```python
399
+ coordination = pn.Game("Coordination", [[1, 0], [0, 1]], strategy_labels=["A", "B"])
400
+ fig, ax = pn.phase_portrait(coordination, figsize=(8, 2.2))
401
+
402
+ fig, ax = pn.bifurcation_diagram(
403
+ lambda s: [[s, 0], [1, 2]],
404
+ parameter_range=(-1, 4),
405
+ parameter_values=[1],
406
+ phase_line_values=[0, 2, 3],
407
+ phase_line_labels=["I", "II", "II"],
408
+ stable_linestyle="-", unstable_linestyle="--",
409
+ )
410
+ ```
411
+
412
+ For phase lines, x is the first strategy's frequency. `trajectory_arrows=None`
413
+ centers one head between equilibria; explicit values are frequencies, and `[]`
414
+ hides heads. Marker styling follows the existing API. `continuum_color` styles
415
+ an entire stationary interval. Non-hyperbolic isolated points are classified
416
+ from one-sided flow without special markers or warnings.
417
+
418
+ Bifurcation diagrams sample a payoff-matrix function; they do not guarantee
419
+ exhaustive bifurcation detection. See the two introductory tutorial sections
420
+ and `help(pn.bifurcation_diagram)` for styling and parameter controls.
421
+
422
+ ## Possible future directions
423
+
424
+ pyNamo focuses on analytical models whose state spaces can be visualized.
425
+ Natural extensions include:
426
+
427
+ - **More evolutionary dynamics and learning rules.** Refactor `dynamics.py`
428
+ around updating-rule objects, allowing each population or player to have its
429
+ own rule. Candidate additions include logit dynamics, best-response dynamics,
430
+ and differential equations for reinforcement learning and stochastic
431
+ fictitious play.
432
+ - **Nonlinear frequency-dependent fitness.** Accept user-defined fitness
433
+ functions $f_i(x)$ in addition to payoff matrices.
434
+ - **Equilibrium manifolds.** Detect continua of rest points, analyze their
435
+ stability, and plot them automatically when the result can be established
436
+ reliably. Report inconclusive cases explicitly.