gtlab 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.
Files changed (42) hide show
  1. gtlab-0.1.0/LICENSE +21 -0
  2. gtlab-0.1.0/PKG-INFO +137 -0
  3. gtlab-0.1.0/README.md +97 -0
  4. gtlab-0.1.0/pyproject.toml +54 -0
  5. gtlab-0.1.0/setup.cfg +4 -0
  6. gtlab-0.1.0/src/gtlab/__init__.py +39 -0
  7. gtlab-0.1.0/src/gtlab/_memo.py +31 -0
  8. gtlab-0.1.0/src/gtlab/core/__init__.py +17 -0
  9. gtlab-0.1.0/src/gtlab/core/bayesian.py +335 -0
  10. gtlab-0.1.0/src/gtlab/core/correlated.py +120 -0
  11. gtlab-0.1.0/src/gtlab/core/extensive_form.py +133 -0
  12. gtlab-0.1.0/src/gtlab/core/normal_form.py +176 -0
  13. gtlab-0.1.0/src/gtlab/core/stochastic.py +95 -0
  14. gtlab-0.1.0/src/gtlab/core/zero_sum.py +119 -0
  15. gtlab-0.1.0/src/gtlab/games/__init__.py +27 -0
  16. gtlab-0.1.0/src/gtlab/games/applied.py +36 -0
  17. gtlab-0.1.0/src/gtlab/games/classic.py +44 -0
  18. gtlab-0.1.0/src/gtlab/solvers/__init__.py +33 -0
  19. gtlab-0.1.0/src/gtlab/solvers/best_response.py +51 -0
  20. gtlab-0.1.0/src/gtlab/solvers/correlated.py +105 -0
  21. gtlab-0.1.0/src/gtlab/solvers/dominance.py +83 -0
  22. gtlab-0.1.0/src/gtlab/solvers/learning.py +95 -0
  23. gtlab-0.1.0/src/gtlab/solvers/linprog.py +78 -0
  24. gtlab-0.1.0/src/gtlab/solvers/nash.py +82 -0
  25. gtlab-0.1.0/src/gtlab/solvers/pareto.py +39 -0
  26. gtlab-0.1.0/src/gtlab/solvers/value_iteration.py +66 -0
  27. gtlab-0.1.0/src/gtlab/solvers/welfare.py +48 -0
  28. gtlab-0.1.0/src/gtlab/viz/__init__.py +12 -0
  29. gtlab-0.1.0/src/gtlab/viz/format.py +65 -0
  30. gtlab-0.1.0/src/gtlab/viz/html.py +171 -0
  31. gtlab-0.1.0/src/gtlab/viz/plots.py +103 -0
  32. gtlab-0.1.0/src/gtlab/viz/theme.py +101 -0
  33. gtlab-0.1.0/src/gtlab.egg-info/PKG-INFO +137 -0
  34. gtlab-0.1.0/src/gtlab.egg-info/SOURCES.txt +40 -0
  35. gtlab-0.1.0/src/gtlab.egg-info/dependency_links.txt +1 -0
  36. gtlab-0.1.0/src/gtlab.egg-info/requires.txt +17 -0
  37. gtlab-0.1.0/src/gtlab.egg-info/top_level.txt +1 -0
  38. gtlab-0.1.0/tests/test_bayesian.py +60 -0
  39. gtlab-0.1.0/tests/test_display.py +60 -0
  40. gtlab-0.1.0/tests/test_games.py +36 -0
  41. gtlab-0.1.0/tests/test_perf.py +114 -0
  42. gtlab-0.1.0/tests/test_solvers.py +72 -0
