Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 62 additions & 62 deletions build_support/catalog/test_update.py

Large diffs are not rendered by default.

38 changes: 19 additions & 19 deletions build_support/catalog/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@

import pandas as pd
import yaml
from draw_tree import generate_pdf, generate_png, generate_svg, generate_tex
from gtdraw import pdf, png, svg, tex

import pygambit as gbt

CATALOG_RST_TABLE = Path(__file__).parent.parent.parent / "doc" / "catalog_table.rst"
CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog"
MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am"
DRAW_TREE_SETTINGS_CONFIG = Path(__file__).parent / "draw_tree_settings.yaml"
GTDRAW_SETTINGS_CONFIG = Path(__file__).parent / "gtdraw_settings.yaml"
CATALOG_HIERARCHY_CONFIG = Path(__file__).parent / "catalog_hierarchy.yaml"
SUPPORTED_GAME_FORMATS = {"efg", "nfg"}


def catalog_draw_tree_settings(slug: str) -> dict:
"""Return the draw_tree settings for a given catalog slug."""
with open(DRAW_TREE_SETTINGS_CONFIG, encoding="utf-8") as f:
def catalog_gtdraw_settings(slug: str) -> dict:
"""Return the gtdraw settings for a given catalog slug."""
with open(GTDRAW_SETTINGS_CONFIG, encoding="utf-8") as f:
config = yaml.safe_load(f)
settings = dict(config["defaults"])
overrides = config.get("overrides", {})
Expand Down Expand Up @@ -166,8 +166,8 @@ def _write_game_entry(
if variant["ef_path"].exists()
else gbt.catalog.load(slug)
)
for func in [generate_tex, generate_png, generate_pdf, generate_svg]:
func(source, save_to=str(viz_path), **catalog_draw_tree_settings(vkey))
for func in [tex, png, pdf, svg]:
func(source, save_to=str(viz_path), **catalog_gtdraw_settings(vkey))
img_ef = catalog_dir / "img" / f"{vkey}.ef"
if not img_ef.exists() and variant["ef_path"].exists():
shutil.copy2(variant["ef_path"], img_ef)
Expand All @@ -185,8 +185,8 @@ def _write_game_entry(
viz_path.parent.mkdir(parents=True, exist_ok=True)
curated_ef = catalog_dir / f"{slug}.ef"
source = str(curated_ef) if curated_ef.exists() else gbt.catalog.load(slug)
for func in [generate_tex, generate_png, generate_pdf, generate_svg]:
func(source, save_to=str(viz_path), **catalog_draw_tree_settings(slug))
for func in [tex, png, pdf, svg]:
func(source, save_to=str(viz_path), **catalog_gtdraw_settings(slug))
img_ef = catalog_dir / "img" / f"{slug}.ef"
if not img_ef.exists() and curated_ef.exists():
shutil.copy2(curated_ef, img_ef)
Expand Down Expand Up @@ -228,39 +228,39 @@ def _write_game_entry(
label = variant["label"]
vkey = variant["variant_key"]
settings_str = ", ".join(
f"{k}={v!r}" for k, v in catalog_draw_tree_settings(vkey).items()
f"{k}={v!r}" for k, v in catalog_gtdraw_settings(vkey).items()
)
f.write(f"{i2}.. tab-item:: {label}\n")
f.write(f"{i2}\n")
f.write(f"{i3}.. jupyter-execute::\n")
f.write(f"{i3} :hide-code:\n")
f.write(f"{i3} \n")
f.write(f"{i4}import pygambit\n")
f.write(f"{i4}from draw_tree import draw_tree\n")
f.write(f"{i4}from gtdraw import draw\n")
if variant["ef_path"].exists():
f.write(f'{i4}draw_tree("../catalog/{vkey}.ef", {settings_str})\n')
f.write(f'{i4}draw("../catalog/{vkey}.ef", {settings_str})\n')
else:
f.write(f'{i4}draw_tree(pygambit.catalog.load("{slug}"), {settings_str})\n')
f.write(f'{i4}draw(pygambit.catalog.load("{slug}"), {settings_str})\n')
f.write(f"{i2}\n")
f.write(f"{i1}\n")
else:
f.write(f"{i1}.. jupyter-execute::\n")
f.write(f"{i1} :hide-code:\n")
f.write(f"{i1} \n")
f.write(f"{i2}import pygambit\n")
f.write(f"{i2}from draw_tree import draw_tree\n")
f.write(f"{i2}from gtdraw import draw\n")
if row["Format"] == "efg":
settings_str = ", ".join(
f"{k}={v!r}" for k, v in catalog_draw_tree_settings(slug).items()
f"{k}={v!r}" for k, v in catalog_gtdraw_settings(slug).items()
)
curated_ef = catalog_dir / f"{slug}.ef"
if curated_ef.exists():
f.write(f'{i2}draw_tree("../catalog/{slug}.ef", {settings_str})\n')
f.write(f'{i2}draw("../catalog/{slug}.ef", {settings_str})\n')
else:
f.write(f'{i2}draw_tree(pygambit.catalog.load("{slug}"), {settings_str})\n')
f.write(f'{i2}draw(pygambit.catalog.load("{slug}"), {settings_str})\n')
elif row["Format"] == "nfg":
f.write(
f'{i2}draw_tree(pygambit.catalog.load("{slug}"), '
f'{i2}draw(pygambit.catalog.load("{slug}"), '
f'save_to="../catalog/img/{slug}.png")\n'
)
f.write(f"{i1}\n")
Expand Down Expand Up @@ -403,7 +403,7 @@ def update_makefile(
help=(
"Force regeneration of all game visualisation images (PNG, PDF, SVG, TeX), "
"even if they already exist. Use this to pick up changes to game files or "
"draw_tree_settings.yaml."
"gtdraw_settings.yaml."
),
)
args = parser.parse_args()
Expand Down
12 changes: 6 additions & 6 deletions doc/developer.catalog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Currently supported representations are:
(e.g. ``catalog/source/game.ef``).
When present, ``update.py`` will use this file directly as input to DrawTree instead of
auto-generating the layout from the ``.efg``, preserving any hand-tuned layout.
Consult the `DrawTree docs <https://www.gambit-project.org/draw_tree/>`_ for the ``.ef`` format.
Consult the `DrawTree docs <https://www.gambit-project.org/gtdraw/>`_ for the ``.ef`` format.

In general, ``.ef`` files should only be added when the layout they provide differs significantly
from what DrawTree produces automatically; if the auto-generated layout is reasonable, there is
Expand All @@ -101,10 +101,10 @@ Currently supported representations are:

Ensure you have installed the package in editable mode to automatically pick up the new game file(s) in the ``pygambit.catalog`` module without reinstalling each time.
Then use the ``update.py`` script to update Gambit's documentation & build files, as well as generating images for the new game(s).
If you want to customise the visualisation parameters for your game(s), edit ``build_support/catalog/draw_tree_settings.yaml``.
If you want to customise the visualisation parameters for your game(s), edit ``build_support/catalog/gtdraw_settings.yaml``.
Add an entry under ``overrides`` keyed by your game's exact slug, or by a shared prefix (e.g. the author-year folder name) to apply settings to all games from that source.
More specific entries (longer keys) take precedence over shorter ones.
Consult the `DrawTree docs <https://www.gambit-project.org/draw_tree/>`_ for available settings.
Consult the `DrawTree docs <https://www.gambit-project.org/gtdraw/>`_ for available settings.

.. code-block:: bash

Expand All @@ -129,8 +129,8 @@ Currently supported representations are:

.. tip::

If the game visuals for extensive form games need some work and you aren't sure which settings to change in ``build_support/catalog/draw_tree_settings.yaml``, try loading the EFG in the DrawTree GUI and adjusting the layout there.
There is an option to `download settings <https://www.gambit-project.org/draw_tree/gui/#exporting-and-reusing-settings>`_ which can be used in the Gambit catalog.
If the game visuals for extensive form games need some work and you aren't sure which settings to change in ``build_support/catalog/gtdraw_settings.yaml``, try loading the EFG in the DrawTree GUI and adjusting the layout there.
There is an option to `download settings <https://www.gambit-project.org/gtdraw/gui/#exporting-and-reusing-settings>`_ which can be used in the Gambit catalog.

5. **[Optional] Test your updates to the documentation locally:**

Expand All @@ -142,7 +142,7 @@ Currently supported representations are:
6. **Submit a pull request to GitHub with all changes.**

Submit a PR according to the :ref:`usual workflow <submit-contribution>`.
Ensure that any additions and changes to game files, ``build_support/catalog/draw_tree_settings.yaml``, ``build_support/catalog/update.py`` and ``build_support/catalog/catalog.am`` are included.
Ensure that any additions and changes to game files, ``build_support/catalog/gtdraw_settings.yaml``, ``build_support/catalog/update.py`` and ``build_support/catalog/catalog.am`` are included.

.. important::

Expand Down
60 changes: 9 additions & 51 deletions doc/tutorials/02_extensive_form.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,15 @@
"cell_type": "markdown",
"id": "96019084",
"metadata": {},
"source": [
"# 2) Extensive-form games\n",
"\n",
"In the first tutorial, we used Gambit to set up the Prisoner's Dilemma, an example of a normal (strategic) form game.\n",
"\n",
"Gambit can also be used to set up extensive-form games; the game is represented as a tree, where each node represents a decision point for a player, and the branches represent the possible actions they can take.\n",
"\n",
"**Example: One-shot trust game with binary actions**\n",
"\n",
"[Kreps (1990)](#references) introduced a game commonly referred to as the **trust game**.\n",
"We will build a one-shot version of this game using Gambit's game transformation operations.\n",
"\n",
"The game can be defined as follows:\n",
"- There are two players, a **Buyer** and a **Seller**.\n",
"- The Buyer moves first and has two actions, **Trust** or **Not trust**.\n",
"- If the Buyer chooses **Not trust**, then the game ends, and both players receive payoffs of `0`.\n",
"- If the Buyer chooses **Trust**, then the Seller has a choice with two actions, **Honor** or **Abuse**.\n",
"- If the Seller chooses **Honor**, both players receive payoffs of `1`;\n",
"- If the Seller chooses **Abuse**, the Buyer receives a payoff of `-1` and the Seller receives a payoff of `2`.\n",
"\n",
"In addition to `pygambit`, this tutorial introduces the `draw_tree` package, which can be used to draw extensive form games in Python.\n",
"If you're running this tutorial on your local machine, you'll need to install the requirements for [draw_tree](https://github.com/gambitproject/draw_tree), which include LaTeX, in order to run the `draw_tree` cells.\n",
"Another option for visualising extensive form games is to install the Gambit GUI and use it to load the EFG file generated at the end of this tutorial."
]
"source": "# 2) Extensive-form games\n\nIn the first tutorial, we used Gambit to set up the Prisoner's Dilemma, an example of a normal (strategic) form game.\n\nGambit can also be used to set up extensive-form games; the game is represented as a tree, where each node represents a decision point for a player, and the branches represent the possible actions they can take.\n\n**Example: One-shot trust game with binary actions**\n\n[Kreps (1990)](#references) introduced a game commonly referred to as the **trust game**.\nWe will build a one-shot version of this game using Gambit's game transformation operations.\n\nThe game can be defined as follows:\n- There are two players, a **Buyer** and a **Seller**.\n- The Buyer moves first and has two actions, **Trust** or **Not trust**.\n- If the Buyer chooses **Not trust**, then the game ends, and both players receive payoffs of `0`.\n- If the Buyer chooses **Trust**, then the Seller has a choice with two actions, **Honor** or **Abuse**.\n- If the Seller chooses **Honor**, both players receive payoffs of `1`;\n- If the Seller chooses **Abuse**, the Buyer receives a payoff of `-1` and the Seller receives a payoff of `2`.\n\nIn addition to `pygambit`, this tutorial introduces the `gtdraw` package, which can be used to draw extensive form games in Python.\nIf you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\nAnother option for visualising extensive form games is to install the Gambit GUI and use it to load the EFG file generated at the end of this tutorial."
},
{
"cell_type": "code",
"execution_count": null,
"id": "5946289b",
"metadata": {},
"outputs": [],
"source": [
"from draw_tree import draw_tree\n",
"\n",
"import pygambit as gbt"
]
"source": "from gtdraw import draw\n\nimport pygambit as gbt"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -76,9 +49,7 @@
"id": "3cd94917",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g)"
]
"source": "draw(g)"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -110,9 +81,7 @@
"id": "45638fda-7e25-4c8e-b709-24b05780581b",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g)"
]
"source": "draw(g)"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -142,9 +111,7 @@
"id": "ce41e9fe-cca4-46fb-8e9d-b2c27342e5ef",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g)"
]
"source": "draw(g)"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -180,9 +147,7 @@
"id": "b3408c55-714e-4a6f-b598-e338839442e4",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g)"
]
"source": "draw(g)"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -214,9 +179,7 @@
"id": "09bedb3a-aac7-46e6-ae93-c47932c746d4",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g)"
]
"source": "draw(g)"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -248,9 +211,7 @@
"id": "cba0e562-2989-4dae-a0f0-b121635ba032",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g)"
]
"source": "draw(g)"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -297,10 +258,7 @@
"id": "56899a29-cc53-48db-9eb4-ed2295517400",
"metadata": {},
"outputs": [],
"source": [
"g = gbt.catalog.load(\"journals/ijgt/selten1975/fig2\")\n",
"draw_tree(g)"
]
"source": "g = gbt.catalog.load(\"journals/ijgt/selten1975/fig2\")\ndraw(g)"
},
{
"cell_type": "markdown",
Expand Down
55 changes: 6 additions & 49 deletions doc/tutorials/03_stripped_down_poker.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,15 @@
"cell_type": "markdown",
"id": "98eb65d8",
"metadata": {},
"source": [
"# 3) Stripped-down poker\n",
"\n",
"In this tutorial, we'll create an extensive-form representation of a one-card poker game from [Reiley et al (2008)](#references), a classroom game under the name \"stripped-down poker\".\n",
"This is perhaps the simplest interesting game with imperfect information.\n",
"\n",
"We'll use \"stripped-down poker\" to demonstrate and explain the following with Gambit:\n",
"\n",
"1. Setting up an extensive-form game with imperfect information using [information sets](#information-sets)\n",
"2. [Computing and interpreting Nash equilibria](#computing-and-interpreting-nash-equilibria) and understanding mixed behaviour and mixed strategy profiles\n",
"3. [Acceptance criteria for Nash equilibria](#acceptance-criteria-for-nash-equilibria)\n",
"\n",
"In our version of the game, there are two players, **Alice** and **Bob**, and a deck of cards, with equal numbers of **King** and **Queen** cards.\n",
"\n",
"- The game begins with each player putting \\$1 in the pot.\n",
" - A card is dealt at random to Alice.\n",
" - Alice observes her card.\n",
" - Bob does not observe the card.\n",
"- Alice then chooses either to **Bet** or to **Fold**.\n",
" - If she chooses to Fold, Bob wins the pot and the game ends.\n",
" - If she chooses to Bet, she adds another \\$1 to the pot.\n",
"- Bob then chooses either to **Call** or **Fold**.\n",
" - If he chooses to Fold, Alice wins the pot and the game ends.\n",
" - If he chooses to Call, he adds another $1 to the pot.\n",
"- There is then a showdown, in which Alice reveals her card.\n",
" - If she has a King, then she wins the pot.\n",
" - If she has a Queen, then Bob wins the pot.\n",
"\n",
"In addition to `pygambit`, this tutorial uses the `draw_tree` package, which can be used to draw extensive form games in Python.\n",
"If you're running this tutorial on your local machine, you'll need to install the requirements for [draw_tree](https://github.com/gambitproject/draw_tree), which include LaTeX, in order to run the `draw_tree` cells.\n",
"Another option for visualising extensive form games is to install the Gambit GUI and use it to load a saved EFG file."
]
"source": "# 3) Stripped-down poker\n\nIn this tutorial, we'll create an extensive-form representation of a one-card poker game from [Reiley et al (2008)](#references), a classroom game under the name \"stripped-down poker\".\nThis is perhaps the simplest interesting game with imperfect information.\n\nWe'll use \"stripped-down poker\" to demonstrate and explain the following with Gambit:\n\n1. Setting up an extensive-form game with imperfect information using [information sets](#information-sets)\n2. [Computing and interpreting Nash equilibria](#computing-and-interpreting-nash-equilibria) and understanding mixed behaviour and mixed strategy profiles\n3. [Acceptance criteria for Nash equilibria](#acceptance-criteria-for-nash-equilibria)\n\nIn our version of the game, there are two players, **Alice** and **Bob**, and a deck of cards, with equal numbers of **King** and **Queen** cards.\n\n- The game begins with each player putting \\$1 in the pot.\n - A card is dealt at random to Alice.\n - Alice observes her card.\n - Bob does not observe the card.\n- Alice then chooses either to **Bet** or to **Fold**.\n - If she chooses to Fold, Bob wins the pot and the game ends.\n - If she chooses to Bet, she adds another \\$1 to the pot.\n- Bob then chooses either to **Call** or **Fold**.\n - If he chooses to Fold, Alice wins the pot and the game ends.\n - If he chooses to Call, he adds another $1 to the pot.\n- There is then a showdown, in which Alice reveals her card.\n - If she has a King, then she wins the pot.\n - If she has a Queen, then Bob wins the pot.\n\nIn addition to `pygambit`, this tutorial uses the `gtdraw` package, which can be used to draw extensive form games in Python.\nIf you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\nAnother option for visualising extensive form games is to install the Gambit GUI and use it to load a saved EFG file."
},
{
"cell_type": "code",
"execution_count": null,
"id": "69cbfe81",
"metadata": {},
"outputs": [],
"source": [
"from draw_tree import draw_tree\n",
"\n",
"import pygambit as gbt"
]
"source": "from gtdraw import draw\n\nimport pygambit as gbt"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -124,9 +89,7 @@
"id": "867cb1d8-7a5d-45d1-9349-9bbc2a4e2344",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g, color_scheme=\"gambit\")"
]
"source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -163,9 +126,7 @@
"id": "0c522c2d-992e-48b6-a1f8-0696d33cdbe0",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g, color_scheme=\"gambit\")"
]
"source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -205,9 +166,7 @@
"id": "e85b3346-2fea-4a73-aa72-9efb436c68c1",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g, color_scheme=\"gambit\")"
]
"source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -271,9 +230,7 @@
"id": "fdee7b53-7820-44df-9d17-d15d0b9667aa",
"metadata": {},
"outputs": [],
"source": [
"draw_tree(g, color_scheme=\"gambit\")"
]
"source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
Expand Down
Loading
Loading