Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6085e9d
docs: add wyz2368 as a contributor for code, and research (#970)
allcontributors[bot] Jul 3, 2026
5482aaa
Reject malformed AGG/BAGG headers before construction (#971)
d-kad Jul 3, 2026
39deff0
Add enumpoly solver strategic-form tests (#969)
ameliekleber Jul 3, 2026
1bf645e
Bump actions/checkout from 6 to 7 (#975)
dependabot[bot] Jul 6, 2026
469afe3
Make label normalization mandatory and collision-safe, and retime it …
d-kad Jul 6, 2026
4d06f00
Improve UX of GUI player label editing (#976)
tturocy Jul 6, 2026
49930f3
Enforce optional, unique-when-present labels for nodes and informatio…
d-kad Jul 8, 2026
e02a610
Small UX/layout improvement to dialog warning on unsaved changes (#980)
tturocy Jul 8, 2026
df7ec06
Document default object labeling in new_table, from_arrays, and from_…
d-kad Jul 9, 2026
592fa0b
Enforce unique, nonempty labels for players (#979)
d-kad Jul 9, 2026
7d21fa6
Enforce unique, nonempty labels for strategies (#981)
d-kad Jul 9, 2026
f143296
Fix incorrect remembering of old files in catalog build (#985)
wyz2368 Jul 10, 2026
93b10bb
Correct cross-reference link to enumpoly documentation in `enumpoly_s…
tturocy Jul 10, 2026
6e5a8bd
Enforce unique, nonempty labels for outcomes (#982)
d-kad Jul 10, 2026
a79e549
Improved UX for editing labels in GUI (#966)
tturocy Jul 10, 2026
e962da7
Add EFGs from shohamleytonbrown2008 (#987)
wyz2368 Jul 10, 2026
2e3e53f
Bump version and prepare ChangeLog for 16.7 (#988)
tturocy Jul 11, 2026
a611f8b
Refactor control of long-running external processes in GUI (#993)
tturocy Jul 20, 2026
6b8020d
Create bespoke XML read/write for legacy file format. (#995)
tturocy Jul 20, 2026
91dbc24
Add missing header for std::strlen (#997)
tturocy Jul 20, 2026
cf05ce1
Standardisation cleanups in `lcp_solve` (#996)
tturocy Jul 20, 2026
a1b6b0f
Correct `gnm_solve` to execute callback when equilibria are found rat…
tturocy Jul 21, 2026
644d1c6
Standardise callbacks for Nash computation algorithms (#1000)
tturocy Jul 21, 2026
d58c9f4
Create a specification object to document algorithm selection and par…
tturocy Jul 21, 2026
7ca8952
Correct sparsity violation in representation of behaviour associated …
tturocy Jul 22, 2026
764c361
Bump actions/setup-python from 6 to 7 (#1005)
dependabot[bot] Jul 27, 2026
de4a8bd
One equilibrium tests
AndresFerCervell Jul 28, 2026
a8d4909
One equilibrium tests
AndresFerCervell Jul 28, 2026
d146f7e
Added missing guards against games of imperfect recall in enumpoly. (…
tturocy Jul 28, 2026
160bf99
Merge remote-tracking branch 'upstream/master' into feature/hp_tests
AndresFerCervell Jul 30, 2026
704ea7a
New tests
AndresFerCervell Jul 31, 2026
eaccabb
Removing books/vonstengel2022/fig10.12 test
AndresFerCervell Jul 31, 2026
be0f0c1
Delete tests/test_games/2x2x2.nfg
AndresFerCervell Aug 1, 2026
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
10 changes: 10 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
"contributions": [
"code"
]
},
{
"login": "wyz2368",
"name": "wyz2368",
"avatar_url": "https://avatars.githubusercontent.com/u/25018133?v=4",
"profile": "https://github.com/wyz2368",
"contributions": [
"code",
"research"
]
}
]
}
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
- uses: actions/setup-python@v7
with:
python-version: "3.14"
- uses: py-actions/flake8@v2
Expand All @@ -56,7 +56,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: "3.14"
- name: Install Python packages
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
Expand Down Expand Up @@ -44,7 +44,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
Expand All @@ -67,7 +67,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
Expand All @@ -90,7 +90,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
create-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7

- name: Extract changelog for this version
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: '3.x'
- name: Set up dependencies
Expand Down
7 changes: 0 additions & 7 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,3 @@ wxWidgets, which are Copyright (C) 2004-5 by John Labenski, and distributed
under the wxWidgets license. The version included here is the version
dated 20 July 2005; see http://wxcode.sourceforge.net for details on these
classes.

TinyXML parser:
---------------
The graphical interface reads and writes files in XML format. The parsing
is done using the TinyXml package from http://www.grinninglizard.com/tinyxml,
and is distributed under the zlib license. These are the files named
tiny* in the sources/gui directory of the distribution.
22 changes: 21 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
## [16.7.0] - unreleased
## [17.0.0] - unreleased

### Changed
- `lcp_solve` no longer silently absorbs internal exceptions if they occur, but instead these propagate out
to match the behaviour of all other Nash equilibrium solvers. (#996)
- `gnm_solve` executes callback when equilibrium is found rather than emitting all equilibria at the end of
the run. (#998)
- Implemented bespoke XML parser that handles the subset in the de-facto legacy XML workbook .gbt format;
removes dependency on tinyxml. (#897)

### Fixed
- Converting a behavior profile to a strategy profile, and computing pure-strategy payoffs
no longer inserts spurious entries into a strategy's internal action map.

## [16.7.0] - 2026-07-11

### Added
- Added `Player.sequences` as the collection of sequences available to a player.
Expand All @@ -25,6 +39,9 @@
- Corrected calculation of total number of actions for a player in `pygambit` (#938)
- Corrected a regression in action graph games that left the internal data structure not fully initialised,
leading to segmentation faults.
- Corrected handling of malformed AGG/BAGG files: files with an invalid or degenerate header
(for example a wrong file type, or a header declaring zero players) are now rejected with a
`ValueError` instead of causing a segmentation fault while constructing the game.

### Changed
- Added a new welcome/landing window on launching the GUI without a game. This has the effect of
Expand All @@ -39,6 +56,9 @@
- In `pygambit`, indexing game object collections by integer position has been removed. (#942)
- Validity of game object labels is enforced (printable ASCII and spaces only, no leading/trailing or
double spaces); invalid labels raise `ValueError` in `pygambit`. (#944)
- Nonempty labels are now required for all players, outcomes, actions, and strategies.
Labels must be unique within the game for players and outcomes, within the player for
strategies, and within the information set for actions.
- Refined and clarified the graphical interface's handling (and persisting) of "workspaces", and
improved warning messages on closing windows for games or workspaces with unsaved changes.
- In `pygambit`, the `.outcome`, `.player`, and `.infoset` attributes are now treated as predicates
Expand Down
14 changes: 8 additions & 6 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,7 @@ core_SOURCES = \
src/core/rational.h \
src/core/matrix.cc \
src/core/function.cc \
src/core/function.h \
src/core/tinyxml.cc \
src/core/tinyxmlerror.cc \
src/core/tinyxmlparser.cc \
src/core/tinyxml.h
src/core/function.h

agg_SOURCES = \
src/games/gameagg.cc \
Expand Down Expand Up @@ -270,6 +266,8 @@ game_SOURCES = \
src/games/stratpure.h \
src/games/stratmixed.h \
src/games/file.cc \
src/games/workspace.cc \
src/games/workspace.h \
src/games/writer.cc \
src/games/writer.h \
src/games/layout.cc \
Expand Down Expand Up @@ -477,8 +475,12 @@ gambit_SOURCES = \
src/gui/analysis.h \
src/gui/app.cc \
src/gui/app.h \
src/gui/editlabel.cc \
src/gui/editlabel.h \
src/gui/edittext.cc \
src/gui/edittext.h \
src/gui/labelcell.cc \
src/gui/labelcell.h \
src/gui/dlabout.cc \
src/gui/dlabout.h \
src/gui/dleditmove.cc \
Expand All @@ -500,7 +502,7 @@ gambit_SOURCES = \
src/gui/dlnash.cc \
src/gui/dlnash.h \
src/gui/dlnashmon.cc \
src/gui/dlnashmon.h \
src/gui/nashspec.h \
src/gui/dlnewtable.cc \
src/gui/dlnewtable.h \
src/gui/dlnfglogit.cc \
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ installable via PyPI.
<td align="center" valign="top" width="14.28%"><a href="https://github.com/StephenPasteris"><img src="https://avatars.githubusercontent.com/u/140617768?v=4?s=100" width="100px;" alt="StephenPasteris"/><br /><sub><b>StephenPasteris</b></sub></a><br /><a href="#research-StephenPasteris" title="Research">🔬</a> <a href="#code-StephenPasteris" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/d-kad"><img src="https://avatars.githubusercontent.com/u/165307096?v=4?s=100" width="100px;" alt="Daniel Kadnikov"/><br /><sub><b>Daniel Kadnikov</b></sub></a><br /><a href="#research-d-kad" title="Research">🔬</a> <a href="#code-d-kad" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AndresFerCervell"><img src="https://avatars.githubusercontent.com/u/153729439?v=4?s=100" width="100px;" alt="Andrés Fernández Cervell"/><br /><sub><b>Andrés Fernández Cervell</b></sub></a><br /><a href="#code-AndresFerCervell" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wyz2368"><img src="https://avatars.githubusercontent.com/u/25018133?v=4?s=100" width="100px;" alt="wyz2368"/><br /><sub><b>wyz2368</b></sub></a><br /><a href="#code-wyz2368" title="Code">💻</a> <a href="#research-wyz2368" title="Research">🔬</a></td>
</tr>
</tbody>
</table>
Expand Down
2 changes: 1 addition & 1 deletion build_support/GAMBIT_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.6.0
16.7.0
19 changes: 19 additions & 0 deletions build_support/catalog/catalog.am
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
CATALOG_FILES = \
catalog/books/myerson1991/fig2_1.efg \
catalog/books/myerson1991/fig4_2.efg \
catalog/books/shohamleytonbrown2008/fig5_1.efg \
catalog/books/shohamleytonbrown2008/fig5_10.efg \
catalog/books/shohamleytonbrown2008/fig5_10__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig5_11.efg \
catalog/books/shohamleytonbrown2008/fig5_11__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig5_12.efg \
catalog/books/shohamleytonbrown2008/fig5_12__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig5_15.efg \
catalog/books/shohamleytonbrown2008/fig5_15__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig5_1__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig5_2.efg \
catalog/books/shohamleytonbrown2008/fig5_2__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig5_9.efg \
catalog/books/shohamleytonbrown2008/fig5_9__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig6_2.efg \
catalog/books/shohamleytonbrown2008/fig6_2__original_layout.ef \
catalog/books/shohamleytonbrown2008/fig6_8.efg \
catalog/books/shohamleytonbrown2008/fig6_8__original_layout.ef \
catalog/books/vonstengel2022/fig10.1.efg \
catalog/books/vonstengel2022/fig10.12.efg \
catalog/books/vonstengel2022/fig10.5.efg \
Expand All @@ -23,6 +41,7 @@ CATALOG_FILES = \
catalog/journals/ijgt/selten1975/fig2.efg \
catalog/journals/ijgt/selten1975/fig3.efg \
catalog/journals/mor/vonstengelforges2008/fig1.efg \
catalog/journals/mor/vonstengelforges2008/fig1__Original_Layout.ef \
catalog/journals/mor/vonstengelforges2008/fig6.efg \
catalog/journals/mor/vonstengelforges2008/fig6__Original_Layout.ef \
catalog/journals/mor/vonstengelforges2008/fig9.efg \
Expand Down
1 change: 1 addition & 0 deletions build_support/catalog/catalog_hierarchy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ labels:
books/myerson1991: "Myerson (1991) — Game Theory: Analysis of Conflict"
books/vonstengel2022: "von Stengel (2022) — Game Theory Basics"
books/watson2013: "Watson (2013) — Strategy: An Introduction to Game Theory"
books/shohamleytonbrown2008: "Shoham and Leyton-Brown (2008) — Multiagent Systems, Algorithmic, Game-Theoretic, and Logical Foundations"
journals/geb/gilboa1997: "Gilboa (1997)"
journals/geb/wichardt2008: "Wichardt (2008)"
journals/ijgt/nau2004: "Nau et al. (2004)"
Expand Down
28 changes: 28 additions & 0 deletions build_support/catalog/gtdraw_settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,31 @@ overrides:
2: '#DD79E0'
3: '#1616BC'
4: '#985003'

books/shohamleytonbrown2008/fig6_8:
scale_factor: 1.0
level_scaling: 1.0
sublevel_scaling: 1.0
width_scaling: 1.0
horizontal: false
mirror: false
shared_terminal_depth: false
color_scheme: colorblind
edge_thickness: 1.0
action_label_position: 0.5
action_label_position_by: player
action_label_dist: 1.0
vary_action_label_positions: false
vary_action_label_positions_by: all
font_family: rmfamily
font_bold: false
font_italic: false
font_size: normalsize
node_size: 1.5
label_bg: false
label_bg_color: white
label_bg_opacity: 0.8
iset_fill: true
iset_fill_opacity: 0.2
iset_boundary: none
legend_position: top-left
51 changes: 51 additions & 0 deletions build_support/catalog/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,57 @@ def _make_image_files(catalog_dir, slug, fmt="efg"):
(img_dir / f"{slug}.ef").touch()


# ---------------------------------------------------------------------------
# Tests for catalog resource selection
# ---------------------------------------------------------------------------


@pytest.mark.catalog_update
class TestCatalogResourceSelection:
def test_catalog_games_uses_requested_catalog_dir_and_restores_resource(
self, tmp_path, monkeypatch
):
stale_dir = tmp_path / "installed_catalog_data"
checkout_dir = tmp_path / "checkout_catalog"
stale_dir.mkdir()
checkout_dir.mkdir()
calls = []

def fake_games(**kwargs):
calls.append((update.gbt.catalog._CATALOG_RESOURCE, kwargs))
return _make_df(_efg_row("checkout/game1"))

monkeypatch.setattr(update.gbt.catalog, "_CATALOG_RESOURCE", stale_dir)
monkeypatch.setattr(update.gbt.catalog, "games", fake_games)

df = update._catalog_games(checkout_dir)

assert calls == [(checkout_dir, {"include_descriptions": True})]
assert stale_dir == update.gbt.catalog._CATALOG_RESOURCE
assert list(df["Game"]) == ["checkout/game1"]

def test_generate_rst_table_uses_requested_catalog_dir_while_rendering(
self, tmp_path, monkeypatch
):
stale_dir = tmp_path / "installed_catalog_data"
checkout_dir = tmp_path / "checkout_catalog"
stale_dir.mkdir()
checkout_dir.mkdir()
observed = []

def fake_write_tree_level(*args, **kwargs):
observed.append(update.gbt.catalog._CATALOG_RESOURCE)

monkeypatch.setattr(update.gbt.catalog, "_CATALOG_RESOURCE", stale_dir)
monkeypatch.setattr(update, "load_hierarchy_labels", lambda: {})
monkeypatch.setattr(update, "_write_tree_level", fake_write_tree_level)

update.generate_rst_table(_make_df(), tmp_path / "out.rst", catalog_dir=checkout_dir)

assert observed == [checkout_dir]
assert stale_dir == update.gbt.catalog._CATALOG_RESOURCE


# ---------------------------------------------------------------------------
# Tests for catalog_gtdraw_settings
# ---------------------------------------------------------------------------
Expand Down
23 changes: 21 additions & 2 deletions build_support/catalog/update.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
import shutil
import sys
from contextlib import contextmanager
from pathlib import Path

import pandas as pd
Expand All @@ -17,6 +18,24 @@
SUPPORTED_GAME_FORMATS = {"efg", "nfg"}


@contextmanager
def _using_catalog_dir(catalog_dir: Path):
"""Temporarily make pygambit.catalog read data from the checked-out catalog."""
old_resource = gbt.catalog._CATALOG_RESOURCE
gbt.catalog._CATALOG_RESOURCE = catalog_dir
try:
yield
finally:
gbt.catalog._CATALOG_RESOURCE = old_resource


def _catalog_games(catalog_dir: Path | None = None) -> pd.DataFrame:
"""Return catalog games using files from *catalog_dir*, not installed package data."""
catalog_dir = catalog_dir or CATALOG_DIR
with _using_catalog_dir(catalog_dir):
return gbt.catalog.games(include_descriptions=True)


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:
Expand Down Expand Up @@ -325,7 +344,7 @@ def generate_rst_table(
catalog_dir = catalog_dir or CATALOG_DIR
labels = load_hierarchy_labels()
tree = _build_slug_tree(df)
with open(rst_path, "w", encoding="utf-8") as f:
with _using_catalog_dir(catalog_dir), open(rst_path, "w", encoding="utf-8") as f:
_write_tree_level(
f, tree, "", labels, catalog_dir, indent="", regenerate_images=regenerate_images
)
Expand Down Expand Up @@ -409,7 +428,7 @@ def update_makefile(
args = parser.parse_args()

# Create RST list-table used by doc/catalog.rst
df = gbt.catalog.games(include_descriptions=True)
df = _catalog_games()
_warn_missing_descriptions(df)
generate_rst_table(df, CATALOG_RST_TABLE, regenerate_images=args.regenerate_images)
print(f"Generated {CATALOG_RST_TABLE} for use in local docs build. DO NOT COMMIT.")
Expand Down
21 changes: 21 additions & 0 deletions catalog/books/shohamleytonbrown2008/fig5_1.efg
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
EFG 2 R "Fig 5.1 from Shoham and Leyton-Brown (2008)" { "1" "2" }

"
Figure 5.1 from :cite:p:`ShoLeyB08`.
This is a sharing game. Imagine a brother and sister sharing two indivisible and identical presents
from their parents. First the brother suggests a split, which can be one of three: he
keeps both, she keeps both, or they each keep one. Then the sister chooses whether
to accept or reject the split. If she accepts they each get their allocated present(s),
and otherwise neither gets any gift.
"

p "" 1 1 "" { "2-0" "1-1" "0-2" } 0
p "" 2 2 "" { "no" "yes" } 0
t "" 1 "" { 0 0 }
t "" 2 "" { 2 0 }
p "" 2 3 "" { "no" "yes" } 0
t "" 3 "" { 0 0 }
t "" 4 "" { 1 1 }
p "" 2 4 "" { "no" "yes" } 0
t "" 5 "" { 0 0 }
t "" 6 "" { 0 2 }
Loading
Loading