gtlab-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tamás Takács
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.
gtlab-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: gtlab
3
+ Version: 0.1.0
4
+ Summary: Teaching toolkit for the ELTE Game Theory course: solvers, game library, and Jupyter-friendly visualizations.
5
+ Author-email: Tamás Takács <tamastheactual@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/tamastheactual/gtlab
8
+ Project-URL: Repository, https://github.com/tamastheactual/gtlab
9
+ Project-URL: Issues, https://github.com/tamastheactual/gtlab/issues
10
+ Keywords: game-theory,nash-equilibrium,teaching,elte,education
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
22
+ Classifier: Topic :: Education
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: numpy>=1.21
27
+ Requires-Dist: scipy>=1.7
28
+ Requires-Dist: matplotlib>=3.4
29
+ Requires-Dist: pandas>=1.3
30
+ Provides-Extra: nash
31
+ Requires-Dist: nashpy>=0.0.35; extra == "nash"
32
+ Provides-Extra: welfare
33
+ Requires-Dist: pulp>=2.6; extra == "welfare"
34
+ Provides-Extra: full
35
+ Requires-Dist: nashpy>=0.0.35; extra == "full"
36
+ Requires-Dist: pulp>=2.6; extra == "full"
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest>=7.0; extra == "dev"
39
+ Dynamic: license-file
40
+
41
+ # gtlab — Game Theory Lab
42
+
43
+ A teaching toolkit for the ELTE Game Theory course. It consolidates the solvers,
44
+ example games, and Jupyter visualizations that previously lived (duplicated) in
45
+ six separate Colab notebooks into one installable, extensible package.
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ pip install -e ".[full]" # full = nashpy + pulp extras (recommended in Colab)
51
+ pip install -e . # core only (numpy / scipy / matplotlib / pandas)
52
+ ```
53
+
54
+ ## Quick start
55
+
56
+ ```python
57
+ import gtlab
58
+ gtlab.apply_rc() # shared matplotlib styling (call once)
59
+
60
+ from gtlab.games import prisoners_dilemma
61
+ prisoners_dilemma().solve() # annotated bimatrix in a Jupyter cell
62
+ ```
63
+
64
+ Build your own game:
65
+
66
+ ```python
67
+ import numpy as np
68
+ from gtlab import NormalFormGame
69
+
70
+ g = NormalFormGame(
71
+ A=np.array([[3, 0], [5, 1]]),
72
+ B=np.array([[3, 5], [0, 1]]),
73
+ row_actions=["Cooperate", "Defect"],
74
+ col_actions=["Cooperate", "Defect"],
75
+ name="My Game",
76
+ )
77
+ g.explain()
78
+ ```
79
+
80
+ ## Architecture
81
+
82
+ The design separates the three concerns that were tangled together in the
83
+ notebooks:
84
+
85
+ ```
86
+ gtlab/
87
+ ├── core/ game classes — hold data, expose a thin API
88
+ │ ├── normal_form.py NormalFormGame
89
+ │ ├── zero_sum.py ZeroSumGame
90
+ │ ├── correlated.py CorrelatedGame
91
+ │ ├── stochastic.py StochasticGame
92
+ │ ├── extensive_form.py ExtensiveFormGame
93
+ │ └── bayesian.py PostedPrice, FirstPriceAuction, SecondPriceAuction
94
+ ├── solvers/ pure algorithms — numpy in, numpy/dict out, no display
95
+ │ ├── best_response.py nash.py dominance.py
96
+ │ ├── pareto.py linprog.py value_iteration.py
97
+ │ ├── welfare.py learning.py correlated.py
98
+ ├── viz/ display layer — ONE theme, formatters, HTML, plots
99
+ │ ├── theme.py format.py html.py plots.py
100
+ └── games/ ready-made example games + REGISTRY
101
+ ```
102
+
103
+ Rule of thumb: **math goes in `solvers/`, rendering goes in `viz/`, and the
104
+ classes in `core/` just wire them together.** A theme tweak is one edit in
105
+ `viz/theme.py`; a new algorithm is one file in `solvers/`; a new example is one
106
+ factory in `games/`.
107
+
108
+ ## Extending
109
+
110
+ | To add… | …do this |
111
+ |---|---|
112
+ | a new example game | write a factory in `games/`, add it to `REGISTRY` |
113
+ | a new algorithm | add a pure function in `solvers/`, export it |
114
+ | a new game type | add a class in `core/` that calls `solvers` + `viz` |
115
+ | restyle output | edit `viz/theme.py` (colors / CSS / rcParams) |
116
+
117
+ ## Tests
118
+
119
+ ```bash
120
+ pip install -e ".[dev]"
121
+ pytest
122
+ ```
123
+
124
+ The solver layer has golden-value tests so refactors stay behavior-preserving.
125
+
126
+ ## Notebook migration
127
+
128
+ Each lecture notebook drops its ~2,000-line engine class and imports from
129
+ `gtlab` instead, keeping only narrative and example-specific calls. The methods
130
+ the notebooks relied on (`.summary()`, `.solve()`, `.explain()`, `.plot_*()`)
131
+ are preserved on the core classes.
132
+ ```python
133
+ # old: 1,800 lines of NormalFormGame defined inline
134
+ # new:
135
+ from gtlab.games import prisoners_dilemma
136
+ prisoners_dilemma().solve(show_br=True, show_ne=True)
137
+ ```
gtlab-0.1.0/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # gtlab — Game Theory Lab
2
+
3
+ A teaching toolkit for the ELTE Game Theory course. It consolidates the solvers,
4
+ example games, and Jupyter visualizations that previously lived (duplicated) in
5
+ six separate Colab notebooks into one installable, extensible package.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install -e ".[full]" # full = nashpy + pulp extras (recommended in Colab)
11
+ pip install -e . # core only (numpy / scipy / matplotlib / pandas)
12
+ ```
13
+
14
+ ## Quick start
15
+
16
+ ```python
17
+ import gtlab
18
+ gtlab.apply_rc() # shared matplotlib styling (call once)
19
+
20
+ from gtlab.games import prisoners_dilemma
21
+ prisoners_dilemma().solve() # annotated bimatrix in a Jupyter cell
22
+ ```
23
+
24
+ Build your own game:
25
+
26
+ ```python
27
+ import numpy as np
28
+ from gtlab import NormalFormGame
29
+
30
+ g = NormalFormGame(
31
+ A=np.array([[3, 0], [5, 1]]),
32
+ B=np.array([[3, 5], [0, 1]]),
33
+ row_actions=["Cooperate", "Defect"],
34
+ col_actions=["Cooperate", "Defect"],
35
+ name="My Game",
36
+ )
37
+ g.explain()
38
+ ```
39
+
40
+ ## Architecture
41
+
42
+ The design separates the three concerns that were tangled together in the
43
+ notebooks:
44
+
45
+ ```
46
+ gtlab/
47
+ ├── core/ game classes — hold data, expose a thin API
48
+ │ ├── normal_form.py NormalFormGame
49
+ │ ├── zero_sum.py ZeroSumGame
50
+ │ ├── correlated.py CorrelatedGame
51
+ │ ├── stochastic.py StochasticGame
52
+ │ ├── extensive_form.py ExtensiveFormGame
53
+ │ └── bayesian.py PostedPrice, FirstPriceAuction, SecondPriceAuction
54
+ ├── solvers/ pure algorithms — numpy in, numpy/dict out, no display
55
+ │ ├── best_response.py nash.py dominance.py
56
+ │ ├── pareto.py linprog.py value_iteration.py
57
+ │ ├── welfare.py learning.py correlated.py
58
+ ├── viz/ display layer — ONE theme, formatters, HTML, plots
59
+ │ ├── theme.py format.py html.py plots.py
60
+ └── games/ ready-made example games + REGISTRY
61
+ ```
62
+
63
+ Rule of thumb: **math goes in `solvers/`, rendering goes in `viz/`, and the
64
+ classes in `core/` just wire them together.** A theme tweak is one edit in
65
+ `viz/theme.py`; a new algorithm is one file in `solvers/`; a new example is one
66
+ factory in `games/`.
67
+
68
+ ## Extending
69
+
70
+ | To add… | …do this |
71
+ |---|---|
72
+ | a new example game | write a factory in `games/`, add it to `REGISTRY` |
73
+ | a new algorithm | add a pure function in `solvers/`, export it |
74
+ | a new game type | add a class in `core/` that calls `solvers` + `viz` |
75
+ | restyle output | edit `viz/theme.py` (colors / CSS / rcParams) |
76
+
77
+ ## Tests
78
+
79
+ ```bash
80
+ pip install -e ".[dev]"
81
+ pytest
82
+ ```
83
+
84
+ The solver layer has golden-value tests so refactors stay behavior-preserving.
85
+
86
+ ## Notebook migration
87
+
88
+ Each lecture notebook drops its ~2,000-line engine class and imports from
89
+ `gtlab` instead, keeping only narrative and example-specific calls. The methods
90
+ the notebooks relied on (`.summary()`, `.solve()`, `.explain()`, `.plot_*()`)
91
+ are preserved on the core classes.
92
+ ```python
93
+ # old: 1,800 lines of NormalFormGame defined inline
94
+ # new:
95
+ from gtlab.games import prisoners_dilemma
96
+ prisoners_dilemma().solve(show_br=True, show_ne=True)
97
+ ```
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "gtlab"
7
+ version = "0.1.0"
8
+ description = "Teaching toolkit for the ELTE Game Theory course: solvers, game library, and Jupyter-friendly visualizations."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Tamás Takács", email = "tamastheactual@gmail.com" }]
13
+ keywords = ["game-theory", "nash-equilibrium", "teaching", "elte", "education"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Education",
17
+ "Intended Audience :: Science/Research",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Scientific/Engineering :: Mathematics",
26
+ "Topic :: Education",
27
+ ]
28
+
29
+ dependencies = [
30
+ "numpy>=1.21",
31
+ "scipy>=1.7",
32
+ "matplotlib>=3.4",
33
+ "pandas>=1.3",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ # Mixed-Nash via support enumeration in normal/extensive-form games.
38
+ nash = ["nashpy>=0.0.35"]
39
+ # Linear-programming welfare objectives (utilitarian / egalitarian).
40
+ welfare = ["pulp>=2.6"]
41
+ # Everything, for running the full notebook suite.
42
+ full = ["nashpy>=0.0.35", "pulp>=2.6"]
43
+ dev = ["pytest>=7.0"]
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/tamastheactual/gtlab"
47
+ Repository = "https://github.com/tamastheactual/gtlab"
48
+ Issues = "https://github.com/tamastheactual/gtlab/issues"
49
+
50
+ [tool.setuptools.packages.find]
51
+ where = ["src"]
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
gtlab-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,39 @@
1
+ """gtlab — Game Theory Lab for the ELTE Game Theory course.
2
+
3
+ Quick start::
4
+
5
+ import gtlab
6
+ gtlab.apply_rc() # consistent plot styling (once)
7
+
8
+ from gtlab.games import prisoners_dilemma
9
+ prisoners_dilemma().solve() # annotated bimatrix in Jupyter
10
+
11
+ Build your own::
12
+
13
+ from gtlab import NormalFormGame
14
+ import numpy as np
15
+ g = NormalFormGame(np.array([[3, 0], [5, 1]]), np.array([[3, 5], [0, 1]]))
16
+ g.explain()
17
+
18
+ Layers:
19
+ * ``gtlab.core`` — game classes (data + thin API)
20
+ * ``gtlab.solvers`` — pure algorithms (best response, Nash, value iteration, …)
21
+ * ``gtlab.viz`` — formatting, HTML, plots, theme
22
+ * ``gtlab.games`` — ready-made example games
23
+ """
24
+ from . import games, solvers, viz
25
+ from .core import (CorrelatedGame, ExtensiveFormGame, FirstPriceAuction,
26
+ Mechanism, NormalFormGame, PostedPrice, Procurement,
27
+ PublicProject, SecondPriceAuction, SpenceSignaling,
28
+ StochasticGame, VCGAssignment, ZeroSumGame)
29
+ from .viz import apply_rc
30
+
31
+ __version__ = "0.1.0"
32
+
33
+ __all__ = [
34
+ "NormalFormGame", "ZeroSumGame", "CorrelatedGame", "StochasticGame",
35
+ "ExtensiveFormGame", "Mechanism", "PostedPrice", "FirstPriceAuction",
36
+ "SecondPriceAuction", "SpenceSignaling", "VCGAssignment", "PublicProject",
37
+ "Procurement",
38
+ "solvers", "viz", "games", "apply_rc", "__version__",
39
+ ]
@@ -0,0 +1,31 @@
1
+ """A tiny per-instance memoization decorator for game-class analysis methods.
2
+
3
+ Game classes are dataclasses wrapping numpy arrays, so they are unhashable and
4
+ ``functools.lru_cache`` does not apply. The payoff data is treated as immutable
5
+ after construction, so caching results on the instance is safe and lets repeated
6
+ display calls (and ``compare_via``) reuse expensive solves instead of redoing
7
+ them. Mutating a payoff matrix in place after the first call is unsupported
8
+ (call :func:`clear_cache` if you must).
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import functools
13
+ from typing import Callable
14
+
15
+
16
+ def cached_method(func: Callable) -> Callable:
17
+ """Memoize a method's result on the instance, keyed by ``(name, args)``."""
18
+ @functools.wraps(func)
19
+ def wrapper(self, *args, **kwargs):
20
+ cache = self.__dict__.setdefault("_cache", {})
21
+ key = (func.__name__, args, tuple(sorted(kwargs.items())))
22
+ if key not in cache:
23
+ cache[key] = func(self, *args, **kwargs)
24
+ return cache[key]
25
+
26
+ return wrapper
27
+
28
+
29
+ def clear_cache(instance) -> None:
30
+ """Drop all memoized results on ``instance`` (use after mutating payoffs)."""
31
+ instance.__dict__.pop("_cache", None)
@@ -0,0 +1,17 @@
1
+ """Core game classes — each holds data and delegates math/display to the
2
+ shared :mod:`gtlab.solvers` and :mod:`gtlab.viz` layers."""
3
+ from .bayesian import (FirstPriceAuction, Mechanism, PostedPrice, Procurement,
4
+ PublicProject, SecondPriceAuction, SpenceSignaling,
5
+ VCGAssignment)
6
+ from .correlated import CorrelatedGame
7
+ from .extensive_form import ExtensiveFormGame
8
+ from .normal_form import NormalFormGame
9
+ from .stochastic import StochasticGame
10
+ from .zero_sum import ZeroSumGame
11
+
12
+ __all__ = [
13
+ "NormalFormGame", "ZeroSumGame", "CorrelatedGame", "StochasticGame",
14
+ "ExtensiveFormGame", "Mechanism", "PostedPrice", "FirstPriceAuction",
15
+ "SecondPriceAuction", "SpenceSignaling", "VCGAssignment", "PublicProject",
16
+ "Procurement",
17
+ ]