diff --git a/build_support/catalog/catalog.am b/build_support/catalog/catalog.am index 80b8a9f6c3..58c225f429 100644 --- a/build_support/catalog/catalog.am +++ b/build_support/catalog/catalog.am @@ -14,6 +14,7 @@ CATALOG_FILES = \ catalog/journals/geb/bagwell1995.efg \ catalog/journals/geb/gilboa1997/fig1.efg \ catalog/journals/geb/gilboa1997/fig2.efg \ + catalog/journals/geb/wichardt2008.efg \ catalog/journals/ijgt/nau2004/sec3.nfg \ catalog/journals/ijgt/nau2004/sec4.nfg \ catalog/journals/ijgt/nau2004/sec5.nfg \ diff --git a/build_support/catalog/catalog_hierarchy.yaml b/build_support/catalog/catalog_hierarchy.yaml index 6216467081..9280493a6f 100644 --- a/build_support/catalog/catalog_hierarchy.yaml +++ b/build_support/catalog/catalog_hierarchy.yaml @@ -15,6 +15,7 @@ labels: books/vonstengel2022: "von Stengel (2022) — Game Theory Basics" books/watson2013: "Watson (2013) — Strategy: An Introduction to Game Theory" journals/geb/gilboa1997: "Gilboa (1997)" + journals/geb/wichardt2008: "Wichardt (2008)" journals/ijgt/nau2004: "Nau et al. (2004)" journals/ijgt/selten1975: "Selten (1975)" journals/mor/vonstengelforges2008: "von Stengel & Forges (2008)" diff --git a/tests/test_games/wichardt.efg b/catalog/journals/geb/wichardt2008.efg similarity index 77% rename from tests/test_games/wichardt.efg rename to catalog/journals/geb/wichardt2008.efg index 03e4b05ded..5fcd9be4d6 100644 --- a/tests/test_games/wichardt.efg +++ b/catalog/journals/geb/wichardt2008.efg @@ -1,5 +1,6 @@ EFG 2 R "Wichardt (2008): 2 players, imperfect recall" { "Player 1" "Player 2" } -"" +"The first counterexample showing that finite extensive-form games +with imperfect recall need not have a Nash equilibrium in behaviour strategies" p "" 1 1 "" { "R" "L" } 0 p "" 1 2 "" { "r" "l" } 0 diff --git a/doc/references.bib b/doc/references.bib index a7453ca1e8..108be64fea 100644 --- a/doc/references.bib +++ b/doc/references.bib @@ -392,3 +392,15 @@ @inbook{Shap74 pages = {175--189}, category = {articles_equilibria} } + + +@article{Wichardt2008, + author = {Wichardt, P. C.}, + title = {Existence of Nash equilibria in finite extensive form games with imperfect recall: A counterexample}, + journal = {Games and Economic Behavior}, + volume = {63}, + number = {1}, + pages = {366--369}, + year = {2008}, + category = {articles_equilibria} +} diff --git a/tests/test_extensive.py b/tests/test_extensive.py index fbef465bfe..2ccfe97fa4 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -61,7 +61,7 @@ def test_game_add_players_nolabel(): # Games with imperfect recall from files (game_input is a string) # - imperfect recall without absent-mindedness - ("wichardt.efg", False), # forgetting past action; Wichardt (GEB, 2008) + (gbt.catalog.load("journals/geb/wichardt2008"), False), # forgetting past action ("gilboa_two_am_agents.efg", False), # forgetting past information; Gilboa (GEB, 1997) # - imperfect recall with absent-mindedness ("noPR-AM-driver-one-player.efg", False), # 1 players, one infoset unreached @@ -370,7 +370,7 @@ def test_outcome_index_exception_label(): # I M P E R F E C T R E C A L L --- commented out in the test suite # Wichardt (2008): binary tree of height 3; 2 players; the root player forgets the action # ( - # games.read_from_file("wichardt.efg"), + # gbt.catalog.load("journals/geb/wichardt2008"), # [["11", "12", "21", "22"], ["1", "2"]], # [ # np.array([[1, -1], [-5, -5], [-5, -5], [-1, 1]]), diff --git a/tests/test_infosets.py b/tests/test_infosets.py index 6caf8fb3ca..e4edae3d2f 100644 --- a/tests/test_infosets.py +++ b/tests/test_infosets.py @@ -104,7 +104,7 @@ class AbsentMindednessTestCase: ), pytest.param( PriorActionsTestCase( - factory=functools.partial(games.read_from_file, "wichardt.efg"), + factory=functools.partial(gbt.catalog.load, "journals/geb/wichardt2008"), expected_results=[ ("Player 1", 0, {None}), ("Player 1", 1, {("Player 1", 0, "L"), ("Player 1", 0, "R")}), @@ -178,7 +178,7 @@ class AbsentMindednessTestCase: ), pytest.param( AbsentMindednessTestCase( - factory=functools.partial(games.read_from_file, "wichardt.efg"), + factory=functools.partial(gbt.catalog.load, "journals/geb/wichardt2008"), expected_am_paths=[] ), id="wichardt_forgetting_action" diff --git a/tests/test_node.py b/tests/test_node.py index ce479afabb..e77fa3c890 100644 --- a/tests/test_node.py +++ b/tests/test_node.py @@ -150,7 +150,7 @@ class SubgameRootsTestCase: # ------------------------------------------------------------------------ pytest.param( SubgameRootsTestCase( - factory=functools.partial(games.read_from_file, "wichardt.efg"), + factory=functools.partial(gbt.catalog.load, "journals/geb/wichardt2008"), expected_paths=[[]] ), id="wichardt_no_nontrivial_subgames" @@ -261,7 +261,7 @@ class SubgameStructureTestCase: # ------------------------------------------------------------------------ pytest.param( SubgameStructureTestCase( - factory=functools.partial(games.read_from_file, "wichardt.efg"), + factory=functools.partial(gbt.catalog.load, "journals/geb/wichardt2008"), roots=[[]], parents={(): None}, children={(): set()}, @@ -390,7 +390,7 @@ def test_minimal_subgame_for_each_infoset(test_case: SubgameStructureTestCase): ] ), ( - "wichardt.efg", + gbt.catalog.load("journals/geb/wichardt2008"), [ ([], None), (["R"], ("Player 1", 0, "R")), @@ -438,7 +438,7 @@ def test_node_own_prior_action_non_terminal(game_file, expected_node_data): Tests `node.own_prior_action` for non-terminal nodes. Also verifies that all terminal nodes return None. """ - game = games.read_from_file(game_file) + game = game_file if isinstance(game_file, gbt.Game) else games.read_from_file(game_file) actual_node_data = [] @@ -461,7 +461,7 @@ def test_node_own_prior_action_non_terminal(game_file, expected_node_data): @pytest.mark.parametrize("game_file, expected_unreachable_paths", [ # Games without absent-mindedness, where all nodes are reachable - ("wichardt.efg", []), + (gbt.catalog.load("journals/geb/wichardt2008"), []), ("subgames.efg", []), # An absent-minded driver game with an unreachable terminal node @@ -482,7 +482,7 @@ def test_is_strategy_reachable(game_file: str, expected_unreachable_paths: list[ converting them to their action-label paths, and comparing the resulting list of paths against a known-correct list. """ - game = games.read_from_file(game_file) + game = game_file if isinstance(game_file, gbt.Game) else games.read_from_file(game_file) nodes = game.nodes actual_unreachable_paths = [