From a90a1373bc5e9a277996bb10381ca3b13757cb6d Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 13:16:02 +0000 Subject: [PATCH 01/84] update pyproject.toml with optional dependencies for test suite and docs --- pyproject.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 71ea25bfc..6fa68394e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,20 @@ dependencies = [ "scipy", ] +[project.optional-dependencies] +test = ["pytest", "nbformat", "nbclient", "ipykernel"] +doc = [ + "pydata-sphinx-themesphinx_design", + "sphinx-autobuild", + "nbsphinx", + "ipython", + "matplotlib", + "pickleshare", + "jupyter", + "open_spiel; sys_platform != 'win32'", + "draw-tree @ git+https://github.com/gambitproject/draw_tree.git@v0.3.1" +] + [project.urls] Homepage = "https://www.gambit-project.org" Documentation = "https://gambitproject.readthedocs.io" From adc322fc3ee7b6cf962a93d431c9b825bcce4bf6 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 13:22:25 +0000 Subject: [PATCH 02/84] update GitHub actions to install optional dependencies when installing pygambit instead of using requirements.txt --- .github/workflows/python.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 5e23dff61..54ffd641e 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -22,15 +22,13 @@ jobs: run: | python -m pip install --upgrade pip pip install setuptools build cython wheel - pip install -r tests/requirements.txt - pip install -r doc/requirements.txt - name: Build source distribution run: python -m build - name: Build from source distribution run: | cd dist - pip install -v pygambit*.tar.gz + pip install -v "pygambit[test,doc] @ pygambit*.tar.gz" - name: Run tests run: pytest --run-tutorials @@ -51,11 +49,9 @@ jobs: run: | python -m pip install --upgrade pip pip install setuptools build cython wheel - pip install -r tests/requirements.txt - pip install -r doc/requirements.txt - name: Build extension run: | - python -m pip install -v . + python -m pip install -v .[test,doc] - name: Run tests run: pytest --run-tutorials @@ -76,11 +72,9 @@ jobs: run: | python -m pip install --upgrade pip pip install setuptools build cython wheel - pip install -r tests/requirements.txt - pip install -r doc/requirements.txt - name: Build extension run: | - python -m pip install -v . + python -m pip install -v .[test,doc] - name: Run tests run: pytest --run-tutorials @@ -101,10 +95,8 @@ jobs: run: | python -m pip install --upgrade pip pip install setuptools build cython wheel - pip install -r tests/requirements.txt - pip install -r doc/requirements.txt - name: Build extension run: | - python -m pip install -v . + python -m pip install -v .[test,doc] - name: Run tests run: pytest --run-tutorials From 38ddfa23d9384f926a8f477723222f262052fc62 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 13:30:39 +0000 Subject: [PATCH 03/84] add doc dependencies: Cython, numpy, scipy --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 6fa68394e..d48c3f3ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,9 @@ dependencies = [ [project.optional-dependencies] test = ["pytest", "nbformat", "nbclient", "ipykernel"] doc = [ + "Cython", + "numpy", + "scipy", "pydata-sphinx-themesphinx_design", "sphinx-autobuild", "nbsphinx", From 4d542628c73bd26448d5d62b1574aa69d9c836b9 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 13:35:31 +0000 Subject: [PATCH 04/84] try GH actions without testing docs --- .github/workflows/python.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 54ffd641e..708220289 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -28,9 +28,9 @@ jobs: - name: Build from source distribution run: | cd dist - pip install -v "pygambit[test,doc] @ pygambit*.tar.gz" + pip install -v "pygambit[test] @ pygambit*.tar.gz" - name: Run tests - run: pytest --run-tutorials + run: pytest macos-14: runs-on: macos-14 @@ -51,9 +51,9 @@ jobs: pip install setuptools build cython wheel - name: Build extension run: | - python -m pip install -v .[test,doc] + python -m pip install -v .[test] - name: Run tests - run: pytest --run-tutorials + run: pytest macos-15: runs-on: macos-15 @@ -74,9 +74,9 @@ jobs: pip install setuptools build cython wheel - name: Build extension run: | - python -m pip install -v .[test,doc] + python -m pip install -v .[test] - name: Run tests - run: pytest --run-tutorials + run: pytest windows: runs-on: windows-latest @@ -97,6 +97,6 @@ jobs: pip install setuptools build cython wheel - name: Build extension run: | - python -m pip install -v .[test,doc] + python -m pip install -v .[test] - name: Run tests - run: pytest --run-tutorials + run: pytest From 0a46de2253b719a803f7569967407c7d6e983ae6 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 13:48:53 +0000 Subject: [PATCH 05/84] Revert "try GH actions without testing docs" This reverts commit 4d542628c73bd26448d5d62b1574aa69d9c836b9. --- .github/workflows/python.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 708220289..54ffd641e 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -28,9 +28,9 @@ jobs: - name: Build from source distribution run: | cd dist - pip install -v "pygambit[test] @ pygambit*.tar.gz" + pip install -v "pygambit[test,doc] @ pygambit*.tar.gz" - name: Run tests - run: pytest + run: pytest --run-tutorials macos-14: runs-on: macos-14 @@ -51,9 +51,9 @@ jobs: pip install setuptools build cython wheel - name: Build extension run: | - python -m pip install -v .[test] + python -m pip install -v .[test,doc] - name: Run tests - run: pytest + run: pytest --run-tutorials macos-15: runs-on: macos-15 @@ -74,9 +74,9 @@ jobs: pip install setuptools build cython wheel - name: Build extension run: | - python -m pip install -v .[test] + python -m pip install -v .[test,doc] - name: Run tests - run: pytest + run: pytest --run-tutorials windows: runs-on: windows-latest @@ -97,6 +97,6 @@ jobs: pip install setuptools build cython wheel - name: Build extension run: | - python -m pip install -v .[test] + python -m pip install -v .[test,doc] - name: Run tests - run: pytest + run: pytest --run-tutorials From 7c59b5f78d2035677b40b7576f8c1829607913ed Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 13:55:28 +0000 Subject: [PATCH 06/84] remove pip install that is already covered by build-system in pyproject.toml --- .github/workflows/python.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 54ffd641e..a19bc7f35 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -21,7 +21,6 @@ jobs: - name: Set up dependencies run: | python -m pip install --upgrade pip - pip install setuptools build cython wheel - name: Build source distribution run: python -m build @@ -48,7 +47,6 @@ jobs: - name: Set up dependencies run: | python -m pip install --upgrade pip - pip install setuptools build cython wheel - name: Build extension run: | python -m pip install -v .[test,doc] @@ -71,7 +69,6 @@ jobs: - name: Set up dependencies run: | python -m pip install --upgrade pip - pip install setuptools build cython wheel - name: Build extension run: | python -m pip install -v .[test,doc] @@ -94,7 +91,6 @@ jobs: - name: Set up dependencies run: | python -m pip install --upgrade pip - pip install setuptools build cython wheel - name: Build extension run: | python -m pip install -v .[test,doc] From fa8c42f3cc1f4003390423d7cbe2de9327ad0bc4 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:04:05 +0000 Subject: [PATCH 07/84] fix typo mistake in doc dependencies list --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d48c3f3ce..76737913c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,8 @@ doc = [ "Cython", "numpy", "scipy", - "pydata-sphinx-themesphinx_design", + "pydata-sphinx-theme", + "sphinx_design", "sphinx-autobuild", "nbsphinx", "ipython", From eadf1b44f3fe0b01b5b734535723a53f43412c1f Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:04:58 +0000 Subject: [PATCH 08/84] remove Cython, numpy and scipy from doc dependency list as these are already included in build-system or dependencies --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 76737913c..173c8e3b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,9 +33,6 @@ dependencies = [ [project.optional-dependencies] test = ["pytest", "nbformat", "nbclient", "ipykernel"] doc = [ - "Cython", - "numpy", - "scipy", "pydata-sphinx-theme", "sphinx_design", "sphinx-autobuild", From a403b5b98f081271b00fbab441b9ef988476ead6 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:10:42 +0000 Subject: [PATCH 09/84] restore installation of build on linux job --- .github/workflows/python.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index a19bc7f35..8e84475e7 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -21,6 +21,7 @@ jobs: - name: Set up dependencies run: | python -m pip install --upgrade pip + python -m pip install build - name: Build source distribution run: python -m build From 06fe0881e056199fc04bd4bee3cf86c4d426576a Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:11:21 +0000 Subject: [PATCH 10/84] remove requirements.txt files --- doc/requirements.txt | 13 ------------- tests/requirements.txt | 4 ---- 2 files changed, 17 deletions(-) delete mode 100644 doc/requirements.txt delete mode 100644 tests/requirements.txt diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index 6b2fbe573..000000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -Cython -numpy -scipy -pydata-sphinx-theme -sphinx_design -sphinx-autobuild -nbsphinx -ipython -matplotlib -pickleshare -jupyter -open_spiel; sys_platform != 'win32' -draw-tree @ git+https://github.com/gambitproject/draw_tree.git@v0.3.1 diff --git a/tests/requirements.txt b/tests/requirements.txt deleted file mode 100644 index 545fd9b00..000000000 --- a/tests/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -pytest -nbformat -nbclient -ipykernel From 317e6017d43bcc66acab5adbd25e638ee96a5652 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:29:48 +0000 Subject: [PATCH 11/84] update docs for new installation method --- doc/developer.build.rst | 6 +++++- doc/developer.contributing.rst | 15 ++++++--------- doc/tutorials/running_locally.rst | 19 +++++++------------ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/doc/developer.build.rst b/doc/developer.build.rst index 1088b3402..d50c9c36d 100644 --- a/doc/developer.build.rst +++ b/doc/developer.build.rst @@ -188,7 +188,11 @@ Use `pip` to install from the **root directory of the source tree**: python -m venv venv source venv/bin/activate - python -m pip install . + python -m pip install .[test,doc] + +.. tip:: + + The "test" and "doc" optional dependencies are useful for developers wishing to run the test suite or build this documentation locally. Once installed, simply ``import pygambit`` in your Python shell or diff --git a/doc/developer.contributing.rst b/doc/developer.contributing.rst index f86939850..539358fad 100644 --- a/doc/developer.contributing.rst +++ b/doc/developer.contributing.rst @@ -102,19 +102,16 @@ Be sure to familiarise yourself with :ref:`contributing-code` before reading thi By default, pull requests on GitHub will trigger the running of Gambit's test suite using GitHub Actions. You can also run the tests locally before submitting your pull request, using `pytest`. -1. Install the test dependencies (into the virtual environment where you installed PyGambit): :: +1. Ensure `pygambit` is installed with test dependencies: see :ref:`build-python`. - pip install -r tests/requirements.txt +2. Run pytest: :: -2. Navigate to the Gambit repository and run the tests: :: - - pytest - -3. [Optional] If you wish to run the tutorial notebook tests, you will need to add the ``--run-tutorials`` flag, which require the `doc` dependencies: :: - - pip install -r doc/requirements.txt pytest --run-tutorials +.. tip:: + You can omit the `--run-tutorials` to skip running the tutorial notebook tests which take longest to run. + Running tests including tutorials requires `doc` as well as `test` dependencies; see :ref:`build-python`. + Adding to the test suite ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/tutorials/running_locally.rst b/doc/tutorials/running_locally.rst index c5457fa9b..5407afec1 100644 --- a/doc/tutorials/running_locally.rst +++ b/doc/tutorials/running_locally.rst @@ -8,29 +8,24 @@ The tutorials are available as Jupyter notebooks and can be run interactively us .. tip:: Create a virtual environment with Python 3.10 or higher. -1. To download the tutorials, open your OS's command prompt and clone the Gambit repository from GitHub, then navigate to the tutorials directory: :: +1. To download the tutorials, open your OS's command prompt and clone the Gambit repository from GitHub: :: git clone https://github.com/gambitproject/gambit.git -2. Install `pygambit`: +2. Install `pygambit` with additional documentation dependencies: * To install the latest release from PyPI:: - pip install pygambit + pip install pygambit[doc] - * Alternatively, to install the latest development version:: + * Alternatively, to install the latest development version (from the top level of the gambit repo):: - pip install . - -3. Install other requirements (including `JupyterLab`) used by the tutorials :: - - cd gambit/doc - pip install -r requirements.txt + pip install .[doc] .. warning:: Windows users wishing to run the "Using Gambit with OpenSpiel" tutorial will need to install OpenSpiel manually; see the `OpenSpiel installation instructions `_ for details. -4. Open `JupyterLab` and click on any of the tutorial notebooks (files ending in `.ipynb`) :: +3. Open `JupyterLab` and click on any of the tutorial notebooks in ``doc/tutorials`` (files ending in `.ipynb`) :: - cd tutorials + cd doc/tutorials jupyter lab From d89b891133b949ea5f454be80fda9dffae06086e Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:38:21 +0000 Subject: [PATCH 12/84] update documentation instructions --- doc/developer.contributing.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/developer.contributing.rst b/doc/developer.contributing.rst index 539358fad..fc016ac4b 100644 --- a/doc/developer.contributing.rst +++ b/doc/developer.contributing.rst @@ -131,9 +131,7 @@ You can also build the documentation locally to preview your changes before subm 1. `Install Pandoc `_ for your OS -2. Install the docs dependencies (into the virtual environment where you installed PyGambit): :: - - pip install -r doc/requirements.txt +2. Ensure `pygambit` is installed with doc dependencies: see :ref:`build-python`. 3. Navigate to the Gambit repo and build the docs: :: @@ -153,7 +151,7 @@ To submit a tutorial for inclusion in the Gambit documentation, please follow th 3. Update `doc/pygambit.rst` to ensure the tutorial is listed in the docs at an appropriate location. -4. *[Optional]* If your tutorial requires additional dependencies not already listed in `doc/requirements.txt`, please add them to the file. +4. *[Optional]* If your tutorial requires additional dependencies not already listed in the ``doc`` list under ``[project.optional-dependencies]`` inside ``pyproject.toml``, please add them to the file. Recognising contributions From af6ece0f5c2da696620cc28b3c03cd5f6d42fc70 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:38:32 +0000 Subject: [PATCH 13/84] update readthedocs config --- .readthedocs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 73522dfdf..2af0b2e52 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -16,6 +16,7 @@ build: python: install: - - requirements: doc/requirements.txt - - method: setuptools + - method: pip path: "." + extra_requirements: + - doc From 476efc187f506f7e8cec7ec3e0e976cb2a42464f Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:42:37 +0000 Subject: [PATCH 14/84] try fixing linux build --- .github/workflows/python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 8e84475e7..a18e0287a 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -28,7 +28,7 @@ jobs: - name: Build from source distribution run: | cd dist - pip install -v "pygambit[test,doc] @ pygambit*.tar.gz" + pip install -v ./pygambit-*.tar.gz[test,doc] - name: Run tests run: pytest --run-tutorials From b8db5ca1a48e2f871da172a6213f75c173449af8 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 28 Jan 2026 14:50:49 +0000 Subject: [PATCH 15/84] try again to fix linux job: let bash expand the filename first, then append extras --- .github/workflows/python.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index a18e0287a..b670261dc 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -28,7 +28,8 @@ jobs: - name: Build from source distribution run: | cd dist - pip install -v ./pygambit-*.tar.gz[test,doc] + sdist=$(ls pygambit-*.tar.gz) + pip install -v "${sdist}[test,doc]" - name: Run tests run: pytest --run-tutorials From 90a5e367095e2b842374dc0de491f7829b17f724 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 10:11:54 +0000 Subject: [PATCH 16/84] Create catalog dir and move one EFG and one NFG into it from contrib/games --- {contrib/games => catalog}/2smp.efg | 0 {contrib/games => catalog}/pd.nfg | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {contrib/games => catalog}/2smp.efg (100%) rename {contrib/games => catalog}/pd.nfg (100%) diff --git a/contrib/games/2smp.efg b/catalog/2smp.efg similarity index 100% rename from contrib/games/2smp.efg rename to catalog/2smp.efg diff --git a/contrib/games/pd.nfg b/catalog/pd.nfg similarity index 100% rename from contrib/games/pd.nfg rename to catalog/pd.nfg From 83dd41034563bf808001be8cde74bece58a315fb Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 10:17:38 +0000 Subject: [PATCH 17/84] ignore catalog files copied into pygambit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9d37e0d3b..85c959981 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ Gambit.app/* *.ef build_support/msw/gambit.wxs build_support/osx/Info.plist +src/pygambit/catalog From 7fc21994294b10d09b2bc82ca3dedcb84ef26afe Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 10:25:18 +0000 Subject: [PATCH 18/84] add failing tests --- tests/test_catalog.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/test_catalog.py diff --git a/tests/test_catalog.py b/tests/test_catalog.py new file mode 100644 index 000000000..6b8888072 --- /dev/null +++ b/tests/test_catalog.py @@ -0,0 +1,11 @@ +import pygambit as gbt + + +def test_catalog_load_efg(): + g = gbt.catalog.load("2smp") + assert isinstance(g, gbt.Game) + + +def test_catalog_load_nfg(): + g = gbt.catalog.load("pd") + assert isinstance(g, gbt.Game) From 3c53beaefce05ca9236bc713a2286bb537705532 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 10:39:07 +0000 Subject: [PATCH 19/84] improve tests --- tests/test_catalog.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 6b8888072..95c3ededa 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -1,11 +1,26 @@ +import pandas as pd + import pygambit as gbt def test_catalog_load_efg(): + """Test loading an extensive form game""" g = gbt.catalog.load("2smp") assert isinstance(g, gbt.Game) + assert g.title == "Two-stage matching pennies game" def test_catalog_load_nfg(): + """Test loading a normal form game""" g = gbt.catalog.load("pd") assert isinstance(g, gbt.Game) + assert g.title == "Two person Prisoner's Dilemma game" + + +def test_catalog_games(): + """Test games() function returns df of game slugs and titles""" + all_games = gbt.catalog.games() + assert isinstance(all_games, pd.DataFrame) + assert len(all_games) > 0 + assert "2smp" in list(all_games.slug) + assert "Two-stage matching pennies game" in list(all_games.title) From 898a916d38c2056e1418863e12250f44acfa3c78 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 10:39:24 +0000 Subject: [PATCH 20/84] add pandas to pyproject.toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 71ea25bfc..36dfb494b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ classifiers=[ dependencies = [ "numpy", "scipy", + "pandas", ] [project.urls] From 8f916db6b0eef5ec03f3ca8afc9d4390c17da3e4 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 11:02:19 +0000 Subject: [PATCH 21/84] add test_catalog_load_invalid_slug --- tests/test_catalog.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 95c3ededa..2564b1209 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -1,4 +1,5 @@ import pandas as pd +import pytest import pygambit as gbt @@ -17,6 +18,12 @@ def test_catalog_load_nfg(): assert g.title == "Two person Prisoner's Dilemma game" +def test_catalog_load_invalid_slug(): + """Test loading an invalid game slug""" + with pytest.raises(FileNotFoundError): + gbt.catalog.load("invalid_slug") + + def test_catalog_games(): """Test games() function returns df of game slugs and titles""" all_games = gbt.catalog.games() From 606dd8aed8424cd17486537d94926317cec83deb Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 11:32:32 +0000 Subject: [PATCH 22/84] create load function --- src/pygambit/catalog.py | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/pygambit/catalog.py diff --git a/src/pygambit/catalog.py b/src/pygambit/catalog.py new file mode 100644 index 000000000..565ea6b33 --- /dev/null +++ b/src/pygambit/catalog.py @@ -0,0 +1,46 @@ +from importlib.resources import files + +import pygambit as gbt + +_GAMEFILES_DIR = files(__package__) / "catalog" + + +def load(slug: str) -> gbt.Game: + """ + Load a game from the package catalog. + + The function looks for a catalog entry matching the given ``slug`` in the + ``catalog`` resource directory. Files are tried in the following order: + + 1. ``.nfg`` (normal-form game) + 2. ``.efg`` (extensive-form game) + + The first matching file found is loaded and returned as a + :class:`pygambit.Game`. + + Parameters + ---------- + slug : str + Base name of the catalog entry, without file extension. + + Returns + ------- + pygambit.Game + The loaded game. + + Raises + ------ + FileNotFoundError + If no ``.nfg`` or ``.efg`` file exists for the given slug. + """ + candidates = { + ".nfg": gbt.read_nfg, + ".efg": gbt.read_efg, + } + + for suffix, reader in candidates.items(): + path = _GAMEFILES_DIR / f"{slug}{suffix}" + if path.is_file(): + return reader(str(path)) + + raise FileNotFoundError(f"No catalog entry called {slug}.nfg or {slug}.efg") From 00beed38fd6897088b0b8172d4cdba6ce3028dd8 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 11:32:55 +0000 Subject: [PATCH 23/84] add catalog to __init__ --- src/pygambit/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pygambit/__init__.py b/src/pygambit/__init__.py index 1d6f730bf..8b72c0682 100644 --- a/src/pygambit/__init__.py +++ b/src/pygambit/__init__.py @@ -26,6 +26,7 @@ nash, # noqa: F401 qre, # noqa: F401 supports, # noqa: F401 + catalog, ) import importlib.metadata From 64eb3106c8a7790643da15d54fca9579937b438a Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 11:43:15 +0000 Subject: [PATCH 24/84] add games() function --- src/pygambit/catalog.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/pygambit/catalog.py b/src/pygambit/catalog.py index 565ea6b33..da1284af6 100644 --- a/src/pygambit/catalog.py +++ b/src/pygambit/catalog.py @@ -1,5 +1,7 @@ from importlib.resources import files +import pandas as pd + import pygambit as gbt _GAMEFILES_DIR = files(__package__) / "catalog" @@ -44,3 +46,41 @@ def load(slug: str) -> gbt.Game: return reader(str(path)) raise FileNotFoundError(f"No catalog entry called {slug}.nfg or {slug}.efg") + + +def games() -> pd.DataFrame: + """ + List games available in the package catalog. + + Iterates over ``.nfg`` and ``.efg`` files found in the catalog resource + directory, loads each game, and returns a pandas DataFrame summarising + the results. + + The returned DataFrame has two columns: + - ``slug``: the filename without its extension + - ``title``: the game's ``title`` attribute + + Returns + ------- + pandas.DataFrame + A DataFrame with columns ``slug`` and ``title``. + """ + records: list[dict[str, str]] = [] + + readers = { + ".nfg": gbt.read_nfg, + ".efg": gbt.read_efg, + } + + for path in sorted(_GAMEFILES_DIR.iterdir()): + reader = readers.get(path.suffix) + if reader is not None and path.is_file(): + game = reader(str(path)) + records.append( + { + "slug": path.stem, + "title": game.title, + } + ) + + return pd.DataFrame.from_records(records, columns=["slug", "title"]) From d24befd117fdde8bbd415639a95999c368a83e98 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 11:44:33 +0000 Subject: [PATCH 25/84] refactor to define READERS once --- src/pygambit/catalog.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/pygambit/catalog.py b/src/pygambit/catalog.py index da1284af6..8c1736ce3 100644 --- a/src/pygambit/catalog.py +++ b/src/pygambit/catalog.py @@ -5,6 +5,10 @@ import pygambit as gbt _GAMEFILES_DIR = files(__package__) / "catalog" +READERS = { + ".nfg": gbt.read_nfg, + ".efg": gbt.read_efg, +} def load(slug: str) -> gbt.Game: @@ -35,12 +39,7 @@ def load(slug: str) -> gbt.Game: FileNotFoundError If no ``.nfg`` or ``.efg`` file exists for the given slug. """ - candidates = { - ".nfg": gbt.read_nfg, - ".efg": gbt.read_efg, - } - - for suffix, reader in candidates.items(): + for suffix, reader in READERS.items(): path = _GAMEFILES_DIR / f"{slug}{suffix}" if path.is_file(): return reader(str(path)) @@ -67,13 +66,8 @@ def games() -> pd.DataFrame: """ records: list[dict[str, str]] = [] - readers = { - ".nfg": gbt.read_nfg, - ".efg": gbt.read_efg, - } - for path in sorted(_GAMEFILES_DIR.iterdir()): - reader = readers.get(path.suffix) + reader = READERS.get(path.suffix) if reader is not None and path.is_file(): game = reader(str(path)) records.append( From 72aade140ff347ad53530cddeee2cfe0e52c3753 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 16:24:23 +0000 Subject: [PATCH 26/84] Big refactor to get catalog files from catalog dir external to pygambit --- MANIFEST.in | 1 + catalog/__init__.py | 51 ++++++++++++++++++++++++++ pyproject.toml | 7 ++++ setup.py | 2 -- src/pygambit/catalog.py | 80 ----------------------------------------- 5 files changed, 59 insertions(+), 82 deletions(-) create mode 100644 catalog/__init__.py delete mode 100644 src/pygambit/catalog.py diff --git a/MANIFEST.in b/MANIFEST.in index d1d71b9a6..69fed7e1d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ recursive-include src/core *.cc *.h *.imp recursive-include src/games *.cc *.h *.imp recursive-include src/solvers *.c *.cc *.h *.imp +recursive-include catalog * include src/gambit.h include src/pygambit/*.pxd include src/pygambit/*.pyx diff --git a/catalog/__init__.py b/catalog/__init__.py new file mode 100644 index 000000000..6e844fe40 --- /dev/null +++ b/catalog/__init__.py @@ -0,0 +1,51 @@ +from importlib.resources import as_file, files + +import pandas as pd + +import pygambit as gbt + +# Use the full string path to the virtual package we created +_CATALOG_RESOURCE = files(__name__) + +READERS = { + ".nfg": gbt.read_nfg, + ".efg": gbt.read_efg, +} + + +def load(slug: str) -> gbt.Game: + """ + Load a game from the package catalog. + """ + for suffix, reader in READERS.items(): + resource_path = _CATALOG_RESOURCE / f"{slug}{suffix}" + + if resource_path.is_file(): + # as_file ensures we have a real filesystem path for the reader + with as_file(resource_path) as path: + return reader(str(path)) + + raise FileNotFoundError(f"No catalog entry called {slug}.nfg or {slug}.efg") + + +def games() -> pd.DataFrame: + """ + List games available in the package catalog. + """ + records: list[dict[str, str]] = [] + + # iterdir() works directly on the Traversable object + for resource_path in sorted(_CATALOG_RESOURCE.iterdir()): + reader = READERS.get(resource_path.suffix) + + if reader is not None and resource_path.is_file(): + with as_file(resource_path) as path: + game = reader(str(path)) + records.append( + { + "slug": resource_path.stem, + "title": game.title, + } + ) + + return pd.DataFrame.from_records(records, columns=["slug", "title"]) diff --git a/pyproject.toml b/pyproject.toml index 36dfb494b..270f77d06 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,5 +88,12 @@ markers = [ "slow: all time-consuming tests", ] +[tool.setuptools] +packages = ["pygambit", "pygambit.catalog"] +package-dir = { "pygambit" = "src/pygambit", "pygambit.catalog" = "catalog" } + +[tool.setuptools.package-data] +"pygambit.catalog" = ["*"] + [tool.setuptools.dynamic] version = {file = "build_support/GAMBIT_VERSION"} diff --git a/setup.py b/setup.py index c8e7125f5..4a1e82b5a 100644 --- a/setup.py +++ b/setup.py @@ -103,8 +103,6 @@ def solver_library_config(library_name: str, paths: list) -> tuple: libraries=[cppgambit_bimatrix, cppgambit_liap, cppgambit_logit, cppgambit_simpdiv, cppgambit_gtracer, cppgambit_enumpoly, cppgambit_games, cppgambit_core], - package_dir={"": "src"}, - packages=["pygambit"], ext_modules=Cython.Build.cythonize(libgambit, language_level="3str", compiler_directives={"binding": True}) diff --git a/src/pygambit/catalog.py b/src/pygambit/catalog.py deleted file mode 100644 index 8c1736ce3..000000000 --- a/src/pygambit/catalog.py +++ /dev/null @@ -1,80 +0,0 @@ -from importlib.resources import files - -import pandas as pd - -import pygambit as gbt - -_GAMEFILES_DIR = files(__package__) / "catalog" -READERS = { - ".nfg": gbt.read_nfg, - ".efg": gbt.read_efg, -} - - -def load(slug: str) -> gbt.Game: - """ - Load a game from the package catalog. - - The function looks for a catalog entry matching the given ``slug`` in the - ``catalog`` resource directory. Files are tried in the following order: - - 1. ``.nfg`` (normal-form game) - 2. ``.efg`` (extensive-form game) - - The first matching file found is loaded and returned as a - :class:`pygambit.Game`. - - Parameters - ---------- - slug : str - Base name of the catalog entry, without file extension. - - Returns - ------- - pygambit.Game - The loaded game. - - Raises - ------ - FileNotFoundError - If no ``.nfg`` or ``.efg`` file exists for the given slug. - """ - for suffix, reader in READERS.items(): - path = _GAMEFILES_DIR / f"{slug}{suffix}" - if path.is_file(): - return reader(str(path)) - - raise FileNotFoundError(f"No catalog entry called {slug}.nfg or {slug}.efg") - - -def games() -> pd.DataFrame: - """ - List games available in the package catalog. - - Iterates over ``.nfg`` and ``.efg`` files found in the catalog resource - directory, loads each game, and returns a pandas DataFrame summarising - the results. - - The returned DataFrame has two columns: - - ``slug``: the filename without its extension - - ``title``: the game's ``title`` attribute - - Returns - ------- - pandas.DataFrame - A DataFrame with columns ``slug`` and ``title``. - """ - records: list[dict[str, str]] = [] - - for path in sorted(_GAMEFILES_DIR.iterdir()): - reader = READERS.get(path.suffix) - if reader is not None and path.is_file(): - game = reader(str(path)) - records.append( - { - "slug": path.stem, - "title": game.title, - } - ) - - return pd.DataFrame.from_records(records, columns=["slug", "title"]) From e7953e96efbe5582eb629d4b187eff74317bd05b Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 3 Feb 2026 16:45:17 +0000 Subject: [PATCH 27/84] update Makefile.am for the 2 examples we moved into the catalog so far --- Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index eccc92c12..7b88649ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -101,7 +101,6 @@ EXTRA_DIST = \ src/gui/bitmaps/zoom1.xpm \ src/gui/bitmaps/gambitrc.rc \ contrib/games/2s2x2x2.efg \ - contrib/games/2smp.efg \ contrib/games/2x2x2.efg \ contrib/games/4cards.efg \ contrib/games/artist1.efg \ @@ -224,7 +223,6 @@ EXTRA_DIST = \ contrib/games/mixdom2.nfg \ contrib/games/mixdom.nfg \ contrib/games/oneill.nfg \ - contrib/games/pd.nfg \ contrib/games/perfect1.nfg \ contrib/games/perfect2.nfg \ contrib/games/perfect3.nfg \ @@ -240,7 +238,9 @@ EXTRA_DIST = \ contrib/games/winkels.nfg \ contrib/games/yamamoto.nfg \ contrib/games/zero.nfg \ - src/README.rst + src/README.rst \ + catalog/2smp.efg \ + catalog/pd.nfg core_SOURCES = \ src/core/core.h \ From 7490ae6bbe20601aff1fba435d7d852341e1d8a7 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 09:43:36 +0000 Subject: [PATCH 28/84] update Game.comment to be Game.description in Python code --- doc/pygambit.api.rst | 2 +- src/pygambit/game.pxi | 10 +++++----- tests/test_extensive.py | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/pygambit.api.rst b/doc/pygambit.api.rst index ae029bae7..7568cfd5a 100644 --- a/doc/pygambit.api.rst +++ b/doc/pygambit.api.rst @@ -95,7 +95,7 @@ Information about the game :toctree: api/ Game.title - Game.comment + Game.description Game.is_const_sum Game.is_tree Game.is_perfect_recall diff --git a/src/pygambit/game.pxi b/src/pygambit/game.pxi index 2fbde8186..403eb9f98 100644 --- a/src/pygambit/game.pxi +++ b/src/pygambit/game.pxi @@ -661,16 +661,16 @@ class Game: self.game.deref().SetTitle(value.encode("ascii")) @property - def comment(self) -> str: - """Get or set the comment of the game. + def description(self) -> str: + """Get or set the description of the game. - A game's comment is an arbitrary string, and may be more discursive + A game's description/comment is an arbitrary string, and may be more discursive than a title. """ return self.game.deref().GetComment().decode("ascii") - @comment.setter - def comment(self, value: str) -> None: + @description.setter + def description(self, value: str) -> None: self.game.deref().SetComment(value.encode("ascii")) @property diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 41528afbe..2695e473d 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -25,12 +25,12 @@ def test_game_title(title: str): @pytest.mark.parametrize( - "comment", ["This is a comment describing the game in more detail"] + "description", ["This is a description of the game with more detail"] ) -def test_game_comment(comment: str): +def test_game_description(description: str): game = gbt.Game.new_tree() - game.comment = comment - assert game.comment == comment + game.description = description + assert game.description == description @pytest.mark.parametrize("players", [["Alice"], ["Oscar", "Felix"]]) From ebf6829e83e2bf0f0fa2adc7e5848f35c87b89c6 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 09:47:10 +0000 Subject: [PATCH 29/84] Revert "update Game.comment to be Game.description in Python code" This reverts commit 7490ae6bbe20601aff1fba435d7d852341e1d8a7. --- doc/pygambit.api.rst | 2 +- src/pygambit/game.pxi | 10 +++++----- tests/test_extensive.py | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/pygambit.api.rst b/doc/pygambit.api.rst index 7568cfd5a..ae029bae7 100644 --- a/doc/pygambit.api.rst +++ b/doc/pygambit.api.rst @@ -95,7 +95,7 @@ Information about the game :toctree: api/ Game.title - Game.description + Game.comment Game.is_const_sum Game.is_tree Game.is_perfect_recall diff --git a/src/pygambit/game.pxi b/src/pygambit/game.pxi index 403eb9f98..2fbde8186 100644 --- a/src/pygambit/game.pxi +++ b/src/pygambit/game.pxi @@ -661,16 +661,16 @@ class Game: self.game.deref().SetTitle(value.encode("ascii")) @property - def description(self) -> str: - """Get or set the description of the game. + def comment(self) -> str: + """Get or set the comment of the game. - A game's description/comment is an arbitrary string, and may be more discursive + A game's comment is an arbitrary string, and may be more discursive than a title. """ return self.game.deref().GetComment().decode("ascii") - @description.setter - def description(self, value: str) -> None: + @comment.setter + def comment(self, value: str) -> None: self.game.deref().SetComment(value.encode("ascii")) @property diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 2695e473d..41528afbe 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -25,12 +25,12 @@ def test_game_title(title: str): @pytest.mark.parametrize( - "description", ["This is a description of the game with more detail"] + "comment", ["This is a comment describing the game in more detail"] ) -def test_game_description(description: str): +def test_game_comment(comment: str): game = gbt.Game.new_tree() - game.description = description - assert game.description == description + game.comment = comment + assert game.comment == comment @pytest.mark.parametrize("players", [["Alice"], ["Oscar", "Felix"]]) From fbf6b89967c1a89b9e57f89d66960687904bad32 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 11:47:55 +0000 Subject: [PATCH 30/84] Add initial update catalog script and RST page --- .gitignore | 1 + doc/catalog.rst | 8 ++++++++ doc/index.rst | 1 + src/pygambit/update_catalog.py | 7 +++++++ 4 files changed, 17 insertions(+) create mode 100644 doc/catalog.rst create mode 100644 src/pygambit/update_catalog.py diff --git a/.gitignore b/.gitignore index 85c959981..f8be35fcf 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ Gambit.app/* build_support/msw/gambit.wxs build_support/osx/Info.plist src/pygambit/catalog +doc/catalog.csv diff --git a/doc/catalog.rst b/doc/catalog.rst new file mode 100644 index 000000000..cf8d45e2c --- /dev/null +++ b/doc/catalog.rst @@ -0,0 +1,8 @@ +Catalog of games +================ + +.. csv-table:: + :file: catalog.csv + :header-rows: 1 + :widths: 20, 80 + :class: tight-table diff --git a/doc/index.rst b/doc/index.rst index 79076153a..72843860d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -64,6 +64,7 @@ We recommended most new users install the PyGambit Python package and read the a pygambit tools gui + catalog samples developer formats diff --git a/src/pygambit/update_catalog.py b/src/pygambit/update_catalog.py new file mode 100644 index 000000000..e1c7d098c --- /dev/null +++ b/src/pygambit/update_catalog.py @@ -0,0 +1,7 @@ +import pygambit as gbt + +DOC = "../../doc" + +if __name__ == "__main__": + # Create CSV used by RST docs page + gbt.catalog.games().to_csv(DOC + "/catalog.csv", index=False) From 1ca3461549b7ed10f587f0ff20a02f07451af28c Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 11:53:24 +0000 Subject: [PATCH 31/84] rename table headers on output df from game() func --- catalog/__init__.py | 6 +++--- tests/test_catalog.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index 6e844fe40..4164041f5 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -43,9 +43,9 @@ def games() -> pd.DataFrame: game = reader(str(path)) records.append( { - "slug": resource_path.stem, - "title": game.title, + "Game": resource_path.stem, + "Title": game.title, } ) - return pd.DataFrame.from_records(records, columns=["slug", "title"]) + return pd.DataFrame.from_records(records, columns=["Game", "Title"]) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 2564b1209..f281cc353 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -29,5 +29,5 @@ def test_catalog_games(): all_games = gbt.catalog.games() assert isinstance(all_games, pd.DataFrame) assert len(all_games) > 0 - assert "2smp" in list(all_games.slug) - assert "Two-stage matching pennies game" in list(all_games.title) + assert "2smp" in list(all_games.Game) + assert "Two-stage matching pennies game" in list(all_games.Title) From bd3c1f3646bc908805b100e116e9246d25a460f5 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 11:58:17 +0000 Subject: [PATCH 32/84] add generating the catalog csv for docs into GH actions --- .github/workflows/python.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 5e23dff61..1fe0f6f6d 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -31,6 +31,10 @@ jobs: run: | cd dist pip install -v pygambit*.tar.gz + - name: Generate Catalog CSV for docs + run: | + cd src/pygambit + python update_catalog.py - name: Run tests run: pytest --run-tutorials @@ -56,6 +60,10 @@ jobs: - name: Build extension run: | python -m pip install -v . + - name: Generate Catalog CSV for docs + run: | + cd src/pygambit + python update_catalog.py - name: Run tests run: pytest --run-tutorials @@ -81,6 +89,10 @@ jobs: - name: Build extension run: | python -m pip install -v . + - name: Generate Catalog CSV for docs + run: | + cd src/pygambit + python update_catalog.py - name: Run tests run: pytest --run-tutorials @@ -106,5 +118,9 @@ jobs: - name: Build extension run: | python -m pip install -v . + - name: Generate Catalog CSV for docs + run: | + cd src/pygambit + python update_catalog.py - name: Run tests run: pytest --run-tutorials From 569148c071f834a7430c2b86d8b37b55ee502fbd Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 13:48:59 +0000 Subject: [PATCH 33/84] Revert "add generating the catalog csv for docs into GH actions" This reverts commit bd3c1f3646bc908805b100e116e9246d25a460f5. --- .github/workflows/python.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 1fe0f6f6d..5e23dff61 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -31,10 +31,6 @@ jobs: run: | cd dist pip install -v pygambit*.tar.gz - - name: Generate Catalog CSV for docs - run: | - cd src/pygambit - python update_catalog.py - name: Run tests run: pytest --run-tutorials @@ -60,10 +56,6 @@ jobs: - name: Build extension run: | python -m pip install -v . - - name: Generate Catalog CSV for docs - run: | - cd src/pygambit - python update_catalog.py - name: Run tests run: pytest --run-tutorials @@ -89,10 +81,6 @@ jobs: - name: Build extension run: | python -m pip install -v . - - name: Generate Catalog CSV for docs - run: | - cd src/pygambit - python update_catalog.py - name: Run tests run: pytest --run-tutorials @@ -118,9 +106,5 @@ jobs: - name: Build extension run: | python -m pip install -v . - - name: Generate Catalog CSV for docs - run: | - cd src/pygambit - python update_catalog.py - name: Run tests run: pytest --run-tutorials From 8cf0396977b3e148ebfc444126ff65de73c31ede Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 13:52:17 +0000 Subject: [PATCH 34/84] refactor update script so its run from repo root --- src/pygambit/update_catalog.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pygambit/update_catalog.py b/src/pygambit/update_catalog.py index e1c7d098c..f4b776093 100644 --- a/src/pygambit/update_catalog.py +++ b/src/pygambit/update_catalog.py @@ -1,7 +1,7 @@ import pygambit as gbt -DOC = "../../doc" +CATALOG_CSV = "doc/catalog.csv" if __name__ == "__main__": # Create CSV used by RST docs page - gbt.catalog.games().to_csv(DOC + "/catalog.csv", index=False) + gbt.catalog.games().to_csv(CATALOG_CSV, index=False) From 1b20438eac5474bdb521e12d34a1b55afc666ac7 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 13:54:46 +0000 Subject: [PATCH 35/84] update readthedocs to build the catalog csv before docs build --- .readthedocs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index 73522dfdf..5cc214ac8 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -13,6 +13,10 @@ build: - libgmp-dev - pandoc - texlive-full + jobs: + # Create CSV for catalog table in docs + post_install: + - python src/pygambit/update_catalog.py python: install: From e977e64dab2dbe3ab974a62e1027f4c58c9aa5e8 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 14:25:18 +0000 Subject: [PATCH 36/84] add function which updates Makefile.am --- src/pygambit/update_catalog.py | 56 ++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/pygambit/update_catalog.py b/src/pygambit/update_catalog.py index f4b776093..6d4c59b2d 100644 --- a/src/pygambit/update_catalog.py +++ b/src/pygambit/update_catalog.py @@ -1,7 +1,59 @@ +from pathlib import Path + import pygambit as gbt -CATALOG_CSV = "doc/catalog.csv" +CATALOG_CSV = "doc/catalog.csv" # Relative to where script run from (root) +MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am" +ALL_GAMES = gbt.catalog.games() +CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog" +efg_files = list(CATALOG_DIR.rglob("*.efg")) +nfg_files = list(CATALOG_DIR.rglob("*.nfg")) + + +def update_makefile(): + """Update the Makefile.am with all games from the catalog.""" + + game_files = [] + for entry in efg_files + nfg_files: + filename = str(entry).split("/")[-1] + game_files.append(f"catalog/{filename}") + game_files.sort() + + with open(MAKEFILE_AM, encoding="utf-8") as f: + content = f.readlines() + + with open(MAKEFILE_AM, "w", encoding="utf-8") as f: + in_gamefiles_section = False + for line in content: + # Add to the EXTRA_DIST after the README.rst line + if line.startswith(" src/README.rst \\"): + in_gamefiles_section = True + f.write(" src/README.rst \\\n") + for gf in game_files: + if gf == game_files[-1]: + f.write(f"\t{gf}\n") + else: + f.write(f"\t{gf} \\\n") + f.write("\n") + elif in_gamefiles_section: + if line.strip() == "": + in_gamefiles_section = False + continue # Skip old gamefiles lines + else: + f.write(line) + + with open(MAKEFILE_AM, encoding="utf-8") as f: + updated_content = f.readlines() + + if content != updated_content: + print(f"Updated {str(MAKEFILE_AM)}") + if __name__ == "__main__": + # Create CSV used by RST docs page - gbt.catalog.games().to_csv(CATALOG_CSV, index=False) + ALL_GAMES.to_csv(CATALOG_CSV, index=False) + print(f"Generated {CATALOG_CSV} for use in docs build.") + + # Update the Makefile.am with the current list of catalog files + update_makefile() From af08d29e0cb10d7dcdb5c27dc31f472951a50d6e Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 14:41:17 +0000 Subject: [PATCH 37/84] use a proper path for CATALOG_CSV --- src/pygambit/update_catalog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pygambit/update_catalog.py b/src/pygambit/update_catalog.py index 6d4c59b2d..2ab6c0e73 100644 --- a/src/pygambit/update_catalog.py +++ b/src/pygambit/update_catalog.py @@ -2,7 +2,7 @@ import pygambit as gbt -CATALOG_CSV = "doc/catalog.csv" # Relative to where script run from (root) +CATALOG_CSV = Path(__file__).parent.parent.parent / "doc" / "catalog.csv" MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am" ALL_GAMES = gbt.catalog.games() CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog" From cd2ffc9ee4cc6400ecb2fa1be41db45abbfef7aa Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 14:43:10 +0000 Subject: [PATCH 38/84] tidy update script --- src/pygambit/update_catalog.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pygambit/update_catalog.py b/src/pygambit/update_catalog.py index 2ab6c0e73..1b05669da 100644 --- a/src/pygambit/update_catalog.py +++ b/src/pygambit/update_catalog.py @@ -4,14 +4,13 @@ CATALOG_CSV = Path(__file__).parent.parent.parent / "doc" / "catalog.csv" MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am" -ALL_GAMES = gbt.catalog.games() -CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog" -efg_files = list(CATALOG_DIR.rglob("*.efg")) -nfg_files = list(CATALOG_DIR.rglob("*.nfg")) def update_makefile(): """Update the Makefile.am with all games from the catalog.""" + catalog_dir = Path(__file__).parent.parent.parent / "catalog" + efg_files = list(catalog_dir.rglob("*.efg")) + nfg_files = list(catalog_dir.rglob("*.nfg")) game_files = [] for entry in efg_files + nfg_files: @@ -52,7 +51,7 @@ def update_makefile(): if __name__ == "__main__": # Create CSV used by RST docs page - ALL_GAMES.to_csv(CATALOG_CSV, index=False) + gbt.catalog.games().to_csv(CATALOG_CSV, index=False) print(f"Generated {CATALOG_CSV} for use in docs build.") # Update the Makefile.am with the current list of catalog files From 5675444b1fabb0375a0f602858c04d7dcc101826 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 14:45:20 +0000 Subject: [PATCH 39/84] use explicit python executable from the virtualenv to create CSV for catalog docs table in readthedocs yml --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 5cc214ac8..03dc4edad 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -16,7 +16,7 @@ build: jobs: # Create CSV for catalog table in docs post_install: - - python src/pygambit/update_catalog.py + - $READTHEDOCS_VIRTUALENV_PATH/bin/python src/pygambit/update_catalog.py python: install: From f57422322b210c8286664f091611ac8e490fa2de Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 15:06:39 +0000 Subject: [PATCH 40/84] add developer doc for updating the catalog --- doc/developer.catalog.rst | 41 ++++++++++++++++++++++++++++++++++ doc/developer.contributing.rst | 2 ++ doc/developer.rst | 1 + 3 files changed, 44 insertions(+) create mode 100644 doc/developer.catalog.rst diff --git a/doc/developer.catalog.rst b/doc/developer.catalog.rst new file mode 100644 index 000000000..0f347670f --- /dev/null +++ b/doc/developer.catalog.rst @@ -0,0 +1,41 @@ +Updating the Games Catalog +========================== + +This page covers the process for contributing to and updating Gambit's :ref:`Games Catalog `. +To do so, you will need to have the `gambit` GitHub repo cloned and be able to submit pull request via GitHub; +you may wish to first review the :ref:`contributor guidelines `. + +You can add games to the catalog saved in a valid representation :ref:`format `. +Currently supported representations are: + +- `.efg` for extensive form games +- `.nfg` for normal form games + +Add new games +------------- + +1. **Create the game file:** + + Use either :ref:`pygambit `, the Gambit :ref:`CLI ` or :ref:`GUI ` to create and save game in a valid representation :ref:`format `. + +2. **Add the game file:** + + Create a new branch in the ``gambit`` repo. Add your new game file(s) inside the ``catalog`` dir and commit them. + +3. **Update the catalog:** + + Use the ``update_catalog.py`` script to update the Gambit's documentation & build files. + + .. code-block:: bash + + python src/pygambit/update_catalog.py + + .. note:: + + Run this script in a Python environment where ``pygambit`` itself is also :ref:`installed `. + +4. **Submit a pull request to GitHub with all changes.** + + .. warning:: + + Make sure you commit all changed files e.g. run ``git add --all`` before committing and pushing. diff --git a/doc/developer.contributing.rst b/doc/developer.contributing.rst index f86939850..02ca37747 100644 --- a/doc/developer.contributing.rst +++ b/doc/developer.contributing.rst @@ -1,3 +1,5 @@ +.. _contributing: + Contributing to Gambit ====================== diff --git a/doc/developer.rst b/doc/developer.rst index 0a1512659..b954f0850 100644 --- a/doc/developer.rst +++ b/doc/developer.rst @@ -11,3 +11,4 @@ This section contains information for developers who want to contribute to the G developer.build developer.contributing + developer.catalog From 5147278cfb188cdb3496bd54da6df5db430fc0bd Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 15:13:32 +0000 Subject: [PATCH 41/84] Don't update Makefile.am by default --- doc/developer.catalog.rst | 4 ++-- src/pygambit/update_catalog.py | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/developer.catalog.rst b/doc/developer.catalog.rst index 0f347670f..1a4d953e5 100644 --- a/doc/developer.catalog.rst +++ b/doc/developer.catalog.rst @@ -24,11 +24,11 @@ Add new games 3. **Update the catalog:** - Use the ``update_catalog.py`` script to update the Gambit's documentation & build files. + Use the ``update_catalog.py`` script to update Gambit's documentation & build files. .. code-block:: bash - python src/pygambit/update_catalog.py + python src/pygambit/update_catalog.py --build .. note:: diff --git a/src/pygambit/update_catalog.py b/src/pygambit/update_catalog.py index 1b05669da..c6787f170 100644 --- a/src/pygambit/update_catalog.py +++ b/src/pygambit/update_catalog.py @@ -1,3 +1,4 @@ +import argparse from pathlib import Path import pygambit as gbt @@ -46,13 +47,20 @@ def update_makefile(): if content != updated_content: print(f"Updated {str(MAKEFILE_AM)}") + else: + print(f"No changes to add to {str(MAKEFILE_AM)}") if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--build", action="store_true") + args = parser.parse_args() + # Create CSV used by RST docs page gbt.catalog.games().to_csv(CATALOG_CSV, index=False) - print(f"Generated {CATALOG_CSV} for use in docs build.") + print(f"Generated {CATALOG_CSV} for use in local docs build. DO NOT COMMIT.") # Update the Makefile.am with the current list of catalog files - update_makefile() + if args.build: + update_makefile() From 4b033c9ca4de6b12aac75c04c4618036cdaf3154 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 15:15:13 +0000 Subject: [PATCH 42/84] consistency in notebook comment --- doc/tutorials/01_quickstart.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 06ec6f91e..4c1d85f7b 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -467,13 +467,13 @@ } ], "source": [ - "# gbt.read_nfg(\"test_games/prisoners_dilemma.nfg\")" + "# gbt.read_nfg(\"prisoners_dilemma.nfg\")" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "gambitvenv313", "language": "python", "name": "python3" }, From b14402ad9af308bdd9eb75a6866e2c03d47b4650 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 15:29:49 +0000 Subject: [PATCH 43/84] demo loading from catalog in tutorial 1 --- doc/tutorials/01_quickstart.ipynb | 169 +++++++++++++++++++++++------- 1 file changed, 132 insertions(+), 37 deletions(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 4c1d85f7b..012ee466a 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -38,7 +38,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "c58d382d", "metadata": {}, "outputs": [], @@ -50,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "2060c1ed", "metadata": {}, "outputs": [ @@ -60,7 +60,7 @@ "pygambit.gambit.Game" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -83,7 +83,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "9d8203e8", "metadata": {}, "outputs": [], @@ -111,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "61030607", "metadata": {}, "outputs": [], @@ -135,7 +135,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "caecc334", "metadata": {}, "outputs": [ @@ -143,13 +143,13 @@ "data": { "text/html": [ "

Prisoner's Dilemma

\n", - "
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
\n" + "
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
\n" ], "text/plain": [ "Game(title='Prisoner's Dilemma')" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -189,7 +189,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "843ba7f3", "metadata": {}, "outputs": [ @@ -197,13 +197,13 @@ "data": { "text/html": [ "

Another Prisoner's Dilemma

\n", - "
12
1-1,-1-3,0
20,-3-2,-2
\n" + "
12
1-1,-1-3,0
20,-3-2,-2
12
1-1,-1-3,0
20,-3-2,-2
12
1-1,-1-3,0
20,-3-2,-2
12
1-1,-1-3,0
20,-3-2,-2
\n" ], "text/plain": [ "Game(title='Another Prisoner's Dilemma')" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -233,7 +233,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "5ee752c4", "metadata": {}, "outputs": [ @@ -270,7 +270,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "a81c06c7", "metadata": {}, "outputs": [ @@ -280,7 +280,7 @@ "pygambit.nash.NashComputationResult" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -300,7 +300,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "bd395180", "metadata": {}, "outputs": [ @@ -310,7 +310,7 @@ "1" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -329,7 +329,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "76570ebc", "metadata": {}, "outputs": [ @@ -342,7 +342,7 @@ "[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]]" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -354,7 +354,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "6e8cfcde", "metadata": {}, "outputs": [ @@ -364,7 +364,7 @@ "pygambit.gambit.MixedStrategyProfileRational" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -385,7 +385,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "980bf6b1", "metadata": {}, "outputs": [ @@ -417,11 +417,117 @@ }, { "cell_type": "markdown", - "id": "24f36b0d", + "id": "c27c50f0-e8cc-4160-9975-aa02b33c6879", "metadata": {}, "source": [ "The equilibrium shows that both players are playing their dominant strategy, which is to defect. This is because defecting is the best response to the other player's strategy, regardless of what that strategy is.\n", "\n", + "Loading games from the catalog \n", + "------------------------------\n", + "\n", + "Gambit includes a catalog of standard games that can be loaded directly by name. You can list all the available games like so:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e1b060fb-94cc-432d-a9cc-4ccae5908f79", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GameTitle
02smpTwo-stage matching pennies game
1pdTwo person Prisoner's Dilemma game
\n", + "
" + ], + "text/plain": [ + " Game Title\n", + "0 2smp Two-stage matching pennies game\n", + "1 pd Two person Prisoner's Dilemma game" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbt.catalog.games()" + ] + }, + { + "cell_type": "markdown", + "id": "3030ee7e-2d5e-4560-ab1b-7c865d0fe19d", + "metadata": {}, + "source": [ + "You can then load a specific game by its name. For example, to load the \"Prisoner's Dilemma\" game from the catalog, you would do the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "9ee2c3bd-22d1-4c8e-996c-cd9e0dfd64cc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "

Two person Prisoner's Dilemma game

\n", + "
12
19,90,10
210,01,1
12
19,90,10
210,01,1
12
19,90,10
210,01,1
12
19,90,10
210,01,1
\n" + ], + "text/plain": [ + "Game(title='Two person Prisoner's Dilemma game')" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g = gbt.catalog.load(\"pd\")\n", + "g" + ] + }, + { + "cell_type": "markdown", + "id": "24f36b0d", + "metadata": {}, + "source": [ "Saving and reading strategic form games to and from file\n", "--------------------\n", "\n", @@ -433,7 +539,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "f58eaa77", "metadata": {}, "outputs": [], @@ -451,21 +557,10 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "4119a2ac", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.Game" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# gbt.read_nfg(\"prisoners_dilemma.nfg\")" ] @@ -473,7 +568,7 @@ ], "metadata": { "kernelspec": { - "display_name": "gambitvenv313", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, From 264f7fb742a67e68adfcd55ac545100dc37b08e5 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 15:55:26 +0000 Subject: [PATCH 44/84] load from catalog for game examples in advanced tutorials --- Makefile.am | 2 + {contrib/games => catalog}/2x2x2.nfg | 0 .../games => catalog}/myerson_fig_4_2.efg | 0 .../agent_versus_non_agent_regret.ipynb | 200 +++++++++--------- .../advanced_tutorials/starting_points.ipynb | 28 +-- 5 files changed, 112 insertions(+), 118 deletions(-) rename {contrib/games => catalog}/2x2x2.nfg (100%) rename {contrib/games => catalog}/myerson_fig_4_2.efg (100%) diff --git a/Makefile.am b/Makefile.am index 7b88649ac..b2a4b4395 100644 --- a/Makefile.am +++ b/Makefile.am @@ -240,6 +240,8 @@ EXTRA_DIST = \ contrib/games/zero.nfg \ src/README.rst \ catalog/2smp.efg \ + catalog/2x2x2.nfg \ + catalog/myerson_fig_4_2.efg \ catalog/pd.nfg core_SOURCES = \ diff --git a/contrib/games/2x2x2.nfg b/catalog/2x2x2.nfg similarity index 100% rename from contrib/games/2x2x2.nfg rename to catalog/2x2x2.nfg diff --git a/contrib/games/myerson_fig_4_2.efg b/catalog/myerson_fig_4_2.efg similarity index 100% rename from contrib/games/myerson_fig_4_2.efg rename to catalog/myerson_fig_4_2.efg diff --git a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb index 68b78ee11..c7e16ba80 100644 --- a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb +++ b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb @@ -35,235 +35,225 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", - "\n", + "\n", "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", - "\n", + "\n", "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "" ], "text/plain": [ @@ -280,7 +270,7 @@ "\n", "import pygambit as gbt\n", "\n", - "g = gbt.read_efg(\"../../../contrib/games/myerson_fig_4_2.efg\")\n", + "g = gbt.catalog.load(\"myerson_fig_4_2\")\n", "draw_tree(g)" ] }, @@ -436,7 +426,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[4.2517925671604327e-07, 0.49999911111761514, 0.5000004637031282], [0.3333333517938241, 0.6666666482061759]]\n" + "[[6.949101896011271e-07, 0.49999858461819596, 0.5000007204716144], [0.33333333942537524, 0.6666666605746248]]\n" ] } ], @@ -455,8 +445,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Liap value: 4.43446520109796e-14\n", - "Max regret: 1.694170896904268e-07\n" + "Liap value: 1.0863970174089946e-13\n", + "Max regret: 2.407747583532682e-07\n" ] } ], @@ -699,7 +689,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.9" + "version": "3.13.5" } }, "nbformat": 4, diff --git a/doc/tutorials/advanced_tutorials/starting_points.ipynb b/doc/tutorials/advanced_tutorials/starting_points.ipynb index fb976245b..4fa281746 100644 --- a/doc/tutorials/advanced_tutorials/starting_points.ipynb +++ b/doc/tutorials/advanced_tutorials/starting_points.ipynb @@ -25,7 +25,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "493cafb8", "metadata": {}, "outputs": [ @@ -33,7 +33,7 @@ "data": { "text/html": [ "

2x2x2 Example from McKelvey-McLennan, with 9 Nash equilibria, 2 totally mixed

\n", - "
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
\n" + "
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
\n" ], "text/plain": [ "Game(title='2x2x2 Example from McKelvey-McLennan, with 9 Nash equilibria, 2 totally mixed')" @@ -45,8 +45,11 @@ } ], "source": [ + "import numpy as np\n", + "\n", "import pygambit as gbt\n", - "g = gbt.read_nfg(\"../../2x2x2.nfg\")\n", + "\n", + "g = gbt.catalog.load(\"2x2x2\")\n", "g" ] }, @@ -93,10 +96,10 @@ { "data": { "text/latex": [ - "$\\left[[0.3999999026224355, 0.6000000973775644],[0.49999981670851457, 0.5000001832914854],[0.3333329684317666, 0.6666670315682334]\\right]$" + "$\\left[[0.3999998880351315, 0.6000001119648686],[0.5000000683119051, 0.4999999316880949],[0.3333335574724357, 0.6666664425275644]\\right]$" ], "text/plain": [ - "[[0.3999999026224355, 0.6000000973775644], [0.49999981670851457, 0.5000001832914854], [0.3333329684317666, 0.6666670315682334]]" + "[[0.3999998880351315, 0.6000001119648686], [0.5000000683119051, 0.4999999316880949], [0.3333335574724357, 0.6666664425275644]]" ] }, "execution_count": 3, @@ -153,10 +156,10 @@ { "data": { "text/latex": [ - "$\\left[[1.0, 0.0],[0.9999999944750116, 5.524988446860122e-09],[0.9999999991845827, 8.154173380971617e-10]\\right]$" + "$\\left[[1.0, 0.0],[0.9999999916299683, 8.370031632789431e-09],[1.0, 0.0]\\right]$" ], "text/plain": [ - "[[1.0, 0.0], [0.9999999944750116, 5.524988446860122e-09], [0.9999999991845827, 8.154173380971617e-10]]" + "[[1.0, 0.0], [0.9999999916299683, 8.370031632789431e-09], [1.0, 0.0]]" ] }, "execution_count": 5, @@ -185,10 +188,10 @@ { "data": { "text/latex": [ - "$\\left[[0.7187961367413075, 0.2812038632586925],[0.1291105793795489, 0.8708894206204512],[0.12367227612277114, 0.876327723877229]\\right]$" + "$\\left[[0.9835790201705958, 0.01642097982940421],[0.7494285573591715, 0.2505714426408285],[0.14967367720546837, 0.8503263227945317]\\right]$" ], "text/plain": [ - "[[0.7187961367413075, 0.2812038632586925], [0.1291105793795489, 0.8708894206204512], [0.12367227612277114, 0.876327723877229]]" + "[[0.9835790201705958, 0.01642097982940421], [0.7494285573591715, 0.2505714426408285], [0.14967367720546837, 0.8503263227945317]]" ] }, "execution_count": 6, @@ -210,10 +213,10 @@ { "data": { "text/latex": [ - "$\\left[[0.5000003932357804, 0.4999996067642197],[0.3999998501612186, 0.6000001498387814],[0.2500001518113522, 0.7499998481886477]\\right]$" + "$\\left[[0.5000000583093926, 0.49999994169060735],[0.39999989404863995, 0.6000001059513601],[0.2499996298123818, 0.7500003701876182]\\right]$" ], "text/plain": [ - "[[0.5000003932357804, 0.4999996067642197], [0.3999998501612186, 0.6000001498387814], [0.2500001518113522, 0.7499998481886477]]" + "[[0.5000000583093926, 0.49999994169060735], [0.39999989404863995, 0.6000001059513601], [0.2499996298123818, 0.7500003701876182]]" ] }, "execution_count": 7, @@ -254,7 +257,6 @@ } ], "source": [ - "import numpy as np\n", "gen = np.random.default_rng(seed=1234567890)\n", "p1 = g.random_strategy_profile(gen=gen)\n", "gen = np.random.default_rng(seed=1234567890)\n", @@ -427,7 +429,7 @@ ], "metadata": { "kernelspec": { - "display_name": "gambitvenv313", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, From 0e268a2d5d83a9ce499e8a68315f7575b10b0dd2 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 16:03:55 +0000 Subject: [PATCH 45/84] Try using pip instead of setuptools to ensure pyproject.toml deps installed for readthedocs build --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 03dc4edad..1bbd415f8 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -21,5 +21,5 @@ build: python: install: - requirements: doc/requirements.txt - - method: setuptools + - method: pip path: "." From 86499461b8b3de26b9d56cc4c88295bd20684145 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 16:13:40 +0000 Subject: [PATCH 46/84] remove deleted contrib games from Makefile.am --- Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index b2a4b4395..ca6e0dfd8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -168,7 +168,6 @@ EXTRA_DIST = \ contrib/games/my_3-3d.efg \ contrib/games/my_3-3e.efg \ contrib/games/my_3-4.efg \ - contrib/games/myerson.efg \ contrib/games/nim7.efg \ contrib/games/nim.efg \ contrib/games/palf2.efg \ @@ -194,7 +193,6 @@ EXTRA_DIST = \ contrib/games/2x2a.nfg \ contrib/games/2x2const.nfg \ contrib/games/2x2.nfg \ - contrib/games/2x2x2.nfg \ contrib/games/2x2x2x2.nfg \ contrib/games/2x2x2x2x2.nfg \ contrib/games/3x3x3.nfg \ From adea4f202b26f50514212b01f9587553291141d0 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 16:19:46 +0000 Subject: [PATCH 47/84] add a warning about moving games from contrib --- doc/developer.catalog.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/developer.catalog.rst b/doc/developer.catalog.rst index 1a4d953e5..40680c8e9 100644 --- a/doc/developer.catalog.rst +++ b/doc/developer.catalog.rst @@ -34,6 +34,10 @@ Add new games Run this script in a Python environment where ``pygambit`` itself is also :ref:`installed `. + .. warning:: + + This script updates `Makefile.am` with the game file added to the catalog, but if you moved games that were previously in `contrib/games` you'll want to manually remove those files from `EXTRA_DIST`. + 4. **Submit a pull request to GitHub with all changes.** .. warning:: From a72f7a2f106ba0fcada0a78f8b9a5d2bf55aa69e Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 16:24:28 +0000 Subject: [PATCH 48/84] check if pandas duplications error exists if we dont save outputs on notebooks --- doc/tutorials/01_quickstart.ipynb | 234 ++-------- .../agent_versus_non_agent_regret.ipynb | 399 ++---------------- 2 files changed, 53 insertions(+), 580 deletions(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 012ee466a..62949a4b4 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -38,7 +38,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "c58d382d", "metadata": {}, "outputs": [], @@ -50,21 +50,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "2060c1ed", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.Game" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "n_strategies = [2, 2]\n", "g = gbt.Game.new_table(n_strategies, title=\"Prisoner's Dilemma\")\n", @@ -83,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "9d8203e8", "metadata": {}, "outputs": [], @@ -111,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "61030607", "metadata": {}, "outputs": [], @@ -135,25 +124,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "caecc334", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Prisoner's Dilemma

\n", - "
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
\n" - ], - "text/plain": [ - "Game(title='Prisoner's Dilemma')" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# View the payout matrix\n", "g" @@ -189,25 +163,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "843ba7f3", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Another Prisoner's Dilemma

\n", - "
12
1-1,-1-3,0
20,-3-2,-2
12
1-1,-1-3,0
20,-3-2,-2
12
1-1,-1-3,0
20,-3-2,-2
12
1-1,-1-3,0
20,-3-2,-2
\n" - ], - "text/plain": [ - "Game(title='Another Prisoner's Dilemma')" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "player1_payoffs = np.array([[-1, -3], [0, -2]])\n", "player2_payoffs = np.transpose(player1_payoffs)\n", @@ -233,19 +192,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "5ee752c4", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-1\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "tom_payoffs, jerry_payoffs = g.to_arrays(\n", " # dtype=float\n", @@ -270,21 +220,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "a81c06c7", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.nash.NashComputationResult" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "result = gbt.nash.enumpure_solve(g)\n", "type(result)" @@ -300,21 +239,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "bd395180", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "len(result.equilibria)" ] @@ -329,24 +257,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "76570ebc", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[0,1\\right],\\left[0,1\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "msp = result.equilibria[0]\n", "msp" @@ -354,21 +268,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "6e8cfcde", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.MixedStrategyProfileRational" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "type(msp)" ] @@ -385,27 +288,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "980bf6b1", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tom plays the equilibrium strategy:\n", - "Probability of cooperating: 0\n", - "Probability of defecting: 1\n", - "Payoff: -2\n", - "\n", - "Jerry plays the equilibrium strategy:\n", - "Probability of cooperating: 0\n", - "Probability of defecting: 1\n", - "Payoff: -2\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "for player in g.players:\n", " print(f\"{player.label} plays the equilibrium strategy:\")\n", @@ -430,61 +316,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "e1b060fb-94cc-432d-a9cc-4ccae5908f79", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
GameTitle
02smpTwo-stage matching pennies game
1pdTwo person Prisoner's Dilemma game
\n", - "
" - ], - "text/plain": [ - " Game Title\n", - "0 2smp Two-stage matching pennies game\n", - "1 pd Two person Prisoner's Dilemma game" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.catalog.games()" ] @@ -499,25 +334,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "9ee2c3bd-22d1-4c8e-996c-cd9e0dfd64cc", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Two person Prisoner's Dilemma game

\n", - "
12
19,90,10
210,01,1
12
19,90,10
210,01,1
12
19,90,10
210,01,1
12
19,90,10
210,01,1
\n" - ], - "text/plain": [ - "Game(title='Two person Prisoner's Dilemma game')" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "g = gbt.catalog.load(\"pd\")\n", "g" @@ -539,7 +359,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "f58eaa77", "metadata": {}, "outputs": [], @@ -557,7 +377,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "4119a2ac", "metadata": {}, "outputs": [], diff --git a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb index c7e16ba80..f32c6e1a5 100644 --- a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb +++ b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb @@ -28,243 +28,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "5142d6ba-da13-4500-bca6-e68b608bfae9", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from draw_tree import draw_tree\n", "\n", @@ -284,19 +51,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "7882d327-ce04-43d3-bb5a-36cff6da6e96", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of pure equilibria: 1\n", - "Max regret: 0\n" - ] - } - ], + "outputs": [], "source": [ "pure_Nash_equilibria = gbt.nash.enumpure_solve(g).equilibria\n", "print(\"Number of pure equilibria:\", len(pure_Nash_equilibria))\n", @@ -314,20 +72,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "6e3e9303-453a-4bac-a449-fa8fda2ba5ec", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Player 1 infoset: 0 behavior probabilities: [Rational(1, 1), Rational(0, 1)]\n", - "Player 1 infoset: 1 behavior probabilities: [Rational(0, 1), Rational(1, 1)]\n", - "Player 2 infoset: 0 behavior probabilities: [Rational(0, 1), Rational(1, 1)]\n" - ] - } - ], + "outputs": [], "source": [ "eq = pure_Nash_equilibria[0]\n", "for infoset, probs in eq.as_behavior().mixed_actions():\n", @@ -344,18 +92,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "804345b9-d32b-4f60-b4a0-f9d69dca10a8", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Liap value: 0\n" - ] - } - ], + "outputs": [], "source": [ "print(\"Liap value:\", pure_eq.liap_value())" ] @@ -380,19 +120,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "9d18768b-db9b-41ef-aee7-5fe5f524a59e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Max regret of starting profile: 3\n", - "Liapunov value of starting profile: 14\n" - ] - } - ], + "outputs": [], "source": [ "starting_profile_double = g.mixed_strategy_profile(data=[[0,1,0],[1,0]], rational=False)\n", "starting_profile_rational = g.mixed_strategy_profile(data=[[0,1,0],[1,0]], rational=True)\n", @@ -418,18 +149,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "b885271f-7279-4d87-a0b9-bc28449b00ba", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[6.949101896011271e-07, 0.49999858461819596, 0.5000007204716144], [0.33333333942537524, 0.6666666605746248]]\n" - ] - } - ], + "outputs": [], "source": [ "candidate_eq = gbt.nash.liap_solve(start=starting_profile_double).equilibria[0]\n", "print(candidate_eq)" @@ -437,19 +160,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "f8a90a9c-393e-4812-9418-76e705880f6f", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Liap value: 1.0863970174089946e-13\n", - "Max regret: 2.407747583532682e-07\n" - ] - } - ], + "outputs": [], "source": [ "print(\"Liap value:\", candidate_eq.liap_value())\n", "print(\"Max regret:\", candidate_eq.max_regret())" @@ -457,19 +171,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "567e6a6a-fc8d-4142-806c-6510b2a4c624", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Liap value: 0\n", - "Max regret: 0\n" - ] - } - ], + "outputs": [], "source": [ "candidate_eq_rat = g.mixed_strategy_profile(data=[[0,\"1/2\",\"1/2\"],[\"1/3\",\"2/3\"]], rational=True)\n", "print(\"Liap value:\", candidate_eq_rat.liap_value())\n", @@ -486,20 +191,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "87a62c9e-b109-4f88-ac25-d0e0db3f27ea", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[Rational(0, 1), Rational(1, 1), Rational(0, 1)], [Rational(0, 1), Rational(1, 1)]]\n", - "[[Rational(1, 4), Rational(0, 1), Rational(3, 4)], [Rational(1, 2), Rational(1, 2)]]\n", - "[[Rational(0, 1), Rational(1, 2), Rational(1, 2)], [Rational(1, 3), Rational(2, 3)]]\n" - ] - } - ], + "outputs": [], "source": [ "all_extreme_Nash_equilibria = gbt.nash.enummixed_solve(g).equilibria\n", "for eq in all_extreme_Nash_equilibria:\n", @@ -516,20 +211,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "2c8ed3df-958e-4ee9-aed6-a106547fbd37", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[Rational(0, 1), Rational(1, 2), Rational(1, 2)], [Rational(1, 3), Rational(2, 3)]]\n", - "Liap value: 0\n", - "Max regret: 0\n" - ] - } - ], + "outputs": [], "source": [ "print(all_extreme_Nash_equilibria[2])\n", "print(\"Liap value:\", all_extreme_Nash_equilibria[2].liap_value())\n", @@ -563,20 +248,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "f46ce825-d2b7-492f-b0cf-6f213607e121", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n", - "[[[Rational(1, 1), Rational(0, 1)], [Rational(0, 1), Rational(1, 1)]], [[Rational(0, 1), Rational(1, 1)]]]\n", - "[[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]], [[Rational(1, 1), Rational(0, 1)]]]\n" - ] - } - ], + "outputs": [], "source": [ "pure_agent_equilibria = gbt.nash.enumpure_agent_solve(g).equilibria\n", "print(len(pure_agent_equilibria))\n", @@ -594,21 +269,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "dbfa7035", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "pure_Nash_equilibria[0] == pure_agent_equilibria[0].as_strategy()" ] @@ -623,21 +287,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "85760cec-5760-4f9d-8ca2-99fba79c7c3c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Max regret: 1\n", - "Liapunov value: 1\n", - "Agent max regret 0\n", - "Agent Liapunov value: 0\n" - ] - } - ], + "outputs": [], "source": [ "aeq = pure_agent_equilibria[1]\n", "print(\"Max regret:\", aeq.max_regret())\n", From 57863d4248926e1fbe6dce1a131f044afbb36b3f Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 17:01:04 +0000 Subject: [PATCH 49/84] fix problem with print function --- src/games/writer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/games/writer.cc b/src/games/writer.cc index 744f3efad..47baedc1e 100644 --- a/src/games/writer.cc +++ b/src/games/writer.cc @@ -91,6 +91,7 @@ std::string WriteHTMLFile(const Game &p_game, const GamePlayer &p_rowPlayer, } theHtml += ""; + break; } theHtml += "\n"; return theHtml; From b687e204db43e66b5999e116ffc15adbabeb6ddc Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 4 Feb 2026 17:01:56 +0000 Subject: [PATCH 50/84] resave notebook outputs --- doc/tutorials/01_quickstart.ipynb | 246 +++++++++-- .../agent_versus_non_agent_regret.ipynb | 399 ++++++++++++++++-- .../advanced_tutorials/starting_points.ipynb | 10 +- 3 files changed, 597 insertions(+), 58 deletions(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 62949a4b4..7e4de7599 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -38,7 +38,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "c58d382d", "metadata": {}, "outputs": [], @@ -50,10 +50,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "2060c1ed", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "pygambit.gambit.Game" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "n_strategies = [2, 2]\n", "g = gbt.Game.new_table(n_strategies, title=\"Prisoner's Dilemma\")\n", @@ -72,7 +83,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "9d8203e8", "metadata": {}, "outputs": [], @@ -100,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "61030607", "metadata": {}, "outputs": [], @@ -124,10 +135,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "caecc334", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "

Prisoner's Dilemma

\n", + "
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
\n" + ], + "text/plain": [ + "Game(title='Prisoner's Dilemma')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# View the payout matrix\n", "g" @@ -163,10 +189,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "843ba7f3", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "

Another Prisoner's Dilemma

\n", + "
12
1-1,-1-3,0
20,-3-2,-2
\n" + ], + "text/plain": [ + "Game(title='Another Prisoner's Dilemma')" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "player1_payoffs = np.array([[-1, -3], [0, -2]])\n", "player2_payoffs = np.transpose(player1_payoffs)\n", @@ -192,10 +233,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "5ee752c4", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-1\n", + "\n" + ] + } + ], "source": [ "tom_payoffs, jerry_payoffs = g.to_arrays(\n", " # dtype=float\n", @@ -220,10 +270,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "a81c06c7", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "pygambit.nash.NashComputationResult" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "result = gbt.nash.enumpure_solve(g)\n", "type(result)" @@ -239,10 +300,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "bd395180", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "len(result.equilibria)" ] @@ -257,10 +329,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "76570ebc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/latex": [ + "$\\left[\\left[0,1\\right],\\left[0,1\\right]\\right]$" + ], + "text/plain": [ + "[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "msp = result.equilibria[0]\n", "msp" @@ -268,10 +354,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "6e8cfcde", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "pygambit.gambit.MixedStrategyProfileRational" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "type(msp)" ] @@ -288,10 +385,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "980bf6b1", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tom plays the equilibrium strategy:\n", + "Probability of cooperating: 0\n", + "Probability of defecting: 1\n", + "Payoff: -2\n", + "\n", + "Jerry plays the equilibrium strategy:\n", + "Probability of cooperating: 0\n", + "Probability of defecting: 1\n", + "Payoff: -2\n", + "\n" + ] + } + ], "source": [ "for player in g.players:\n", " print(f\"{player.label} plays the equilibrium strategy:\")\n", @@ -316,10 +430,73 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "e1b060fb-94cc-432d-a9cc-4ccae5908f79", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GameTitle
02smpTwo-stage matching pennies game
12x2x22x2x2 Example from McKelvey-McLennan, with 9 N...
2myerson_fig_4_2Myerson (1991) Fig 4.2
3pdTwo person Prisoner's Dilemma game
\n", + "
" + ], + "text/plain": [ + " Game Title\n", + "0 2smp Two-stage matching pennies game\n", + "1 2x2x2 2x2x2 Example from McKelvey-McLennan, with 9 N...\n", + "2 myerson_fig_4_2 Myerson (1991) Fig 4.2\n", + "3 pd Two person Prisoner's Dilemma game" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "gbt.catalog.games()" ] @@ -334,10 +511,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "9ee2c3bd-22d1-4c8e-996c-cd9e0dfd64cc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "

Two person Prisoner's Dilemma game

\n", + "
12
19,90,10
210,01,1
\n" + ], + "text/plain": [ + "Game(title='Two person Prisoner's Dilemma game')" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "g = gbt.catalog.load(\"pd\")\n", "g" @@ -359,7 +551,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "f58eaa77", "metadata": {}, "outputs": [], @@ -377,7 +569,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "4119a2ac", "metadata": {}, "outputs": [], diff --git a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb index f32c6e1a5..c7e16ba80 100644 --- a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb +++ b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb @@ -28,10 +28,243 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "5142d6ba-da13-4500-bca6-e68b608bfae9", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from draw_tree import draw_tree\n", "\n", @@ -51,10 +284,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "7882d327-ce04-43d3-bb5a-36cff6da6e96", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of pure equilibria: 1\n", + "Max regret: 0\n" + ] + } + ], "source": [ "pure_Nash_equilibria = gbt.nash.enumpure_solve(g).equilibria\n", "print(\"Number of pure equilibria:\", len(pure_Nash_equilibria))\n", @@ -72,10 +314,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "6e3e9303-453a-4bac-a449-fa8fda2ba5ec", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Player 1 infoset: 0 behavior probabilities: [Rational(1, 1), Rational(0, 1)]\n", + "Player 1 infoset: 1 behavior probabilities: [Rational(0, 1), Rational(1, 1)]\n", + "Player 2 infoset: 0 behavior probabilities: [Rational(0, 1), Rational(1, 1)]\n" + ] + } + ], "source": [ "eq = pure_Nash_equilibria[0]\n", "for infoset, probs in eq.as_behavior().mixed_actions():\n", @@ -92,10 +344,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "804345b9-d32b-4f60-b4a0-f9d69dca10a8", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Liap value: 0\n" + ] + } + ], "source": [ "print(\"Liap value:\", pure_eq.liap_value())" ] @@ -120,10 +380,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "9d18768b-db9b-41ef-aee7-5fe5f524a59e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Max regret of starting profile: 3\n", + "Liapunov value of starting profile: 14\n" + ] + } + ], "source": [ "starting_profile_double = g.mixed_strategy_profile(data=[[0,1,0],[1,0]], rational=False)\n", "starting_profile_rational = g.mixed_strategy_profile(data=[[0,1,0],[1,0]], rational=True)\n", @@ -149,10 +418,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "b885271f-7279-4d87-a0b9-bc28449b00ba", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[6.949101896011271e-07, 0.49999858461819596, 0.5000007204716144], [0.33333333942537524, 0.6666666605746248]]\n" + ] + } + ], "source": [ "candidate_eq = gbt.nash.liap_solve(start=starting_profile_double).equilibria[0]\n", "print(candidate_eq)" @@ -160,10 +437,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "f8a90a9c-393e-4812-9418-76e705880f6f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Liap value: 1.0863970174089946e-13\n", + "Max regret: 2.407747583532682e-07\n" + ] + } + ], "source": [ "print(\"Liap value:\", candidate_eq.liap_value())\n", "print(\"Max regret:\", candidate_eq.max_regret())" @@ -171,10 +457,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "567e6a6a-fc8d-4142-806c-6510b2a4c624", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Liap value: 0\n", + "Max regret: 0\n" + ] + } + ], "source": [ "candidate_eq_rat = g.mixed_strategy_profile(data=[[0,\"1/2\",\"1/2\"],[\"1/3\",\"2/3\"]], rational=True)\n", "print(\"Liap value:\", candidate_eq_rat.liap_value())\n", @@ -191,10 +486,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "87a62c9e-b109-4f88-ac25-d0e0db3f27ea", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[Rational(0, 1), Rational(1, 1), Rational(0, 1)], [Rational(0, 1), Rational(1, 1)]]\n", + "[[Rational(1, 4), Rational(0, 1), Rational(3, 4)], [Rational(1, 2), Rational(1, 2)]]\n", + "[[Rational(0, 1), Rational(1, 2), Rational(1, 2)], [Rational(1, 3), Rational(2, 3)]]\n" + ] + } + ], "source": [ "all_extreme_Nash_equilibria = gbt.nash.enummixed_solve(g).equilibria\n", "for eq in all_extreme_Nash_equilibria:\n", @@ -211,10 +516,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "2c8ed3df-958e-4ee9-aed6-a106547fbd37", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[Rational(0, 1), Rational(1, 2), Rational(1, 2)], [Rational(1, 3), Rational(2, 3)]]\n", + "Liap value: 0\n", + "Max regret: 0\n" + ] + } + ], "source": [ "print(all_extreme_Nash_equilibria[2])\n", "print(\"Liap value:\", all_extreme_Nash_equilibria[2].liap_value())\n", @@ -248,10 +563,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "f46ce825-d2b7-492f-b0cf-6f213607e121", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "[[[Rational(1, 1), Rational(0, 1)], [Rational(0, 1), Rational(1, 1)]], [[Rational(0, 1), Rational(1, 1)]]]\n", + "[[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]], [[Rational(1, 1), Rational(0, 1)]]]\n" + ] + } + ], "source": [ "pure_agent_equilibria = gbt.nash.enumpure_agent_solve(g).equilibria\n", "print(len(pure_agent_equilibria))\n", @@ -269,10 +594,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "dbfa7035", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "pure_Nash_equilibria[0] == pure_agent_equilibria[0].as_strategy()" ] @@ -287,10 +623,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "85760cec-5760-4f9d-8ca2-99fba79c7c3c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Max regret: 1\n", + "Liapunov value: 1\n", + "Agent max regret 0\n", + "Agent Liapunov value: 0\n" + ] + } + ], "source": [ "aeq = pure_agent_equilibria[1]\n", "print(\"Max regret:\", aeq.max_regret())\n", diff --git a/doc/tutorials/advanced_tutorials/starting_points.ipynb b/doc/tutorials/advanced_tutorials/starting_points.ipynb index 4fa281746..9e8f72d5e 100644 --- a/doc/tutorials/advanced_tutorials/starting_points.ipynb +++ b/doc/tutorials/advanced_tutorials/starting_points.ipynb @@ -33,7 +33,7 @@ "data": { "text/html": [ "

2x2x2 Example from McKelvey-McLennan, with 9 Nash equilibria, 2 totally mixed

\n", - "
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
Subtable with strategies:
Player 3 Strategy 2
12
10,0,03,4,6
23,4,60,0,0
\n" + "
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
\n" ], "text/plain": [ "Game(title='2x2x2 Example from McKelvey-McLennan, with 9 Nash equilibria, 2 totally mixed')" @@ -188,10 +188,10 @@ { "data": { "text/latex": [ - "$\\left[[0.9835790201705958, 0.01642097982940421],[0.7494285573591715, 0.2505714426408285],[0.14967367720546837, 0.8503263227945317]\\right]$" + "$\\left[[0.5172260574334439, 0.48277394256655615],[0.5372523987305369, 0.462747601269463],[0.8261013405886477, 0.17389865941135238]\\right]$" ], "text/plain": [ - "[[0.9835790201705958, 0.01642097982940421], [0.7494285573591715, 0.2505714426408285], [0.14967367720546837, 0.8503263227945317]]" + "[[0.5172260574334439, 0.48277394256655615], [0.5372523987305369, 0.462747601269463], [0.8261013405886477, 0.17389865941135238]]" ] }, "execution_count": 6, @@ -213,10 +213,10 @@ { "data": { "text/latex": [ - "$\\left[[0.5000000583093926, 0.49999994169060735],[0.39999989404863995, 0.6000001059513601],[0.2499996298123818, 0.7500003701876182]\\right]$" + "$\\left[[0.49999999983005444, 0.5000000001699455],[0.4999999947343101, 0.5000000052656899],[0.9999989483984311, 1.0516015689453635e-06]\\right]$" ], "text/plain": [ - "[[0.5000000583093926, 0.49999994169060735], [0.39999989404863995, 0.6000001059513601], [0.2499996298123818, 0.7500003701876182]]" + "[[0.49999999983005444, 0.5000000001699455], [0.4999999947343101, 0.5000000052656899], [0.9999989483984311, 1.0516015689453635e-06]]" ] }, "execution_count": 7, From 6562433b4223d7915a81b6ff4b3d69abce913ccb Mon Sep 17 00:00:00 2001 From: Ted Turocy Date: Tue, 10 Feb 2026 12:30:59 +0000 Subject: [PATCH 51/84] Update writer.cc --- src/games/writer.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/games/writer.cc b/src/games/writer.cc index 47baedc1e..744f3efad 100644 --- a/src/games/writer.cc +++ b/src/games/writer.cc @@ -91,7 +91,6 @@ std::string WriteHTMLFile(const Game &p_game, const GamePlayer &p_rowPlayer, } theHtml += ""; - break; } theHtml += "\n"; return theHtml; From f84bcc8c885116ea5cbaa0abc637714aea36e60a Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:11:12 +0000 Subject: [PATCH 52/84] move catalog update script into build support --- {src/pygambit => build_support/catalog}/update_catalog.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src/pygambit => build_support/catalog}/update_catalog.py (100%) diff --git a/src/pygambit/update_catalog.py b/build_support/catalog/update_catalog.py similarity index 100% rename from src/pygambit/update_catalog.py rename to build_support/catalog/update_catalog.py From d17f976382c18ed6efe73299760636f97900f3ce Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:11:46 +0000 Subject: [PATCH 53/84] rename script --- build_support/catalog/{update_catalog.py => update.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build_support/catalog/{update_catalog.py => update.py} (100%) diff --git a/build_support/catalog/update_catalog.py b/build_support/catalog/update.py similarity index 100% rename from build_support/catalog/update_catalog.py rename to build_support/catalog/update.py From f07fdaee550295d17314145b90ec962e70217bfc Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:14:32 +0000 Subject: [PATCH 54/84] rename var --- build_support/catalog/update.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build_support/catalog/update.py b/build_support/catalog/update.py index c6787f170..c5305d092 100644 --- a/build_support/catalog/update.py +++ b/build_support/catalog/update.py @@ -4,14 +4,14 @@ import pygambit as gbt CATALOG_CSV = Path(__file__).parent.parent.parent / "doc" / "catalog.csv" +CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog" MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am" def update_makefile(): """Update the Makefile.am with all games from the catalog.""" - catalog_dir = Path(__file__).parent.parent.parent / "catalog" - efg_files = list(catalog_dir.rglob("*.efg")) - nfg_files = list(catalog_dir.rglob("*.nfg")) + efg_files = list(CATALOG_DIR.rglob("*.efg")) + nfg_files = list(CATALOG_DIR.rglob("*.nfg")) game_files = [] for entry in efg_files + nfg_files: From fd66e41de287dcfdaf4951757c482f773c4346b4 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:17:54 +0000 Subject: [PATCH 55/84] update path to catalog update script in readthedocs yml and docs page --- .readthedocs.yml | 2 +- doc/developer.catalog.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 1bbd415f8..9cc997431 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -16,7 +16,7 @@ build: jobs: # Create CSV for catalog table in docs post_install: - - $READTHEDOCS_VIRTUALENV_PATH/bin/python src/pygambit/update_catalog.py + - $READTHEDOCS_VIRTUALENV_PATH/bin/python build_support/catalog/update.py python: install: diff --git a/doc/developer.catalog.rst b/doc/developer.catalog.rst index 40680c8e9..ded101f3c 100644 --- a/doc/developer.catalog.rst +++ b/doc/developer.catalog.rst @@ -24,11 +24,11 @@ Add new games 3. **Update the catalog:** - Use the ``update_catalog.py`` script to update Gambit's documentation & build files. + Use the ``update.py`` script to update Gambit's documentation & build files. .. code-block:: bash - python src/pygambit/update_catalog.py --build + python build_support/catalog/update.py --build .. note:: From bb1e9206748f985dc28385372e73c96e6f11143f Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:22:11 +0000 Subject: [PATCH 56/84] move myserson fig into subfolder --- catalog/{myerson_fig_4_2.efg => myerson/fig_4_2.efg} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename catalog/{myerson_fig_4_2.efg => myerson/fig_4_2.efg} (100%) diff --git a/catalog/myerson_fig_4_2.efg b/catalog/myerson/fig_4_2.efg similarity index 100% rename from catalog/myerson_fig_4_2.efg rename to catalog/myerson/fig_4_2.efg From 5c7a60f75046a3d5c6c9b31277fc3df6d0b1cf16 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:29:12 +0000 Subject: [PATCH 57/84] clarify script usage --- doc/developer.catalog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/developer.catalog.rst b/doc/developer.catalog.rst index ded101f3c..b60a56705 100644 --- a/doc/developer.catalog.rst +++ b/doc/developer.catalog.rst @@ -36,7 +36,7 @@ Add new games .. warning:: - This script updates `Makefile.am` with the game file added to the catalog, but if you moved games that were previously in `contrib/games` you'll want to manually remove those files from `EXTRA_DIST`. + Running the script with the ``--build`` flag updates `Makefile.am`. If you moved games that were previously in `contrib/games` you'll need to also manually remove those files from `EXTRA_DIST`. 4. **Submit a pull request to GitHub with all changes.** From dc7a37380e06468029f78e9f5dd90de287fa103b Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:29:23 +0000 Subject: [PATCH 58/84] add test_catalog_load_subdir_slug --- tests/test_catalog.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index f281cc353..1be67c2f1 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -24,6 +24,12 @@ def test_catalog_load_invalid_slug(): gbt.catalog.load("invalid_slug") +def test_catalog_load_subdir_slug(): + """Test loading a game from catalog/somedir""" + g = gbt.catalog.load("myerson/fig_4_2") + assert isinstance(g, gbt.Game) + + def test_catalog_games(): """Test games() function returns df of game slugs and titles""" all_games = gbt.catalog.games() From 78505851e30ecf313e5798bdbd59e16561992d0c Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:32:32 +0000 Subject: [PATCH 59/84] update makefile --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index ca6e0dfd8..14d5552bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -239,7 +239,7 @@ EXTRA_DIST = \ src/README.rst \ catalog/2smp.efg \ catalog/2x2x2.nfg \ - catalog/myerson_fig_4_2.efg \ + catalog/fig_4_2.efg \ catalog/pd.nfg core_SOURCES = \ From f6ea5dfda1314a0f3491bbddcc68db36a9611b93 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:34:29 +0000 Subject: [PATCH 60/84] update agent nb --- .../agent_versus_non_agent_regret.ipynb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb index c7e16ba80..3c3ac80b1 100644 --- a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb +++ b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb @@ -270,7 +270,7 @@ "\n", "import pygambit as gbt\n", "\n", - "g = gbt.catalog.load(\"myerson_fig_4_2\")\n", + "g = gbt.catalog.load(\"myerson/fig_4_2\")\n", "draw_tree(g)" ] }, @@ -426,7 +426,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[6.949101896011271e-07, 0.49999858461819596, 0.5000007204716144], [0.33333333942537524, 0.6666666605746248]]\n" + "[[4.2517925671604327e-07, 0.49999911111761514, 0.5000004637031282], [0.3333333517938241, 0.6666666482061759]]\n" ] } ], @@ -445,8 +445,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Liap value: 1.0863970174089946e-13\n", - "Max regret: 2.407747583532682e-07\n" + "Liap value: 4.43446520109796e-14\n", + "Max regret: 1.694170896904268e-07\n" ] } ], From f655645edd245882c36a00f04104e38b96327c1b Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:39:08 +0000 Subject: [PATCH 61/84] add test for slug in subdir of catalog --- tests/test_catalog.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 1be67c2f1..84d741022 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -33,7 +33,10 @@ def test_catalog_load_subdir_slug(): def test_catalog_games(): """Test games() function returns df of game slugs and titles""" all_games = gbt.catalog.games() + slugs = list(all_games.Game) assert isinstance(all_games, pd.DataFrame) assert len(all_games) > 0 - assert "2smp" in list(all_games.Game) + assert "2smp" in slugs assert "Two-stage matching pennies game" in list(all_games.Title) + # Check slug of game in subdir + assert "myerson/fig_4_2" in slugs From 56cd19a0b6733033c8622a6cf9313f9b96474a2c Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:50:45 +0000 Subject: [PATCH 62/84] update games func to list slugs correctly --- catalog/__init__.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index 4164041f5..f6bfd5eb0 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -30,20 +30,25 @@ def load(slug: str) -> gbt.Game: def games() -> pd.DataFrame: """ - List games available in the package catalog. + List games available in the package catalog, including subdirectories. """ records: list[dict[str, str]] = [] - # iterdir() works directly on the Traversable object - for resource_path in sorted(_CATALOG_RESOURCE.iterdir()): + # Using rglob("*") to find files in all subdirectories + for resource_path in sorted(_CATALOG_RESOURCE.rglob("*")): reader = READERS.get(resource_path.suffix) if reader is not None and resource_path.is_file(): + # Calculate the path relative to the root resource + # and remove the suffix to get the "slug" + rel_path = resource_path.relative_to(_CATALOG_RESOURCE) + game_slug = str(rel_path.with_suffix("")) + with as_file(resource_path) as path: game = reader(str(path)) records.append( { - "Game": resource_path.stem, + "Game": game_slug, "Title": game.title, } ) From 6a4df8f6e5dc4da26d14d1c4cc554e271707aaec Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 15:55:11 +0000 Subject: [PATCH 63/84] update test to avoid duplicates --- tests/test_catalog.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 84d741022..317e37477 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -40,3 +40,4 @@ def test_catalog_games(): assert "Two-stage matching pennies game" in list(all_games.Title) # Check slug of game in subdir assert "myerson/fig_4_2" in slugs + assert "myerson_fig_4_2" not in slugs From 886131ca36bdc975484540be5a31572e413fa350 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 16:25:32 +0000 Subject: [PATCH 64/84] fix code for handling slugs that duplicates of those in subfolders --- catalog/__init__.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index f6bfd5eb0..1ec77e0a4 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -43,14 +43,19 @@ def games() -> pd.DataFrame: # and remove the suffix to get the "slug" rel_path = resource_path.relative_to(_CATALOG_RESOURCE) game_slug = str(rel_path.with_suffix("")) - - with as_file(resource_path) as path: - game = reader(str(path)) - records.append( - { - "Game": game_slug, - "Title": game.title, - } - ) + bad_slug = False + dir_names = [p.name for p in _CATALOG_RESOURCE.iterdir() if p.is_dir()] + for d in dir_names: + if d in game_slug and d != game_slug and "/" not in game_slug: + bad_slug = True + if not bad_slug: + with as_file(resource_path) as path: + game = reader(str(path)) + records.append( + { + "Game": game_slug, + "Title": game.title, + } + ) return pd.DataFrame.from_records(records, columns=["Game", "Title"]) From 68909b95350aa67ae32b25bf4c94f9a0a5742dfd Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 16:31:02 +0000 Subject: [PATCH 65/84] tidy the games() refactor --- catalog/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index 1ec77e0a4..bba0d8333 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -6,6 +6,7 @@ # Use the full string path to the virtual package we created _CATALOG_RESOURCE = files(__name__) +_CATALOG_SUBDIRS = [p.name for p in _CATALOG_RESOURCE.iterdir() if p.is_dir()] READERS = { ".nfg": gbt.read_nfg, @@ -39,15 +40,19 @@ def games() -> pd.DataFrame: reader = READERS.get(resource_path.suffix) if reader is not None and resource_path.is_file(): + # Calculate the path relative to the root resource # and remove the suffix to get the "slug" rel_path = resource_path.relative_to(_CATALOG_RESOURCE) game_slug = str(rel_path.with_suffix("")) + + # This code prevents duplicate slugs e.g. subdir/game1 and subdir_game1 bad_slug = False - dir_names = [p.name for p in _CATALOG_RESOURCE.iterdir() if p.is_dir()] - for d in dir_names: + for d in _CATALOG_SUBDIRS: if d in game_slug and d != game_slug and "/" not in game_slug: bad_slug = True + + # Update the dataframe if not bad_slug: with as_file(resource_path) as path: game = reader(str(path)) From bb8f483be5fd66a419d3d72cbf9285ab635be427 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 16:31:41 +0000 Subject: [PATCH 66/84] resave notebook --- doc/tutorials/01_quickstart.ipynb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 7e4de7599..7bf6e949d 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -472,7 +472,7 @@ " \n", " \n", " 2\n", - " myerson_fig_4_2\n", + " myerson/fig_4_2\n", " Myerson (1991) Fig 4.2\n", " \n", " \n", @@ -480,6 +480,11 @@ " pd\n", " Two person Prisoner's Dilemma game\n", " \n", + " \n", + " 4\n", + " pd2\n", + " Two person Prisoner's Dilemma game\n", + " \n", " \n", "\n", "" @@ -488,8 +493,9 @@ " Game Title\n", "0 2smp Two-stage matching pennies game\n", "1 2x2x2 2x2x2 Example from McKelvey-McLennan, with 9 N...\n", - "2 myerson_fig_4_2 Myerson (1991) Fig 4.2\n", - "3 pd Two person Prisoner's Dilemma game" + "2 myerson/fig_4_2 Myerson (1991) Fig 4.2\n", + "3 pd Two person Prisoner's Dilemma game\n", + "4 pd2 Two person Prisoner's Dilemma game" ] }, "execution_count": 13, From 50e618b9c9d486c5230e3615737d00d19e0afc78 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 16:51:45 +0000 Subject: [PATCH 67/84] strip nb outputs --- doc/tutorials/01_quickstart.ipynb | 252 ++++-------------------------- 1 file changed, 27 insertions(+), 225 deletions(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 7bf6e949d..62949a4b4 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -38,7 +38,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "c58d382d", "metadata": {}, "outputs": [], @@ -50,21 +50,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "2060c1ed", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.Game" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "n_strategies = [2, 2]\n", "g = gbt.Game.new_table(n_strategies, title=\"Prisoner's Dilemma\")\n", @@ -83,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "9d8203e8", "metadata": {}, "outputs": [], @@ -111,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "61030607", "metadata": {}, "outputs": [], @@ -135,25 +124,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "caecc334", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Prisoner's Dilemma

\n", - "
CooperateDefect
Cooperate-1,-1-3,0
Defect0,-3-2,-2
\n" - ], - "text/plain": [ - "Game(title='Prisoner's Dilemma')" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# View the payout matrix\n", "g" @@ -189,25 +163,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "843ba7f3", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Another Prisoner's Dilemma

\n", - "
12
1-1,-1-3,0
20,-3-2,-2
\n" - ], - "text/plain": [ - "Game(title='Another Prisoner's Dilemma')" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "player1_payoffs = np.array([[-1, -3], [0, -2]])\n", "player2_payoffs = np.transpose(player1_payoffs)\n", @@ -233,19 +192,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "5ee752c4", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-1\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "tom_payoffs, jerry_payoffs = g.to_arrays(\n", " # dtype=float\n", @@ -270,21 +220,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "a81c06c7", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.nash.NashComputationResult" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "result = gbt.nash.enumpure_solve(g)\n", "type(result)" @@ -300,21 +239,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "bd395180", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "len(result.equilibria)" ] @@ -329,24 +257,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "76570ebc", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[0,1\\right],\\left[0,1\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "msp = result.equilibria[0]\n", "msp" @@ -354,21 +268,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "6e8cfcde", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.MixedStrategyProfileRational" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "type(msp)" ] @@ -385,27 +288,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "980bf6b1", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tom plays the equilibrium strategy:\n", - "Probability of cooperating: 0\n", - "Probability of defecting: 1\n", - "Payoff: -2\n", - "\n", - "Jerry plays the equilibrium strategy:\n", - "Probability of cooperating: 0\n", - "Probability of defecting: 1\n", - "Payoff: -2\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "for player in g.players:\n", " print(f\"{player.label} plays the equilibrium strategy:\")\n", @@ -430,79 +316,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "e1b060fb-94cc-432d-a9cc-4ccae5908f79", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
GameTitle
02smpTwo-stage matching pennies game
12x2x22x2x2 Example from McKelvey-McLennan, with 9 N...
2myerson/fig_4_2Myerson (1991) Fig 4.2
3pdTwo person Prisoner's Dilemma game
4pd2Two person Prisoner's Dilemma game
\n", - "
" - ], - "text/plain": [ - " Game Title\n", - "0 2smp Two-stage matching pennies game\n", - "1 2x2x2 2x2x2 Example from McKelvey-McLennan, with 9 N...\n", - "2 myerson/fig_4_2 Myerson (1991) Fig 4.2\n", - "3 pd Two person Prisoner's Dilemma game\n", - "4 pd2 Two person Prisoner's Dilemma game" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.catalog.games()" ] @@ -517,25 +334,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "9ee2c3bd-22d1-4c8e-996c-cd9e0dfd64cc", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Two person Prisoner's Dilemma game

\n", - "
12
19,90,10
210,01,1
\n" - ], - "text/plain": [ - "Game(title='Two person Prisoner's Dilemma game')" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "g = gbt.catalog.load(\"pd\")\n", "g" @@ -557,7 +359,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "f58eaa77", "metadata": {}, "outputs": [], @@ -575,7 +377,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "4119a2ac", "metadata": {}, "outputs": [], From 67dedb274e75b859136e000d193af2799df6d4cb Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 16:52:39 +0000 Subject: [PATCH 68/84] remove modification to games() that was fixing a local issue --- catalog/__init__.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index bba0d8333..b740a5504 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -46,21 +46,13 @@ def games() -> pd.DataFrame: rel_path = resource_path.relative_to(_CATALOG_RESOURCE) game_slug = str(rel_path.with_suffix("")) - # This code prevents duplicate slugs e.g. subdir/game1 and subdir_game1 - bad_slug = False - for d in _CATALOG_SUBDIRS: - if d in game_slug and d != game_slug and "/" not in game_slug: - bad_slug = True - - # Update the dataframe - if not bad_slug: - with as_file(resource_path) as path: - game = reader(str(path)) - records.append( - { - "Game": game_slug, - "Title": game.title, - } - ) + with as_file(resource_path) as path: + game = reader(str(path)) + records.append( + { + "Game": game_slug, + "Title": game.title, + } + ) return pd.DataFrame.from_records(records, columns=["Game", "Title"]) From 1794a83b924e1906ede4c24f7934f5ef74424fab Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 17:08:05 +0000 Subject: [PATCH 69/84] fix the update script to get correct paths --- Makefile.am | 2 +- build_support/catalog/update.py | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 14d5552bf..4b31fe0a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -239,7 +239,7 @@ EXTRA_DIST = \ src/README.rst \ catalog/2smp.efg \ catalog/2x2x2.nfg \ - catalog/fig_4_2.efg \ + catalog/myerson/fig_4_2.efg \ catalog/pd.nfg core_SOURCES = \ diff --git a/build_support/catalog/update.py b/build_support/catalog/update.py index c5305d092..e42a18ad9 100644 --- a/build_support/catalog/update.py +++ b/build_support/catalog/update.py @@ -10,13 +10,21 @@ def update_makefile(): """Update the Makefile.am with all games from the catalog.""" - efg_files = list(CATALOG_DIR.rglob("*.efg")) - nfg_files = list(CATALOG_DIR.rglob("*.nfg")) + + # Using rglob("*") to find files in all subdirectories + slugs = [] + for resource_path in sorted(CATALOG_DIR.rglob("*.efg")): + if resource_path.is_file(): + rel_path = resource_path.relative_to(CATALOG_DIR) + slugs.append(str(rel_path)) + for resource_path in sorted(CATALOG_DIR.rglob("*.nfg")): + if resource_path.is_file(): + rel_path = resource_path.relative_to(CATALOG_DIR) + slugs.append(str(rel_path)) game_files = [] - for entry in efg_files + nfg_files: - filename = str(entry).split("/")[-1] - game_files.append(f"catalog/{filename}") + for slug in slugs: + game_files.append(f"catalog/{slug}") game_files.sort() with open(MAKEFILE_AM, encoding="utf-8") as f: From 079aacd2fd84dfaaea82467bf2f51a494a5c32ba Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 17:08:45 +0000 Subject: [PATCH 70/84] remove unused var --- catalog/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index b740a5504..1d2ac8535 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -6,7 +6,6 @@ # Use the full string path to the virtual package we created _CATALOG_RESOURCE = files(__name__) -_CATALOG_SUBDIRS = [p.name for p in _CATALOG_RESOURCE.iterdir() if p.is_dir()] READERS = { ".nfg": gbt.read_nfg, From e57cfce21452e8aea6aa3d6c51bd5155b8cdc036 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 10 Feb 2026 17:18:49 +0000 Subject: [PATCH 71/84] Add Windows handling --- catalog/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catalog/__init__.py b/catalog/__init__.py index 1d2ac8535..d44200551 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -1,3 +1,4 @@ +import sys from importlib.resources import as_file, files import pandas as pd @@ -17,6 +18,10 @@ def load(slug: str) -> gbt.Game: """ Load a game from the package catalog. """ + # Handle backslashes for Windows + if sys.platform == "win32": + game_slug.replace("/", "\\") # noqa: F821 + for suffix, reader in READERS.items(): resource_path = _CATALOG_RESOURCE / f"{slug}{suffix}" @@ -45,6 +50,10 @@ def games() -> pd.DataFrame: rel_path = resource_path.relative_to(_CATALOG_RESOURCE) game_slug = str(rel_path.with_suffix("")) + # Replace backslashes for Windows + if sys.platform == "win32": + game_slug.replace("\\", "/") # noqa: F821 + with as_file(resource_path) as path: game = reader(str(path)) records.append( From bdc5d3a9366a0832f4fe9283f1b8a27218ca6f24 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 11 Feb 2026 12:10:41 +0000 Subject: [PATCH 72/84] fix incorrect var name and make consistent --- catalog/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index d44200551..fd94bb7c7 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -20,7 +20,7 @@ def load(slug: str) -> gbt.Game: """ # Handle backslashes for Windows if sys.platform == "win32": - game_slug.replace("/", "\\") # noqa: F821 + slug.replace("/", "\\") # noqa: F821 for suffix, reader in READERS.items(): resource_path = _CATALOG_RESOURCE / f"{slug}{suffix}" @@ -48,17 +48,17 @@ def games() -> pd.DataFrame: # Calculate the path relative to the root resource # and remove the suffix to get the "slug" rel_path = resource_path.relative_to(_CATALOG_RESOURCE) - game_slug = str(rel_path.with_suffix("")) + slug = str(rel_path.with_suffix("")) # Replace backslashes for Windows if sys.platform == "win32": - game_slug.replace("\\", "/") # noqa: F821 + slug.replace("\\", "/") # noqa: F821 with as_file(resource_path) as path: game = reader(str(path)) records.append( { - "Game": game_slug, + "Game": slug, "Title": game.title, } ) From 69d8cb968a488f6a6def5c27ceb730df6801acab Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Wed, 11 Feb 2026 13:32:48 +0000 Subject: [PATCH 73/84] use as_posix for slugs --- catalog/__init__.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/catalog/__init__.py b/catalog/__init__.py index fd94bb7c7..4a972d917 100644 --- a/catalog/__init__.py +++ b/catalog/__init__.py @@ -1,5 +1,5 @@ -import sys from importlib.resources import as_file, files +from pathlib import Path import pandas as pd @@ -18,9 +18,7 @@ def load(slug: str) -> gbt.Game: """ Load a game from the package catalog. """ - # Handle backslashes for Windows - if sys.platform == "win32": - slug.replace("/", "\\") # noqa: F821 + slug = str(Path(slug)).replace("\\", "/") for suffix, reader in READERS.items(): resource_path = _CATALOG_RESOURCE / f"{slug}{suffix}" @@ -48,11 +46,7 @@ def games() -> pd.DataFrame: # Calculate the path relative to the root resource # and remove the suffix to get the "slug" rel_path = resource_path.relative_to(_CATALOG_RESOURCE) - slug = str(rel_path.with_suffix("")) - - # Replace backslashes for Windows - if sys.platform == "win32": - slug.replace("\\", "/") # noqa: F821 + slug = rel_path.with_suffix("").as_posix() with as_file(resource_path) as path: game = reader(str(path)) From d7290f41eba9b96b3436517691417470c951e34e Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Thu, 12 Feb 2026 16:54:40 +0000 Subject: [PATCH 74/84] add new notebook --- doc/pygambit.rst | 1 + doc/tutorials/creating_images.ipynb | 46 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 doc/tutorials/creating_images.ipynb diff --git a/doc/pygambit.rst b/doc/pygambit.rst index cf4302efa..2bc678eb5 100644 --- a/doc/pygambit.rst +++ b/doc/pygambit.rst @@ -24,6 +24,7 @@ They are numbered in the order they should be read. tutorials/01_quickstart tutorials/02_extensive_form tutorials/03_stripped_down_poker + tutorials/creating_images Advanced user tutorials ----------------------- diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/creating_images.ipynb new file mode 100644 index 000000000..c43fe34b1 --- /dev/null +++ b/doc/tutorials/creating_images.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a2d556ea-37b0-47c5-a199-2cbfc68c95a9", + "metadata": {}, + "source": [ + "# Creating publication-ready game images\n", + "\n", + "Using a combination of `pygambit` and the Gambit project's LaTeX graphics package `draw_tree`, we can generate publication quality images for games with just a few lines of code.\n", + "\n", + "This tutorial will demonstrate the key functionality of `draw_tree` when used for games built with `pygambit`, using a \"Kuhn poker\" game derived from the Gambit catalog of games.\n", + "First, let's load the game:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "338dd237-2280-453c-a687-d65b9f9a56b6", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From d32570ffe54c20e0bf5d09216c4567f6d7ddea8a Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Thu, 12 Feb 2026 16:59:06 +0000 Subject: [PATCH 75/84] upgrade draw_tree version to 0.4.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ed73f4eb8..1703d2109 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ doc = [ "pickleshare", "jupyter", "open_spiel; sys_platform != 'win32'", - "draw-tree @ git+https://github.com/gambitproject/draw_tree.git@v0.3.1" + "draw-tree @ git+https://github.com/gambitproject/draw_tree.git@v0.4.0" ] [project.urls] From b56c95b4498884ea28cf88011580fcc1e4847237 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 11:33:00 +0000 Subject: [PATCH 76/84] 2smp game looks good --- doc/tutorials/creating_images.ipynb | 3849 ++++++++++++++++++++++++++- 1 file changed, 3844 insertions(+), 5 deletions(-) diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/creating_images.ipynb index c43fe34b1..a3f979c5a 100644 --- a/doc/tutorials/creating_images.ipynb +++ b/doc/tutorials/creating_images.ipynb @@ -5,21 +5,3860 @@ "id": "a2d556ea-37b0-47c5-a199-2cbfc68c95a9", "metadata": {}, "source": [ - "# Creating publication-ready game images\n", + "# Creating publication-ready game images" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "338dd237-2280-453c-a687-d65b9f9a56b6", + "metadata": {}, + "outputs": [], + "source": [ + "from draw_tree import draw_tree\n", "\n", + "import pygambit as gbt" + ] + }, + { + "cell_type": "markdown", + "id": "53808931-cdc1-4b39-9a62-8c5166077a84", + "metadata": {}, + "source": [ "Using a combination of `pygambit` and the Gambit project's LaTeX graphics package `draw_tree`, we can generate publication quality images for games with just a few lines of code.\n", "\n", - "This tutorial will demonstrate the key functionality of `draw_tree` when used for games built with `pygambit`, using a \"Kuhn poker\" game derived from the Gambit catalog of games.\n", + "This tutorial will demonstrate the key functionality of `draw_tree` when used for games built with `pygambit`, using an example game derived from the Gambit catalog.\n", "First, let's load the game:" ] }, { "cell_type": "code", - "execution_count": null, - "id": "338dd237-2280-453c-a687-d65b9f9a56b6", + "execution_count": 3, + "id": "7f1dfa89-84fb-45cd-ab99-0a8ed44c17bc", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "g = gbt.catalog.load(\"2smp\")" + ] + }, + { + "cell_type": "markdown", + "id": "f4141e1a-9728-4186-b547-d37050a63e66", + "metadata": {}, + "source": [ + "Now let's see how `draw_tree` renders it with default settings:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e76fc30e-c03c-4fc6-ada1-733500609ca0", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(g)" + ] + }, + { + "cell_type": "markdown", + "id": "76363e9d-94df-430a-8ca9-c16b95f3880a", + "metadata": {}, + "source": [ + "Already this looks good, but perhaps it would look neater if the terminal nodes were all extended to the bottom of the image for consistency.\n", + "To achieve this, set `shared_terminal_depth=True`:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c9d4639a-8dc6-42c5-99a0-0a831117b551", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e6f72192-1ba3-4252-9a4c-40c37df98ef0", + "metadata": {}, + "source": [ + "This image is quite large, but the game isn't overly complex, so we can reduce the size with the `scale_factor`:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d6e7638e-9380-45ac-8809-9fd4da71be46", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "98614120-85e4-4d6c-b1b0-3f03755e094e", + "metadata": {}, + "source": [ + "Perhaps the size of the image is roughly correct, but we want to reduce the distance between node levels; we can scale the level spacing with `level_scaling`:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "0abb278d-2887-46fd-b9c3-0dc987d2da25", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f0991616-248f-4f90-b1ef-492d93d9db67", + "metadata": {}, + "source": [ + "The player labels are looking a little cramped. Let's adjust the width by increasing the `width_scaling`:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "7cb624c2-b3c3-4775-b1cd-7ef0e9d24eb1", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7e06766f-91aa-4eea-aca8-d4ef8d8270b0", + "metadata": {}, + "source": [ + "If we want to use color in our image, we can set the `color_scheme`. Here let's use the \"gambit\" color scheme:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "6d326b08-87e2-4d49-80bf-e16981ee221f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25,\n", + " color_scheme=\"gambit\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "35b1415d-84b9-45c2-a4e0-a05f04651042", + "metadata": {}, + "source": [ + "An advantage to using a color scheme is that nodes no longer require player labels, which are handled by the legend, de-cluttering the image further.\n", + "\n", + "Let's make our image more striking by increasing the `edge_thickness`:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c7aec967-77f5-434d-bb83-73c8518dd997", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25,\n", + " color_scheme=\"gambit\",\n", + " edge_thickness=1.5\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "eec80871-03cd-4f8b-9b47-3d4a4ad16ce5", + "metadata": {}, + "source": [ + "One final adjustment we could make would be to adjust the positioning of action labels on the image.\n", + "This can be helpful in cases where the action labels overlap visually with information sets boundaries or other features.\n", + "The default value of 0.5 places the labels halfway along the edges, which for this game looks about right, but we can change this by setting `action_label_position`:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "0f82b80c-8f7d-41ff-9e24-ffb1524a95be", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25,\n", + " color_scheme=\"gambit\",\n", + " edge_thickness=1.5,\n", + " action_label_position=0.6\n", + ")" + ] } ], "metadata": { From e73dfe8f65bffd579c6135361bd4ecc13ce1532c Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 11:58:14 +0000 Subject: [PATCH 77/84] add sections on saving images and further adjustments --- doc/tutorials/creating_images.ipynb | 506 +++++++++++++++++++++++++++- 1 file changed, 505 insertions(+), 1 deletion(-) diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/creating_images.ipynb index a3f979c5a..b19116040 100644 --- a/doc/tutorials/creating_images.ipynb +++ b/doc/tutorials/creating_images.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 23, "id": "338dd237-2280-453c-a687-d65b9f9a56b6", "metadata": {}, "outputs": [], @@ -3859,6 +3859,510 @@ " action_label_position=0.6\n", ")" ] + }, + { + "cell_type": "markdown", + "id": "f77731a4-1c3a-4e83-a69e-b3b8404059b5", + "metadata": {}, + "source": [ + "# Saving images\n", + "\n", + "Once we are happy with our image, we can save it as a Tex file, or generate a PNG or PDF with the rendered image.\n", + "Each of the following functions takes the same arguments as the `draw_tree` examples above.\n", + "Setting the `save_to` argument will determine where the `.ef` file used by `draw_tree` to preserve layout information is saved, as well as the output image or Tex file:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "e6045291-653e-4702-a95c-5c00159d4b43", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tree(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25,\n", + " color_scheme=\"gambit\",\n", + " edge_thickness=1.5,\n", + " action_label_position=0.6,\n", + " save_to=\"2smp\" # Creates 2smp.ef\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d21634cc-64fd-4eed-8887-b4e3a80734fd", + "metadata": {}, + "source": [ + "### Tex\n", + "\n", + "```python\n", + "from draw_tree generate_tex\n", + "generate_tex(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25,\n", + " color_scheme=\"gambit\",\n", + " edge_thickness=1.5,\n", + " action_label_position=0.6,\n", + " save_to=\"2smp\" # Creates 2smp.ef and 2smp.tex\n", + ")\n", + "```\n", + "\n", + "### PDF\n", + "\n", + "```python\n", + "from draw_tree import generate_pdf\n", + "generate_pdf(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25,\n", + " color_scheme=\"gambit\",\n", + " edge_thickness=1.5,\n", + " action_label_position=0.6,\n", + " save_to=\"2smp\" # Creates 2smp.ef and 2smp.pdf\n", + ")\n", + "```\n", + "\n", + "### PNG\n", + "\n", + "```python\n", + "from draw_tree import generate_png\n", + "generate_png(\n", + " g,\n", + " shared_terminal_depth=True,\n", + " scale_factor=0.5,\n", + " level_scaling=0.75,\n", + " width_scaling=1.25,\n", + " color_scheme=\"gambit\",\n", + " edge_thickness=1.5,\n", + " action_label_position=0.6,\n", + " save_to=\"2smp\" # Creates 2smp.ef and 2smp.png\n", + ")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "0fa1bb4f-4dc4-4619-b20a-f84948a69185", + "metadata": {}, + "source": [ + "# Further adjustments\n", + "\n", + "If your image requires further adjustments, you can manually edit your games `.ef` file.\n", + "You can find information on EF format specs in the [draw_tree docs](https://github.com/gambitproject/draw_tree).\n", + "\n", + "EF files that are manually created or (exported from [Game Theory Explorer](https://gametheoryexplorer-a68c7.web.app/) can be drawn by `draw_tree` with the same functions explored in this tutorial, but you should drop the formatting parameters:\n", + "\n", + "```python\n", + "draw_tree('path/to/game.ef')\n", + "generate_tex('path/to/game.ef')\n", + "generate_pdf('path/to/game.ef')\n", + "generate_png('path/to/game.ef')\n", + "```" + ] } ], "metadata": { From 1962e0692d5abcdb04e5152f86f1da58989a9d86 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 13:22:43 +0000 Subject: [PATCH 78/84] update headers --- doc/tutorials/creating_images.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/creating_images.ipynb index b19116040..4b7721cf2 100644 --- a/doc/tutorials/creating_images.ipynb +++ b/doc/tutorials/creating_images.ipynb @@ -3865,7 +3865,7 @@ "id": "f77731a4-1c3a-4e83-a69e-b3b8404059b5", "metadata": {}, "source": [ - "# Saving images\n", + "## Saving images\n", "\n", "Once we are happy with our image, we can save it as a Tex file, or generate a PNG or PDF with the rendered image.\n", "Each of the following functions takes the same arguments as the `draw_tree` examples above.\n", @@ -4349,7 +4349,7 @@ "id": "0fa1bb4f-4dc4-4619-b20a-f84948a69185", "metadata": {}, "source": [ - "# Further adjustments\n", + "## Further adjustments\n", "\n", "If your image requires further adjustments, you can manually edit your games `.ef` file.\n", "You can find information on EF format specs in the [draw_tree docs](https://github.com/gambitproject/draw_tree).\n", From a4fc7448676f1dc65d24c1a1698b4e8f1a29ee21 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 13:27:19 +0000 Subject: [PATCH 79/84] update header further --- doc/tutorials/creating_images.ipynb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/creating_images.ipynb index 4b7721cf2..c51b47788 100644 --- a/doc/tutorials/creating_images.ipynb +++ b/doc/tutorials/creating_images.ipynb @@ -4292,7 +4292,7 @@ "id": "d21634cc-64fd-4eed-8887-b4e3a80734fd", "metadata": {}, "source": [ - "### Tex\n", + "### Save to TeX\n", "\n", "```python\n", "from draw_tree generate_tex\n", @@ -4309,7 +4309,7 @@ ")\n", "```\n", "\n", - "### PDF\n", + "### Save to PDF\n", "\n", "```python\n", "from draw_tree import generate_pdf\n", @@ -4326,7 +4326,7 @@ ")\n", "```\n", "\n", - "### PNG\n", + "### Save to PNG\n", "\n", "```python\n", "from draw_tree import generate_png\n", @@ -4349,7 +4349,7 @@ "id": "0fa1bb4f-4dc4-4619-b20a-f84948a69185", "metadata": {}, "source": [ - "## Further adjustments\n", + "## Further adjustments to game images\n", "\n", "If your image requires further adjustments, you can manually edit your games `.ef` file.\n", "You can find information on EF format specs in the [draw_tree docs](https://github.com/gambitproject/draw_tree).\n", From 59dd0dd8b97b9e73a9efe0aeaf1c037c41b25465 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 13:30:09 +0000 Subject: [PATCH 80/84] add comment --- doc/tutorials/01_quickstart.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 62949a4b4..5b83324f6 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -354,7 +354,8 @@ "You can use Gambit to save games to, and read from files.\n", "The specific format depends on whether the game is normal or extensive-form.\n", "\n", - "Here we'll save the Prisoner's Dilemma (Normal-form) to the `.nfg` format." + "Here we'll save the Prisoner's Dilemma (Normal-form) to the `.nfg` format.\n", + "Uncomment these lines of code if you're running the tutorial locally:" ] }, { From c27f805a0f4fa731d2066abde48eb8ce455a8d58 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 13:33:04 +0000 Subject: [PATCH 81/84] clear saved outputs from all tutorials --- doc/tutorials/02_extensive_form.ipynb | 951 +--- doc/tutorials/03_stripped_down_poker.ipynb | 1793 +------- .../agent_versus_non_agent_regret.ipynb | 399 +- .../advanced_tutorials/quantal_response.ipynb | 156 +- .../advanced_tutorials/starting_points.ipynb | 250 +- doc/tutorials/creating_images.ipynb | 4063 +---------------- .../openspiel.ipynb | 2367 +--------- 7 files changed, 284 insertions(+), 9695 deletions(-) diff --git a/doc/tutorials/02_extensive_form.ipynb b/doc/tutorials/02_extensive_form.ipynb index 528970c61..2f444b0ca 100644 --- a/doc/tutorials/02_extensive_form.ipynb +++ b/doc/tutorials/02_extensive_form.ipynb @@ -31,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "5946289b", "metadata": {}, "outputs": [], @@ -51,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "91ed4dfb", "metadata": {}, "outputs": [], @@ -72,39 +72,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "3cd94917", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g)" ] @@ -121,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "5d27a07a", "metadata": {}, "outputs": [], @@ -135,138 +106,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "45638fda-7e25-4c8e-b709-24b05780581b", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g)" ] @@ -281,7 +124,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "47c4a31b", "metadata": {}, "outputs": [], @@ -295,199 +138,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "ce41e9fe-cca4-46fb-8e9d-b2c27342e5ef", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g)" ] @@ -506,7 +160,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "716e9b9a", "metadata": {}, "outputs": [], @@ -522,175 +176,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "b3408c55-714e-4a6f-b598-e338839442e4", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g)" ] @@ -705,7 +194,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "695b1aad", "metadata": {}, "outputs": [], @@ -721,189 +210,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "09bedb3a-aac7-46e6-ae93-c47932c746d4", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g)" ] @@ -918,7 +228,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "0704ef86", "metadata": {}, "outputs": [], @@ -934,197 +244,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "cba0e562-2989-4dae-a0f0-b121635ba032", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g)" ] @@ -1156,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "37c51152", "metadata": {}, "outputs": [], @@ -1174,7 +297,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "0d86a750", "metadata": {}, "outputs": [], @@ -1182,38 +305,6 @@ "# gbt.read_efg(\"trust_game.efg\")" ] }, - { - "cell_type": "markdown", - "id": "182f2424-274e-4044-84ff-3323cd70ec68", - "metadata": {}, - "source": [ - "You can also use the `draw_tree` package to save the game in the `.ef` format which encodes layout information.\n", - "This can in turn be used to render the image for use in publications, for example as a `.png` (there are also `.pdf` and `.tex` options, see [draw_tree](https://github.com/gambitproject/draw_tree)):" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "1bab777f-8a0b-4f1e-9c0c-270690288243", - "metadata": {}, - "outputs": [], - "source": [ - "# from draw_tree import generate_png\n", - "# draw_tree(g, save_to=\"trust_game.ef\")\n", - "# trust_game_png = generate_png(\"trust_game.ef\")" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "2b715221-e427-4092-ad2f-9f4f2b548fa4", - "metadata": {}, - "outputs": [], - "source": [ - "# from IPython.display import Image\n", - "# Image(trust_game_png)" - ] - }, { "cell_type": "markdown", "id": "be034836", diff --git a/doc/tutorials/03_stripped_down_poker.ipynb b/doc/tutorials/03_stripped_down_poker.ipynb index 10c425d36..f8649c919 100644 --- a/doc/tutorials/03_stripped_down_poker.ipynb +++ b/doc/tutorials/03_stripped_down_poker.ipynb @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "69cbfe81", "metadata": {}, "outputs": [], @@ -59,7 +59,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "ad6a1119", "metadata": {}, "outputs": [], @@ -80,20 +80,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "841f9f74", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Player(game=Game(title='Stripped-Down Poker: a simple game of one-card poker from Reiley et al (2008).'), label='Alice')\n", - "Player(game=Game(title='Stripped-Down Poker: a simple game of one-card poker from Reiley et al (2008).'), label='Bob')\n", - "ChancePlayer(game=Game(title='Stripped-Down Poker: a simple game of one-card poker from Reiley et al (2008).'))\n" - ] - } - ], + "outputs": [], "source": [ "print(g.players[\"Alice\"])\n", "print(g.players[\"Bob\"])\n", @@ -116,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "fe80c64c", "metadata": {}, "outputs": [], @@ -130,166 +120,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "867cb1d8-7a5d-45d1-9349-9bbc2a4e2344", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g, color_scheme=\"gambit\")" ] @@ -310,7 +144,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "0e3bb5ef", "metadata": {}, "outputs": [], @@ -325,281 +159,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "0c522c2d-992e-48b6-a1f8-0696d33cdbe0", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g, color_scheme=\"gambit\")" ] @@ -624,7 +187,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "dbfa7035", "metadata": {}, "outputs": [], @@ -638,361 +201,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "e85b3346-2fea-4a73-aa72-9efb436c68c1", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g, color_scheme=\"gambit\")" ] @@ -1012,7 +224,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "87c988be", "metadata": {}, "outputs": [], @@ -1033,7 +245,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "29aa60a0", "metadata": {}, "outputs": [], @@ -1055,344 +267,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "fdee7b53-7820-44df-9d17-d15d0b9667aa", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g, color_scheme=\"gambit\")" ] @@ -1410,21 +288,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "4d92c8d9", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "NashComputationResult(method='lcp', rational=True, use_strategic=False, equilibria=[[[[Rational(1, 1), Rational(0, 1)], [Rational(1, 3), Rational(2, 3)]], [[Rational(2, 3), Rational(1, 3)]]]], parameters={'stop_after': None, 'max_depth': None})" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "result = gbt.nash.lcp_solve(g)\n", "result" @@ -1444,18 +311,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "9967d6f7", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of equilibria found: 1\n" - ] - } - ], + "outputs": [], "source": [ "print(\"Number of equilibria found:\", len(result.equilibria))\n", "eqm = result.equilibria[0]" @@ -1471,21 +330,10 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "3293e818", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.MixedBehaviorProfileRational" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "type(eqm)" ] @@ -1502,45 +350,20 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "4cf38264", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.MixedBehavior" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "type(eqm[\"Alice\"])" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "85e7fdda", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[1,0\\right],\\left[\\frac{1}{3},\\frac{2}{3}\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(1, 1), Rational(0, 1)], [Rational(1, 3), Rational(2, 3)]]" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm[\"Alice\"]" ] @@ -1561,19 +384,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "f45a82b6", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "At information set 0, Alice plays Bet with probability: 1 and Fold with probability: 0\n", - "At information set 1, Alice plays Bet with probability: 1/3 and Fold with probability: 2/3\n" - ] - } - ], + "outputs": [], "source": [ "for infoset, mixed_action in eqm[\"Alice\"].mixed_actions():\n", " print(\n", @@ -1593,21 +407,10 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "83bbd3e5", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "At information set 0, Alice plays Bet with probability: 1\n", - "At information set 0, Alice plays Fold with probability: 0\n", - "At information set 1, Alice plays Bet with probability: 1/3\n", - "At information set 1, Alice plays Fold with probability: 2/3\n" - ] - } - ], + "outputs": [], "source": [ "for action in g.players[\"Alice\"].actions:\n", " print(\n", @@ -1626,24 +429,10 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "6bf51b38", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[\\frac{2}{3},\\frac{1}{3}\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(2, 3), Rational(1, 3)]]" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm[\"Bob\"]" ] @@ -1662,24 +451,10 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "2966e700", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\frac{2}{3}$" - ], - "text/plain": [ - "Rational(2, 3)" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm[\"Bob\"][\"Call\"]" ] @@ -1694,24 +469,10 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "f5a7f110", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\frac{2}{3}$" - ], - "text/plain": [ - "Rational(2, 3)" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm[\"Call\"]" ] @@ -1728,19 +489,10 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "a7d3816d", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "When Bob plays Call his expected payoff is -1\n", - "When Bob plays Fold his expected payoff is -1\n" - ] - } - ], + "outputs": [], "source": [ "# Remember that Bob has a single information set\n", "for action in g.players[\"Bob\"].infosets[0].actions:\n", @@ -1763,19 +515,10 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "4a54b20c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Bob's belief in reaching the King -> Bet node is: 3/4\n", - "Bob's belief in reaching the Queen -> Bet node is: 1/4\n" - ] - } - ], + "outputs": [], "source": [ "for node in g.players[\"Bob\"].infosets[0].members:\n", " print(\n", @@ -1796,24 +539,10 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "id": "b250c1cd", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\frac{2}{3}$" - ], - "text/plain": [ - "Rational(2, 3)" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm.infoset_prob(g.players[\"Bob\"].infosets[0])" ] @@ -1828,19 +557,10 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "id": "6f01846b", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The probability that the node King -> Bet is reached is: 1/2. Bob's expected payoff conditional on reaching this node is -5/3\n", - "The probability that the node Queen -> Bet is reached is: 1/6. Bob's expected payoff conditional on reaching this node is 1\n" - ] - } - ], + "outputs": [], "source": [ "for node in g.players[\"Bob\"].infosets[0].members:\n", " print(\n", @@ -1860,48 +580,20 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "id": "5079d231", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\frac{1}{3}$" - ], - "text/plain": [ - "Rational(1, 3)" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm.payoff(\"Alice\")" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "id": "c55f2c7a", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\frac{-1}{3}$" - ], - "text/plain": [ - "Rational(-1, 3)" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm.payoff(\"Bob\")" ] @@ -1924,21 +616,10 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "id": "d4ecff88", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['11', '12', '21', '22']" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "[s.label for s in g.players[\"Alice\"].strategies]" ] @@ -1958,21 +639,10 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "24e4b6e8", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "NashComputationResult(method='gnm', rational=False, use_strategic=True, equilibria=[[[0.33333333333866677, 0.6666666666613335, 0.0, 0.0], [0.6666666666559997, 0.3333333333440004]]], parameters={'perturbation': [[1.0, 0.0, 0.0, 0.0], [1.0, 0.0]], 'end_lambda': -10.0, 'steps': 100, 'local_newton_interval': 3, 'local_newton_maxits': 10})" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gnm_result = gbt.nash.gnm_solve(g)\n", "gnm_result" @@ -1990,21 +660,10 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "id": "d9ffb4b8", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.gambit.MixedStrategyProfileDouble" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gnm_eqm = gnm_result.equilibria[0]\n", "type(gnm_eqm)" @@ -2022,29 +681,10 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "id": "56e2f847", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Alice's expected payoffs playing:\n", - "Strategy 11: 0.3333\n", - "Strategy 12: 0.3333\n", - "Strategy 21: -1.0000\n", - "Strategy 22: -1.0000\n", - "Alice's overall expected payoff: 0.3333\n", - "\n", - "Bob's expected payoffs playing:\n", - "Strategy 1: -0.3333\n", - "Strategy 2: -0.3333\n", - "Bob's overall expected payoff: -0.3333\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "for player in g.players:\n", " print(\n", @@ -2075,27 +715,10 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "id": "d18a91f0", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Alice's expected payoffs:\n", - "At information set 0, when playing Bet - gnm: 1.6667, lcp: 5/3\n", - "At information set 0, when playing Fold - gnm: -1.0000, lcp: -1\n", - "At information set 1, when playing Bet - gnm: -1.0000, lcp: -1\n", - "At information set 1, when playing Fold - gnm: -1.0000, lcp: -1\n", - "\n", - "Bob's expected payoffs:\n", - "At information set 0, when playing Call - gnm: -1.0000, lcp: -1\n", - "At information set 0, when playing Fold - gnm: -1.0000, lcp: -1\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "for player in g.players:\n", " print(\n", @@ -2141,21 +764,10 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "id": "0c55f745", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(Rational(2, 1), Rational(-2, 1))" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "g.max_payoff, g.min_payoff" ] @@ -2173,21 +785,10 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, "id": "101598c6", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "logit_solve_result = gbt.nash.logit_solve(g, maxregret=1e-8)\n", "len(logit_solve_result.equilibria)" @@ -2195,21 +796,10 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "id": "9b142728", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2.6582744783176793e-08" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ls_eqm = logit_solve_result.equilibria[0]\n", "ls_eqm.max_regret()" @@ -2226,21 +816,10 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "id": "ff405409", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6.645686195794198e-09" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ls_eqm.max_regret() / (g.max_payoff - g.min_payoff)" ] @@ -2257,21 +836,10 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": null, "id": "31b0143c", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6.265863445531483e-05" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "(\n", " gbt.nash.logit_solve(g, maxregret=1e-4).equilibria[0]\n", @@ -2289,29 +857,10 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": null, "id": "7cfba34a", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 9.91 ms, sys: 68 μs, total: 9.98 ms\n", - "Wall time: 9.97 ms\n" - ] - }, - { - "data": { - "text/plain": [ - "NashComputationResult(method='logit', rational=False, use_strategic=False, equilibria=[[[[1.0, 0.0], [0.3338351656285655, 0.666164834417892]], [[0.6670407651644307, 0.3329592348608147]]]], parameters={'first_step': 0.03, 'max_accel': 1.1})" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "%%time\n", "gbt.nash.logit_solve(g, maxregret=1e-4)" @@ -2319,29 +868,10 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": null, "id": "6f1809a7", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 18.9 ms, sys: 166 μs, total: 19 ms\n", - "Wall time: 19 ms\n" - ] - }, - { - "data": { - "text/plain": [ - "NashComputationResult(method='logit', rational=False, use_strategic=False, equilibria=[[[[1.0, 0.0], [0.33333338649882943, 0.6666666135011706]], [[0.6666667065407631, 0.3333332934592369]]]], parameters={'first_step': 0.03, 'max_accel': 1.1})" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "%%time\n", "gbt.nash.logit_solve(g, maxregret=1e-8)" @@ -2359,21 +889,10 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": null, "id": "414b6f65", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.036578041721892926" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "(\n", " gbt.nash.liap_solve(g.mixed_strategy_profile(), maxregret=1e-1)\n", @@ -2391,21 +910,10 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": null, "id": "a892dc2b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.036578041721892926" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "for outcome in g.outcomes:\n", " outcome[\"Alice\"] = outcome[\"Alice\"] * 2\n", @@ -2432,21 +940,10 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": null, "id": "2f79695a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Rational(1, 3), Rational(1, 3), Rational(1, 3)]" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "small_game = gbt.Game.new_tree()\n", "small_game.append_move(small_game.root, small_game.players.chance, [\"a\", \"b\", \"c\"])\n", @@ -2466,21 +963,10 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": null, "id": "5de6acb2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Rational(1, 4), Rational(1, 2), Rational(1, 4)]" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "small_game.set_chance_probs(\n", " small_game.root.infoset,\n", @@ -2499,21 +985,10 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": null, "id": "c47d2ab6", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Decimal('0.25'), Decimal('0.50'), Decimal('0.25')]" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "small_game.set_chance_probs(\n", " small_game.root.infoset,\n", @@ -2536,21 +1011,10 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": null, "id": "04329084", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Rational(1, 4), Rational(1, 2), Rational(1, 4)]" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "small_game.set_chance_probs(small_game.root.infoset, [\"1/4\", \"1/2\", \"1/4\"])\n", "[act.prob for act in small_game.root.infoset.actions]" @@ -2558,21 +1022,10 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": null, "id": "9015e129", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Decimal('0.25'), Decimal('0.50'), Decimal('0.25')]" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "small_game.set_chance_probs(small_game.root.infoset, [\".25\", \".50\", \".25\"])\n", "[act.prob for act in small_game.root.infoset.actions]" @@ -2593,21 +1046,10 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": null, "id": "0a019aa5", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Decimal('0.25'), Decimal('0.5'), Decimal('0.25')]" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "small_game.set_chance_probs(small_game.root.infoset, [.25, .50, .25])\n", "[act.prob for act in small_game.root.infoset.actions]" @@ -2623,18 +1065,10 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": null, "id": "1991d288", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ValueError: set_chance_probs(): must specify non-negative probabilities that sum to one\n" - ] - } - ], + "outputs": [], "source": [ "try:\n", " small_game.set_chance_probs(small_game.root.infoset, [1/3, 1/3, 1/3])\n", @@ -2653,21 +1087,10 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": null, "id": "b1dc37fd", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1.0" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "1/3 + 1/3 + 1/3" ] @@ -2682,21 +1105,10 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": null, "id": "dc1edea2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Decimal('0.3333333333333333')" - ] - }, - "execution_count": 51, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.Decimal(str(1/3))" ] @@ -2711,21 +1123,10 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": null, "id": "1edd90d6", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Decimal('0.9999999999999999')" - ] - }, - "execution_count": 52, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.Decimal(str(1/3)) + gbt.Decimal(str(1/3)) + gbt.Decimal(str(1/3))" ] diff --git a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb index 3c3ac80b1..05913abdb 100644 --- a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb +++ b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb @@ -28,243 +28,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "5142d6ba-da13-4500-bca6-e68b608bfae9", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from draw_tree import draw_tree\n", "\n", @@ -284,19 +51,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "7882d327-ce04-43d3-bb5a-36cff6da6e96", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of pure equilibria: 1\n", - "Max regret: 0\n" - ] - } - ], + "outputs": [], "source": [ "pure_Nash_equilibria = gbt.nash.enumpure_solve(g).equilibria\n", "print(\"Number of pure equilibria:\", len(pure_Nash_equilibria))\n", @@ -314,20 +72,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "6e3e9303-453a-4bac-a449-fa8fda2ba5ec", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Player 1 infoset: 0 behavior probabilities: [Rational(1, 1), Rational(0, 1)]\n", - "Player 1 infoset: 1 behavior probabilities: [Rational(0, 1), Rational(1, 1)]\n", - "Player 2 infoset: 0 behavior probabilities: [Rational(0, 1), Rational(1, 1)]\n" - ] - } - ], + "outputs": [], "source": [ "eq = pure_Nash_equilibria[0]\n", "for infoset, probs in eq.as_behavior().mixed_actions():\n", @@ -344,18 +92,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "804345b9-d32b-4f60-b4a0-f9d69dca10a8", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Liap value: 0\n" - ] - } - ], + "outputs": [], "source": [ "print(\"Liap value:\", pure_eq.liap_value())" ] @@ -380,19 +120,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "9d18768b-db9b-41ef-aee7-5fe5f524a59e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Max regret of starting profile: 3\n", - "Liapunov value of starting profile: 14\n" - ] - } - ], + "outputs": [], "source": [ "starting_profile_double = g.mixed_strategy_profile(data=[[0,1,0],[1,0]], rational=False)\n", "starting_profile_rational = g.mixed_strategy_profile(data=[[0,1,0],[1,0]], rational=True)\n", @@ -418,18 +149,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "b885271f-7279-4d87-a0b9-bc28449b00ba", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[4.2517925671604327e-07, 0.49999911111761514, 0.5000004637031282], [0.3333333517938241, 0.6666666482061759]]\n" - ] - } - ], + "outputs": [], "source": [ "candidate_eq = gbt.nash.liap_solve(start=starting_profile_double).equilibria[0]\n", "print(candidate_eq)" @@ -437,19 +160,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "f8a90a9c-393e-4812-9418-76e705880f6f", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Liap value: 4.43446520109796e-14\n", - "Max regret: 1.694170896904268e-07\n" - ] - } - ], + "outputs": [], "source": [ "print(\"Liap value:\", candidate_eq.liap_value())\n", "print(\"Max regret:\", candidate_eq.max_regret())" @@ -457,19 +171,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "567e6a6a-fc8d-4142-806c-6510b2a4c624", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Liap value: 0\n", - "Max regret: 0\n" - ] - } - ], + "outputs": [], "source": [ "candidate_eq_rat = g.mixed_strategy_profile(data=[[0,\"1/2\",\"1/2\"],[\"1/3\",\"2/3\"]], rational=True)\n", "print(\"Liap value:\", candidate_eq_rat.liap_value())\n", @@ -486,20 +191,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "87a62c9e-b109-4f88-ac25-d0e0db3f27ea", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[Rational(0, 1), Rational(1, 1), Rational(0, 1)], [Rational(0, 1), Rational(1, 1)]]\n", - "[[Rational(1, 4), Rational(0, 1), Rational(3, 4)], [Rational(1, 2), Rational(1, 2)]]\n", - "[[Rational(0, 1), Rational(1, 2), Rational(1, 2)], [Rational(1, 3), Rational(2, 3)]]\n" - ] - } - ], + "outputs": [], "source": [ "all_extreme_Nash_equilibria = gbt.nash.enummixed_solve(g).equilibria\n", "for eq in all_extreme_Nash_equilibria:\n", @@ -516,20 +211,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "2c8ed3df-958e-4ee9-aed6-a106547fbd37", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[Rational(0, 1), Rational(1, 2), Rational(1, 2)], [Rational(1, 3), Rational(2, 3)]]\n", - "Liap value: 0\n", - "Max regret: 0\n" - ] - } - ], + "outputs": [], "source": [ "print(all_extreme_Nash_equilibria[2])\n", "print(\"Liap value:\", all_extreme_Nash_equilibria[2].liap_value())\n", @@ -563,20 +248,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "f46ce825-d2b7-492f-b0cf-6f213607e121", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n", - "[[[Rational(1, 1), Rational(0, 1)], [Rational(0, 1), Rational(1, 1)]], [[Rational(0, 1), Rational(1, 1)]]]\n", - "[[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]], [[Rational(1, 1), Rational(0, 1)]]]\n" - ] - } - ], + "outputs": [], "source": [ "pure_agent_equilibria = gbt.nash.enumpure_agent_solve(g).equilibria\n", "print(len(pure_agent_equilibria))\n", @@ -594,21 +269,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "dbfa7035", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "pure_Nash_equilibria[0] == pure_agent_equilibria[0].as_strategy()" ] @@ -623,21 +287,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "85760cec-5760-4f9d-8ca2-99fba79c7c3c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Max regret: 1\n", - "Liapunov value: 1\n", - "Agent max regret 0\n", - "Agent Liapunov value: 0\n" - ] - } - ], + "outputs": [], "source": [ "aeq = pure_agent_equilibria[1]\n", "print(\"Max regret:\", aeq.max_regret())\n", diff --git a/doc/tutorials/advanced_tutorials/quantal_response.ipynb b/doc/tutorials/advanced_tutorials/quantal_response.ipynb index f345ff0e6..feea3a27c 100644 --- a/doc/tutorials/advanced_tutorials/quantal_response.ipynb +++ b/doc/tutorials/advanced_tutorials/quantal_response.ipynb @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "ebc4c60e", "metadata": {}, "outputs": [], @@ -23,24 +23,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "202786ef", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.5000000234106035, 0.49999997658939654],[0.19998563837426647, 0.8000143616257336]\\right]$" - ], - "text/plain": [ - "[[0.5000000234106035, 0.49999997658939654], [0.19998563837426647, 0.8000143616257336]]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "g = gbt.Game.from_arrays(\n", " [[1.1141, 0], [0, 0.2785]],\n", @@ -64,21 +50,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "840d9203", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "193" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "qres = gbt.qre.logit_solve_branch(g)\n", "len(qres)" @@ -86,48 +61,20 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "be419db2", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.5, 0.5],[0.5, 0.5]\\right]$" - ], - "text/plain": [ - "[[0.5, 0.5], [0.5, 0.5]]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "qres[0].profile" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "582838de", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.5182276540742868, 0.4817723459257562],[0.49821668880066783, 0.5017833111993909]\\right]$" - ], - "text/plain": [ - "[[0.5182276540742868, 0.4817723459257562], [0.49821668880066783, 0.5017833111993909]]" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "qres[5].profile" ] @@ -149,24 +96,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "ce354b49", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.5867840364385154, 0.4132159635614846],[0.4518070316997103, 0.5481929683002897]\\right]$" - ], - "text/plain": [ - "[[0.5867840364385154, 0.4132159635614846], [0.4518070316997103, 0.5481929683002897]]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "qres = gbt.qre.logit_solve_lambda(g, lam=[1, 2, 3])\n", "qres[0].profile" @@ -174,48 +107,20 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "280fa428", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.6175219458400859, 0.3824780541599141],[0.3719816648492249, 0.6280183351507751]\\right]$" - ], - "text/plain": [ - "[[0.6175219458400859, 0.3824780541599141], [0.3719816648492249, 0.6280183351507751]]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "qres[1].profile" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "3dee57df", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.6168968501329284, 0.3831031498670716],[0.31401636202001226, 0.6859836379799877]\\right]$" - ], - "text/plain": [ - "[[0.6168968501329284, 0.3831031498670716], [0.31401636202001226, 0.6859836379799877]]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "qres[2].profile" ] @@ -232,21 +137,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "b34a9278", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pygambit.qre.LogitQREMixedStrategyFitResult" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "data = g.mixed_strategy_profile([[128*0.527, 128*(1-0.527)], [128*0.366, 128*(1-0.366)]])\n", "fit = gbt.qre.logit_estimate(data)\n", @@ -267,20 +161,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "e10e9abd", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.8456097536855862\n", - "[[0.615651314427859, 0.3843486855721409], [0.38329094004562914, 0.6167090599543709]]\n", - "-174.76453191087447\n" - ] - } - ], + "outputs": [], "source": [ "print(fit.lam)\n", "print(fit.profile)\n", @@ -314,7 +198,7 @@ ], "metadata": { "kernelspec": { - "display_name": "gambitvenv313", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, diff --git a/doc/tutorials/advanced_tutorials/starting_points.ipynb b/doc/tutorials/advanced_tutorials/starting_points.ipynb index 9e8f72d5e..a49263a5c 100644 --- a/doc/tutorials/advanced_tutorials/starting_points.ipynb +++ b/doc/tutorials/advanced_tutorials/starting_points.ipynb @@ -25,25 +25,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "493cafb8", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

2x2x2 Example from McKelvey-McLennan, with 9 Nash equilibria, 2 totally mixed

\n", - "
Subtable with strategies:
Player 3 Strategy 1
12
19,8,120,0,0
20,0,09,8,2
\n" - ], - "text/plain": [ - "Game(title='2x2x2 Example from McKelvey-McLennan, with 9 Nash equilibria, 2 totally mixed')" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import numpy as np\n", "\n", @@ -64,24 +49,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "b32adf22", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.5, 0.5],[0.5, 0.5],[0.5, 0.5]\\right]$" - ], - "text/plain": [ - "[[0.5, 0.5], [0.5, 0.5], [0.5, 0.5]]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "centroid_start = g.mixed_strategy_profile()\n", "centroid_start" @@ -89,24 +60,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "c0b62502", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.3999998880351315, 0.6000001119648686],[0.5000000683119051, 0.4999999316880949],[0.3333335574724357, 0.6666664425275644]\\right]$" - ], - "text/plain": [ - "[[0.3999998880351315, 0.6000001119648686], [0.5000000683119051, 0.4999999316880949], [0.3333335574724357, 0.6666664425275644]]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.liap_solve(centroid_start).equilibria[0]" ] @@ -124,24 +81,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "cf22064e", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.9, 0.1],[0.9, 0.1],[0.9, 0.1]\\right]$" - ], - "text/plain": [ - "[[0.9, 0.1], [0.9, 0.1], [0.9, 0.1]]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "new_start = g.mixed_strategy_profile([[.9, .1], [.9, .1], [.9, .1]])\n", "new_start" @@ -149,24 +92,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "08a22505", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[1.0, 0.0],[0.9999999916299683, 8.370031632789431e-09],[1.0, 0.0]\\right]$" - ], - "text/plain": [ - "[[1.0, 0.0], [0.9999999916299683, 8.370031632789431e-09], [1.0, 0.0]]" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.liap_solve(new_start).equilibria[0]" ] @@ -181,24 +110,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "cfbc2714", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.5172260574334439, 0.48277394256655615],[0.5372523987305369, 0.462747601269463],[0.8261013405886477, 0.17389865941135238]\\right]$" - ], - "text/plain": [ - "[[0.5172260574334439, 0.48277394256655615], [0.5372523987305369, 0.462747601269463], [0.8261013405886477, 0.17389865941135238]]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "random_start = g.random_strategy_profile()\n", "random_start" @@ -206,24 +121,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "eb53062a", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[[0.49999999983005444, 0.5000000001699455],[0.4999999947343101, 0.5000000052656899],[0.9999989483984311, 1.0516015689453635e-06]\\right]$" - ], - "text/plain": [ - "[[0.49999999983005444, 0.5000000001699455], [0.4999999947343101, 0.5000000052656899], [0.9999989483984311, 1.0516015689453635e-06]]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.liap_solve(random_start).equilibria[0]" ] @@ -241,21 +142,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "4293343a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gen = np.random.default_rng(seed=1234567890)\n", "p1 = g.random_strategy_profile(gen=gen)\n", @@ -280,24 +170,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "e9716ae0", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[\\frac{1}{2},\\frac{1}{2}\\right],\\left[\\frac{7}{10},\\frac{3}{10}\\right],\\left[0,1\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(1, 2), Rational(1, 2)], [Rational(7, 10), Rational(3, 10)], [Rational(0, 1), Rational(1, 1)]]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gen = np.random.default_rng(seed=1234567890)\n", "rsp = g.random_strategy_profile(denom=10, gen=gen)\n", @@ -306,48 +182,20 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "c153918a", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[1,0\\right],\\left[1,0\\right],\\left[1,0\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(1, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1)]]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.simpdiv_solve(rsp).equilibria[0]" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "70a57b26", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[\\frac{1}{10},\\frac{9}{10}\\right],\\left[\\frac{3}{5},\\frac{2}{5}\\right],\\left[\\frac{3}{5},\\frac{2}{5}\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(1, 10), Rational(9, 10)], [Rational(3, 5), Rational(2, 5)], [Rational(3, 5), Rational(2, 5)]]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "rsp1 = g.random_strategy_profile(denom=10, gen=gen)\n", "rsp1" @@ -355,48 +203,20 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "11995836", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[0,1\\right],\\left[0,1\\right],\\left[1,0\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)], [Rational(1, 1), Rational(0, 1)]]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.simpdiv_solve(rsp1).equilibria[0]" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "2791ffe2", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[\\frac{7}{10},\\frac{3}{10}\\right],\\left[\\frac{4}{5},\\frac{1}{5}\\right],\\left[0,1\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(7, 10), Rational(3, 10)], [Rational(4, 5), Rational(1, 5)], [Rational(0, 1), Rational(1, 1)]]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "rsp2 = g.random_strategy_profile(denom=10, gen=gen)\n", "rsp2" @@ -404,24 +224,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "2ab2caa4", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[1,0\\right],\\left[1,0\\right],\\left[1,0\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(1, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1)]]" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.simpdiv_solve(rsp2).equilibria[0]" ] diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/creating_images.ipynb index c51b47788..73af14da5 100644 --- a/doc/tutorials/creating_images.ipynb +++ b/doc/tutorials/creating_images.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "338dd237-2280-453c-a687-d65b9f9a56b6", "metadata": {}, "outputs": [], @@ -33,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "7f1dfa89-84fb-45cd-ab99-0a8ed44c17bc", "metadata": {}, "outputs": [], @@ -51,501 +51,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "e76fc30e-c03c-4fc6-ada1-733500609ca0", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(g)" ] @@ -561,501 +70,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "c9d4639a-8dc6-42c5-99a0-0a831117b551", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", @@ -1073,511 +91,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "d6e7638e-9380-45ac-8809-9fd4da71be46", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", @@ -1596,501 +113,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "0abb278d-2887-46fd-b9c3-0dc987d2da25", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", @@ -2110,501 +136,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "7cb624c2-b3c3-4775-b1cd-7ef0e9d24eb1", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", @@ -2625,383 +160,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "6d326b08-87e2-4d49-80bf-e16981ee221f", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", @@ -3025,405 +187,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "c7aec967-77f5-434d-bb83-73c8518dd997", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", @@ -3448,405 +215,10 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "0f82b80c-8f7d-41ff-9e24-ffb1524a95be", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", @@ -3874,405 +246,10 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "e6045291-653e-4702-a95c-5c00159d4b43", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(\n", " g,\n", diff --git a/doc/tutorials/interoperability_tutorials/openspiel.ipynb b/doc/tutorials/interoperability_tutorials/openspiel.ipynb index 8863e5e37..505f269be 100644 --- a/doc/tutorials/interoperability_tutorials/openspiel.ipynb +++ b/doc/tutorials/interoperability_tutorials/openspiel.ipynb @@ -25,7 +25,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "ebb78322", "metadata": {}, "outputs": [], @@ -56,18 +56,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "b3eb3671", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['2048', 'add_noise', 'amazons', 'backgammon', 'bargaining', 'battleship', 'blackjack', 'blotto', 'breakthrough', 'bridge', 'bridge_uncontested_bidding', 'cached_tree', 'catch', 'checkers', 'chess', 'cliff_walking', 'clobber', 'coin_game', 'colored_trails', 'connect_four', 'coop_box_pushing', 'coop_to_1p', 'coordinated_mp', 'crazy_eights', 'cribbage', 'cursor_go', 'dark_chess', 'dark_hex', 'dark_hex_ir', 'deep_sea', 'dots_and_boxes', 'dou_dizhu', 'efg_game', 'einstein_wurfelt_nicht', 'euchre', 'first_sealed_auction', 'gin_rummy', 'go', 'goofspiel', 'hanabi', 'havannah', 'hearts', 'hex', 'hive', 'kriegspiel', 'kuhn_poker', 'laser_tag', 'latent_ttt', 'leduc_poker', 'lewis_signaling', 'liars_dice', 'liars_dice_ir', 'lines_of_action', 'maedn', 'mancala', 'markov_soccer', 'matching_pennies_3p', 'matrix_bos', 'matrix_brps', 'matrix_cd', 'matrix_coordination', 'matrix_mp', 'matrix_pd', 'matrix_rps', 'matrix_rpsw', 'matrix_sh', 'matrix_shapleys_game', 'mfg_crowd_modelling', 'mfg_crowd_modelling_2d', 'mfg_dynamic_routing', 'mfg_garnet', 'misere', 'mnk', 'morpion_solitaire', 'negotiation', 'nfg_game', 'nim', 'nine_mens_morris', 'normal_form_extensive_game', 'oh_hell', 'oshi_zumo', 'othello', 'oware', 'pathfinding', 'pentago', 'phantom_go', 'phantom_ttt', 'phantom_ttt_ir', 'pig', 'quoridor', 'rbc', 'repeated_game', 'repeated_leduc_poker', 'repeated_poker', 'restricted_nash_response', 'sheriff', 'skat', 'solitaire', 'spades', 'start_at', 'stones_and_gems', 'tarok', 'tic_tac_toe', 'tiny_bridge_2p', 'tiny_bridge_4p', 'tiny_hanabi', 'trade_comm', 'turn_based_simultaneous_game', 'twixt', 'ultimate_tic_tac_toe', 'universal_poker', 'y', 'zerosum']\n" - ] - } - ], + "outputs": [], "source": [ "print(pyspiel.registered_names())" ] @@ -86,7 +78,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "1d51af0a", "metadata": {}, "outputs": [], @@ -104,27 +96,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "1bcdb97b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Terminal? false\n", - "Row actions: Rock Paper Scissors \n", - "Col actions: Rock Paper Scissors \n", - "Utility matrix:\n", - "0,0 -1,1 1,-1 \n", - "1,-1 0,0 -1,1 \n", - "-1,1 1,-1 0,0 " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state = ops_matrix_rps_game.new_initial_state()\n", "state" @@ -140,19 +115,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "70575dc7", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0, 1, 2]\n", - "[0, 1, 2]\n" - ] - } - ], + "outputs": [], "source": [ "print(state.legal_actions(0)) # Player 0 (row) actions\n", "print(state.legal_actions(1)) # Player 1 (column) actions" @@ -170,29 +136,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "a532321e", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Terminal? true\n", - "History: 0, 1\n", - "Returns: -1,1\n", - "Row actions: \n", - "Col actions: \n", - "Utility matrix:\n", - "0,0 -1,1 1,-1 \n", - "1,-1 0,0 -1,1 \n", - "-1,1 1,-1 0,0 " - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state.apply_actions([0, 1])\n", "state" @@ -208,21 +155,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "f5fa4e42", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'NFG 1 R \"OpenSpiel export of matrix_rps()\"\\n{ \"Player 0\" \"Player 1\" } { 3 3 }\\n\\n0 0\\n1 -1\\n-1 1\\n-1 1\\n0 0\\n1 -1\\n1 -1\\n-1 1\\n0 0\\n'" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nfg_matrix_rps_game = pyspiel.game_to_nfg_string(ops_matrix_rps_game)\n", "nfg_matrix_rps_game" @@ -239,25 +175,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "b684325e", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Rock-Paper-Scissors

\n", - "
RockPaperScissors
Rock0,0-1,11,-1
Paper1,-10,0-1,1
Scissors-1,11,-10,0
\n" - ], - "text/plain": [ - "Game(title='Rock-Paper-Scissors')" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt_matrix_rps_game = gbt.read_nfg(StringIO(nfg_matrix_rps_game))\n", "\n", @@ -281,24 +202,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "707c6c30", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[\\frac{1}{3},\\frac{1}{3},\\frac{1}{3}\\right],\\left[\\frac{1}{3},\\frac{1}{3},\\frac{1}{3}\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(1, 3), Rational(1, 3), Rational(1, 3)], [Rational(1, 3), Rational(1, 3), Rational(1, 3)]]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.lcp_solve(gbt_matrix_rps_game).equilibria[0]" ] @@ -315,21 +222,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "cf1acdeb", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 0.03, -0.03, 0. ])" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "matrix_rps_payoffs = game_payoffs_array(ops_matrix_rps_game)\n", "dyn = dynamics.SinglePopulationDynamics(matrix_rps_payoffs, dynamics.replicator)\n", @@ -350,21 +246,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "b9a352c5", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "def plot_rps_dynamics(proportions, steps=100, alpha=0.1, plot_average_strategy=False):\n", " x = np.array(proportions)\n", @@ -412,21 +297,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "86c6aa52", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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BKT333/faz1VqlT2iJEOHTrIgAEDEvLaAAAAAiMg6Yg1AACA5CzBapAAAABSbAuSDuXXB9TGxbx58+JzTQAAAIHVgqTTcy9fvlw2b97s2bZlyxZZsWKFDffX/e4FAAAgRQSk3Llzy9NPP221SNpCpMv+/fulTZs2Vqz96aefepa4mjRpkoSGhkr69OmlevXqsnHjxliP1ferUqWKZM2aVUJCQqRChQo2gi66oUOHSokSJWx/tmzZ7EG6GzZs8DpG309bwqIvo0aN8vV2AACAZMjnh9VqCFq7dq0UL17ca/vevXvlH//4h5w7d86nC5g7d660b99epk6dauFo3Lhx8uWXX9r5cuXKdcvxP/74o/z1118WgNKmTSsLFy6UV199Vb777jtp1KiRHfP555/ba4sUKSJ///23jbzTc+7bt8+u3x2QOnXqJJ07d/acO3PmzBaq4oKH1QIAEHji+vntcwvSzZs3Zc+ePbds121RUVE+X+jYsWMtpHTs2FFKlSplQSljxozyySefxHh8nTp1rA6qZMmS9uy33r17S7ly5Sy0uT377LPWaqQBqXTp0vYeekN27NjhdS4NRHny5PEstwtHN27csHNEXwAAQPLkc0DSIKMtLxo6NJToMmbMGHnxxRdtny/Cw8OtfknDjOeCUqWy9XXr1t3x9dr4pfVQ2tpUq1atWN/jo48+srRYvnx5r33apZYjRw6pWLGivPvuuxb+YhMWFuZVX1WgQAGfflYAAJCMR7G999571tqioUhn0FZ58+aV119/3bq6fHH27FmJjIy0uqbodD2mVio3bRbLnz+/teqkTp1aJk+eLA0aNPA6Rrve2rZtK9euXbPrW7p0qeTMmdOzv1evXlKpUiXJnj27/PzzzzbJpf48Gvxiovv79u3rWdcWJEISAADJk88BSVt43njjDVvc3Uz3ugZHu8a2bdsmV65csRYkDS7anabdb25169a1YzSETZs2zQrLtVDbXdcUPexoF53WM7300kvWUpQuXbpb3lO3xbQdAAAkP/GaKFK7opYtWyZffPGFZ06k48ePW2DxhbboaAvQqVOnvLbrurZSxXrRqVJJsWLFbASbtlo99dRTFmyi03oiPebhhx+Wjz/+WIKDg+1rbLRAXH+ugwcP+vQzAACA5MfngHTo0CEpW7asPPHEE9K9e3c5c+aMbR89erS89tprPp1L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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plot_rps_dynamics([1/3, 1/3, 1/3])" ] @@ -441,21 +315,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "189f898f", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plot_rps_dynamics([0.3, 0.3, 0.4], plot_average_strategy=True)" ] @@ -472,25 +335,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "cdd0bfe0", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Prisoner's Dilemma

\n", - "
12
1-1,-1-3,0
20,-3-2,-2
\n" - ], - "text/plain": [ - "Game(title='Prisoner's Dilemma')" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "player1_payoffs = np.array([[-1, -3], [0, -2]])\n", "player2_payoffs = np.transpose(player1_payoffs)\n", @@ -505,24 +353,10 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "d42e6545", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[0,1\\right],\\left[0,1\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]]" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "gbt.nash.lcp_solve(gbt_prisoners_dilemma_game).equilibria[0]" ] @@ -539,7 +373,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "fcd42af0", "metadata": {}, "outputs": [], @@ -565,28 +399,10 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "7ce6f2e2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Terminal? true\n", - "History: 1, 1\n", - "Returns: -2,-2\n", - "Row actions: \n", - "Col actions: \n", - "Utility matrix:\n", - "-1,-1 -3,0 \n", - "0,-3 -2,-2 " - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state = ops_prisoners_dilemma_game.new_initial_state()\n", "state.apply_actions([1, 1])\n", @@ -604,21 +420,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "d1495c7c", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "matrix_pd_payoffs = game_payoffs_array(ops_prisoners_dilemma_game)\n", "pd_dyn = dynamics.SinglePopulationDynamics(matrix_pd_payoffs, dynamics.replicator)\n", @@ -662,21 +467,10 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "02a42600", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'EFG 2 R \"tiny_hanabi()\" { \"Pl0\" \"Pl1\" } \\nc \"\" 1 \"\" { \"d0\" 0.5000000000000000 \"d1\" 0.5000000000000000 } 0\\n c \"p0:d0\" 2 \"\" { \"d0\" 0.5000000000000000 \"d1\" 0.5000000000000000 } 0\\n p \"\" 1 1 \"\" { \"p0a0\" \"p0a1\" \"p0a2\" } 0\\n p \"\" 2 1 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 1 \"\" { 10.0 10.0 }\\n t \"\" 2 \"\" { 0.0 0.0 }\\n t \"\" 3 \"\" { 0.0 0.0 }\\n p \"\" 2 2 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 4 \"\" { 4.0 4.0 }\\n t \"\" 5 \"\" { 8.0 8.0 }\\n t \"\" 6 \"\" { 4.0 4.0 }\\n p \"\" 2 3 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 7 \"\" { 10.0 10.0 }\\n t \"\" 8 \"\" { 0.0 0.0 }\\n t \"\" 9 \"\" { 0.0 0.0 }\\n p \"\" 1 1 \"\" { \"p0a0\" \"p0a1\" \"p0a2\" } 0\\n p \"\" 2 4 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 10 \"\" { 0.0 0.0 }\\n t \"\" 11 \"\" { 0.0 0.0 }\\n t \"\" 12 \"\" { 10.0 10.0 }\\n p \"\" 2 5 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 13 \"\" { 4.0 4.0 }\\n t \"\" 14 \"\" { 8.0 8.0 }\\n t \"\" 15 \"\" { 4.0 4.0 }\\n p \"\" 2 6 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 16 \"\" { 0.0 0.0 }\\n t \"\" 17 \"\" { 0.0 0.0 }\\n t \"\" 18 \"\" { 10.0 10.0 }\\n c \"p0:d1\" 3 \"\" { \"d0\" 0.5000000000000000 \"d1\" 0.5000000000000000 } 0\\n p \"\" 1 2 \"\" { \"p0a0\" \"p0a1\" \"p0a2\" } 0\\n p \"\" 2 1 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 19 \"\" { 0.0 0.0 }\\n t \"\" 20 \"\" { 0.0 0.0 }\\n t \"\" 21 \"\" { 10.0 10.0 }\\n p \"\" 2 2 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 22 \"\" { 4.0 4.0 }\\n t \"\" 23 \"\" { 8.0 8.0 }\\n t \"\" 24 \"\" { 4.0 4.0 }\\n p \"\" 2 3 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 25 \"\" { 0.0 0.0 }\\n t \"\" 26 \"\" { 0.0 0.0 }\\n t \"\" 27 \"\" { 0.0 0.0 }\\n p \"\" 1 2 \"\" { \"p0a0\" \"p0a1\" \"p0a2\" } 0\\n p \"\" 2 4 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 28 \"\" { 10.0 10.0 }\\n t \"\" 29 \"\" { 0.0 0.0 }\\n t \"\" 30 \"\" { 0.0 0.0 }\\n p \"\" 2 5 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 31 \"\" { 4.0 4.0 }\\n t \"\" 32 \"\" { 8.0 8.0 }\\n t \"\" 33 \"\" { 4.0 4.0 }\\n p \"\" 2 6 \"\" { \"p1a0\" \"p1a1\" \"p1a2\" } 0\\n t \"\" 34 \"\" { 10.0 10.0 }\\n t \"\" 35 \"\" { 0.0 0.0 }\\n t \"\" 36 \"\" { 0.0 0.0 }\\n'" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ops_hanabi_game = pyspiel.load_game(\"tiny_hanabi\")\n", "efg_hanabi_game = export_gambit(ops_hanabi_game)\n", @@ -694,7 +488,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "1a534e25", "metadata": {}, "outputs": [], @@ -705,1517 +499,10 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "b913fc7a", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from draw_tree import draw_tree\n", "\n", @@ -2238,24 +525,10 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "1ec19b1c", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[0,0,1\\right],\\left[0,1,0\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(0, 1), Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1), Rational(0, 1)]]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm[\"Pl0\"]" ] @@ -2270,19 +543,10 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "ae9fc7a7", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "At information set 0, Player 0 plays action 0 with probability: 0 and action 1 with probability: 0 and action 2 with probability: 1\n", - "At information set 1, Player 0 plays action 0 with probability: 0 and action 1 with probability: 1 and action 2 with probability: 0\n" - ] - } - ], + "outputs": [], "source": [ "for infoset, mixed_action in eqm[\"Pl0\"].mixed_actions():\n", " print(\n", @@ -2303,47 +567,20 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "id": "8528e1bd", "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\left[\\left[0,0,1\\right],\\left[0,1,0\\right],\\left[1,0,0\\right],\\left[0,0,1\\right],\\left[0,1,0\\right],\\left[0,0,1\\right]\\right]$" - ], - "text/plain": [ - "[[Rational(0, 1), Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1), Rational(0, 1)], [Rational(0, 1), Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1), Rational(0, 1)], [Rational(0, 1), Rational(0, 1), Rational(1, 1)]]" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "eqm[\"Pl1\"]" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "id": "2965aed0", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "At information set 0, Player 1 plays action 0 with probability: 0 and action 1 with probability: 0 and action 2 with probability: 1\n", - "At information set 1, Player 1 plays action 0 with probability: 0 and action 1 with probability: 1 and action 2 with probability: 0\n", - "At information set 2, Player 1 plays action 0 with probability: 1 and action 1 with probability: 0 and action 2 with probability: 0\n", - "At information set 3, Player 1 plays action 0 with probability: 0 and action 1 with probability: 0 and action 2 with probability: 1\n", - "At information set 4, Player 1 plays action 0 with probability: 0 and action 1 with probability: 1 and action 2 with probability: 0\n", - "At information set 5, Player 1 plays action 0 with probability: 0 and action 1 with probability: 0 and action 2 with probability: 1\n" - ] - } - ], + "outputs": [], "source": [ "for infoset, mixed_action in eqm[\"Pl1\"].mixed_actions():\n", " print(\n", @@ -2368,7 +605,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "id": "4e72c924", "metadata": {}, "outputs": [], @@ -2395,21 +632,10 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "id": "53547263", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Episodes: 0\n", - "Episodes: 10000\n", - "Episodes: 20000\n", - "Episodes: 30000\n" - ] - } - ], + "outputs": [], "source": [ "for cur_episode in range(30000):\n", " if cur_episode % 10000 == 0:\n", @@ -2438,26 +664,10 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "id": "d71bc733", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "p0:d0 p1:d0\n", - "Agent 0 chooses p0a2\n", - "\n", - "p0:d0 p1:d0 p0:a2\n", - "Agent 1 chooses p1a0\n", - "\n", - "p0:d0 p1:d0 p0:a2 p1:a0\n", - "Rewards: [10.0, 10.0]\n" - ] - } - ], + "outputs": [], "source": [ "time_step = env.reset()\n", "\n", @@ -2500,7 +710,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "77dc34c8", "metadata": {}, "outputs": [], @@ -2572,344 +782,10 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "id": "ed920d33-b7c6-4cc1-b055-7244a5bf42d8", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "draw_tree(gbt_one_card_poker, color_scheme=\"gambit\")" ] @@ -2924,21 +800,10 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "id": "07340e32", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "efg_game()" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ops_one_card_poker = pyspiel.load_efg_game(gbt_one_card_poker.to_efg())\n", "ops_one_card_poker" @@ -2956,21 +821,10 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "id": "c01c4d6f", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ops_one_card_poker.num_distinct_actions()" ] @@ -2987,21 +841,10 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "id": "3b9cc43b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0: Chance: 1 King 0.5 Queen 0.5" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state = ops_one_card_poker.new_initial_state()\n", "state" @@ -3009,21 +852,10 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, "id": "e23df723", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[0, 1]" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state.legal_actions()" ] @@ -3038,21 +870,10 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "id": "4dd5d504", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1: Player: 1 1 Bet Fold" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state.apply_action(0)\n", "state" @@ -3060,21 +881,10 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "id": "be557706", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[0, 1]" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state.legal_actions()" ] @@ -3090,21 +900,10 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": null, "id": "bd15369f", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3: Player: 2 1 Call Fold" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state.apply_action(0)\n", "state" @@ -3120,21 +919,10 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": null, "id": "8d81ff6b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2]" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state.legal_actions()" ] @@ -3150,21 +938,10 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": null, "id": "97913fe5", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6: Terminal: Win 1 -1" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "state.apply_action(2)\n", "state" From 4be788798e132656fdc7aea79af54a925caca156 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 13:59:59 +0000 Subject: [PATCH 82/84] typo --- doc/tutorials/creating_images.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/creating_images.ipynb index 73af14da5..ca7542697 100644 --- a/doc/tutorials/creating_images.ipynb +++ b/doc/tutorials/creating_images.ipynb @@ -328,7 +328,7 @@ "source": [ "## Further adjustments to game images\n", "\n", - "If your image requires further adjustments, you can manually edit your games `.ef` file.\n", + "If your image requires further adjustments, you can manually edit your game's `.ef` file.\n", "You can find information on EF format specs in the [draw_tree docs](https://github.com/gambitproject/draw_tree).\n", "\n", "EF files that are manually created or (exported from [Game Theory Explorer](https://gametheoryexplorer-a68c7.web.app/) can be drawn by `draw_tree` with the same functions explored in this tutorial, but you should drop the formatting parameters:\n", From e1a7e98789091c75d592706a481ba69b9ca7b138 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 14:01:17 +0000 Subject: [PATCH 83/84] tidy read and save sections --- doc/tutorials/01_quickstart.ipynb | 39 +++++++-------------------- doc/tutorials/02_extensive_form.ipynb | 39 +++++++-------------------- 2 files changed, 20 insertions(+), 58 deletions(-) diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb index 5b83324f6..354f74dda 100644 --- a/doc/tutorials/01_quickstart.ipynb +++ b/doc/tutorials/01_quickstart.ipynb @@ -355,35 +355,16 @@ "The specific format depends on whether the game is normal or extensive-form.\n", "\n", "Here we'll save the Prisoner's Dilemma (Normal-form) to the `.nfg` format.\n", - "Uncomment these lines of code if you're running the tutorial locally:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f58eaa77", - "metadata": {}, - "outputs": [], - "source": [ - "# g.to_nfg(\"prisoners_dilemma.nfg\")" - ] - }, - { - "cell_type": "markdown", - "id": "e373be1e", - "metadata": {}, - "source": [ - "You can easily restore the game object from file like so:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4119a2ac", - "metadata": {}, - "outputs": [], - "source": [ - "# gbt.read_nfg(\"prisoners_dilemma.nfg\")" + "\n", + "```python\n", + "g.to_nfg(\"prisoners_dilemma.nfg\")\n", + "```\n", + "\n", + "You can easily restore the game object from file like so:\n", + "\n", + "```python\n", + "gbt.read_nfg(\"prisoners_dilemma.nfg\")\n", + "```" ] } ], diff --git a/doc/tutorials/02_extensive_form.ipynb b/doc/tutorials/02_extensive_form.ipynb index 2f444b0ca..81fd527bf 100644 --- a/doc/tutorials/02_extensive_form.ipynb +++ b/doc/tutorials/02_extensive_form.ipynb @@ -274,35 +274,16 @@ "The specific format depends on whether the game is normal or extensive-form.\n", "\n", "Here we'll save the Trust game (extensive-form) to the `.efg` format.\n", - "Uncomment these lines of code if you're running the tutorial locally:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "37c51152", - "metadata": {}, - "outputs": [], - "source": [ - "# g.to_efg(\"trust_game.efg\")" - ] - }, - { - "cell_type": "markdown", - "id": "0eb31525", - "metadata": {}, - "source": [ - "You can easily restore the game object from file like so:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0d86a750", - "metadata": {}, - "outputs": [], - "source": [ - "# gbt.read_efg(\"trust_game.efg\")" + "\n", + "```python\n", + "g.to_efg(\"trust_game.efg\")\n", + "```\n", + "\n", + "You can easily restore the game object from file like so:\n", + "\n", + "```python\n", + "gbt.read_efg(\"trust_game.efg\")\n", + "```" ] }, { From f4113e88fb21eea6b142ffbe85ba85dbb634feda Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Fri, 13 Feb 2026 14:10:20 +0000 Subject: [PATCH 84/84] renumber and reorder tutorials --- doc/pygambit.rst | 8 ++++---- .../{creating_images.ipynb => 04_creating_images.ipynb} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename doc/tutorials/{creating_images.ipynb => 04_creating_images.ipynb} (99%) diff --git a/doc/pygambit.rst b/doc/pygambit.rst index 2bc678eb5..c4c0cbf69 100644 --- a/doc/pygambit.rst +++ b/doc/pygambit.rst @@ -8,8 +8,9 @@ See installation instructions in the :ref:`install` section. For newcomers to Gambit, we recommend reading through the PyGambit tutorials, which demonstrate the API's key capabilities for analyzing and solving games. -These tutorials are available to be run interactively as Jupyter notebooks, see :ref:`local_tutorials`. -All of the tutorials assume a basic knowledge of programming in Python. +All of these tutorials assume a basic knowledge of programming in Python. + +You can run the tutorials interactively as Jupyter notebooks, see :ref:`local_tutorials`. New user tutorials ------------------ @@ -20,11 +21,10 @@ They are numbered in the order they should be read. .. toctree:: :maxdepth: 2 - tutorials/running_locally tutorials/01_quickstart tutorials/02_extensive_form tutorials/03_stripped_down_poker - tutorials/creating_images + tutorials/04_creating_images Advanced user tutorials ----------------------- diff --git a/doc/tutorials/creating_images.ipynb b/doc/tutorials/04_creating_images.ipynb similarity index 99% rename from doc/tutorials/creating_images.ipynb rename to doc/tutorials/04_creating_images.ipynb index ca7542697..19f618d6d 100644 --- a/doc/tutorials/creating_images.ipynb +++ b/doc/tutorials/04_creating_images.ipynb @@ -5,7 +5,7 @@ "id": "a2d556ea-37b0-47c5-a199-2cbfc68c95a9", "metadata": {}, "source": [ - "# Creating publication-ready game images" + "# 4) Creating publication-ready game images" ] }, {