From fc4ccf037b60a370766fe3dda0a807374a3405b4 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 10:27:27 +0000 Subject: [PATCH 01/24] removed create_2x2x2_nfg from games.py --- tests/games.py | 20 - ...g_from_local_max_cut_2_pure_1_mixed_eq.nfg | 20 + .../2x2x2_nfg_with_two_pure_one_mixed_eq.nfg | 4 - tests/test_io.py | 22 +- tests/test_mixed.py | 2183 +++++++++++------ tests/test_players.py | 2 +- 6 files changed, 1488 insertions(+), 763 deletions(-) create mode 100644 tests/test_games/2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg delete mode 100644 tests/test_games/2x2x2_nfg_with_two_pure_one_mixed_eq.nfg diff --git a/tests/games.py b/tests/games.py index deb1eb580..dbadfe033 100644 --- a/tests/games.py +++ b/tests/games.py @@ -66,26 +66,6 @@ def create_2x2_zero_nfg() -> gbt.Game: return game -def create_2x2x2_nfg() -> gbt.Game: - """ - - This comes from a local max cut instance: - players {1,2,3} are nodes; edge weight{1,2} = 2; weight{1,3} = -1; weight{2,3} = 2 - - Pure strategies {a,b} encode if respective player is on left or right of the cut - - The payoff to a player is the sum of their incident edges across the implied cut - - Pure equilibrium iff local max cuts; in addition, uniform mixture is an equilibrium - - Equilibrium analysis for pure profiles: - a a a: 0 0 0 -- Not Nash (regrets: 1, 4, 1) - b a a: 1 2 -1 -- Not Nash (regrets: 0, 0, 3) - a b a: 2 4 2 -- Nash (global max cut) - b b a: -1 2 1 -- Not Nash (regrets: 3, 0, 0) - a a b: -1 2 1 -- Not Nash (regrets: 3, 0, 0) - b a b: 2 4 2 -- Nash (global max cut) - a b b: 1 2 -1 -- Not Nash (regrets: 0, 0, 3) - b b b: 0 0 0 -- Not Nash (regrets: 1, 4, 1) - """ - return read_from_file("2x2x2_nfg_with_two_pure_one_mixed_eq.nfg") - - def create_coord_4x4_nfg(outcome_version: bool = False) -> gbt.Game: """ Returns diff --git a/tests/test_games/2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg b/tests/test_games/2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg new file mode 100644 index 000000000..f28f234f6 --- /dev/null +++ b/tests/test_games/2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg @@ -0,0 +1,20 @@ +NFG 1 R "2x2x2 game with 2 pure and 1 mixed equilibrium" +{ "Player 1" "Player 2" "Player 3" } { 2 2 2 } +" +- This comes from a local max cut instance: + players {1,2,3} are nodes; edge weight{1,2} = 2; weight{1,3} = -1; weight{2,3} = 2 +- Pure strategies {a,b} encode if respective player is on left or right of the cut +- The payoff to a player is the sum of their incident edges across the implied cut +- Pure equilibrium iff local max cuts; in addition, uniform mixture is an equilibrium +- Equilibrium analysis for pure profiles: + a a a: 0 0 0 -- Not Nash (regrets: 1, 4, 1) + b a a: 1 2 -1 -- Not Nash (regrets: 0, 0, 3) + a b a: 2 4 2 -- Nash (global max cut) + b b a: -1 2 1 -- Not Nash (regrets: 3, 0, 0) + a a b: -1 2 1 -- Not Nash (regrets: 3, 0, 0) + b a b: 2 4 2 -- Nash (global max cut) + a b b: 1 2 -1 -- Not Nash (regrets: 0, 0, 3) + b b b: 0 0 0 -- Not Nash (regrets: 1, 4, 1) +" + +0 0 0 1 2 -1 2 4 2 -1 2 1 -1 2 1 2 4 2 1 2 -1 0 0 0 diff --git a/tests/test_games/2x2x2_nfg_with_two_pure_one_mixed_eq.nfg b/tests/test_games/2x2x2_nfg_with_two_pure_one_mixed_eq.nfg deleted file mode 100644 index 8c4e999d3..000000000 --- a/tests/test_games/2x2x2_nfg_with_two_pure_one_mixed_eq.nfg +++ /dev/null @@ -1,4 +0,0 @@ -NFG 1 R "2x2x2 game with 2 pure and 1 mixed equilibrium" -{ "Player 1" "Player 2" "Player 3" } { 2 2 2 } - -0 0 0 1 2 -1 2 4 2 -1 2 1 -1 2 1 2 4 2 1 2 -1 0 0 0 diff --git a/tests/test_io.py b/tests/test_io.py index 1a6c328de..05046b8fa 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -16,7 +16,9 @@ def test_read_efg(game_path): def test_read_efg_invalid(): - game_path = os.path.join("tests", "test_games", "2x2x2_nfg_with_two_pure_one_mixed_eq.nfg") + game_path = os.path.join( + "tests", "test_games", "2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg" + ) with pytest.raises(ValueError): gbt.read_efg(game_path) @@ -40,13 +42,17 @@ def test_read_agg(game_path): def test_read_agg_invalid(): - game_path = os.path.join("tests", "test_games", "2x2x2_nfg_with_two_pure_one_mixed_eq.nfg") + game_path = os.path.join( + "tests", "test_games", "2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg" + ) with pytest.raises(ValueError): gbt.read_agg(game_path) def test_read_gbt_invalid(): - game_path = os.path.join("tests", "test_games", "2x2x2_nfg_with_two_pure_one_mixed_eq.nfg") + game_path = os.path.join( + "tests", "test_games", "2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg" + ) with pytest.raises(ValueError): gbt.read_gbt(game_path) @@ -116,8 +122,9 @@ def test_read_write_efg(): def test_read_write_nfg(): nfg_game = create_2x2_zero_nfg() serialized_nfg_game = nfg_game.to_nfg() - deserialized_nfg_game = gbt.read_nfg(io.BytesIO(serialized_nfg_game.encode()), - normalize_labels=False) + deserialized_nfg_game = gbt.read_nfg( + io.BytesIO(serialized_nfg_game.encode()), normalize_labels=False + ) double_serialized_nfg_game = deserialized_nfg_game.to_nfg() assert serialized_nfg_game == double_serialized_nfg_game @@ -125,7 +132,8 @@ def test_read_write_nfg(): def test_read_write_nfg_normalize(): nfg_game = create_2x2_zero_nfg() serialized_nfg_game = nfg_game.to_nfg() - deserialized_nfg_game = gbt.read_nfg(io.BytesIO(serialized_nfg_game.encode()), - normalize_labels=True) + deserialized_nfg_game = gbt.read_nfg( + io.BytesIO(serialized_nfg_game.encode()), normalize_labels=True + ) double_serialized_nfg_game = deserialized_nfg_game.to_nfg() assert serialized_nfg_game != double_serialized_nfg_game diff --git a/tests/test_mixed.py b/tests/test_mixed.py index be6935634..975e26ee5 100644 --- a/tests/test_mixed.py +++ b/tests/test_mixed.py @@ -76,49 +76,64 @@ def test_normalize_neg_entry_value_error(game, profile_data, rational_flag): [ ############################################################################### # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), [[1, 2, 3, 14], [1, 1, 1, 1]], - [["1/20", "2/20", "3/20", "14/20"], ["1/4", "1/4", "1/4", "1/4"]], True), - (games.create_coord_4x4_nfg(), [[1.0, 2.0, 3.0, 14.0], [1, 1, 1, 1]], - [[1 / 20, 2 / 20, 3 / 20, 14 / 20], [0.25, 0.25, 0.25, 0.25]], False), + ( + games.create_coord_4x4_nfg(), + [[1, 2, 3, 14], [1, 1, 1, 1]], + [["1/20", "2/20", "3/20", "14/20"], ["1/4", "1/4", "1/4", "1/4"]], + True, + ), + ( + games.create_coord_4x4_nfg(), + [[1.0, 2.0, 3.0, 14.0], [1, 1, 1, 1]], + [[1 / 20, 2 / 20, 3 / 20, 14 / 20], [0.25, 0.25, 0.25, 0.25]], + False, + ), ############################################################################### # centipede with chance efg - (games.create_centipede_game_with_chance_efg(), [[1, 2, 3, 14], [1, 1, 1, 1]], - [["1/20", "2/20", "3/20", "14/20"], ["1/4", "1/4", "1/4", "1/4"]], True), - (games.create_centipede_game_with_chance_efg(), [[1.0, 2.0, 3.0, 14.0], [1, 1, 1, 1]], - [[1 / 20, 2 / 20, 3 / 20, 14 / 20], [0.25, 0.25, 0.25, 0.25]], False), + ( + games.create_centipede_game_with_chance_efg(), + [[1, 2, 3, 14], [1, 1, 1, 1]], + [["1/20", "2/20", "3/20", "14/20"], ["1/4", "1/4", "1/4", "1/4"]], + True, + ), + ( + games.create_centipede_game_with_chance_efg(), + [[1.0, 2.0, 3.0, 14.0], [1, 1, 1, 1]], + [[1 / 20, 2 / 20, 3 / 20, 14 / 20], [0.25, 0.25, 0.25, 0.25]], + False, + ), ], ) def test_normalize(game, profile_data, expected_data, rational_flag): - assert ( - game.mixed_strategy_profile(data=profile_data, rational=rational_flag).normalize() == - game.mixed_strategy_profile(data=expected_data, rational=rational_flag) - ) + assert game.mixed_strategy_profile( + data=profile_data, rational=rational_flag + ).normalize() == game.mixed_strategy_profile(data=expected_data, rational=rational_flag) @pytest.mark.parametrize( "game,strategy_label,rational_flag,prob", [ - ############################################################################## - # zero matrix nfg - (games.create_2x2_zero_nfg(), "cooperate", False, 0.72), - (games.create_2x2_zero_nfg(), "cooperate", True, "7/9"), - ############################################################################### - # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", 0.25, False), - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", "1/4", True), - ############################################################################### - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), "11", 0.25, False), - (games.create_stripped_down_poker_efg(), "12", 0.15, False), - (games.create_stripped_down_poker_efg(), "21", 0.99, False), - (games.create_stripped_down_poker_efg(), "11", "1/4", True), - (games.create_stripped_down_poker_efg(), "12", "3/4", True), - (games.create_stripped_down_poker_efg(), "21", "7/9", True), + ############################################################################## + # zero matrix nfg + (games.create_2x2_zero_nfg(), "cooperate", False, 0.72), + (games.create_2x2_zero_nfg(), "cooperate", True, "7/9"), + ############################################################################### + # coordination 4x4 nfg outcome version with strategy labels + (games.create_coord_4x4_nfg(outcome_version=True), "1-1", 0.25, False), + (games.create_coord_4x4_nfg(outcome_version=True), "1-1", "1/4", True), + ############################################################################### + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), "11", 0.25, False), + (games.create_stripped_down_poker_efg(), "12", 0.15, False), + (games.create_stripped_down_poker_efg(), "21", 0.99, False), + (games.create_stripped_down_poker_efg(), "11", "1/4", True), + (games.create_stripped_down_poker_efg(), "12", "3/4", True), + (games.create_stripped_down_poker_efg(), "21", "7/9", True), ], ) -def test_set_and_get_probability_by_strategy_label(game: gbt.Game, strategy_label: str, - rational_flag: bool, - prob: float | str): +def test_set_and_get_probability_by_strategy_label( + game: gbt.Game, strategy_label: str, rational_flag: bool, prob: float | str +): profile = game.mixed_strategy_profile(rational=rational_flag) prob = gbt.Rational(prob) if rational_flag else prob profile[strategy_label] = prob @@ -128,24 +143,25 @@ def test_set_and_get_probability_by_strategy_label(game: gbt.Game, strategy_labe @pytest.mark.parametrize( "game,player_label,rational_flag,profile_data", [ - ############################################################################## - # zero matrix nfg - (games.create_2x2_zero_nfg(), "Joe", False, [0.72, 0.28]), - (games.create_2x2_zero_nfg(), "Joe", True, ["7/9", "2/9"]), - ############################################################################## - # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(), P1, False, [0.25, 0, 0, 0.75]), - (games.create_coord_4x4_nfg(), P1, True, ["1/4", 0, 0, "3/4"]), - ############################################################################## - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), "Alice", False, [0.25, 0.75, 0, 0]), - (games.create_stripped_down_poker_efg(), "Bob", False, [1, 0]), - (games.create_stripped_down_poker_efg(), "Alice", True, ["1/4", "3/4", 0, 0]), - (games.create_stripped_down_poker_efg(), "Bob", True, [1, 0]), + ############################################################################## + # zero matrix nfg + (games.create_2x2_zero_nfg(), "Joe", False, [0.72, 0.28]), + (games.create_2x2_zero_nfg(), "Joe", True, ["7/9", "2/9"]), + ############################################################################## + # coordination 4x4 nfg outcome version with strategy labels + (games.create_coord_4x4_nfg(), P1, False, [0.25, 0, 0, 0.75]), + (games.create_coord_4x4_nfg(), P1, True, ["1/4", 0, 0, "3/4"]), + ############################################################################## + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), "Alice", False, [0.25, 0.75, 0, 0]), + (games.create_stripped_down_poker_efg(), "Bob", False, [1, 0]), + (games.create_stripped_down_poker_efg(), "Alice", True, ["1/4", "3/4", 0, 0]), + (games.create_stripped_down_poker_efg(), "Bob", True, [1, 0]), ], ) -def test_set_and_get_probabilities_by_player_label(game: gbt.Game, player_label: str, - rational_flag: bool, profile_data: list): +def test_set_and_get_probabilities_by_player_label( + game: gbt.Game, player_label: str, rational_flag: bool, profile_data: list +): profile_data = [gbt.Rational(p) for p in profile_data] if rational_flag else profile_data profile = game.mixed_strategy_profile(rational=rational_flag) profile[player_label] = profile_data @@ -155,32 +171,31 @@ def test_set_and_get_probabilities_by_player_label(game: gbt.Game, player_label: @pytest.mark.parametrize( "game,player_label,strategy_label,prob,rational_flag", [ - ############################################################################## - # stripped-down poker efg - # Player 1 - (games.create_stripped_down_poker_efg(), "Alice", "11", 0.25, False), - (games.create_stripped_down_poker_efg(), "Alice", "12", 0.25, False), - (games.create_stripped_down_poker_efg(), "Alice", "21", 0.25, False), - (games.create_stripped_down_poker_efg(), "Alice", "22", 0.25, False), - (games.create_stripped_down_poker_efg(), "Alice", "11", "1/4", True), - (games.create_stripped_down_poker_efg(), "Alice", "12", "1/4", True), - (games.create_stripped_down_poker_efg(), "Alice", "21", "1/4", True), - (games.create_stripped_down_poker_efg(), "Alice", "22", "1/4", True), - # Player 2 - (games.create_stripped_down_poker_efg(), "Bob", "1", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob", "2", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob", "1", "1/2", True), - (games.create_stripped_down_poker_efg(), "Bob", "2", "1/2", True), - ############################################################################## - # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(outcome_version=True), P1, "1-1", "1/4", True), - (games.create_coord_4x4_nfg(outcome_version=True), P2, "2-1", "1/4", True), - ] + ############################################################################## + # stripped-down poker efg + # Player 1 + (games.create_stripped_down_poker_efg(), "Alice", "11", 0.25, False), + (games.create_stripped_down_poker_efg(), "Alice", "12", 0.25, False), + (games.create_stripped_down_poker_efg(), "Alice", "21", 0.25, False), + (games.create_stripped_down_poker_efg(), "Alice", "22", 0.25, False), + (games.create_stripped_down_poker_efg(), "Alice", "11", "1/4", True), + (games.create_stripped_down_poker_efg(), "Alice", "12", "1/4", True), + (games.create_stripped_down_poker_efg(), "Alice", "21", "1/4", True), + (games.create_stripped_down_poker_efg(), "Alice", "22", "1/4", True), + # Player 2 + (games.create_stripped_down_poker_efg(), "Bob", "1", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob", "2", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob", "1", "1/2", True), + (games.create_stripped_down_poker_efg(), "Bob", "2", "1/2", True), + ############################################################################## + # coordination 4x4 nfg outcome version with strategy labels + (games.create_coord_4x4_nfg(outcome_version=True), P1, "1-1", "1/4", True), + (games.create_coord_4x4_nfg(outcome_version=True), P2, "2-1", "1/4", True), + ], ) -def test_profile_indexing_by_player_and_strategy_label_reference(game: gbt.Game, player_label: str, - strategy_label: str, - prob: str | float, - rational_flag: bool): +def test_profile_indexing_by_player_and_strategy_label_reference( + game: gbt.Game, player_label: str, strategy_label: str, prob: str | float, rational_flag: bool +): profile = game.mixed_strategy_profile(rational=rational_flag) prob = gbt.Rational(prob) if rational_flag else prob assert profile[player_label][strategy_label] == prob @@ -189,24 +204,23 @@ def test_profile_indexing_by_player_and_strategy_label_reference(game: gbt.Game, @pytest.mark.parametrize( "game,player_label,strategy_label,rational_flag", [ - ############################################################################## - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), "Bob", "11", True), - (games.create_stripped_down_poker_efg(), "Bob", "11", False), - (games.create_stripped_down_poker_efg(), "Alice", "1", True), - (games.create_stripped_down_poker_efg(), "Alice", "1", False), - (games.create_stripped_down_poker_efg(), "Alice", "2", True), - (games.create_stripped_down_poker_efg(), "Alice", "2", False), - ############################################################################## - # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(outcome_version=True), P1, "2-1", True), - (games.create_coord_4x4_nfg(outcome_version=True), P2, "1-1", True), - ] + ############################################################################## + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), "Bob", "11", True), + (games.create_stripped_down_poker_efg(), "Bob", "11", False), + (games.create_stripped_down_poker_efg(), "Alice", "1", True), + (games.create_stripped_down_poker_efg(), "Alice", "1", False), + (games.create_stripped_down_poker_efg(), "Alice", "2", True), + (games.create_stripped_down_poker_efg(), "Alice", "2", False), + ############################################################################## + # coordination 4x4 nfg outcome version with strategy labels + (games.create_coord_4x4_nfg(outcome_version=True), P1, "2-1", True), + (games.create_coord_4x4_nfg(outcome_version=True), P2, "1-1", True), + ], ) -def test_profile_indexing_by_player_and_invalid_strategy_label(game: gbt.Game, - player_label: str, - strategy_label: str, - rational_flag: bool): +def test_profile_indexing_by_player_and_invalid_strategy_label( + game: gbt.Game, player_label: str, strategy_label: str, rational_flag: bool +): """Test that we get a KeyError and that "player" appears in the error message""" with pytest.raises(KeyError, match="for player"): game.mixed_strategy_profile(rational=rational_flag)[player_label][strategy_label] @@ -215,22 +229,25 @@ def test_profile_indexing_by_player_and_invalid_strategy_label(game: gbt.Game, @pytest.mark.parametrize( "game,strategy_label,rational_flag,error,message", [ - ############################################################################## - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), "13", True, KeyError, "player or strategy"), - ############################################################################## - # coordination 4x4 nfg payoff version (default strategy labels created with duplicates) - (games.create_coord_4x4_nfg(), "1", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "2", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "3", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "4", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "5", True, KeyError, "player or strategy"), - ] + ############################################################################## + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), "13", True, KeyError, "player or strategy"), + ############################################################################## + # coordination 4x4 nfg payoff version (default strategy labels created with duplicates) + (games.create_coord_4x4_nfg(), "1", True, ValueError, "multiple strategies"), + (games.create_coord_4x4_nfg(), "2", True, ValueError, "multiple strategies"), + (games.create_coord_4x4_nfg(), "3", True, ValueError, "multiple strategies"), + (games.create_coord_4x4_nfg(), "4", True, ValueError, "multiple strategies"), + (games.create_coord_4x4_nfg(), "5", True, KeyError, "player or strategy"), + ], ) -def test_profile_indexing_by_invalid_strategy_label(game: gbt.Game, strategy_label: str, - rational_flag: bool, - error: ValueError | KeyError, - message: str | None): +def test_profile_indexing_by_invalid_strategy_label( + game: gbt.Game, + strategy_label: str, + rational_flag: bool, + error: ValueError | KeyError, + message: str | None, +): """Check that we get a ValueError for an ambigious strategy label and a KeyError for one that is neither a player or strategy label in the game """ @@ -248,35 +265,35 @@ def test_profile_indexing_by_player_and_duplicate_strategy_label(): @pytest.mark.parametrize( "game,strategy_label,prob,rational_flag", [ - ########################################################################### - # stripped-down poker efg - # Player 1 - (games.create_stripped_down_poker_efg(), "11", 0.25, False), - (games.create_stripped_down_poker_efg(), "12", 0.25, False), - (games.create_stripped_down_poker_efg(), "21", 0.25, False), - (games.create_stripped_down_poker_efg(), "22", 0.25, False), - (games.create_stripped_down_poker_efg(), "11", "1/4", True), - (games.create_stripped_down_poker_efg(), "12", "1/4", True), - (games.create_stripped_down_poker_efg(), "21", "1/4", True), - (games.create_stripped_down_poker_efg(), "22", "1/4", True), - # Player 2 - (games.create_stripped_down_poker_efg(), "1", 0.5, False), - (games.create_stripped_down_poker_efg(), "2", 0.5, False), - (games.create_stripped_down_poker_efg(), "1", "1/2", True), - (games.create_stripped_down_poker_efg(), "2", "1/2", True), - ############################################################################ - # coordination 4x4 nfg outcome version with strategy labels - # Player 1 - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", "1/4", True), - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", 0.25, False), - # Player 2 - (games.create_coord_4x4_nfg(outcome_version=True), "2-1", "1/4", True), - (games.create_coord_4x4_nfg(outcome_version=True), "2-1", 0.25, False), - ] + ########################################################################### + # stripped-down poker efg + # Player 1 + (games.create_stripped_down_poker_efg(), "11", 0.25, False), + (games.create_stripped_down_poker_efg(), "12", 0.25, False), + (games.create_stripped_down_poker_efg(), "21", 0.25, False), + (games.create_stripped_down_poker_efg(), "22", 0.25, False), + (games.create_stripped_down_poker_efg(), "11", "1/4", True), + (games.create_stripped_down_poker_efg(), "12", "1/4", True), + (games.create_stripped_down_poker_efg(), "21", "1/4", True), + (games.create_stripped_down_poker_efg(), "22", "1/4", True), + # Player 2 + (games.create_stripped_down_poker_efg(), "1", 0.5, False), + (games.create_stripped_down_poker_efg(), "2", 0.5, False), + (games.create_stripped_down_poker_efg(), "1", "1/2", True), + (games.create_stripped_down_poker_efg(), "2", "1/2", True), + ############################################################################ + # coordination 4x4 nfg outcome version with strategy labels + # Player 1 + (games.create_coord_4x4_nfg(outcome_version=True), "1-1", "1/4", True), + (games.create_coord_4x4_nfg(outcome_version=True), "1-1", 0.25, False), + # Player 2 + (games.create_coord_4x4_nfg(outcome_version=True), "2-1", "1/4", True), + (games.create_coord_4x4_nfg(outcome_version=True), "2-1", 0.25, False), + ], ) -def test_profile_indexing_by_strategy_label_reference(game: gbt.Game, strategy_label: str, - prob: str | float, - rational_flag: bool): +def test_profile_indexing_by_strategy_label_reference( + game: gbt.Game, strategy_label: str, prob: str | float, rational_flag: bool +): profile = game.mixed_strategy_profile(rational=rational_flag) prob = gbt.Rational(prob) if rational_flag else prob assert profile[strategy_label] == prob @@ -285,30 +302,31 @@ def test_profile_indexing_by_strategy_label_reference(game: gbt.Game, strategy_l @pytest.mark.parametrize( "game,player_label,strategy_data,rational_flag", [ - ############################################################################ - # mixed behav efg - (games.create_mixed_behav_game_efg(), P1, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), P2, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), P3, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), P1, ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), P2, ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), P3, ["1/2", "1/2"], True), - ############################################################################ - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), "Alice", [0.25, 0.25, 0.25, 0.25], False), - (games.create_stripped_down_poker_efg(), "Bob", [0.5, 0.5], False), - (games.create_stripped_down_poker_efg(), "Alice", ["1/4", "1/4", "1/4", "1/4"], True), - (games.create_stripped_down_poker_efg(), "Bob", ["1/2", "1/2"], True), - ############################################################################ - # coordination 4x4 nfg - (games.create_coord_4x4_nfg(), P1, [0.25, 0.25, 0.25, 0.25], False), - (games.create_coord_4x4_nfg(), P2, [0.25, 0.25, 0.25, 0.25], False), - (games.create_coord_4x4_nfg(), P1, ["1/4", "1/4", "1/4", "1/4"], True), - (games.create_coord_4x4_nfg(), P2, ["1/4", "1/4", "1/4", "1/4"], True), - ] + ############################################################################ + # mixed behav efg + (games.create_mixed_behav_game_efg(), P1, [0.5, 0.5], False), + (games.create_mixed_behav_game_efg(), P2, [0.5, 0.5], False), + (games.create_mixed_behav_game_efg(), P3, [0.5, 0.5], False), + (games.create_mixed_behav_game_efg(), P1, ["1/2", "1/2"], True), + (games.create_mixed_behav_game_efg(), P2, ["1/2", "1/2"], True), + (games.create_mixed_behav_game_efg(), P3, ["1/2", "1/2"], True), + ############################################################################ + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), "Alice", [0.25, 0.25, 0.25, 0.25], False), + (games.create_stripped_down_poker_efg(), "Bob", [0.5, 0.5], False), + (games.create_stripped_down_poker_efg(), "Alice", ["1/4", "1/4", "1/4", "1/4"], True), + (games.create_stripped_down_poker_efg(), "Bob", ["1/2", "1/2"], True), + ############################################################################ + # coordination 4x4 nfg + (games.create_coord_4x4_nfg(), P1, [0.25, 0.25, 0.25, 0.25], False), + (games.create_coord_4x4_nfg(), P2, [0.25, 0.25, 0.25, 0.25], False), + (games.create_coord_4x4_nfg(), P1, ["1/4", "1/4", "1/4", "1/4"], True), + (games.create_coord_4x4_nfg(), P2, ["1/4", "1/4", "1/4", "1/4"], True), + ], ) -def test_profile_indexing_by_player_label_reference(game: gbt.Game, player_label: str, - strategy_data: list, rational_flag: bool): +def test_profile_indexing_by_player_label_reference( + game: gbt.Game, player_label: str, strategy_data: list, rational_flag: bool +): profile = game.mixed_strategy_profile(rational=rational_flag) if rational_flag: strategy_data = [gbt.Rational(prob) for prob in strategy_data] @@ -318,55 +336,62 @@ def test_profile_indexing_by_player_label_reference(game: gbt.Game, player_label @pytest.mark.parametrize( "game,rational_flag,profile_data,label,payoff", [ - ######################################################################### - # zero matrix nfg - (games.create_2x2_zero_nfg(), False, None, "Joe", 0), - (games.create_2x2_zero_nfg(), True, None, "Joe", 0), - ######################################################################### - # coordination 4x4 nfg - (games.create_coord_4x4_nfg(), False, None, P1, 0.25), - (games.create_coord_4x4_nfg(), True, None, P1, "1/4"), - (games.create_coord_4x4_nfg(), False, None, P2, 0.25), - (games.create_coord_4x4_nfg(), True, None, P2, "1/4"), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [1, 0, 0, 0]], P1, 1), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [1, 0, 0, 0]], P1, 1), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [1, 0, 0, 0]], P2, 1), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [1, 0, 0, 0]], P2, 1), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [0, 1, 0, 0]], P1, 0), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [0, 1, 0, 0]], P1, 0), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [0, 1, 0, 0]], P2, 0), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [0, 1, 0, 0]], P2, 0), - ######################################################################### - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), False, None, "Alice", -0.25), - (games.create_stripped_down_poker_efg(), False, None, "Bob", 0.25), - (games.create_stripped_down_poker_efg(), True, None, "Alice", "-1/4"), - (games.create_stripped_down_poker_efg(), True, None, "Bob", "1/4"), - # Bet/Call - (games.create_stripped_down_poker_efg(), False, [[1, 0, 0, 0], [1, 0]], "Alice", 0), - (games.create_stripped_down_poker_efg(), False, [[1, 0, 0, 0], [1, 0]], "Bob", 0), - (games.create_stripped_down_poker_efg(), True, [[1, 0, 0, 0], [1, 0]], "Alice", 0), - (games.create_stripped_down_poker_efg(), True, [[1, 0, 0, 0], [1, 0]], "Bob", 0), - # Fold/Fold for player 1 (player 2's strategy is payoff-irrelevant) - (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [1, 0]], "Alice", -1), - (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [1, 0]], "Bob", 1), - (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], [1, 0]], "Alice", -1), - (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], [1, 0]], "Bob", 1), - (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [0.5, 0.5]], "Alice", -1), - (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [0.5, 0.5]], "Bob", 1), - (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], ["1/2", "1/2"]], "Alice", -1), - (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], ["1/2", "1/2"]], "Bob", 1), - ######################################################################### - (games.create_mixed_behav_game_efg(), False, None, P1, 3.0), - (games.create_mixed_behav_game_efg(), False, None, P2, 3.0), - (games.create_mixed_behav_game_efg(), False, None, P3, 3.25), - (games.create_mixed_behav_game_efg(), True, None, P1, 3), - (games.create_mixed_behav_game_efg(), True, None, P2, 3), - (games.create_mixed_behav_game_efg(), True, None, P3, "13/4"), - ] + ######################################################################### + # zero matrix nfg + (games.create_2x2_zero_nfg(), False, None, "Joe", 0), + (games.create_2x2_zero_nfg(), True, None, "Joe", 0), + ######################################################################### + # coordination 4x4 nfg + (games.create_coord_4x4_nfg(), False, None, P1, 0.25), + (games.create_coord_4x4_nfg(), True, None, P1, "1/4"), + (games.create_coord_4x4_nfg(), False, None, P2, 0.25), + (games.create_coord_4x4_nfg(), True, None, P2, "1/4"), + (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [1, 0, 0, 0]], P1, 1), + (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [1, 0, 0, 0]], P1, 1), + (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [1, 0, 0, 0]], P2, 1), + (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [1, 0, 0, 0]], P2, 1), + (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [0, 1, 0, 0]], P1, 0), + (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [0, 1, 0, 0]], P1, 0), + (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [0, 1, 0, 0]], P2, 0), + (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [0, 1, 0, 0]], P2, 0), + ######################################################################### + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), False, None, "Alice", -0.25), + (games.create_stripped_down_poker_efg(), False, None, "Bob", 0.25), + (games.create_stripped_down_poker_efg(), True, None, "Alice", "-1/4"), + (games.create_stripped_down_poker_efg(), True, None, "Bob", "1/4"), + # Bet/Call + (games.create_stripped_down_poker_efg(), False, [[1, 0, 0, 0], [1, 0]], "Alice", 0), + (games.create_stripped_down_poker_efg(), False, [[1, 0, 0, 0], [1, 0]], "Bob", 0), + (games.create_stripped_down_poker_efg(), True, [[1, 0, 0, 0], [1, 0]], "Alice", 0), + (games.create_stripped_down_poker_efg(), True, [[1, 0, 0, 0], [1, 0]], "Bob", 0), + # Fold/Fold for player 1 (player 2's strategy is payoff-irrelevant) + (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [1, 0]], "Alice", -1), + (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [1, 0]], "Bob", 1), + (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], [1, 0]], "Alice", -1), + (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], [1, 0]], "Bob", 1), + (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [0.5, 0.5]], "Alice", -1), + (games.create_stripped_down_poker_efg(), False, [[0, 0, 0, 1], [0.5, 0.5]], "Bob", 1), + ( + games.create_stripped_down_poker_efg(), + True, + [[0, 0, 0, 1], ["1/2", "1/2"]], + "Alice", + -1, + ), + (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], ["1/2", "1/2"]], "Bob", 1), + ######################################################################### + (games.create_mixed_behav_game_efg(), False, None, P1, 3.0), + (games.create_mixed_behav_game_efg(), False, None, P2, 3.0), + (games.create_mixed_behav_game_efg(), False, None, P3, 3.25), + (games.create_mixed_behav_game_efg(), True, None, P1, 3), + (games.create_mixed_behav_game_efg(), True, None, P2, 3), + (games.create_mixed_behav_game_efg(), True, None, P3, "13/4"), + ], ) -def test_payoff_by_label_reference(game: gbt.Game, rational_flag: bool, profile_data: list, - label: str, payoff: float | str): +def test_payoff_by_label_reference( + game: gbt.Game, rational_flag: bool, profile_data: list, label: str, payoff: float | str +): payoff = gbt.Rational(payoff) if rational_flag else payoff profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) assert profile.payoff(label) == payoff @@ -375,28 +400,29 @@ def test_payoff_by_label_reference(game: gbt.Game, rational_flag: bool, profile_ @pytest.mark.parametrize( "game,rational_flag,label,value", [ - ############################################################################## - # zero matrix nfg - (games.create_2x2_zero_nfg(), False, "cooperate", 0), - (games.create_2x2_zero_nfg(), True, "cooperate", 0), - ############################################################################## - # coordination 4x4 nfg - (games.create_coord_4x4_nfg(outcome_version=True), False, "1-1", 0.25), - (games.create_coord_4x4_nfg(outcome_version=True), True, "1-1", "1/4"), - ############################################################################## - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), False, "11", 0.5), # Bet/Bet - (games.create_stripped_down_poker_efg(), False, "12", 0.25), # Bet King/Fold Queen - (games.create_stripped_down_poker_efg(), False, "21", -0.75), # Fold King/Bet Queen - (games.create_stripped_down_poker_efg(), False, "22", -1), # Fold/Fold - (games.create_stripped_down_poker_efg(), True, "11", "1/2"), - (games.create_stripped_down_poker_efg(), True, "12", "1/4"), - (games.create_stripped_down_poker_efg(), True, "21", "-3/4"), - (games.create_stripped_down_poker_efg(), True, "22", -1), - ] + ############################################################################## + # zero matrix nfg + (games.create_2x2_zero_nfg(), False, "cooperate", 0), + (games.create_2x2_zero_nfg(), True, "cooperate", 0), + ############################################################################## + # coordination 4x4 nfg + (games.create_coord_4x4_nfg(outcome_version=True), False, "1-1", 0.25), + (games.create_coord_4x4_nfg(outcome_version=True), True, "1-1", "1/4"), + ############################################################################## + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), False, "11", 0.5), # Bet/Bet + (games.create_stripped_down_poker_efg(), False, "12", 0.25), # Bet King/Fold Queen + (games.create_stripped_down_poker_efg(), False, "21", -0.75), # Fold King/Bet Queen + (games.create_stripped_down_poker_efg(), False, "22", -1), # Fold/Fold + (games.create_stripped_down_poker_efg(), True, "11", "1/2"), + (games.create_stripped_down_poker_efg(), True, "12", "1/4"), + (games.create_stripped_down_poker_efg(), True, "21", "-3/4"), + (games.create_stripped_down_poker_efg(), True, "22", -1), + ], ) -def test_strategy_value_by_label_reference(game: gbt.Game, rational_flag: bool, label: str, - value: float | str): +def test_strategy_value_by_label_reference( + game: gbt.Game, rational_flag: bool, label: str, value: float | str +): value = gbt.Rational(value) if rational_flag else value assert game.mixed_strategy_profile(rational=rational_flag).strategy_value(label) == value @@ -408,13 +434,12 @@ def test_strategy_value_by_label_reference(game: gbt.Game, rational_flag: bool, (games.create_mixed_behav_game_efg(), True), (games.create_centipede_game_with_chance_efg(), False), (games.create_centipede_game_with_chance_efg(), True), - ] + ], ) def test_as_behavior_roundtrip(game: gbt.Game, rational_flag: bool): - assert ( - game.mixed_strategy_profile(rational=rational_flag).as_behavior().as_strategy() == - game.mixed_strategy_profile(rational=rational_flag) - ) + assert game.mixed_strategy_profile( + rational=rational_flag + ).as_behavior().as_strategy() == game.mixed_strategy_profile(rational=rational_flag) @pytest.mark.parametrize( @@ -424,7 +449,7 @@ def test_as_behavior_roundtrip(game: gbt.Game, rational_flag: bool): (games.create_2x2_zero_nfg(), True), (games.create_coord_4x4_nfg(), False), (games.create_coord_4x4_nfg(), True), - ] + ], ) def test_as_behavior_error(game: gbt.Game, rational_flag: bool): with pytest.raises(gbt.UndefinedOperationError): @@ -434,27 +459,56 @@ def test_as_behavior_error(game: gbt.Game, rational_flag: bool): @pytest.mark.parametrize( "game,profile_data,rational_flag,payoffs", [ - ############################################################################### - # zero matrix nfg - (games.create_2x2_zero_nfg(), None, True, (0, 0)), - ############################################################################### - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), None, False, (0.25, 0.25)), - (games.create_coord_4x4_nfg(), None, True, ("1/4", "1/4")), - (games.create_coord_4x4_nfg(), - [["1/3", "1/3", "1/3", 0], ["1/3", "1/3", "1/3", 0]], True, ("1/3", "1/3")), - (games.create_coord_4x4_nfg(), - [["1/3", "1/3", 0, "1/3"], ["1/3", "1/3", "1/3", 0]], True, ("2/9", "2/9")), - ############################################################################### - # 2x2x2 nfg - (games.create_2x2x2_nfg(), None, True, ("4/8", "16/8", "4/8")), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], True, (0, 0, 0)), - (games.create_2x2x2_nfg(), [[0, 1], [1, 0], [1, 0]], True, (1, 2, -1)), - (games.create_2x2x2_nfg(), [["1/2", "1/2"], [1, 0], [1, 0]], True, ("1/2", 1, "-1/2")), + ############################################################################### + # zero matrix nfg + (games.create_2x2_zero_nfg(), None, True, (0, 0)), + ############################################################################### + # 4x4 coordination nfg + (games.create_coord_4x4_nfg(), None, False, (0.25, 0.25)), + (games.create_coord_4x4_nfg(), None, True, ("1/4", "1/4")), + ( + games.create_coord_4x4_nfg(), + [["1/3", "1/3", "1/3", 0], ["1/3", "1/3", "1/3", 0]], + True, + ("1/3", "1/3"), + ), + ( + games.create_coord_4x4_nfg(), + [["1/3", "1/3", 0, "1/3"], ["1/3", "1/3", "1/3", 0]], + True, + ("2/9", "2/9"), + ), + ############################################################################### + # 2x2x2 nfg + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + True, + ("4/8", "16/8", "4/8"), + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + True, + (0, 0, 0), + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [1, 0], [1, 0]], + True, + (1, 2, -1), + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [["1/2", "1/2"], [1, 0], [1, 0]], + True, + ("1/2", 1, "-1/2"), + ), ], ) -def test_payoffs_reference(game: gbt.Game, profile_data: list, rational_flag: bool, - payoffs: tuple): +def test_payoffs_reference( + game: gbt.Game, profile_data: list, rational_flag: bool, payoffs: tuple +): profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) for payoff, player in zip(payoffs, profile.game.players, strict=True): payoff = gbt.Rational(payoff) if rational_flag else payoff @@ -464,35 +518,61 @@ def test_payoffs_reference(game: gbt.Game, profile_data: list, rational_flag: bo @pytest.mark.parametrize( "game,profile_data,rational_flag,strategy_values", [ - ############################################################################### - # zero matrix nfg - (games.create_2x2_zero_nfg(), None, False, ([0, 0], [0, 0])), - (games.create_2x2_zero_nfg(), None, True, ([0, 0], [0, 0])), - ############################################################################### - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), None, False, - ([0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25])), - (games.create_coord_4x4_nfg(), None, True, - ([0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25])), - (games.create_coord_4x4_nfg(), [["1", "0", "0", "0"], ["1", "0", "0", "0"]], - True, (["1", "0", "0", "0"], ["1", "0", "0", "0"])), - (games.create_coord_4x4_nfg(), [["3/7", "0", "0", "4/7"], ["1/3", "1/3", "1/3", "0"]], - True, (["1/3", "1/3", "1/3", "0"], ["3/7", "0", "0", "4/7"])), - ############################################################################### - # 2x2x2 nfg - (games.create_2x2x2_nfg(), None, True, (["1/2", "1/2"], [2, 2], ["1/2", "1/2"])), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], True, ([0, 1], [0, 4], [0, 1])), - ############################################################################### - # stripped-down poker efg - (games.create_stripped_down_poker_efg(), None, False, [(0.5, 0.25, -0.75, -1), (0.5, 0)]), - ] + ############################################################################### + # zero matrix nfg + (games.create_2x2_zero_nfg(), None, False, ([0, 0], [0, 0])), + (games.create_2x2_zero_nfg(), None, True, ([0, 0], [0, 0])), + ############################################################################### + # 4x4 coordination nfg + ( + games.create_coord_4x4_nfg(), + None, + False, + ([0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]), + ), + ( + games.create_coord_4x4_nfg(), + None, + True, + ([0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]), + ), + ( + games.create_coord_4x4_nfg(), + [["1", "0", "0", "0"], ["1", "0", "0", "0"]], + True, + (["1", "0", "0", "0"], ["1", "0", "0", "0"]), + ), + ( + games.create_coord_4x4_nfg(), + [["3/7", "0", "0", "4/7"], ["1/3", "1/3", "1/3", "0"]], + True, + (["1/3", "1/3", "1/3", "0"], ["3/7", "0", "0", "4/7"]), + ), + ############################################################################### + # 2x2x2 nfg + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + True, + (["1/2", "1/2"], [2, 2], ["1/2", "1/2"]), + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + True, + ([0, 1], [0, 4], [0, 1]), + ), + ############################################################################### + # stripped-down poker efg + (games.create_stripped_down_poker_efg(), None, False, [(0.5, 0.25, -0.75, -1), (0.5, 0)]), + ], ) -def test_strategy_value_reference(game: gbt.Game, profile_data: list, rational_flag: bool, - strategy_values: list): +def test_strategy_value_reference( + game: gbt.Game, profile_data: list, rational_flag: bool, strategy_values: list +): profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) for strategy_values_for_player, player in zip( - strategy_values, profile.game.players, - strict=True + strategy_values, profile.game.players, strict=True ): for i, s in enumerate(player.strategies): sv = strategy_values_for_player[i] @@ -503,55 +583,148 @@ def test_strategy_value_reference(game: gbt.Game, profile_data: list, rational_f @pytest.mark.parametrize( "game,profile_data,liap_exp,tol,rational_flag", [ - ############################################################################## - # Zero matrix nfg, all liap_values are zero - (games.create_2x2_zero_nfg(), [["3/4", "1/4"], ["2/5", "3/5"]], 0, ZERO, True), - (games.create_2x2_zero_nfg(), [["1/2", "1/2"], ["1/2", "1/2"]], 0, ZERO, True), - (games.create_2x2_zero_nfg(), [[1, 0], [1, 0]], 0, ZERO, True), - (games.create_2x2_zero_nfg(), [[1/4, 3/4], [2/5, 3/5]], 0, TOL, False), - ############################################################################## - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), None, 0, ZERO, True), - (games.create_coord_4x4_nfg(), None, 0, TOL, False), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], 0, ZERO, True), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], 0, TOL, False), - (games.create_coord_4x4_nfg(), - [["1/3", "1/2", "1/12", "1/12"], ["3/8", "1/8", "1/4", "1/4"]], - "245/2304", ZERO, True), - (games.create_coord_4x4_nfg(), [[1/3, 1/2, 1/12, 1/12], [3/8, 1/8, 1/4, 1/4]], - 245/2304, TOL, False), - (games.create_coord_4x4_nfg(), - [["1/3", 0, 0, "2/3"], [1, 0, 0, 0]], "5/9", ZERO, True), - (games.create_coord_4x4_nfg(), - [[1/3, 0, 0, 2/3], [1, 0, 0, 0]], 5/9, TOL, False), - ############################################################################## - # El Farol bar game efg - (games.create_el_farol_bar_game_efg(), - [["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"]], - 0, ZERO, True), - (games.create_el_farol_bar_game_efg(), [[1, 0], [1, 0], [0, 1], [0, 1], [0, 1]], - 0, ZERO, True), - ############################################################################## - # # 2x2x2 nfg with 2 pure and 1 mixed eq - # Pure non-Nash eq: - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], 18, ZERO, True), # 4^2+1+1 - (games.create_2x2x2_nfg(), [[0, 1], [0, 1], [0, 1]], 18, ZERO, True), # 4^2+1+1 - (games.create_2x2x2_nfg(), [[1, 0], [0, 1], [0, 1]], 9, ZERO, True), # 3^2 - (games.create_2x2x2_nfg(), [[0, 1], [1, 0], [1, 0]], 9, ZERO, True), # 3^2 - (games.create_2x2x2_nfg(), [[1, 0], [0, 1], [0, 1]], 9, ZERO, True), # 3^2 - (games.create_2x2x2_nfg(), [[1, 1], [1, 0], [0, 0]], 9, ZERO, True), # 3^2 - # Non-pure non-Nash eq: - (games.create_2x2x2_nfg(), [["1/2", "1/2"], [1, 0], [1, 0]], "33/4", ZERO, True), - (games.create_2x2x2_nfg(), [[1, 0], ["1/2", "1/2"], [1, 0]], 4, ZERO, True), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], ["1/2", "1/2"]], "33/4", ZERO, True), - # Nash eq: - (games.create_2x2x2_nfg(), [[1, 0], [0, 1], [1, 0]], 0, ZERO, True), - (games.create_2x2x2_nfg(), [[0, 1], [1, 0], [0, 1]], 0, ZERO, True), - (games.create_2x2x2_nfg(), None, 0, ZERO, True), # uniform is Nash - ] + ############################################################################## + # Zero matrix nfg, all liap_values are zero + (games.create_2x2_zero_nfg(), [["3/4", "1/4"], ["2/5", "3/5"]], 0, ZERO, True), + (games.create_2x2_zero_nfg(), [["1/2", "1/2"], ["1/2", "1/2"]], 0, ZERO, True), + (games.create_2x2_zero_nfg(), [[1, 0], [1, 0]], 0, ZERO, True), + (games.create_2x2_zero_nfg(), [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], 0, TOL, False), + ############################################################################## + # 4x4 coordination nfg + (games.create_coord_4x4_nfg(), None, 0, ZERO, True), + (games.create_coord_4x4_nfg(), None, 0, TOL, False), + (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], 0, ZERO, True), + (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], 0, TOL, False), + ( + games.create_coord_4x4_nfg(), + [["1/3", "1/2", "1/12", "1/12"], ["3/8", "1/8", "1/4", "1/4"]], + "245/2304", + ZERO, + True, + ), + ( + games.create_coord_4x4_nfg(), + [[1 / 3, 1 / 2, 1 / 12, 1 / 12], [3 / 8, 1 / 8, 1 / 4, 1 / 4]], + 245 / 2304, + TOL, + False, + ), + (games.create_coord_4x4_nfg(), [["1/3", 0, 0, "2/3"], [1, 0, 0, 0]], "5/9", ZERO, True), + (games.create_coord_4x4_nfg(), [[1 / 3, 0, 0, 2 / 3], [1, 0, 0, 0]], 5 / 9, TOL, False), + ############################################################################## + # El Farol bar game efg + ( + games.create_el_farol_bar_game_efg(), + [["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"]], + 0, + ZERO, + True, + ), + ( + games.create_el_farol_bar_game_efg(), + [[1, 0], [1, 0], [0, 1], [0, 1], [0, 1]], + 0, + ZERO, + True, + ), + ############################################################################## + # # 2x2x2 nfg with 2 pure and 1 mixed eq + # Pure non-Nash eq: + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + 18, + ZERO, + True, + ), # 4^2+1+1 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [0, 1], [0, 1]], + 18, + ZERO, + True, + ), # 4^2+1+1 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [0, 1], [0, 1]], + 9, + ZERO, + True, + ), # 3^2 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [1, 0], [1, 0]], + 9, + ZERO, + True, + ), # 3^2 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [0, 1], [0, 1]], + 9, + ZERO, + True, + ), # 3^2 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 1], [1, 0], [0, 0]], + 9, + ZERO, + True, + ), # 3^2 + # Non-pure non-Nash eq: + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [["1/2", "1/2"], [1, 0], [1, 0]], + "33/4", + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], ["1/2", "1/2"], [1, 0]], + 4, + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], ["1/2", "1/2"]], + "33/4", + ZERO, + True, + ), + # Nash eq: + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [0, 1], [1, 0]], + 0, + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [1, 0], [0, 1]], + 0, + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + 0, + ZERO, + True, + ), # uniform is Nash + ], ) -def test_liap_value_reference(game: gbt.Game, profile_data: list, liap_exp: float | str, - tol: float | gbt.Rational | int, rational_flag: bool): +def test_liap_value_reference( + game: gbt.Game, + profile_data: list, + liap_exp: float | str, + tol: float | gbt.Rational | int, + rational_flag: bool, +): profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) liap_exp = gbt.Rational(liap_exp) if rational_flag else liap_exp assert abs(profile.liap_value() - liap_exp) <= tol @@ -560,57 +733,160 @@ def test_liap_value_reference(game: gbt.Game, profile_data: list, liap_exp: floa @pytest.mark.parametrize( "game,profile_data,player_regrets_exp,tol,rational_flag", [ - ############################################################################## - # Zero matrix nfg, all liap_values are zero - (games.create_2x2_zero_nfg(), [["3/4", "1/4"], ["2/5", "3/5"]], [0]*2, ZERO, True), - (games.create_2x2_zero_nfg(), [["1/2", "1/2"], ["1/2", "1/2"]], [0]*2, ZERO, True), - (games.create_2x2_zero_nfg(), [[1, 0], [1, 0]], [0]*2, ZERO, True), - (games.create_2x2_zero_nfg(), [[1/4, 3/4], [2/5, 3/5]], [0]*2, TOL, False), - ############################################################################## - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), None, [0]*2, ZERO, True), - (games.create_coord_4x4_nfg(), None, [0]*2, TOL, False), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], [0]*2, ZERO, True), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], [0]*2, TOL, False), - (games.create_coord_4x4_nfg(), - [["1/3", "1/2", "1/12", "1/12"], ["3/8", "1/8", "1/4", "1/4"]], - ["7/48", "13/48"], ZERO, True), - (games.create_coord_4x4_nfg(), [[1/3, 1/2, 1/12, 1/12], [3/8, 1/8, 1/4, 1/4]], - [7/48, 13/48], TOL, False), - (games.create_coord_4x4_nfg(), - [["1/3", 0, 0, "2/3"], [1, 0, 0, 0]], ["2/3", "1/3"], ZERO, True), - (games.create_coord_4x4_nfg(), - [[1/3, 0, 0, 2/3], [1, 0, 0, 0]], [2/3, 1/3], TOL, False), - ############################################################################## - # El Farol bar game efg - (games.create_el_farol_bar_game_efg(), - [["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"]], - [0]*5, ZERO, True), - (games.create_el_farol_bar_game_efg(), [[1, 0], [1, 0], [0, 1], [0, 1], [0, 1]], - [0]*5, ZERO, True), - ############################################################################## - # 2x2x2 nfg with 2 pure and 1 mixed eq - # Pure non-Nash - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], [1, 4, 1], ZERO, True), # 111 - (games.create_2x2x2_nfg(), [[0, 1], [0, 1], [0, 1]], [1, 4, 1], ZERO, True), # 000 - (games.create_2x2x2_nfg(), [[1, 0], [0, 1], [0, 1]], [0, 0, 3], ZERO, True), # 100 - (games.create_2x2x2_nfg(), [[0, 1], [1, 0], [1, 0]], [0, 0, 3], ZERO, True), # 011 - (games.create_2x2x2_nfg(), [[0, 1], [0, 1], [1, 0]], [3, 0, 0], ZERO, True), # 001 - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [0, 1]], [3, 0, 0], ZERO, True), # 110 - # Mixed non-Nash - (games.create_2x2x2_nfg(), [["1/2", "1/2"], [1, 0], [1, 0]], ["1/2", 2, 2], ZERO, True), - (games.create_2x2x2_nfg(), [[1, 0], ["1/2", "1/2"], [1, 0]], [0, 2, 0], ZERO, True), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], ["1/2", "1/2"]], [2, 2, "1/2"], ZERO, True), - # Nash eq: - (games.create_2x2x2_nfg(), [[1, 0], [0, 1], [1, 0]], [0]*3, ZERO, True), # 101 - (games.create_2x2x2_nfg(), [[0, 1], [1, 0], [0, 1]], [0]*3, ZERO, True), # 010 - (games.create_2x2x2_nfg(), None, [0]*3, ZERO, True), # uniform is Nash - ] + ############################################################################## + # Zero matrix nfg, all liap_values are zero + (games.create_2x2_zero_nfg(), [["3/4", "1/4"], ["2/5", "3/5"]], [0] * 2, ZERO, True), + (games.create_2x2_zero_nfg(), [["1/2", "1/2"], ["1/2", "1/2"]], [0] * 2, ZERO, True), + (games.create_2x2_zero_nfg(), [[1, 0], [1, 0]], [0] * 2, ZERO, True), + (games.create_2x2_zero_nfg(), [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], [0] * 2, TOL, False), + ############################################################################## + # 4x4 coordination nfg + (games.create_coord_4x4_nfg(), None, [0] * 2, ZERO, True), + (games.create_coord_4x4_nfg(), None, [0] * 2, TOL, False), + (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], [0] * 2, ZERO, True), + (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], [0] * 2, TOL, False), + ( + games.create_coord_4x4_nfg(), + [["1/3", "1/2", "1/12", "1/12"], ["3/8", "1/8", "1/4", "1/4"]], + ["7/48", "13/48"], + ZERO, + True, + ), + ( + games.create_coord_4x4_nfg(), + [[1 / 3, 1 / 2, 1 / 12, 1 / 12], [3 / 8, 1 / 8, 1 / 4, 1 / 4]], + [7 / 48, 13 / 48], + TOL, + False, + ), + ( + games.create_coord_4x4_nfg(), + [["1/3", 0, 0, "2/3"], [1, 0, 0, 0]], + ["2/3", "1/3"], + ZERO, + True, + ), + ( + games.create_coord_4x4_nfg(), + [[1 / 3, 0, 0, 2 / 3], [1, 0, 0, 0]], + [2 / 3, 1 / 3], + TOL, + False, + ), + ############################################################################## + # El Farol bar game efg + ( + games.create_el_farol_bar_game_efg(), + [["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"]], + [0] * 5, + ZERO, + True, + ), + ( + games.create_el_farol_bar_game_efg(), + [[1, 0], [1, 0], [0, 1], [0, 1], [0, 1]], + [0] * 5, + ZERO, + True, + ), + ############################################################################## + # 2x2x2 nfg with 2 pure and 1 mixed eq + # Pure non-Nash + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + [1, 4, 1], + ZERO, + True, + ), # 111 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [0, 1], [0, 1]], + [1, 4, 1], + ZERO, + True, + ), # 000 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [0, 1], [0, 1]], + [0, 0, 3], + ZERO, + True, + ), # 100 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [1, 0], [1, 0]], + [0, 0, 3], + ZERO, + True, + ), # 011 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [0, 1], [1, 0]], + [3, 0, 0], + ZERO, + True, + ), # 001 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [0, 1]], + [3, 0, 0], + ZERO, + True, + ), # 110 + # Mixed non-Nash + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [["1/2", "1/2"], [1, 0], [1, 0]], + ["1/2", 2, 2], + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], ["1/2", "1/2"], [1, 0]], + [0, 2, 0], + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], ["1/2", "1/2"]], + [2, 2, "1/2"], + ZERO, + True, + ), + # Nash eq: + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [0, 1], [1, 0]], + [0] * 3, + ZERO, + True, + ), # 101 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[0, 1], [1, 0], [0, 1]], + [0] * 3, + ZERO, + True, + ), # 010 + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + [0] * 3, + ZERO, + True, + ), # uniform is Nash + ], ) -def test_player_regret_max_regret_reference(game: gbt.Game, profile_data: list, - player_regrets_exp: list, - tol: float | gbt.Rational | int, - rational_flag: bool): +def test_player_regret_max_regret_reference( + game: gbt.Game, + profile_data: list, + player_regrets_exp: list, + tol: float | gbt.Rational | int, + rational_flag: bool, +): profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) if rational_flag: player_regrets_exp = [gbt.Rational(r) for r in player_regrets_exp] @@ -622,119 +898,216 @@ def test_player_regret_max_regret_reference(game: gbt.Game, profile_data: list, @pytest.mark.parametrize( "game,rational_flag", [ - ################################################################################# - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), False), - (games.create_coord_4x4_nfg(), True), - ################################################################################# - # Zero matrix nfg - (games.create_2x2_zero_nfg(), False), - (games.create_2x2_zero_nfg(), True), - ################################################################################# - # El Farol bar game efg - (games.create_el_farol_bar_game_efg(), False), - (games.create_el_farol_bar_game_efg(), True), - ################################################################################# - # Centipede with chance efg - (games.create_centipede_game_with_chance_efg(), False), - (games.create_centipede_game_with_chance_efg(), True), - ################################################################################# - # 2x2x2 nfg - (games.create_2x2x2_nfg(), False), - (games.create_2x2x2_nfg(), True), - ] + ################################################################################# + # 4x4 coordination nfg + (games.create_coord_4x4_nfg(), False), + (games.create_coord_4x4_nfg(), True), + ################################################################################# + # Zero matrix nfg + (games.create_2x2_zero_nfg(), False), + (games.create_2x2_zero_nfg(), True), + ################################################################################# + # El Farol bar game efg + (games.create_el_farol_bar_game_efg(), False), + (games.create_el_farol_bar_game_efg(), True), + ################################################################################# + # Centipede with chance efg + (games.create_centipede_game_with_chance_efg(), False), + (games.create_centipede_game_with_chance_efg(), True), + ################################################################################# + # 2x2x2 nfg + (games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), False), + (games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), True), + ], ) def test_strategy_regret_consistency(game: gbt.Game, rational_flag: bool): profile = game.mixed_strategy_profile(rational=False) for player in game.players: for strategy in player.strategies: - assert ( - profile.strategy_regret(strategy) == - ( - max(profile.strategy_value(s) for s in player.strategies) - - profile.strategy_value(strategy) - ) + assert profile.strategy_regret(strategy) == ( + max(profile.strategy_value(s) for s in player.strategies) + - profile.strategy_value(strategy) ) @pytest.mark.parametrize( "game,profile_data,tol,rational_flag", [ - ################################################################################# - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), - [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], ZERO, True), - (games.create_coord_4x4_nfg(), - [[1/3, 1/3, 0/3, 1/3], [1/4, 1/4, 3/8, 1/8]], TOL, False), - ################################################################################# - # Centipede with chance efg - (games.create_centipede_game_with_chance_efg(), - [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", 0]], ZERO, True), - (games.create_centipede_game_with_chance_efg(), - [[1/3, 1/3, 1/3, 0], [.10, 3/5, .3, 0]], TOL, False), - ################################################################################# - # El Farol bar game efg - (games.create_el_farol_bar_game_efg(), - [[1, 0], ["1/2", "1/2"], ["1/3", "2/3"], ["1/5", "4/5"], ["1/8", "7/8"]], ZERO, True), - (games.create_el_farol_bar_game_efg(), - [[1, 0], [1/2, 1/2], [1/3, 2/3], [1/5, 4/5], [1/8, 7/8]], TOL, False), - ################################################################################# - # 2x2x2 nfg with 2 pure and 1 mixed eq - (games.create_2x2x2_nfg(), None, ZERO, True), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], ZERO, True), - (games.create_2x2x2_nfg(), None, TOL, False), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], TOL, False), - ] + ################################################################################# + # 4x4 coordination nfg + ( + games.create_coord_4x4_nfg(), + [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], + ZERO, + True, + ), + ( + games.create_coord_4x4_nfg(), + [[1 / 3, 1 / 3, 0 / 3, 1 / 3], [1 / 4, 1 / 4, 3 / 8, 1 / 8]], + TOL, + False, + ), + ################################################################################# + # Centipede with chance efg + ( + games.create_centipede_game_with_chance_efg(), + [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", 0]], + ZERO, + True, + ), + ( + games.create_centipede_game_with_chance_efg(), + [[1 / 3, 1 / 3, 1 / 3, 0], [0.10, 3 / 5, 0.3, 0]], + TOL, + False, + ), + ################################################################################# + # El Farol bar game efg + ( + games.create_el_farol_bar_game_efg(), + [[1, 0], ["1/2", "1/2"], ["1/3", "2/3"], ["1/5", "4/5"], ["1/8", "7/8"]], + ZERO, + True, + ), + ( + games.create_el_farol_bar_game_efg(), + [[1, 0], [1 / 2, 1 / 2], [1 / 3, 2 / 3], [1 / 5, 4 / 5], [1 / 8, 7 / 8]], + TOL, + False, + ), + ################################################################################# + # 2x2x2 nfg with 2 pure and 1 mixed eq + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + TOL, + False, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + TOL, + False, + ), + ], ) -def test_liap_value_consistency(game: gbt.Game, profile_data: list, - tol: float | gbt.Rational, - rational_flag: bool): +def test_liap_value_consistency( + game: gbt.Game, profile_data: list, tol: float | gbt.Rational, rational_flag: bool +): profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) assert ( - abs(profile.liap_value() - - sum([max(profile.strategy_value(strategy) - profile.payoff(player), 0)**2 - for player in game.players for strategy in player.strategies])) <= tol + abs( + profile.liap_value() + - sum( + [ + max(profile.strategy_value(strategy) - profile.payoff(player), 0) ** 2 + for player in game.players + for strategy in player.strategies + ] + ) + ) + <= tol ) @pytest.mark.parametrize( "game,profile_data,tol,rational_flag", [ - ################################################################################# - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), - [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], ZERO, True), - (games.create_coord_4x4_nfg(), - [[1/3, 1/3, 0/3, 1/3], [1/4, 1/4, 3/8, 1/8]], TOL, False), - ################################################################################# - # Centipede with chance efg - (games.create_centipede_game_with_chance_efg(), - [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", 0]], ZERO, True), - (games.create_centipede_game_with_chance_efg(), - [[1/3, 1/3, 1/3, 0], [.10, 3/5, .3, 0]], TOL, False), - ################################################################################# - # El Farol bar game efg - (games.create_el_farol_bar_game_efg(), - [[1, 0], ["1/2", "1/2"], ["1/3", "2/3"], ["1/5", "4/5"], ["1/8", "7/8"]], ZERO, True), - (games.create_el_farol_bar_game_efg(), - [[1, 0], [1/2, 1/2], [1/3, 2/3], [1/5, 4/5], [1/8, 7/8]], TOL, False), - ################################################################################# - # 2x2x2 nfg with 2 pure and 1 mixed eq - (games.create_2x2x2_nfg(), None, ZERO, True), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], ZERO, True), - (games.create_2x2x2_nfg(), None, TOL, False), - (games.create_2x2x2_nfg(), [[1, 0], [1, 0], [1, 0]], TOL, False), - ] + ################################################################################# + # 4x4 coordination nfg + ( + games.create_coord_4x4_nfg(), + [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], + ZERO, + True, + ), + ( + games.create_coord_4x4_nfg(), + [[1 / 3, 1 / 3, 0 / 3, 1 / 3], [1 / 4, 1 / 4, 3 / 8, 1 / 8]], + TOL, + False, + ), + ################################################################################# + # Centipede with chance efg + ( + games.create_centipede_game_with_chance_efg(), + [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", 0]], + ZERO, + True, + ), + ( + games.create_centipede_game_with_chance_efg(), + [[1 / 3, 1 / 3, 1 / 3, 0], [0.10, 3 / 5, 0.3, 0]], + TOL, + False, + ), + ################################################################################# + # El Farol bar game efg + ( + games.create_el_farol_bar_game_efg(), + [[1, 0], ["1/2", "1/2"], ["1/3", "2/3"], ["1/5", "4/5"], ["1/8", "7/8"]], + ZERO, + True, + ), + ( + games.create_el_farol_bar_game_efg(), + [[1, 0], [1 / 2, 1 / 2], [1 / 3, 2 / 3], [1 / 5, 4 / 5], [1 / 8, 7 / 8]], + TOL, + False, + ), + ################################################################################# + # 2x2x2 nfg with 2 pure and 1 mixed eq + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + ZERO, + True, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + None, + TOL, + False, + ), + ( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + [[1, 0], [1, 0], [1, 0]], + TOL, + False, + ), + ], ) -def test_player_regret_max_regret_consistency(game: gbt.Game, profile_data: list, - tol: float | gbt.Rational, - rational_flag: bool): +def test_player_regret_max_regret_consistency( + game: gbt.Game, profile_data: list, tol: float | gbt.Rational, rational_flag: bool +): profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) player_regrets = [] for p in game.players: - p_regret = max([max(profile.strategy_value(strategy) - profile.payoff(p), 0) - for strategy in p.strategies]) + p_regret = max( + [ + max(profile.strategy_value(strategy) - profile.payoff(p), 0) + for strategy in p.strategies + ] + ) player_regrets.append(p_regret) assert abs(profile.player_regret(p) - p_regret) <= tol assert abs(profile.max_regret() - max(player_regrets)) <= tol @@ -743,147 +1116,262 @@ def test_player_regret_max_regret_consistency(game: gbt.Game, profile_data: list @pytest.mark.parametrize( "game,profile1,profile2,alpha,tol,rational_flag", [ - ################################################################################# - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), - [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], - [["1/5", "2/5", "0/5", "2/5"], ["1/4", "3/8", "0/4", "3/8"]], - gbt.Rational("3/5"), ZERO, True), - (games.create_coord_4x4_nfg(), - [[1/5, 2/5, 0/5, 2/5], [3/8, 1/4, 3/8, 0/4]], [[1/5, 2/5, 0/5, 2/5], [1/4, 3/8, 0/4, 3/8]], - 3/5, TOL, False), - ################################################################################# - # Zero matrix nfg - (games.create_2x2_zero_nfg(), - [["1/4", "3/4"], ["3/5", "2/5"]], [["1/2", "1/2"], ["3/5", "2/5"]], - gbt.Rational("5/6"), ZERO, True), - ################################################################################# - # Centipede game with chance - (games.create_centipede_game_with_chance_efg(), - [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", "0/1"]], - [["1/3", "1/3", "1/3", "0/1"], ["1/5", "2/5", "1/5", "1/5"]], - gbt.Rational("1/12"), ZERO, True), - (games.create_centipede_game_with_chance_efg(), - [[1/3, 1/3, 1/3, 0/1], [1/10, 3/5, 3/10, 0/1]], [[1/3, 1/3, 1/3, 0/1], [1/5, 2/5, 1/5, 1/5]], - 1/12, TOL, False), - ################################################################################# - # Selten's horse game - (games.create_selten_horse_game_efg(), - [["4/9", "5/9"], ["1/11", "10/11"], ["8/9", "1/9"]], - [["4/9", "5/9"], ["10/11", "1/11"], ["8/9", "1/9"]], - gbt.Rational("4/9"), ZERO, True), - ################################################################################# - # El Farol bar game - (games.create_el_farol_bar_game_efg(), - [["4/9", "5/9"], ["1/3", "2/3"], ["1/2", "1/2"], ["11/12", "1/12"], ["1/2", "1/2"]], - [["4/9", "5/9"], ["1/3", "2/3"], ["1/2", "1/2"], ["1/12", "11/12"], ["1/2", "1/2"]], - gbt.Rational("1/2"), ZERO, True), - ] + ################################################################################# + # 4x4 coordination nfg + ( + games.create_coord_4x4_nfg(), + [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], + [["1/5", "2/5", "0/5", "2/5"], ["1/4", "3/8", "0/4", "3/8"]], + gbt.Rational("3/5"), + ZERO, + True, + ), + ( + games.create_coord_4x4_nfg(), + [[1 / 5, 2 / 5, 0 / 5, 2 / 5], [3 / 8, 1 / 4, 3 / 8, 0 / 4]], + [[1 / 5, 2 / 5, 0 / 5, 2 / 5], [1 / 4, 3 / 8, 0 / 4, 3 / 8]], + 3 / 5, + TOL, + False, + ), + ################################################################################# + # Zero matrix nfg + ( + games.create_2x2_zero_nfg(), + [["1/4", "3/4"], ["3/5", "2/5"]], + [["1/2", "1/2"], ["3/5", "2/5"]], + gbt.Rational("5/6"), + ZERO, + True, + ), + ################################################################################# + # Centipede game with chance + ( + games.create_centipede_game_with_chance_efg(), + [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", "0/1"]], + [["1/3", "1/3", "1/3", "0/1"], ["1/5", "2/5", "1/5", "1/5"]], + gbt.Rational("1/12"), + ZERO, + True, + ), + ( + games.create_centipede_game_with_chance_efg(), + [[1 / 3, 1 / 3, 1 / 3, 0 / 1], [1 / 10, 3 / 5, 3 / 10, 0 / 1]], + [[1 / 3, 1 / 3, 1 / 3, 0 / 1], [1 / 5, 2 / 5, 1 / 5, 1 / 5]], + 1 / 12, + TOL, + False, + ), + ################################################################################# + # Selten's horse game + ( + games.create_selten_horse_game_efg(), + [["4/9", "5/9"], ["1/11", "10/11"], ["8/9", "1/9"]], + [["4/9", "5/9"], ["10/11", "1/11"], ["8/9", "1/9"]], + gbt.Rational("4/9"), + ZERO, + True, + ), + ################################################################################# + # El Farol bar game + ( + games.create_el_farol_bar_game_efg(), + [["4/9", "5/9"], ["1/3", "2/3"], ["1/2", "1/2"], ["11/12", "1/12"], ["1/2", "1/2"]], + [["4/9", "5/9"], ["1/3", "2/3"], ["1/2", "1/2"], ["1/12", "11/12"], ["1/2", "1/2"]], + gbt.Rational("1/2"), + ZERO, + True, + ), + ], ) -def test_linearity_payoff_property(game: gbt.Game, profile1: list, profile2: list, - alpha: float | gbt.Rational, - tol: float | gbt.Rational, rational_flag: bool): +def test_linearity_payoff_property( + game: gbt.Game, + profile1: list, + profile2: list, + alpha: float | gbt.Rational, + tol: float | gbt.Rational, + rational_flag: bool, +): profile1 = game.mixed_strategy_profile(rational=rational_flag, data=profile1) profile2 = game.mixed_strategy_profile(rational=rational_flag, data=profile2) - profile_data = [[alpha*profile1[strategy] + (1-alpha)*profile2[strategy] - for strategy in player.strategies] for player in game.players] + profile_data = [ + [ + alpha * profile1[strategy] + (1 - alpha) * profile2[strategy] + for strategy in player.strategies + ] + for player in game.players + ] profile3 = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) for player in game.players: assert ( - abs(alpha*profile1.payoff(player) + (1 - alpha)*profile2.payoff(player) - - profile3.payoff(player)) <= tol + abs( + alpha * profile1.payoff(player) + + (1 - alpha) * profile2.payoff(player) + - profile3.payoff(player) + ) + <= tol ) @pytest.mark.parametrize( "game,profile_data,tol,rational_flag", [ - ################################################################################# - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), - [["1/5", "2/5", "0/5", "2/5"], ["1/4", "3/8", "0/4", "3/8"]], ZERO, True), - (games.create_coord_4x4_nfg(), [[0.2, 0.4, 0, 0.4], [1/4, 3/8, 0, 3/8]], TOL, False), - (gbt.Game.from_arrays([[1, 2], [-3, 4]], [[-4, 3], [2, 1]]), [[1/2, 1/2], [3/5, 2/5]], - TOL, False), - ################################################################################# - # Zero matrix nfg - (games.create_2x2_zero_nfg(), [["4/5", "1/5"], ["4/7", "3/7"]], ZERO, True), - ################################################################################# - # Centipede game with chance - (games.create_centipede_game_with_chance_efg(), - [["1/5", "2/5", "1/5", "1/5"], ["1/10", "3/5", "3/10", "0/1"]], ZERO, True), - (games.create_centipede_game_with_chance_efg(), - [[1/3, 1/3, 1/3, 0/1], [1/10, 3/5, 3/10, 0/1]], TOL, False), - ################################################################################# - # Selten's horse - (games.create_selten_horse_game_efg(), [["4/9", "5/9"], ["6/11", "5/11"], ["4/7", "3/7"]], - ZERO, True), - (games.create_selten_horse_game_efg(), [[4/9, 5/9], [6/11, 5/11], [4/7, 3/7]], TOL, False), - ################################################################################# - # El Farol bar game - (games.create_el_farol_bar_game_efg(), - [["4/9", "5/9"], ["1/3", "2/3"], ["0/1", "1/1"], ["11/12", "1/12"], ["1/3", "2/3"]], - ZERO, True), - ] + ################################################################################# + # 4x4 coordination nfg + ( + games.create_coord_4x4_nfg(), + [["1/5", "2/5", "0/5", "2/5"], ["1/4", "3/8", "0/4", "3/8"]], + ZERO, + True, + ), + (games.create_coord_4x4_nfg(), [[0.2, 0.4, 0, 0.4], [1 / 4, 3 / 8, 0, 3 / 8]], TOL, False), + ( + gbt.Game.from_arrays([[1, 2], [-3, 4]], [[-4, 3], [2, 1]]), + [[1 / 2, 1 / 2], [3 / 5, 2 / 5]], + TOL, + False, + ), + ################################################################################# + # Zero matrix nfg + (games.create_2x2_zero_nfg(), [["4/5", "1/5"], ["4/7", "3/7"]], ZERO, True), + ################################################################################# + # Centipede game with chance + ( + games.create_centipede_game_with_chance_efg(), + [["1/5", "2/5", "1/5", "1/5"], ["1/10", "3/5", "3/10", "0/1"]], + ZERO, + True, + ), + ( + games.create_centipede_game_with_chance_efg(), + [[1 / 3, 1 / 3, 1 / 3, 0 / 1], [1 / 10, 3 / 5, 3 / 10, 0 / 1]], + TOL, + False, + ), + ################################################################################# + # Selten's horse + ( + games.create_selten_horse_game_efg(), + [["4/9", "5/9"], ["6/11", "5/11"], ["4/7", "3/7"]], + ZERO, + True, + ), + ( + games.create_selten_horse_game_efg(), + [[4 / 9, 5 / 9], [6 / 11, 5 / 11], [4 / 7, 3 / 7]], + TOL, + False, + ), + ################################################################################# + # El Farol bar game + ( + games.create_el_farol_bar_game_efg(), + [["4/9", "5/9"], ["1/3", "2/3"], ["0/1", "1/1"], ["11/12", "1/12"], ["1/3", "2/3"]], + ZERO, + True, + ), + ], ) -def test_payoff_and_strategy_value_consistency(game: gbt.Game, profile_data: list, - tol: float | gbt.Rational, - rational_flag: bool): +def test_payoff_and_strategy_value_consistency( + game: gbt.Game, profile_data: list, tol: float | gbt.Rational, rational_flag: bool +): profile = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) for player in game.players: assert ( - abs(sum([profile[player][strategy] * profile.strategy_value(strategy) - for strategy in player.strategies]) - profile.payoff(player)) <= tol + abs( + sum( + [ + profile[player][strategy] * profile.strategy_value(strategy) + for strategy in player.strategies + ] + ) + - profile.payoff(player) + ) + <= tol ) @pytest.mark.parametrize( "game,profile1,profile2,alpha,rational_flag,tol", [ - ################################################################################# - # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), - [["1/1111", "10/1111", "100/1111", "1000/1111"], ["1/4", "1/8", "3/8", "1/4"]], - [["1/1111", "10/1111", "99/1111", "1001/1111"], ["1/4", "1/8", "3/8", "1/4"]], "1/2", True, - ZERO), - (games.create_coord_4x4_nfg(), - [[1/1111, 10/1111, 100/1111, 1000/1111], [1/4, 1/8, 3/8, 1/4]], - [[1/1111, 10/1111, 99/1111, 1001/1111], [1/4, 1/8, 3/8, 1/4]], 1/2, False, TOL), - ################################################################################# - # centipede game with chance - (games.create_centipede_game_with_chance_efg(), - [["1/3", "1/3", "1/3", "0"], ["1/10", "3/5", "3/10", "0"]], - [["1/3", "1/3", "1/3", "0"], ["1/10", "3/5", "3/10", "0"]], "82943/62500", True, ZERO), - (games.create_centipede_game_with_chance_efg(), - [[1/3, 1/3, 1/3, 0], [1/10, 3/5, 3/10, 0]], - [[1/3, 1/3, 1/3, 0], [1/10, 3/5, 3/10, 0]], 82943/62500, False, TOL), - ] + ################################################################################# + # 4x4 coordination nfg + ( + games.create_coord_4x4_nfg(), + [["1/1111", "10/1111", "100/1111", "1000/1111"], ["1/4", "1/8", "3/8", "1/4"]], + [["1/1111", "10/1111", "99/1111", "1001/1111"], ["1/4", "1/8", "3/8", "1/4"]], + "1/2", + True, + ZERO, + ), + ( + games.create_coord_4x4_nfg(), + [[1 / 1111, 10 / 1111, 100 / 1111, 1000 / 1111], [1 / 4, 1 / 8, 3 / 8, 1 / 4]], + [[1 / 1111, 10 / 1111, 99 / 1111, 1001 / 1111], [1 / 4, 1 / 8, 3 / 8, 1 / 4]], + 1 / 2, + False, + TOL, + ), + ################################################################################# + # centipede game with chance + ( + games.create_centipede_game_with_chance_efg(), + [["1/3", "1/3", "1/3", "0"], ["1/10", "3/5", "3/10", "0"]], + [["1/3", "1/3", "1/3", "0"], ["1/10", "3/5", "3/10", "0"]], + "82943/62500", + True, + ZERO, + ), + ( + games.create_centipede_game_with_chance_efg(), + [[1 / 3, 1 / 3, 1 / 3, 0], [1 / 10, 3 / 5, 3 / 10, 0]], + [[1 / 3, 1 / 3, 1 / 3, 0], [1 / 10, 3 / 5, 3 / 10, 0]], + 82943 / 62500, + False, + TOL, + ), + ], ) -def test_property_linearity_strategy_value(game: gbt.Game, profile1: list, profile2: list, - alpha: float | str, rational_flag: bool, - tol: float | gbt.Rational): - +def test_property_linearity_strategy_value( + game: gbt.Game, + profile1: list, + profile2: list, + alpha: float | str, + rational_flag: bool, + tol: float | gbt.Rational, +): alpha = gbt.Rational(alpha) if rational_flag else alpha profile1 = game.mixed_strategy_profile(rational=rational_flag, data=profile1) profile2 = game.mixed_strategy_profile(rational=rational_flag, data=profile2) - profile_data = [[alpha*profile1[strategy] + (1-alpha)*profile2[strategy] - for strategy in player.strategies] for player in game.players] + profile_data = [ + [ + alpha * profile1[strategy] + (1 - alpha) * profile2[strategy] + for strategy in player.strategies + ] + for player in game.players + ] profile3 = game.mixed_strategy_profile(rational=rational_flag, data=profile_data) for player in game.players: for strategy in player.strategies: - convex_comb = alpha * profile1.strategy_value(strategy) +\ - (1-alpha) * profile2.strategy_value(strategy) + convex_comb = alpha * profile1.strategy_value(strategy) + ( + 1 - alpha + ) * profile2.strategy_value(strategy) assert abs(profile3.strategy_value(strategy) - convex_comb) <= tol -def _get_answers_one_order(game: gbt.Game, action_probs_1st: tuple, action_probs_2nd: tuple, - rational_flag: bool, func_to_test: typing.Callable, - object_to_test_on: typing.Any): +def _get_answers_one_order( + game: gbt.Game, + action_probs_1st: tuple, + action_probs_2nd: tuple, + rational_flag: bool, + func_to_test: typing.Callable, + object_to_test_on: typing.Any, +): """helper function for the 'profile_order' caching tests""" ret = dict() profile = game.mixed_strategy_profile(rational=rational_flag) @@ -894,14 +1382,27 @@ def _get_answers_one_order(game: gbt.Game, action_probs_1st: tuple, action_probs return ret -def _get_and_check_answers(game: gbt.Game, action_probs1: tuple, action_probs2: tuple, - rational_flag: bool, func_to_test: typing.Callable, - objects_to_test_on: typing.Collection): +def _get_and_check_answers( + game: gbt.Game, + action_probs1: tuple, + action_probs2: tuple, + rational_flag: bool, + func_to_test: typing.Callable, + objects_to_test_on: typing.Collection, +): """helper function for the 'profile_order' caching tests""" - order1_answers = {o: _get_answers_one_order(game, action_probs1, action_probs2, rational_flag, - func_to_test, o) for o in objects_to_test_on} - order2_answers = {o: _get_answers_one_order(game, action_probs2, action_probs1, rational_flag, - func_to_test, o) for o in objects_to_test_on} + order1_answers = { + o: _get_answers_one_order( + game, action_probs1, action_probs2, rational_flag, func_to_test, o + ) + for o in objects_to_test_on + } + order2_answers = { + o: _get_answers_one_order( + game, action_probs2, action_probs1, rational_flag, func_to_test, o + ) + for o in objects_to_test_on + } assert order1_answers == order2_answers @@ -920,163 +1421,383 @@ def _get_and_check_answers(game: gbt.Game, action_probs1: tuple, action_probs2: @pytest.mark.parametrize( "game,action_probs1,action_probs2,rational_flag,func_to_test,objects_to_test", [ - ################################################################################# - # payoffs (for players) - ####################### - # 4x4 coordination nfg - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda profile, player: profile.payoff(player), lambda game: game.players, - id="payoffs_coord_doub"), - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda profile, player: profile.payoff(player), lambda game: game.players, - id="payoffs_coord_rat"), - # 2x2x2 nfg - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, player: profile.payoff(player), lambda game: game.players, - id="payoffs_2x2x2_doub"), - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, player: profile.payoff(player), lambda game: game.players, - id="payoffs_2x2x2_rat"), - # stripped-down poker - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, player: profile.payoff(player), lambda game: game.players, - id="payoffs_poker_doub"), - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, player: profile.payoff(player), lambda game: game.players, - id="payoffs_poker_rat"), - ################################################################################# - # regret (for strategies) - # 4x4 coordination nfg - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda profile, strategy: profile.strategy_regret(strategy), - lambda game: game.strategies, id="regret_coord_doub"), - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda profile, strategy: profile.strategy_regret(strategy), - lambda game: game.strategies, id="regret_coord_rat"), - # 2x2x2 nfg - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, strategy: profile.strategy_regret(strategy), - lambda game: game.strategies, id="regret_2x2x2_doub"), - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, strategy: profile.strategy_regret(strategy), - lambda game: game.strategies, id="regret_2x2x2_rat"), - # stripped-down poker - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, strategy: profile.strategy_regret(strategy), - lambda game: game.strategies, id="regret_poker_doub"), - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, strategy: profile.strategy_regret(strategy), - lambda game: game.strategies, id="regret_poker_rat"), - ################################################################################# - # strategy_value (for strategies) - # 4x4 coordination nfg - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda profile, strategy: profile.strategy_value(strategy), - lambda game: game.strategies, id="strat_value_coord_doub"), - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda profile, strategy: profile.strategy_value(strategy), - lambda game: game.strategies, id="strat_value_coord_rat"), - # 2x2x2 nfg - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, strategy: profile.strategy_value(strategy), - lambda game: game.strategies, id="strat_value_2x2x2_doub"), - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, strategy: profile.strategy_value(strategy), - lambda game: game.strategies, id="strat_value_2x2x2_rat"), - # stripped-down poker - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, strategy: profile.strategy_value(strategy), - lambda game: game.strategies, id="strat_value_poker_doub"), - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, strategy: profile.strategy_value(strategy), - lambda game: game.strategies, id="strat_value_poker_rat"), - ################################################################################# - # strategy_value_deriv (for strategies * strategies) - # 4x4 coordination nfg - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda profile, strat_pair: profile.strategy_value_deriv(strategy=strat_pair[0], - other=strat_pair[1]), - lambda game: list(product(game.strategies, game.strategies)), - id="strat_value_deriv_coord_doub"), - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda profile, strat_pair: profile.strategy_value_deriv(strategy=strat_pair[0], - other=strat_pair[1]), - lambda game: list(product(game.strategies, game.strategies)), - id="strat_value_deriv_coord_rat"), - # 2x2x2 nfg - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, strat_pair: profile.strategy_value_deriv(strategy=strat_pair[0], - other=strat_pair[1]), - lambda game: list(product(game.strategies, game.strategies)), - id="strat_value_deriv_2x2x2_doub"), - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, strat_pair: profile.strategy_value_deriv(strategy=strat_pair[0], - other=strat_pair[1]), - lambda game: list(product(game.strategies, game.strategies)), - id="strat_value_deriv_2x2x2_rat"), - # stripped-down poker - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, strat_pair: profile.strategy_value_deriv(strategy=strat_pair[0], - other=strat_pair[1]), - lambda game: list(product(game.strategies, game.strategies)), - id="strat_value_deriv_poker_doub"), - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, strat_pair: profile.strategy_value_deriv(strategy=strat_pair[0], - other=strat_pair[1]), - lambda game: list(product(game.strategies, game.strategies)), - id="strat_value_deriv_poker_rat"), - ################################################################################# - # liap_value (of profile, hence [1] for objects_to_test, any singleton collection would do) - # 4x4 coordination nfg - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda profile, y: profile.liap_value(), lambda x: [1], - id="liap_value_coord_doub"), - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda profile, y: profile.liap_value(), lambda x: [1], - id="liap_value_coord_rat"), - # 2x2x2 nfg - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, y: profile.liap_value(), lambda x: [1], - id="liap_value_2x2x2_doub"), - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, y: profile.liap_value(), lambda x: [1], - id="liap_value_2x2x2_rat"), - # stripped-down poker - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, y: profile.liap_value(), lambda x: [1], - id="liap_value_poker_doub"), - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, y: profile.liap_value(), lambda x: [1], - id="liap_value_poker_rat"), - ################################################################################# - # max_regret (of profile, hence [1] for objects_to_test, any singleton collection would do) - # 4x4 coordination nfg - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda profile, y: profile.max_regret(), lambda x: [1], - id="max_regret_coord_doub"), - pytest.param(games.create_coord_4x4_nfg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda profile, y: profile.max_regret(), lambda x: [1], - id="max_regret_coord_rat"), - # 2x2x2 nfg - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, y: profile.max_regret(), lambda x: [1], - id="max_regret_2x2x2_doub"), - pytest.param(games.create_2x2x2_nfg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, y: profile.max_regret(), lambda x: [1], - id="max_regret_2x2x2_rat"), - # stripped-down poker - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda profile, y: profile.max_regret(), lambda x: [1], - id="max_regret_poker_doub"), - pytest.param(games.create_stripped_down_poker_efg(), PROBS_1B_rat, PROBS_2B_rat, True, - lambda profile, y: profile.max_regret(), lambda x: [1], - id="max_regret_poker_rat"), - ] + ################################################################################# + # payoffs (for players) + ####################### + # 4x4 coordination nfg + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda profile, player: profile.payoff(player), + lambda game: game.players, + id="payoffs_coord_doub", + ), + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda profile, player: profile.payoff(player), + lambda game: game.players, + id="payoffs_coord_rat", + ), + # 2x2x2 nfg + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, player: profile.payoff(player), + lambda game: game.players, + id="payoffs_2x2x2_doub", + ), + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, player: profile.payoff(player), + lambda game: game.players, + id="payoffs_2x2x2_rat", + ), + # stripped-down poker + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, player: profile.payoff(player), + lambda game: game.players, + id="payoffs_poker_doub", + ), + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, player: profile.payoff(player), + lambda game: game.players, + id="payoffs_poker_rat", + ), + ################################################################################# + # regret (for strategies) + # 4x4 coordination nfg + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda profile, strategy: profile.strategy_regret(strategy), + lambda game: game.strategies, + id="regret_coord_doub", + ), + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda profile, strategy: profile.strategy_regret(strategy), + lambda game: game.strategies, + id="regret_coord_rat", + ), + # 2x2x2 nfg + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, strategy: profile.strategy_regret(strategy), + lambda game: game.strategies, + id="regret_2x2x2_doub", + ), + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, strategy: profile.strategy_regret(strategy), + lambda game: game.strategies, + id="regret_2x2x2_rat", + ), + # stripped-down poker + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, strategy: profile.strategy_regret(strategy), + lambda game: game.strategies, + id="regret_poker_doub", + ), + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, strategy: profile.strategy_regret(strategy), + lambda game: game.strategies, + id="regret_poker_rat", + ), + ################################################################################# + # strategy_value (for strategies) + # 4x4 coordination nfg + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda profile, strategy: profile.strategy_value(strategy), + lambda game: game.strategies, + id="strat_value_coord_doub", + ), + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda profile, strategy: profile.strategy_value(strategy), + lambda game: game.strategies, + id="strat_value_coord_rat", + ), + # 2x2x2 nfg + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, strategy: profile.strategy_value(strategy), + lambda game: game.strategies, + id="strat_value_2x2x2_doub", + ), + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, strategy: profile.strategy_value(strategy), + lambda game: game.strategies, + id="strat_value_2x2x2_rat", + ), + # stripped-down poker + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, strategy: profile.strategy_value(strategy), + lambda game: game.strategies, + id="strat_value_poker_doub", + ), + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, strategy: profile.strategy_value(strategy), + lambda game: game.strategies, + id="strat_value_poker_rat", + ), + ################################################################################# + # strategy_value_deriv (for strategies * strategies) + # 4x4 coordination nfg + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda profile, strat_pair: profile.strategy_value_deriv( + strategy=strat_pair[0], other=strat_pair[1] + ), + lambda game: list(product(game.strategies, game.strategies)), + id="strat_value_deriv_coord_doub", + ), + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda profile, strat_pair: profile.strategy_value_deriv( + strategy=strat_pair[0], other=strat_pair[1] + ), + lambda game: list(product(game.strategies, game.strategies)), + id="strat_value_deriv_coord_rat", + ), + # 2x2x2 nfg + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, strat_pair: profile.strategy_value_deriv( + strategy=strat_pair[0], other=strat_pair[1] + ), + lambda game: list(product(game.strategies, game.strategies)), + id="strat_value_deriv_2x2x2_doub", + ), + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, strat_pair: profile.strategy_value_deriv( + strategy=strat_pair[0], other=strat_pair[1] + ), + lambda game: list(product(game.strategies, game.strategies)), + id="strat_value_deriv_2x2x2_rat", + ), + # stripped-down poker + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, strat_pair: profile.strategy_value_deriv( + strategy=strat_pair[0], other=strat_pair[1] + ), + lambda game: list(product(game.strategies, game.strategies)), + id="strat_value_deriv_poker_doub", + ), + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, strat_pair: profile.strategy_value_deriv( + strategy=strat_pair[0], other=strat_pair[1] + ), + lambda game: list(product(game.strategies, game.strategies)), + id="strat_value_deriv_poker_rat", + ), + ################################################################################# + # liap_value (of profile, hence [1] for objects_to_test, any singleton collection would do) + # 4x4 coordination nfg + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda profile, y: profile.liap_value(), + lambda x: [1], + id="liap_value_coord_doub", + ), + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda profile, y: profile.liap_value(), + lambda x: [1], + id="liap_value_coord_rat", + ), + # 2x2x2 nfg + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, y: profile.liap_value(), + lambda x: [1], + id="liap_value_2x2x2_doub", + ), + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, y: profile.liap_value(), + lambda x: [1], + id="liap_value_2x2x2_rat", + ), + # stripped-down poker + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, y: profile.liap_value(), + lambda x: [1], + id="liap_value_poker_doub", + ), + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, y: profile.liap_value(), + lambda x: [1], + id="liap_value_poker_rat", + ), + ################################################################################# + # max_regret (of profile, hence [1] for objects_to_test, any singleton collection would do) + # 4x4 coordination nfg + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda profile, y: profile.max_regret(), + lambda x: [1], + id="max_regret_coord_doub", + ), + pytest.param( + games.create_coord_4x4_nfg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda profile, y: profile.max_regret(), + lambda x: [1], + id="max_regret_coord_rat", + ), + # 2x2x2 nfg + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, y: profile.max_regret(), + lambda x: [1], + id="max_regret_2x2x2_doub", + ), + pytest.param( + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, y: profile.max_regret(), + lambda x: [1], + id="max_regret_2x2x2_rat", + ), + # stripped-down poker + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda profile, y: profile.max_regret(), + lambda x: [1], + id="max_regret_poker_doub", + ), + pytest.param( + games.create_stripped_down_poker_efg(), + PROBS_1B_rat, + PROBS_2B_rat, + True, + lambda profile, y: profile.max_regret(), + lambda x: [1], + id="max_regret_poker_rat", + ), + ], ) -def test_profile_order_consistency(game: gbt.Game, - action_probs1: tuple, - action_probs2: tuple, rational_flag: bool, - func_to_test: typing.Callable, - objects_to_test: typing.Callable): - _get_and_check_answers(game, action_probs1, action_probs2, rational_flag, func_to_test, - objects_to_test(game)) +def test_profile_order_consistency( + game: gbt.Game, + action_probs1: tuple, + action_probs2: tuple, + rational_flag: bool, + func_to_test: typing.Callable, + objects_to_test: typing.Callable, +): + _get_and_check_answers( + game, action_probs1, action_probs2, rational_flag, func_to_test, objects_to_test(game) + ) diff --git a/tests/test_players.py b/tests/test_players.py index dd0257f0a..339ae1de2 100644 --- a/tests/test_players.py +++ b/tests/test_players.py @@ -152,7 +152,7 @@ def test_player_strategy_bad_type(): [ # NFGs ( - games.read_from_file("2x2x2_nfg_with_two_pure_one_mixed_eq.nfg"), + games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), [-1, 0, -1], [2, 4, 2] ), From fa705670c176ff190d4ccb139d9782ebe35e290e Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 13:34:29 +0000 Subject: [PATCH 02/24] removed create_coord_4x4_nfg from games.py --- tests/games.py | 12 -- tests/test_behav.py | 4 +- tests/test_mixed.py | 335 ++++++++++++++++++++++++++++++++------------ 3 files changed, 244 insertions(+), 107 deletions(-) diff --git a/tests/games.py b/tests/games.py index dbadfe033..96bccffa1 100644 --- a/tests/games.py +++ b/tests/games.py @@ -66,18 +66,6 @@ def create_2x2_zero_nfg() -> gbt.Game: return game -def create_coord_4x4_nfg(outcome_version: bool = False) -> gbt.Game: - """ - Returns - ------- - Game - 4x4 coordination game, either via reading in a payoff version nfg, or an - outcome version nfg, which has strategy labels useful for testing - """ - version = "outcome" if outcome_version else "payoff" - return read_from_file(f"coordination_4x4_{version}.nfg") - - ################################################################################################ # Extensive-form games (efg) diff --git a/tests/test_behav.py b/tests/test_behav.py index c3468ef0c..77c3f8e43 100644 --- a/tests/test_behav.py +++ b/tests/test_behav.py @@ -1345,9 +1345,9 @@ def test_profile_data_error(game: gbt.Game, rational_flag: bool, data: list): @pytest.mark.parametrize( "game,rational_flag,data", - [(games.create_coord_4x4_nfg(), True, + [(games.read_from_file("coordination_4x4_payoff.nfg"), True, [["1/5", "2/5", 0, "2/5"], ["1/4", "3/8", "1/4", "3/8"]]), - (games.create_coord_4x4_nfg(), False, + (games.read_from_file("coordination_4x4_payoff.nfg"), False, [[1/5, 2/5, 0/5, 2/5], [1/4, 3/8, 1/4, 3/8]]), ] ) diff --git a/tests/test_mixed.py b/tests/test_mixed.py index 975e26ee5..48d7fe10f 100644 --- a/tests/test_mixed.py +++ b/tests/test_mixed.py @@ -28,10 +28,22 @@ def _set_action_probs(profile: gbt.MixedStrategyProfile, probs: list, rational_f [ ############################################################################### # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), [[0, 0, 0, 0], ["1/3", "1/3", "1/3", 0]], True), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [0, 0, 0, 0]], True), - (games.create_coord_4x4_nfg(), [[0, 0, 0, 0], [1.0, 1.0, 1.0, 1.0]], False), - (games.create_coord_4x4_nfg(), [[1.0, 1.0, 1.0, 1.0], [0, 0, 0, 0]], False), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[0, 0, 0, 0], ["1/3", "1/3", "1/3", 0]], + True, + ), + (games.read_from_file("coordination_4x4_payoff.nfg"), [[1, 0, 0, 0], [0, 0, 0, 0]], True), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[0, 0, 0, 0], [1.0, 1.0, 1.0, 1.0]], + False, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[1.0, 1.0, 1.0, 1.0], [0, 0, 0, 0]], + False, + ), ############################################################################### # centipede with chance efg (games.create_centipede_game_with_chance_efg(), [[0, 0, 0, 0], [1, 0, 0, 0]], True), @@ -51,8 +63,16 @@ def test_normalize_zero_value_error(game, profile_data, rational_flag): [ ############################################################################### # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), [[1, 1, 0, -1], ["1/3", "1/3", "1/3", 0]], True), - (games.create_coord_4x4_nfg(), [[0, 0, 0, -1.0], [1.0, 1.0, 1.0, 1.0]], False), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[1, 1, 0, -1], ["1/3", "1/3", "1/3", 0]], + True, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[0, 0, 0, -1.0], [1.0, 1.0, 1.0, 1.0]], + False, + ), ############################################################################### # zero matrix nfg (games.create_2x2_zero_nfg(), [[1, 0], [0, -1]], True), @@ -77,13 +97,13 @@ def test_normalize_neg_entry_value_error(game, profile_data, rational_flag): ############################################################################### # 4x4 coordination nfg ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1, 2, 3, 14], [1, 1, 1, 1]], [["1/20", "2/20", "3/20", "14/20"], ["1/4", "1/4", "1/4", "1/4"]], True, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1.0, 2.0, 3.0, 14.0], [1, 1, 1, 1]], [[1 / 20, 2 / 20, 3 / 20, 14 / 20], [0.25, 0.25, 0.25, 0.25]], False, @@ -119,8 +139,8 @@ def test_normalize(game, profile_data, expected_data, rational_flag): (games.create_2x2_zero_nfg(), "cooperate", True, "7/9"), ############################################################################### # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", 0.25, False), - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", "1/4", True), + (games.read_from_file("coordination_4x4_outcome.nfg"), "1-1", 0.25, False), + (games.read_from_file("coordination_4x4_outcome.nfg"), "1-1", "1/4", True), ############################################################################### # stripped-down poker efg (games.create_stripped_down_poker_efg(), "11", 0.25, False), @@ -149,8 +169,8 @@ def test_set_and_get_probability_by_strategy_label( (games.create_2x2_zero_nfg(), "Joe", True, ["7/9", "2/9"]), ############################################################################## # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(), P1, False, [0.25, 0, 0, 0.75]), - (games.create_coord_4x4_nfg(), P1, True, ["1/4", 0, 0, "3/4"]), + (games.read_from_file("coordination_4x4_payoff.nfg"), P1, False, [0.25, 0, 0, 0.75]), + (games.read_from_file("coordination_4x4_payoff.nfg"), P1, True, ["1/4", 0, 0, "3/4"]), ############################################################################## # stripped-down poker efg (games.create_stripped_down_poker_efg(), "Alice", False, [0.25, 0.75, 0, 0]), @@ -189,8 +209,8 @@ def test_set_and_get_probabilities_by_player_label( (games.create_stripped_down_poker_efg(), "Bob", "2", "1/2", True), ############################################################################## # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(outcome_version=True), P1, "1-1", "1/4", True), - (games.create_coord_4x4_nfg(outcome_version=True), P2, "2-1", "1/4", True), + (games.read_from_file("coordination_4x4_outcome.nfg"), P1, "1-1", "1/4", True), + (games.read_from_file("coordination_4x4_outcome.nfg"), P2, "2-1", "1/4", True), ], ) def test_profile_indexing_by_player_and_strategy_label_reference( @@ -214,8 +234,8 @@ def test_profile_indexing_by_player_and_strategy_label_reference( (games.create_stripped_down_poker_efg(), "Alice", "2", False), ############################################################################## # coordination 4x4 nfg outcome version with strategy labels - (games.create_coord_4x4_nfg(outcome_version=True), P1, "2-1", True), - (games.create_coord_4x4_nfg(outcome_version=True), P2, "1-1", True), + (games.read_from_file("coordination_4x4_outcome.nfg"), P1, "2-1", True), + (games.read_from_file("coordination_4x4_outcome.nfg"), P2, "1-1", True), ], ) def test_profile_indexing_by_player_and_invalid_strategy_label( @@ -234,11 +254,41 @@ def test_profile_indexing_by_player_and_invalid_strategy_label( (games.create_stripped_down_poker_efg(), "13", True, KeyError, "player or strategy"), ############################################################################## # coordination 4x4 nfg payoff version (default strategy labels created with duplicates) - (games.create_coord_4x4_nfg(), "1", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "2", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "3", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "4", True, ValueError, "multiple strategies"), - (games.create_coord_4x4_nfg(), "5", True, KeyError, "player or strategy"), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + "1", + True, + ValueError, + "multiple strategies", + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + "2", + True, + ValueError, + "multiple strategies", + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + "3", + True, + ValueError, + "multiple strategies", + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + "4", + True, + ValueError, + "multiple strategies", + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + "5", + True, + KeyError, + "player or strategy", + ), ], ) def test_profile_indexing_by_invalid_strategy_label( @@ -284,11 +334,11 @@ def test_profile_indexing_by_player_and_duplicate_strategy_label(): ############################################################################ # coordination 4x4 nfg outcome version with strategy labels # Player 1 - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", "1/4", True), - (games.create_coord_4x4_nfg(outcome_version=True), "1-1", 0.25, False), + (games.read_from_file("coordination_4x4_outcome.nfg"), "1-1", "1/4", True), + (games.read_from_file("coordination_4x4_outcome.nfg"), "1-1", 0.25, False), # Player 2 - (games.create_coord_4x4_nfg(outcome_version=True), "2-1", "1/4", True), - (games.create_coord_4x4_nfg(outcome_version=True), "2-1", 0.25, False), + (games.read_from_file("coordination_4x4_outcome.nfg"), "2-1", "1/4", True), + (games.read_from_file("coordination_4x4_outcome.nfg"), "2-1", 0.25, False), ], ) def test_profile_indexing_by_strategy_label_reference( @@ -318,10 +368,20 @@ def test_profile_indexing_by_strategy_label_reference( (games.create_stripped_down_poker_efg(), "Bob", ["1/2", "1/2"], True), ############################################################################ # coordination 4x4 nfg - (games.create_coord_4x4_nfg(), P1, [0.25, 0.25, 0.25, 0.25], False), - (games.create_coord_4x4_nfg(), P2, [0.25, 0.25, 0.25, 0.25], False), - (games.create_coord_4x4_nfg(), P1, ["1/4", "1/4", "1/4", "1/4"], True), - (games.create_coord_4x4_nfg(), P2, ["1/4", "1/4", "1/4", "1/4"], True), + (games.read_from_file("coordination_4x4_payoff.nfg"), P1, [0.25, 0.25, 0.25, 0.25], False), + (games.read_from_file("coordination_4x4_payoff.nfg"), P2, [0.25, 0.25, 0.25, 0.25], False), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + P1, + ["1/4", "1/4", "1/4", "1/4"], + True, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + P2, + ["1/4", "1/4", "1/4", "1/4"], + True, + ), ], ) def test_profile_indexing_by_player_label_reference( @@ -342,18 +402,66 @@ def test_profile_indexing_by_player_label_reference( (games.create_2x2_zero_nfg(), True, None, "Joe", 0), ######################################################################### # coordination 4x4 nfg - (games.create_coord_4x4_nfg(), False, None, P1, 0.25), - (games.create_coord_4x4_nfg(), True, None, P1, "1/4"), - (games.create_coord_4x4_nfg(), False, None, P2, 0.25), - (games.create_coord_4x4_nfg(), True, None, P2, "1/4"), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [1, 0, 0, 0]], P1, 1), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [1, 0, 0, 0]], P1, 1), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [1, 0, 0, 0]], P2, 1), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [1, 0, 0, 0]], P2, 1), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [0, 1, 0, 0]], P1, 0), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [0, 1, 0, 0]], P1, 0), - (games.create_coord_4x4_nfg(), False, [[1, 0, 0, 0], [0, 1, 0, 0]], P2, 0), - (games.create_coord_4x4_nfg(), True, [[1, 0, 0, 0], [0, 1, 0, 0]], P2, 0), + (games.read_from_file("coordination_4x4_payoff.nfg"), False, None, P1, 0.25), + (games.read_from_file("coordination_4x4_payoff.nfg"), True, None, P1, "1/4"), + (games.read_from_file("coordination_4x4_payoff.nfg"), False, None, P2, 0.25), + (games.read_from_file("coordination_4x4_payoff.nfg"), True, None, P2, "1/4"), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + False, + [[1, 0, 0, 0], [1, 0, 0, 0]], + P1, + 1, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + True, + [[1, 0, 0, 0], [1, 0, 0, 0]], + P1, + 1, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + False, + [[1, 0, 0, 0], [1, 0, 0, 0]], + P2, + 1, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + True, + [[1, 0, 0, 0], [1, 0, 0, 0]], + P2, + 1, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + False, + [[1, 0, 0, 0], [0, 1, 0, 0]], + P1, + 0, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + True, + [[1, 0, 0, 0], [0, 1, 0, 0]], + P1, + 0, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + False, + [[1, 0, 0, 0], [0, 1, 0, 0]], + P2, + 0, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + True, + [[1, 0, 0, 0], [0, 1, 0, 0]], + P2, + 0, + ), ######################################################################### # stripped-down poker efg (games.create_stripped_down_poker_efg(), False, None, "Alice", -0.25), @@ -406,8 +514,8 @@ def test_payoff_by_label_reference( (games.create_2x2_zero_nfg(), True, "cooperate", 0), ############################################################################## # coordination 4x4 nfg - (games.create_coord_4x4_nfg(outcome_version=True), False, "1-1", 0.25), - (games.create_coord_4x4_nfg(outcome_version=True), True, "1-1", "1/4"), + (games.read_from_file("coordination_4x4_outcome.nfg"), False, "1-1", 0.25), + (games.read_from_file("coordination_4x4_outcome.nfg"), True, "1-1", "1/4"), ############################################################################## # stripped-down poker efg (games.create_stripped_down_poker_efg(), False, "11", 0.5), # Bet/Bet @@ -447,8 +555,8 @@ def test_as_behavior_roundtrip(game: gbt.Game, rational_flag: bool): [ (games.create_2x2_zero_nfg(), False), (games.create_2x2_zero_nfg(), True), - (games.create_coord_4x4_nfg(), False), - (games.create_coord_4x4_nfg(), True), + (games.read_from_file("coordination_4x4_payoff.nfg"), False), + (games.read_from_file("coordination_4x4_payoff.nfg"), True), ], ) def test_as_behavior_error(game: gbt.Game, rational_flag: bool): @@ -464,16 +572,16 @@ def test_as_behavior_error(game: gbt.Game, rational_flag: bool): (games.create_2x2_zero_nfg(), None, True, (0, 0)), ############################################################################### # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), None, False, (0.25, 0.25)), - (games.create_coord_4x4_nfg(), None, True, ("1/4", "1/4")), + (games.read_from_file("coordination_4x4_payoff.nfg"), None, False, (0.25, 0.25)), + (games.read_from_file("coordination_4x4_payoff.nfg"), None, True, ("1/4", "1/4")), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/3", "1/3", "1/3", 0], ["1/3", "1/3", "1/3", 0]], True, ("1/3", "1/3"), ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/3", "1/3", 0, "1/3"], ["1/3", "1/3", "1/3", 0]], True, ("2/9", "2/9"), @@ -525,25 +633,25 @@ def test_payoffs_reference( ############################################################################### # 4x4 coordination nfg ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), None, False, ([0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]), ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), None, True, ([0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]), ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1", "0", "0", "0"], ["1", "0", "0", "0"]], True, (["1", "0", "0", "0"], ["1", "0", "0", "0"]), ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["3/7", "0", "0", "4/7"], ["1/3", "1/3", "1/3", "0"]], True, (["1/3", "1/3", "1/3", "0"], ["3/7", "0", "0", "4/7"]), @@ -591,26 +699,50 @@ def test_strategy_value_reference( (games.create_2x2_zero_nfg(), [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], 0, TOL, False), ############################################################################## # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), None, 0, ZERO, True), - (games.create_coord_4x4_nfg(), None, 0, TOL, False), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], 0, ZERO, True), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], 0, TOL, False), + (games.read_from_file("coordination_4x4_payoff.nfg"), None, 0, ZERO, True), + (games.read_from_file("coordination_4x4_payoff.nfg"), None, 0, TOL, False), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[1, 0, 0, 0], [1, 0, 0, 0]], + 0, + ZERO, + True, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[1, 0, 0, 0], [1, 0, 0, 0]], + 0, + TOL, + False, + ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/3", "1/2", "1/12", "1/12"], ["3/8", "1/8", "1/4", "1/4"]], "245/2304", ZERO, True, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1 / 3, 1 / 2, 1 / 12, 1 / 12], [3 / 8, 1 / 8, 1 / 4, 1 / 4]], 245 / 2304, TOL, False, ), - (games.create_coord_4x4_nfg(), [["1/3", 0, 0, "2/3"], [1, 0, 0, 0]], "5/9", ZERO, True), - (games.create_coord_4x4_nfg(), [[1 / 3, 0, 0, 2 / 3], [1, 0, 0, 0]], 5 / 9, TOL, False), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [["1/3", 0, 0, "2/3"], [1, 0, 0, 0]], + "5/9", + ZERO, + True, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[1 / 3, 0, 0, 2 / 3], [1, 0, 0, 0]], + 5 / 9, + TOL, + False, + ), ############################################################################## # El Farol bar game efg ( @@ -741,33 +873,45 @@ def test_liap_value_reference( (games.create_2x2_zero_nfg(), [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], [0] * 2, TOL, False), ############################################################################## # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), None, [0] * 2, ZERO, True), - (games.create_coord_4x4_nfg(), None, [0] * 2, TOL, False), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], [0] * 2, ZERO, True), - (games.create_coord_4x4_nfg(), [[1, 0, 0, 0], [1, 0, 0, 0]], [0] * 2, TOL, False), + (games.read_from_file("coordination_4x4_payoff.nfg"), None, [0] * 2, ZERO, True), + (games.read_from_file("coordination_4x4_payoff.nfg"), None, [0] * 2, TOL, False), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), + [[1, 0, 0, 0], [1, 0, 0, 0]], + [0] * 2, + ZERO, + True, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[1, 0, 0, 0], [1, 0, 0, 0]], + [0] * 2, + TOL, + False, + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/3", "1/2", "1/12", "1/12"], ["3/8", "1/8", "1/4", "1/4"]], ["7/48", "13/48"], ZERO, True, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1 / 3, 1 / 2, 1 / 12, 1 / 12], [3 / 8, 1 / 8, 1 / 4, 1 / 4]], [7 / 48, 13 / 48], TOL, False, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/3", 0, 0, "2/3"], [1, 0, 0, 0]], ["2/3", "1/3"], ZERO, True, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1 / 3, 0, 0, 2 / 3], [1, 0, 0, 0]], [2 / 3, 1 / 3], TOL, @@ -900,8 +1044,8 @@ def test_player_regret_max_regret_reference( [ ################################################################################# # 4x4 coordination nfg - (games.create_coord_4x4_nfg(), False), - (games.create_coord_4x4_nfg(), True), + (games.read_from_file("coordination_4x4_payoff.nfg"), False), + (games.read_from_file("coordination_4x4_payoff.nfg"), True), ################################################################################# # Zero matrix nfg (games.create_2x2_zero_nfg(), False), @@ -936,13 +1080,13 @@ def test_strategy_regret_consistency(game: gbt.Game, rational_flag: bool): ################################################################################# # 4x4 coordination nfg ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], ZERO, True, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1 / 3, 1 / 3, 0 / 3, 1 / 3], [1 / 4, 1 / 4, 3 / 8, 1 / 8]], TOL, False, @@ -1029,13 +1173,13 @@ def test_liap_value_consistency( ################################################################################# # 4x4 coordination nfg ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], ZERO, True, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1 / 3, 1 / 3, 0 / 3, 1 / 3], [1 / 4, 1 / 4, 3 / 8, 1 / 8]], TOL, False, @@ -1119,7 +1263,7 @@ def test_player_regret_max_regret_consistency( ################################################################################# # 4x4 coordination nfg ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/5", "2/5", "0/5", "2/5"], ["3/8", "1/4", "3/8", "0/4"]], [["1/5", "2/5", "0/5", "2/5"], ["1/4", "3/8", "0/4", "3/8"]], gbt.Rational("3/5"), @@ -1127,7 +1271,7 @@ def test_player_regret_max_regret_consistency( True, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1 / 5, 2 / 5, 0 / 5, 2 / 5], [3 / 8, 1 / 4, 3 / 8, 0 / 4]], [[1 / 5, 2 / 5, 0 / 5, 2 / 5], [1 / 4, 3 / 8, 0 / 4, 3 / 8]], 3 / 5, @@ -1221,12 +1365,17 @@ def test_linearity_payoff_property( ################################################################################# # 4x4 coordination nfg ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/5", "2/5", "0/5", "2/5"], ["1/4", "3/8", "0/4", "3/8"]], ZERO, True, ), - (games.create_coord_4x4_nfg(), [[0.2, 0.4, 0, 0.4], [1 / 4, 3 / 8, 0, 3 / 8]], TOL, False), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + [[0.2, 0.4, 0, 0.4], [1 / 4, 3 / 8, 0, 3 / 8]], + TOL, + False, + ), ( gbt.Game.from_arrays([[1, 2], [-3, 4]], [[-4, 3], [2, 1]]), [[1 / 2, 1 / 2], [3 / 5, 2 / 5]], @@ -1299,7 +1448,7 @@ def test_payoff_and_strategy_value_consistency( ################################################################################# # 4x4 coordination nfg ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [["1/1111", "10/1111", "100/1111", "1000/1111"], ["1/4", "1/8", "3/8", "1/4"]], [["1/1111", "10/1111", "99/1111", "1001/1111"], ["1/4", "1/8", "3/8", "1/4"]], "1/2", @@ -1307,7 +1456,7 @@ def test_payoff_and_strategy_value_consistency( ZERO, ), ( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), [[1 / 1111, 10 / 1111, 100 / 1111, 1000 / 1111], [1 / 4, 1 / 8, 3 / 8, 1 / 4]], [[1 / 1111, 10 / 1111, 99 / 1111, 1001 / 1111], [1 / 4, 1 / 8, 3 / 8, 1 / 4]], 1 / 2, @@ -1426,7 +1575,7 @@ def _get_and_check_answers( ####################### # 4x4 coordination nfg pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_doub, PROBS_2A_doub, False, @@ -1435,7 +1584,7 @@ def _get_and_check_answers( id="payoffs_coord_doub", ), pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_rat, PROBS_2A_rat, True, @@ -1485,7 +1634,7 @@ def _get_and_check_answers( # regret (for strategies) # 4x4 coordination nfg pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_doub, PROBS_2A_doub, False, @@ -1494,7 +1643,7 @@ def _get_and_check_answers( id="regret_coord_doub", ), pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_rat, PROBS_2A_rat, True, @@ -1544,7 +1693,7 @@ def _get_and_check_answers( # strategy_value (for strategies) # 4x4 coordination nfg pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_doub, PROBS_2A_doub, False, @@ -1553,7 +1702,7 @@ def _get_and_check_answers( id="strat_value_coord_doub", ), pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_rat, PROBS_2A_rat, True, @@ -1603,7 +1752,7 @@ def _get_and_check_answers( # strategy_value_deriv (for strategies * strategies) # 4x4 coordination nfg pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_doub, PROBS_2A_doub, False, @@ -1614,7 +1763,7 @@ def _get_and_check_answers( id="strat_value_deriv_coord_doub", ), pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_rat, PROBS_2A_rat, True, @@ -1674,7 +1823,7 @@ def _get_and_check_answers( # liap_value (of profile, hence [1] for objects_to_test, any singleton collection would do) # 4x4 coordination nfg pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_doub, PROBS_2A_doub, False, @@ -1683,7 +1832,7 @@ def _get_and_check_answers( id="liap_value_coord_doub", ), pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_rat, PROBS_2A_rat, True, @@ -1733,7 +1882,7 @@ def _get_and_check_answers( # max_regret (of profile, hence [1] for objects_to_test, any singleton collection would do) # 4x4 coordination nfg pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_doub, PROBS_2A_doub, False, @@ -1742,7 +1891,7 @@ def _get_and_check_answers( id="max_regret_coord_doub", ), pytest.param( - games.create_coord_4x4_nfg(), + games.read_from_file("coordination_4x4_payoff.nfg"), PROBS_1A_rat, PROBS_2A_rat, True, From 543c937fe1d08dfb8960d5c08101b3768ffc0036 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 13:50:07 +0000 Subject: [PATCH 03/24] removed create_2x2_zero_nfg from games.py --- tests/games.py | 28 ----------- tests/test_io.py | 8 ++-- tests/test_mixed.py | 113 +++++++++++++++++++++++++++++++++----------- 3 files changed, 89 insertions(+), 60 deletions(-) diff --git a/tests/games.py b/tests/games.py index 96bccffa1..8197f8d93 100644 --- a/tests/games.py +++ b/tests/games.py @@ -5,7 +5,6 @@ from abc import ABC, abstractmethod import numpy as np -import pytest import pygambit as gbt @@ -39,33 +38,6 @@ def create_efg_corresponding_to_bimatrix_game( return g -################################################################################################ -# Normal-form (aka strategic-form) games (nfg) - - -def create_2x2_zero_nfg() -> gbt.Game: - """ - Returns - ------- - Game - 2x2 all-zero-payoffs bimatrix, with player names and a duplicate label set intentionally - for testing purposes - """ - game = gbt.Game.new_table([2, 2]) - - game.players[0].label = "Joe" - game.players["Joe"].strategies[0].label = "cooperate" - game.players["Joe"].strategies[1].label = "defect" - - game.players[1].label = "Dan" - game.players["Dan"].strategies[0].label = "defect" - # intentional duplicate label for player - with pytest.warns(FutureWarning): - game.players["Dan"].strategies[1].label = "defect" - - return game - - ################################################################################################ # Extensive-form games (efg) diff --git a/tests/test_io.py b/tests/test_io.py index 05046b8fa..c0bf876ec 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -6,7 +6,7 @@ import pygambit as gbt -from .games import create_2x2_zero_nfg, create_selten_horse_game_efg +from . import games @pytest.mark.parametrize("game_path", glob(os.path.join("tests", "test_games", "*.efg"))) @@ -112,7 +112,7 @@ def test_write_latex(): def test_read_write_efg(): - efg_game = create_selten_horse_game_efg() + efg_game = games.create_selten_horse_game_efg() serialized_efg_game = efg_game.to_efg() deserialized_efg_game = gbt.read_efg(io.BytesIO(serialized_efg_game.encode())) double_serialized_efg_game = deserialized_efg_game.to_efg() @@ -120,7 +120,7 @@ def test_read_write_efg(): def test_read_write_nfg(): - nfg_game = create_2x2_zero_nfg() + nfg_game = games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg") serialized_nfg_game = nfg_game.to_nfg() deserialized_nfg_game = gbt.read_nfg( io.BytesIO(serialized_nfg_game.encode()), normalize_labels=False @@ -130,7 +130,7 @@ def test_read_write_nfg(): def test_read_write_nfg_normalize(): - nfg_game = create_2x2_zero_nfg() + nfg_game = games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg") serialized_nfg_game = nfg_game.to_nfg() deserialized_nfg_game = gbt.read_nfg( io.BytesIO(serialized_nfg_game.encode()), normalize_labels=True diff --git a/tests/test_mixed.py b/tests/test_mixed.py index 48d7fe10f..731f6f35f 100644 --- a/tests/test_mixed.py +++ b/tests/test_mixed.py @@ -75,8 +75,12 @@ def test_normalize_zero_value_error(game, profile_data, rational_flag): ), ############################################################################### # zero matrix nfg - (games.create_2x2_zero_nfg(), [[1, 0], [0, -1]], True), - (games.create_2x2_zero_nfg(), [[1.0, 1.0], [0, -1.0]], False), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), [[1, 0], [0, -1]], True), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [[1.0, 1.0], [0, -1.0]], + False, + ), ############################################################################### # centipede with chance efg (games.create_centipede_game_with_chance_efg(), [[-1, 0, 0, 0], [1, 0, 0, 0]], True), @@ -135,8 +139,8 @@ def test_normalize(game, profile_data, expected_data, rational_flag): [ ############################################################################## # zero matrix nfg - (games.create_2x2_zero_nfg(), "cooperate", False, 0.72), - (games.create_2x2_zero_nfg(), "cooperate", True, "7/9"), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), "cooperate", False, 0.72), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), "cooperate", True, "7/9"), ############################################################################### # coordination 4x4 nfg outcome version with strategy labels (games.read_from_file("coordination_4x4_outcome.nfg"), "1-1", 0.25, False), @@ -165,8 +169,8 @@ def test_set_and_get_probability_by_strategy_label( [ ############################################################################## # zero matrix nfg - (games.create_2x2_zero_nfg(), "Joe", False, [0.72, 0.28]), - (games.create_2x2_zero_nfg(), "Joe", True, ["7/9", "2/9"]), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), "Joe", False, [0.72, 0.28]), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), "Joe", True, ["7/9", "2/9"]), ############################################################################## # coordination 4x4 nfg outcome version with strategy labels (games.read_from_file("coordination_4x4_payoff.nfg"), P1, False, [0.25, 0, 0, 0.75]), @@ -306,7 +310,7 @@ def test_profile_indexing_by_invalid_strategy_label( def test_profile_indexing_by_player_and_duplicate_strategy_label(): - game = games.create_2x2_zero_nfg() + game = games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg") profile = game.mixed_strategy_profile() with pytest.raises(ValueError): profile["Dan"]["defect"] @@ -398,8 +402,8 @@ def test_profile_indexing_by_player_label_reference( [ ######################################################################### # zero matrix nfg - (games.create_2x2_zero_nfg(), False, None, "Joe", 0), - (games.create_2x2_zero_nfg(), True, None, "Joe", 0), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), False, None, "Joe", 0), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), True, None, "Joe", 0), ######################################################################### # coordination 4x4 nfg (games.read_from_file("coordination_4x4_payoff.nfg"), False, None, P1, 0.25), @@ -510,8 +514,8 @@ def test_payoff_by_label_reference( [ ############################################################################## # zero matrix nfg - (games.create_2x2_zero_nfg(), False, "cooperate", 0), - (games.create_2x2_zero_nfg(), True, "cooperate", 0), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), False, "cooperate", 0), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), True, "cooperate", 0), ############################################################################## # coordination 4x4 nfg (games.read_from_file("coordination_4x4_outcome.nfg"), False, "1-1", 0.25), @@ -553,8 +557,8 @@ def test_as_behavior_roundtrip(game: gbt.Game, rational_flag: bool): @pytest.mark.parametrize( "game,rational_flag", [ - (games.create_2x2_zero_nfg(), False), - (games.create_2x2_zero_nfg(), True), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), False), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), True), (games.read_from_file("coordination_4x4_payoff.nfg"), False), (games.read_from_file("coordination_4x4_payoff.nfg"), True), ], @@ -569,7 +573,7 @@ def test_as_behavior_error(game: gbt.Game, rational_flag: bool): [ ############################################################################### # zero matrix nfg - (games.create_2x2_zero_nfg(), None, True, (0, 0)), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), None, True, (0, 0)), ############################################################################### # 4x4 coordination nfg (games.read_from_file("coordination_4x4_payoff.nfg"), None, False, (0.25, 0.25)), @@ -628,8 +632,8 @@ def test_payoffs_reference( [ ############################################################################### # zero matrix nfg - (games.create_2x2_zero_nfg(), None, False, ([0, 0], [0, 0])), - (games.create_2x2_zero_nfg(), None, True, ([0, 0], [0, 0])), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), None, False, ([0, 0], [0, 0])), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), None, True, ([0, 0], [0, 0])), ############################################################################### # 4x4 coordination nfg ( @@ -693,10 +697,34 @@ def test_strategy_value_reference( [ ############################################################################## # Zero matrix nfg, all liap_values are zero - (games.create_2x2_zero_nfg(), [["3/4", "1/4"], ["2/5", "3/5"]], 0, ZERO, True), - (games.create_2x2_zero_nfg(), [["1/2", "1/2"], ["1/2", "1/2"]], 0, ZERO, True), - (games.create_2x2_zero_nfg(), [[1, 0], [1, 0]], 0, ZERO, True), - (games.create_2x2_zero_nfg(), [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], 0, TOL, False), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [["3/4", "1/4"], ["2/5", "3/5"]], + 0, + ZERO, + True, + ), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [["1/2", "1/2"], ["1/2", "1/2"]], + 0, + ZERO, + True, + ), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [[1, 0], [1, 0]], + 0, + ZERO, + True, + ), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], + 0, + TOL, + False, + ), ############################################################################## # 4x4 coordination nfg (games.read_from_file("coordination_4x4_payoff.nfg"), None, 0, ZERO, True), @@ -867,10 +895,34 @@ def test_liap_value_reference( [ ############################################################################## # Zero matrix nfg, all liap_values are zero - (games.create_2x2_zero_nfg(), [["3/4", "1/4"], ["2/5", "3/5"]], [0] * 2, ZERO, True), - (games.create_2x2_zero_nfg(), [["1/2", "1/2"], ["1/2", "1/2"]], [0] * 2, ZERO, True), - (games.create_2x2_zero_nfg(), [[1, 0], [1, 0]], [0] * 2, ZERO, True), - (games.create_2x2_zero_nfg(), [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], [0] * 2, TOL, False), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [["3/4", "1/4"], ["2/5", "3/5"]], + [0] * 2, + ZERO, + True, + ), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [["1/2", "1/2"], ["1/2", "1/2"]], + [0] * 2, + ZERO, + True, + ), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [[1, 0], [1, 0]], + [0] * 2, + ZERO, + True, + ), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [[1 / 4, 3 / 4], [2 / 5, 3 / 5]], + [0] * 2, + TOL, + False, + ), ############################################################################## # 4x4 coordination nfg (games.read_from_file("coordination_4x4_payoff.nfg"), None, [0] * 2, ZERO, True), @@ -1048,8 +1100,8 @@ def test_player_regret_max_regret_reference( (games.read_from_file("coordination_4x4_payoff.nfg"), True), ################################################################################# # Zero matrix nfg - (games.create_2x2_zero_nfg(), False), - (games.create_2x2_zero_nfg(), True), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), False), + (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), True), ################################################################################# # El Farol bar game efg (games.create_el_farol_bar_game_efg(), False), @@ -1281,7 +1333,7 @@ def test_player_regret_max_regret_consistency( ################################################################################# # Zero matrix nfg ( - games.create_2x2_zero_nfg(), + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), [["1/4", "3/4"], ["3/5", "2/5"]], [["1/2", "1/2"], ["3/5", "2/5"]], gbt.Rational("5/6"), @@ -1384,7 +1436,12 @@ def test_linearity_payoff_property( ), ################################################################################# # Zero matrix nfg - (games.create_2x2_zero_nfg(), [["4/5", "1/5"], ["4/7", "3/7"]], ZERO, True), + ( + games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), + [["4/5", "1/5"], ["4/7", "3/7"]], + ZERO, + True, + ), ################################################################################# # Centipede game with chance ( From c8f1752593497f7eefed85e86285ac46b9cbce7b Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 14:03:29 +0000 Subject: [PATCH 04/24] removed create_STOC_simplified{,2} from games.py (which were not used anyway) --- tests/games.py | 86 -------------------------------------------------- 1 file changed, 86 deletions(-) diff --git a/tests/games.py b/tests/games.py index 8197f8d93..8c33fe015 100644 --- a/tests/games.py +++ b/tests/games.py @@ -801,92 +801,6 @@ def create_problem_example_efg() -> gbt.Game: return g -def create_STOC_simplified() -> gbt.Game: - """ - """ - g = gbt.Game.new_tree(players=["1", "2"], title="") - g.append_move(g.root, g.players.chance, actions=["1", "2"]) - g.set_chance_probs(g.root.infoset, [0.2, 0.8]) - g.append_move(g.root.children[0], player="1", actions=["l", "r"]) - g.append_move(g.root.children[1], player="1", actions=["c", "d"]) - g.append_move(g.root.children[0].children[1], player="2", actions=["p", "q"]) - g.append_move( - g.root.children[0].children[1].children[0], player="1", actions=["L", "R"] - ) - g.append_infoset( - g.root.children[0].children[1].children[1], - g.root.children[0].children[1].children[0].infoset, - ) - g.set_outcome( - g.root.children[0].children[0], - outcome=g.add_outcome(payoffs=[5, -5], label="l"), - ) - g.set_outcome( - g.root.children[0].children[1].children[0].children[0], - outcome=g.add_outcome(payoffs=[10, -10], label="rpL"), - ) - g.set_outcome( - g.root.children[0].children[1].children[0].children[1], - outcome=g.add_outcome(payoffs=[15, -15], label="rpR"), - ) - g.set_outcome( - g.root.children[0].children[1].children[1].children[0], - outcome=g.add_outcome(payoffs=[20, -20], label="rqL"), - ) - g.set_outcome( - g.root.children[0].children[1].children[1].children[1], - outcome=g.add_outcome(payoffs=[-5, 5], label="rqR"), - ) - g.set_outcome( - g.root.children[1].children[0], - outcome=g.add_outcome(payoffs=[10, -10], label="c"), - ) - g.set_outcome( - g.root.children[1].children[1], - outcome=g.add_outcome(payoffs=[20, -20], label="d"), - ) - return g - - -def create_STOC_simplified2() -> gbt.Game: - """ - """ - g = gbt.Game.new_tree(players=["1", "2"], title="") - g.append_move(g.root, g.players.chance, actions=["1", "2"]) - g.set_chance_probs(g.root.infoset, [0.2, 0.8]) - g.append_move(g.root.children[0], player="1", actions=["r"]) - g.append_move(g.root.children[1], player="1", actions=["c"]) - g.append_move(g.root.children[0].children[0], player="2", actions=["p", "q"]) - g.append_move( - g.root.children[0].children[0].children[0], player="1", actions=["L", "R"] - ) - g.append_infoset( - g.root.children[0].children[0].children[1], - g.root.children[0].children[0].children[0].infoset, - ) - g.set_outcome( - g.root.children[0].children[0].children[0].children[0], - outcome=g.add_outcome(payoffs=[10, -10], label="rpL"), - ) - g.set_outcome( - g.root.children[0].children[0].children[0].children[1], - outcome=g.add_outcome(payoffs=[15, -15], label="rpR"), - ) - g.set_outcome( - g.root.children[0].children[0].children[1].children[0], - outcome=g.add_outcome(payoffs=[20, -20], label="rqL"), - ) - g.set_outcome( - g.root.children[0].children[0].children[1].children[1], - outcome=g.add_outcome(payoffs=[-5, 5], label="rqR"), - ) - g.set_outcome( - g.root.children[1].children[0], - outcome=g.add_outcome(payoffs=[10, -10], label="c"), - ) - return g - - def create_seq_form_STOC_paper_zero_sum_2_player_efg() -> gbt.Game: """ Example from From 68870996a1be9850c6ff86b661726750e43fa5a8 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 14:11:52 +0000 Subject: [PATCH 05/24] added new .nfg files --- .../2x2_bimatrix_all_zero_payoffs.nfg | 14 +++++++++++ tests/test_games/STOC.efg | 24 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/test_games/2x2_bimatrix_all_zero_payoffs.nfg create mode 100644 tests/test_games/STOC.efg diff --git a/tests/test_games/2x2_bimatrix_all_zero_payoffs.nfg b/tests/test_games/2x2_bimatrix_all_zero_payoffs.nfg new file mode 100644 index 000000000..7a290820d --- /dev/null +++ b/tests/test_games/2x2_bimatrix_all_zero_payoffs.nfg @@ -0,0 +1,14 @@ +NFG 1 R "2x2 bimatrix game with all zero payoffs, with strategy labels" { "Joe" "Dan" } + +{ { "cooperate" "defect" } +{ "defect" "defect" } +} +"" + +{ +{ "" 0, 0 } +{ "" 0, 0 } +{ "" 0, 0 } +{ "" 0, 0 } +} +1 2 3 4 diff --git a/tests/test_games/STOC.efg b/tests/test_games/STOC.efg new file mode 100644 index 000000000..73c230af5 --- /dev/null +++ b/tests/test_games/STOC.efg @@ -0,0 +1,24 @@ +EFG 2 R "From STOC'94 paper" { "1" "2" } +"" + +c "" 1 "" { "1" 0.2 "2" 0.2 "3" 0.2 "4" 0.4 } 0 +p "" 1 1 "0" { "l" "r" } 0 +t "" 1 "l" { 5, -5 } +p "" 2 1 "01" { "p" "q" } 0 +p "" 1 3 "010" { "L" "R" } 0 +t "" 2 "rpL" { 10, -10 } +t "" 3 "rpR" { 15, -15 } +p "" 1 3 "010" { "L" "R" } 0 +t "" 4 "rqL" { 20, -20 } +t "" 5 "rqR" { -5, 5 } +p "" 1 2 "1" { "c" "d" } 0 +t "" 6 "c" { 10, -10 } +t "" 7 "d" { 20, -20 } +p "" 1 2 "1" { "c" "d" } 0 +p "" 2 2 "20" { "s" "t" } 0 +t "" 8 "cs" { 20, -20 } +t "" 9 "ct" { 50, -50 } +p "" 2 2 "20" { "s" "t" } 0 +t "" 10 "ds" { 30, -30 } +t "" 11 "dt" { 15, -15 } +t "" 12 "nothing" { 5, -5 } From 00b28c308ca3c8f22484e9a6b975a9a36c569dea Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 14:20:55 +0000 Subject: [PATCH 06/24] removed create_seq_form_STOC_paper_zero_sum_2_player_efg from games.py --- tests/games.py | 81 ------------------- ...m_efg_from_sequence_form_STOC94_paper.efg} | 9 ++- tests/test_nash.py | 2 +- 3 files changed, 8 insertions(+), 84 deletions(-) rename tests/test_games/{STOC.efg => zerosum_efg_from_sequence_form_STOC94_paper.efg} (73%) diff --git a/tests/games.py b/tests/games.py index 8c33fe015..20f997f7b 100644 --- a/tests/games.py +++ b/tests/games.py @@ -801,87 +801,6 @@ def create_problem_example_efg() -> gbt.Game: return g -def create_seq_form_STOC_paper_zero_sum_2_player_efg() -> gbt.Game: - """ - Example from - - Fast Algorithms for Finding Randomized Strategies in Game Trees (1994) - Koller, Megiddo, von Stengel - """ - g = gbt.Game.new_tree(players=["1", "2"], title="From STOC'94 paper") - g.append_move(g.root, g.players.chance, actions=["1", "2", "3", "4"]) - g.set_chance_probs(g.root.infoset, [0.2, 0.2, 0.2, 0.4]) - g.append_move(g.root.children[0], player="1", actions=["l", "r"]) - g.append_move(g.root.children[1], player="1", actions=["c", "d"]) - g.append_infoset(g.root.children[2], g.root.children[1].infoset) - g.append_move(g.root.children[0].children[1], player="2", actions=["p", "q"]) - g.append_move( - g.root.children[0].children[1].children[0], player="1", actions=["L", "R"] - ) - g.append_infoset( - g.root.children[0].children[1].children[1], - g.root.children[0].children[1].children[0].infoset, - ) - g.append_move(g.root.children[2].children[0], player="2", actions=["s", "t"]) - g.append_infoset( - g.root.children[2].children[1], g.root.children[2].children[0].infoset - ) - - g.set_outcome( - g.root.children[0].children[0], - outcome=g.add_outcome(payoffs=[5, -5], label="l"), - ) - g.set_outcome( - g.root.children[0].children[1].children[0].children[0], - outcome=g.add_outcome(payoffs=[10, -10], label="rpL"), - ) - g.set_outcome( - g.root.children[0].children[1].children[0].children[1], - outcome=g.add_outcome(payoffs=[15, -15], label="rpR"), - ) - g.set_outcome( - g.root.children[0].children[1].children[1].children[0], - outcome=g.add_outcome(payoffs=[20, -20], label="rqL"), - ) - g.set_outcome( - g.root.children[0].children[1].children[1].children[1], - outcome=g.add_outcome(payoffs=[-5, 5], label="rqR"), - ) - g.set_outcome( - g.root.children[1].children[0], - outcome=g.add_outcome(payoffs=[10, -10], label="c"), - ) - g.set_outcome( - g.root.children[1].children[1], - outcome=g.add_outcome(payoffs=[20, -20], label="d"), - ) - g.set_outcome( - g.root.children[2].children[0].children[0], - outcome=g.add_outcome(payoffs=[20, -20], label="cs"), - ) - g.set_outcome( - g.root.children[2].children[0].children[1], - outcome=g.add_outcome(payoffs=[50, -50], label="ct"), - ) - g.set_outcome( - g.root.children[2].children[1].children[0], - outcome=g.add_outcome(payoffs=[30, -30], label="ds"), - ) - g.set_outcome( - g.root.children[2].children[1].children[1], - outcome=g.add_outcome(payoffs=[15, -15], label="dt"), - ) - g.set_outcome( - g.root.children[3], outcome=g.add_outcome(payoffs=[5, -5], label="nothing") - ) - g.root.children[0].infoset.label = "0" - g.root.children[1].infoset.label = "1" - g.root.children[0].children[1].infoset.label = "01" - g.root.children[2].children[0].infoset.label = "20" - g.root.children[0].children[1].children[0].infoset.label = "010" - return g - - def create_two_player_perfect_info_win_lose_efg(nonterm_outcomes: bool = False) -> gbt.Game: g = gbt.Game.new_tree(players=["1", "2"], title="2 player perfect info win lose") g.append_move(g.root, "2", ["a", "b"]) diff --git a/tests/test_games/STOC.efg b/tests/test_games/zerosum_efg_from_sequence_form_STOC94_paper.efg similarity index 73% rename from tests/test_games/STOC.efg rename to tests/test_games/zerosum_efg_from_sequence_form_STOC94_paper.efg index 73c230af5..750ff2de7 100644 --- a/tests/test_games/STOC.efg +++ b/tests/test_games/zerosum_efg_from_sequence_form_STOC94_paper.efg @@ -1,5 +1,10 @@ -EFG 2 R "From STOC'94 paper" { "1" "2" } -"" +EFG 2 R "Two-player zero-sum EFG from sequence form STOC'94 paper" { "1" "2" } +" +Example from + +Fast Algorithms for Finding Randomized Strategies in Game Trees (STOC 1994) +Koller, Megiddo, von Stengel +" c "" 1 "" { "1" 0.2 "2" 0.2 "3" 0.2 "4" 0.4 } 0 p "" 1 1 "0" { "l" "r" } 0 diff --git a/tests/test_nash.py b/tests/test_nash.py index f70ac4f2d..d635ffee1 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -758,7 +758,7 @@ def test_lp_behavior_double(): ], ), ( - games.create_seq_form_STOC_paper_zero_sum_2_player_efg(), + games.read_from_file("zerosum_efg_from_sequence_form_STOC94_paper.efg"), [ [[0, 1], ["2/3", "1/3"], ["1/3", "2/3"]], [["5/6", "1/6"], ["5/9", "4/9"]], From 2cfa8a1b4a726d47046905aa493f2d76fb149416 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 14:22:57 +0000 Subject: [PATCH 07/24] removed create_problem_example_efg from games.py --- tests/games.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tests/games.py b/tests/games.py index 20f997f7b..90c8c6563 100644 --- a/tests/games.py +++ b/tests/games.py @@ -788,19 +788,6 @@ def create_reduction_both_players_payoff_ties_efg() -> gbt.Game: return g -def create_problem_example_efg() -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2"], title="") - g.append_move(g.root, player="1", actions=["L", "R"]) - # do the second child first on purpose to diverge from sort infosets order - g.append_move(g.root.children[1], "2", actions=["l2", "r2"]) - g.append_move(g.root.children[0], "2", actions=["l1", "r1"]) - g.set_outcome(g.root.children[0].children[0], outcome=g.add_outcome(payoffs=[5, -5])) - g.set_outcome(g.root.children[0].children[1], outcome=g.add_outcome(payoffs=[2, -2])) - g.set_outcome(g.root.children[1].children[0], outcome=g.add_outcome(payoffs=[-5, 5])) - g.set_outcome(g.root.children[1].children[1], outcome=g.add_outcome(payoffs=[-2, 2])) - return g - - def create_two_player_perfect_info_win_lose_efg(nonterm_outcomes: bool = False) -> gbt.Game: g = gbt.Game.new_tree(players=["1", "2"], title="2 player perfect info win lose") g.append_move(g.root, "2", ["a", "b"]) From f2a80394f8b45bfafeaa7a858d773a61e72b706d Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 15:51:52 +0000 Subject: [PATCH 08/24] removed create_chance_in_middle_efg from games.py --- tests/games.py | 69 ++++++++++++----------------------------- tests/test_extensive.py | 4 +-- tests/test_nash.py | 12 +++---- 3 files changed, 27 insertions(+), 58 deletions(-) diff --git a/tests/games.py b/tests/games.py index 90c8c6563..12e9a91ce 100644 --- a/tests/games.py +++ b/tests/games.py @@ -44,6 +44,8 @@ def create_efg_corresponding_to_bimatrix_game( def create_2x2_zero_sum_efg(missing_term_outcome: bool = False) -> gbt.Game: """ + TODO: use create_efg_corresponding_to_bimatrix_game + EFG corresponding to 2x2 zero-sum game (I,-I). If missing_term_outcome, the terminal node after "T" then "r" does not have an outcome. """ @@ -85,6 +87,7 @@ def create_perfect_info_with_chance_efg() -> gbt.Game: g.root.children[0].children[1].children[1], g.add_outcome([-2, 2], label="aRD") ) g.set_outcome(g.root.children[1], g.add_outcome([-1, 1], label="b")) + g.to_efg("perfect_info_with_chance.efg") return g @@ -129,6 +132,8 @@ def create_three_action_internal_outcomes_efg(nonterm_outcomes: bool = False) -> g.set_outcome(g.root.children[1].children[1].children[1], o_m1) g.set_outcome(g.root.children[1].children[2].children[0], o_m1) g.set_outcome(g.root.children[1].children[2].children[1], o_1) + tmp = "_nonterm_outcomes_and_missing_term_outcomes" if nonterm_outcomes else "" + g.to_efg(f"2_player_chance_3_actions{tmp}.efg") return g @@ -151,6 +156,8 @@ def create_entry_accomodation_efg(nonterm_outcomes: bool = False) -> gbt.Game: g.set_outcome(g.root.children[1].children[0].children[0], g.add_outcome([2, 3])) g.set_outcome(g.root.children[1].children[0].children[1], g.add_outcome([1, 0])) g.set_outcome(g.root.children[1].children[1], g.add_outcome([3, 1])) + tmp = "_with_nonterm_outcomes" if nonterm_outcomes else "" + g.to_efg(f"entry_accomodation{tmp}.efg") return g @@ -173,56 +180,8 @@ def create_non_zero_sum_lacking_outcome_efg(missing_term_outcome: bool = False) g.set_outcome(g.root.children[1].children[0].children[1], g.add_outcome([0, 1])) g.set_outcome(g.root.children[1].children[1].children[0], g.add_outcome([-1, 1])) g.set_outcome(g.root.children[1].children[1].children[1], g.add_outcome([2, -1])) - return g - - -def create_chance_in_middle_efg(nonterm_outcomes: bool = False) -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2"], - title="Chance in middle game") - g.append_move(g.root, "1", ["A", "B"]) - g.append_move(g.root.children[0], g.players.chance, ["H", "L"]) - g.set_chance_probs(g.root.children[0].infoset, ["1/5", "4/5"]) - g.append_move(g.root.children[1], g.players.chance, ["H", "L"]) - g.set_chance_probs(g.root.children[1].infoset, ["7/10", "3/10"]) - for i in range(2): - g.append_move(g.root.children[0].children[i], "2", ["X", "Y"]) - ist = g.root.children[0].children[i].infoset - g.append_infoset(g.root.children[1].children[i], ist) - for i in range(2): - for j in range(2): - g.append_move(g.root.children[i].children[0].children[j], "1", ["C", "D"]) - ist = g.root.children[i].children[0].children[j].infoset - g.append_infoset(g.root.children[i].children[1].children[j], ist) - o_1 = g.add_outcome([1, -1], label="1") - o_m1 = g.add_outcome([-1, 1], label="-1") - o_m2 = g.add_outcome([-2, 2], label="-2") - o_h = g.add_outcome(["1/2", "-1/2"], label="0.5") - o_mh = g.add_outcome(["-1/2", "1/2"], label="-0.5") - o_z = g.add_outcome([0, 0], label="0") - o_m3o2 = g.add_outcome(["-3/2", "3/2"], label="-1.5") - if nonterm_outcomes: - g.set_outcome(g.root.children[0].children[0], g.add_outcome([-1, 1], label="a")) - g.set_outcome(g.root.children[0].children[0].children[0].children[0], o_1) - g.set_outcome(g.root.children[0].children[0].children[0].children[1], o_m1) - g.set_outcome(g.root.children[0].children[0].children[1].children[0], o_h) - g.set_outcome(g.root.children[0].children[0].children[1].children[1], o_mh) - else: - g.set_outcome(g.root.children[0].children[0].children[0].children[0], o_z) - g.set_outcome(g.root.children[0].children[0].children[0].children[1], o_m2) - g.set_outcome(g.root.children[0].children[0].children[1].children[0], o_mh) - g.set_outcome(g.root.children[0].children[0].children[1].children[1], o_m3o2) - g.set_outcome(g.root.children[0].children[1].children[0].children[0], o_h) - g.set_outcome(g.root.children[0].children[1].children[0].children[1], o_mh) - g.set_outcome(g.root.children[0].children[1].children[1].children[0], o_1) - g.set_outcome(g.root.children[0].children[1].children[1].children[1], o_m1) - g.set_outcome(g.root.children[1].children[0].children[0].children[0], o_h) - g.set_outcome(g.root.children[1].children[0].children[0].children[1], o_mh) - g.set_outcome(g.root.children[1].children[0].children[1].children[0], o_1) - g.set_outcome(g.root.children[1].children[0].children[1].children[1], o_m1) - g.set_outcome(g.root.children[1].children[1].children[0].children[0], o_1) - g.set_outcome(g.root.children[1].children[1].children[0].children[1], o_m1) - g.set_outcome(g.root.children[1].children[1].children[1].children[0], o_h) - g.set_outcome(g.root.children[1].children[1].children[1].children[1], o_mh) + tmp = "_missing_term_outcome" if missing_term_outcome else "" + g.to_efg(f"non_zero_sum_2_player{tmp}.efg") return g @@ -246,6 +205,7 @@ def create_large_payoff_game_efg() -> gbt.Game: g.set_outcome(g.root.children[1].children[0].children[1], o_1) g.set_outcome(g.root.children[1].children[1].children[0], o_zero) g.set_outcome(g.root.children[1].children[1].children[1], o_large) + g.to_efg("large_payoff_game.efg") return g @@ -294,11 +254,15 @@ def create_3_player_with_internal_outcomes_efg(nonterm_outcomes: bool = False) - o = g.add_outcome([0, 0, 0]) g.set_outcome(g.root.children[0].children[0].children[1].children[0], o) g.set_outcome(g.root.children[0].children[0].children[1].children[1], o) + tmp = "_with_nonterm_outcomes" if nonterm_outcomes else "" + g.to_efg(f"3_player{tmp}.efg") return g def create_matching_pennies_efg(with_neutral_outcome: bool = False) -> gbt.Game: """ + TODO: use create_efg_corresponding_to_bimatrix_game + The version with_neutral_outcome adds a (0,0) payoff outcomes at a non-terminal node. """ g = gbt.Game.new_tree( @@ -751,6 +715,7 @@ def create_reduction_generic_payoffs_efg() -> gbt.Game: ) g.set_outcome(g.root.children[3], g.add_outcome([12, -12], label="d")) + g.to_efg("reduction_generic_payoffs.efg") return g @@ -763,6 +728,7 @@ def create_reduction_one_player_generic_payoffs_efg() -> gbt.Game: g.set_outcome(g.root.children[1], g.add_outcome([3])) g.set_outcome(g.root.children[2], g.add_outcome([4])) g.set_outcome(g.root.children[3], g.add_outcome([5])) + g.to_efg("reduction_one_player_generic_payoffs.efg") return g @@ -785,6 +751,7 @@ def create_reduction_both_players_payoff_ties_efg() -> gbt.Game: g.set_outcome(g.root.children[2].children[1].children[0], g.add_outcome([7, 8])) g.set_outcome(g.root.children[2].children[1].children[1], g.add_outcome([2, 2])) g.set_outcome(g.root.children[3], g.add_outcome([6, 4])) + g.to_efg("reduction_both_players_payoff_ties_GTE_survey.efg") return g @@ -815,6 +782,8 @@ def create_two_player_perfect_info_win_lose_efg(nonterm_outcomes: bool = False) g.set_outcome(g.root.children[0].children[1], g.add_outcome([101, -51], label="aR")) g.set_outcome(g.root.children[1].children[0], g.add_outcome([1, -1], label="bL")) g.set_outcome(g.root.children[1].children[1], g.add_outcome([-1, 1], label="bR")) + tmp = "_with_nonterm_outcomes" if nonterm_outcomes else "" + g.to_efg(f"two_player_perfect_info_win_lose{tmp}.efg") return g diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 41528afbe..59d0458ac 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -409,8 +409,8 @@ def test_reduced_strategic_form( games.create_3_player_with_internal_outcomes_efg(nonterm_outcomes=True) ), ( - games.create_chance_in_middle_efg(), - games.create_chance_in_middle_efg(nonterm_outcomes=True) + games.read_from_file("chance_in_middle.efg"), + games.read_from_file("chance_in_middle_with_nonterm_outcomes.efg") ), ( games.create_non_zero_sum_lacking_outcome_efg(), diff --git a/tests/test_nash.py b/tests/test_nash.py index d635ffee1..2eebeb07c 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -279,14 +279,14 @@ def test_enummixed_rational(game: gbt.Game, mixed_strategy_prof_data: list): ############################################################################## ############################################################################## ( - games.create_chance_in_middle_efg(), + games.read_from_file("chance_in_middle.efg"), [[[["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]]], ], # [[[1, 0], [1, 0], [1, 0], [0, 0], [0, 0]], [[0, 1], [1, 0]]], # [[[0, 1], [0, 0], [0, 0], [1, 0], [1, 0]], [[1, 0], [0, 1]]], 1, # subsequent eqs have undefined infosets; include after #issue 660 ), ( - games.create_chance_in_middle_efg(nonterm_outcomes=True), + games.read_from_file("chance_in_middle_with_nonterm_outcomes.efg"), [[[["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]]], ], # [[[1, 0], [1, 0], [1, 0], [0, 0], [0, 0]], [[0, 1], [1, 0]]], # [[[0, 1], [0, 0], [0, 0], [1, 0], [1, 0]], [[1, 0], [0, 1]]], @@ -587,14 +587,14 @@ def test_lcp_behavior_double(): ], ), ( - games.create_chance_in_middle_efg(), + games.read_from_file("chance_in_middle.efg"), [ [["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]] ] ), ( - games.create_chance_in_middle_efg(nonterm_outcomes=True), + games.read_from_file("chance_in_middle_with_nonterm_outcomes.efg"), [ [["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]] @@ -791,14 +791,14 @@ def test_lp_behavior_double(): ], ), ( - games.create_chance_in_middle_efg(), + games.read_from_file("chance_in_middle.efg"), [ [["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]] ], ), ( - games.create_chance_in_middle_efg(nonterm_outcomes=True), + games.read_from_file("chance_in_middle_with_nonterm_outcomes.efg"), [ [["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]] From e0f16fb8a7ebbe3047c7491409de85e0dfa26953 Mon Sep 17 00:00:00 2001 From: rahulsavani Date: Wed, 14 Jan 2026 16:42:54 +0000 Subject: [PATCH 09/24] chance_in_middle efgs --- tests/test_games/chance_in_middle.efg | 34 +++++++++++++++++++ ...chance_in_middle_with_nonterm_outcomes.efg | 34 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/test_games/chance_in_middle.efg create mode 100644 tests/test_games/chance_in_middle_with_nonterm_outcomes.efg diff --git a/tests/test_games/chance_in_middle.efg b/tests/test_games/chance_in_middle.efg new file mode 100644 index 000000000..c874b3f99 --- /dev/null +++ b/tests/test_games/chance_in_middle.efg @@ -0,0 +1,34 @@ +EFG 2 R "Chance in middle game" { "1" "2" } +"" + +p "" 1 1 "" { "A" "B" } 0 +c "" 1 "" { "H" 1/5 "L" 4/5 } 0 +p "" 2 1 "" { "X" "Y" } 0 +p "" 1 2 "" { "C" "D" } 0 +t "" 6 "0" { 0, 0 } +t "" 3 "-2" { -2, 2 } +p "" 1 3 "" { "C" "D" } 0 +t "" 5 "-0.5" { -1/2, 1/2 } +t "" 7 "-1.5" { -3/2, 3/2 } +p "" 2 2 "" { "X" "Y" } 0 +p "" 1 2 "" { "C" "D" } 0 +t "" 4 "0.5" { 1/2, -1/2 } +t "" 5 "-0.5" { -1/2, 1/2 } +p "" 1 3 "" { "C" "D" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +c "" 2 "" { "H" 7/10 "L" 3/10 } 0 +p "" 2 1 "" { "X" "Y" } 0 +p "" 1 4 "" { "C" "D" } 0 +t "" 4 "0.5" { 1/2, -1/2 } +t "" 5 "-0.5" { -1/2, 1/2 } +p "" 1 5 "" { "C" "D" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 2 2 "" { "X" "Y" } 0 +p "" 1 4 "" { "C" "D" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 1 5 "" { "C" "D" } 0 +t "" 4 "0.5" { 1/2, -1/2 } +t "" 5 "-0.5" { -1/2, 1/2 } diff --git a/tests/test_games/chance_in_middle_with_nonterm_outcomes.efg b/tests/test_games/chance_in_middle_with_nonterm_outcomes.efg new file mode 100644 index 000000000..7f7cd2132 --- /dev/null +++ b/tests/test_games/chance_in_middle_with_nonterm_outcomes.efg @@ -0,0 +1,34 @@ +EFG 2 R "Chance in middle game" { "1" "2" } +"" + +p "" 1 1 "" { "A" "B" } 0 +c "" 1 "" { "H" 1/5 "L" 4/5 } 0 +p "" 2 1 "" { "X" "Y" } 8 "a" { -1, 1 } +p "" 1 2 "" { "C" "D" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 1 3 "" { "C" "D" } 0 +t "" 4 "0.5" { 1/2, -1/2 } +t "" 5 "-0.5" { -1/2, 1/2 } +p "" 2 2 "" { "X" "Y" } 0 +p "" 1 2 "" { "C" "D" } 0 +t "" 4 "0.5" { 1/2, -1/2 } +t "" 5 "-0.5" { -1/2, 1/2 } +p "" 1 3 "" { "C" "D" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +c "" 2 "" { "H" 7/10 "L" 3/10 } 0 +p "" 2 1 "" { "X" "Y" } 0 +p "" 1 4 "" { "C" "D" } 0 +t "" 4 "0.5" { 1/2, -1/2 } +t "" 5 "-0.5" { -1/2, 1/2 } +p "" 1 5 "" { "C" "D" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 2 2 "" { "X" "Y" } 0 +p "" 1 4 "" { "C" "D" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 1 5 "" { "C" "D" } 0 +t "" 4 "0.5" { 1/2, -1/2 } +t "" 5 "-0.5" { -1/2, 1/2 } From 39332acb4e435456a19438850e3fd1cdacc56b86 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 17:37:30 +0000 Subject: [PATCH 10/24] removed create_two_player_perfect_info_win_lose_efg from games.py --- tests/games.py | 32 ------------------- tests/test_extensive.py | 4 +-- .../two_player_perfect_info_win_lose.efg | 12 +++++++ ...ct_info_win_lose_with_nonterm_outcomes.efg | 12 +++++++ tests/test_nash.py | 29 +++++++++-------- 5 files changed, 41 insertions(+), 48 deletions(-) create mode 100644 tests/test_games/two_player_perfect_info_win_lose.efg create mode 100644 tests/test_games/two_player_perfect_info_win_lose_with_nonterm_outcomes.efg diff --git a/tests/games.py b/tests/games.py index 12e9a91ce..af8277498 100644 --- a/tests/games.py +++ b/tests/games.py @@ -755,38 +755,6 @@ def create_reduction_both_players_payoff_ties_efg() -> gbt.Game: return g -def create_two_player_perfect_info_win_lose_efg(nonterm_outcomes: bool = False) -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2"], title="2 player perfect info win lose") - g.append_move(g.root, "2", ["a", "b"]) - g.append_move(g.root.children[0], "1", ["L", "R"]) - g.append_move(g.root.children[1], "1", ["L", "R"]) - g.append_move(g.root.children[0].children[0], "2", ["l", "r"]) - if not nonterm_outcomes: - g.set_outcome( - g.root.children[0].children[0].children[0], g.add_outcome([1, -1], label="aLl") - ) - g.set_outcome( - g.root.children[0].children[0].children[1], g.add_outcome([-1, 1], label="aLr") - ) - g.set_outcome(g.root.children[0].children[1], g.add_outcome([1, -1], label="aR")) - g.set_outcome(g.root.children[1].children[0], g.add_outcome([1, -1], label="bL")) - g.set_outcome(g.root.children[1].children[1], g.add_outcome([-1, 1], label="bR")) - else: - g.set_outcome(g.root.children[0], g.add_outcome([-100, 50], label="a")) - g.set_outcome( - g.root.children[0].children[0].children[0], g.add_outcome([101, -51], label="aLl") - ) - g.set_outcome( - g.root.children[0].children[0].children[1], g.add_outcome([99, -49], label="aLr") - ) - g.set_outcome(g.root.children[0].children[1], g.add_outcome([101, -51], label="aR")) - g.set_outcome(g.root.children[1].children[0], g.add_outcome([1, -1], label="bL")) - g.set_outcome(g.root.children[1].children[1], g.add_outcome([-1, 1], label="bR")) - tmp = "_with_nonterm_outcomes" if nonterm_outcomes else "" - g.to_efg(f"two_player_perfect_info_win_lose{tmp}.efg") - return g - - def create_EFG_for_nxn_bimatrix_coordination_game(n: int) -> gbt.Game: A = np.eye(n, dtype=int) B = A diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 59d0458ac..5f02ce964 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -401,8 +401,8 @@ def test_reduced_strategic_form( "standard,modified", [ ( - games.create_two_player_perfect_info_win_lose_efg(), - games.create_two_player_perfect_info_win_lose_efg(nonterm_outcomes=True) + games.read_from_file("two_player_perfect_info_win_lose.efg"), + games.read_from_file("two_player_perfect_info_win_lose_with_nonterm_outcomes.efg") ), ( games.create_3_player_with_internal_outcomes_efg(), diff --git a/tests/test_games/two_player_perfect_info_win_lose.efg b/tests/test_games/two_player_perfect_info_win_lose.efg new file mode 100644 index 000000000..aeb5fa62e --- /dev/null +++ b/tests/test_games/two_player_perfect_info_win_lose.efg @@ -0,0 +1,12 @@ +EFG 2 R "2 player perfect info win lose" { "1" "2" } +"" + +p "" 2 1 "" { "a" "b" } 0 +p "" 1 1 "" { "L" "R" } 0 +p "" 2 2 "" { "l" "r" } 0 +t "" 1 "aLl" { 1, -1 } +t "" 2 "aLr" { -1, 1 } +t "" 3 "aR" { 1, -1 } +p "" 1 2 "" { "L" "R" } 0 +t "" 4 "bL" { 1, -1 } +t "" 5 "bR" { -1, 1 } diff --git a/tests/test_games/two_player_perfect_info_win_lose_with_nonterm_outcomes.efg b/tests/test_games/two_player_perfect_info_win_lose_with_nonterm_outcomes.efg new file mode 100644 index 000000000..d2ebceb41 --- /dev/null +++ b/tests/test_games/two_player_perfect_info_win_lose_with_nonterm_outcomes.efg @@ -0,0 +1,12 @@ +EFG 2 R "2 player perfect info win lose" { "1" "2" } +"" + +p "" 2 1 "" { "a" "b" } 0 +p "" 1 1 "" { "L" "R" } 1 "a" { -100, 50 } +p "" 2 2 "" { "l" "r" } 0 +t "" 2 "aLl" { 101, -51 } +t "" 3 "aLr" { 99, -49 } +t "" 4 "aR" { 101, -51 } +p "" 1 2 "" { "L" "R" } 0 +t "" 5 "bL" { 1, -1 } +t "" 6 "bR" { -1, 1 } diff --git a/tests/test_nash.py b/tests/test_nash.py index 2eebeb07c..2dd356bac 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -23,7 +23,7 @@ [ # Zero-sum games ( - games.create_two_player_perfect_info_win_lose_efg(), + games.read_from_file("two_player_perfect_info_win_lose.efg"), [ [[0, 0, 1, 0], [1, 0, 0]], [[0, 0, 1, 0], [0, 1, 0]], @@ -78,7 +78,7 @@ def test_enumpure_strategy(game: gbt.Game, pure_strategy_prof_data: list): ############################################################# # Zero-sum games ( - games.create_two_player_perfect_info_win_lose_efg(), + games.read_from_file("two_player_perfect_info_win_lose.efg"), [ [[[1, 0], [1, 0]], [[0, 1], [1, 0]]], [[[0, 1], [1, 0]], [[1, 0], [1, 0]]], @@ -557,11 +557,11 @@ def test_lcp_behavior_double(): [[[0, 1]], [[0, 1], [0, 1]]], ), ( - games.create_two_player_perfect_info_win_lose_efg(), + games.read_from_file("two_player_perfect_info_win_lose.efg"), [[[0, 1], [1, 0]], [[0, 1], ["1/2", "1/2"]]], ), ( - games.create_two_player_perfect_info_win_lose_efg(nonterm_outcomes=True), + games.read_from_file("two_player_perfect_info_win_lose_with_nonterm_outcomes.efg"), [[[0, 1], [1, 0]], [[0, 1], ["1/2", "1/2"]]], ), ( @@ -707,30 +707,31 @@ def test_lp_behavior_double(): "game,mixed_behav_prof_data", [ ( - games.create_two_player_perfect_info_win_lose_efg(), - [[[0, 1], [1, 0]], [[1, 0], [1, 0]]], + games.read_from_file("two_player_perfect_info_win_lose.efg"), + [[[0, 1], [1, 0]], [[1, 0], [1, 0]]], ), ( - games.create_two_player_perfect_info_win_lose_efg(nonterm_outcomes=True), - [[[0, 1], [1, 0]], [[1, 0], [1, 0]]], + games.read_from_file("two_player_perfect_info_win_lose_with_nonterm_outcomes.efg"), + [[[0, 1], [1, 0]], [[1, 0], [1, 0]]], ), ( - games.create_2x2_zero_sum_efg(missing_term_outcome=False), - [[["1/2", "1/2"]], [["1/2", "1/2"]]] + games.create_2x2_zero_sum_efg(missing_term_outcome=False), + [[["1/2", "1/2"]], [["1/2", "1/2"]]] ), ( games.create_2x2_zero_sum_efg(missing_term_outcome=True), [[["1/2", "1/2"]], [["1/2", "1/2"]]], ), - (games.create_matching_pennies_efg(with_neutral_outcome=False), - [[["1/2", "1/2"]], [["1/2", "1/2"]]]), + ( + games.create_matching_pennies_efg(with_neutral_outcome=False), + [[["1/2", "1/2"]], [["1/2", "1/2"]]]), ( games.create_matching_pennies_efg(with_neutral_outcome=True), [[["1/2", "1/2"]], [["1/2", "1/2"]]], ), ( - games.create_stripped_down_poker_efg(), - [[[1, 0], ["1/3", "2/3"]], [["2/3", "1/3"]]], + games.create_stripped_down_poker_efg(), + [[[1, 0], ["1/3", "2/3"]], [["2/3", "1/3"]]], ), ( games.create_stripped_down_poker_efg(nonterm_outcomes=True), From 47b65002bc48b990c8bd9ed31bb0123d3dcac9c5 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 17:44:07 +0000 Subject: [PATCH 11/24] removed create_reduction_both_players_payoff_ties_efg from games.py --- tests/test_extensive.py | 2 +- ...on_both_players_payoff_ties_GTE_survey.efg | 20 +++++++++++++++++++ tests/test_nash.py | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/test_games/reduction_both_players_payoff_ties_GTE_survey.efg diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 5f02ce964..b3527765b 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -210,7 +210,7 @@ def test_outcome_index_exception_label(): ), # # 2-player game from GTE survey; reduction for both players; payoff ties ( - games.create_reduction_both_players_payoff_ties_efg(), + games.read_from_file("reduction_both_players_payoff_ties_GTE_survey.efg"), [ ["1*", "2*", "31", "32", "4*"], [ diff --git a/tests/test_games/reduction_both_players_payoff_ties_GTE_survey.efg b/tests/test_games/reduction_both_players_payoff_ties_GTE_survey.efg new file mode 100644 index 000000000..1c4adf21c --- /dev/null +++ b/tests/test_games/reduction_both_players_payoff_ties_GTE_survey.efg @@ -0,0 +1,20 @@ +EFG 2 R "From GTE survey" { "1" "2" } +"A reduction in pure strategies is possible for both players" + +p "" 1 1 "" { "A" "B" "C" "D" } 0 +p "" 2 1 "" { "a" "b" } 0 +t "" 1 "" { 2, 8 } +p "" 2 4 "" { "g" "h" } 0 +t "" 2 "" { 0, 1 } +t "" 3 "" { 5, 2 } +p "" 2 2 "" { "c" "d" } 0 +t "" 4 "" { 7, 6 } +t "" 5 "" { 4, 2 } +p "" 2 3 "" { "e" "f" } 0 +p "" 1 2 "" { "E" "F" } 0 +t "" 6 "" { 3, 7 } +t "" 7 "" { 8, 3 } +p "" 1 2 "" { "E" "F" } 0 +t "" 8 "" { 7, 8 } +t "" 9 "" { 2, 2 } +t "" 10 "" { 6, 4 } diff --git a/tests/test_nash.py b/tests/test_nash.py index 2dd356bac..d0c94c9ff 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -602,7 +602,7 @@ def test_lcp_behavior_double(): ), # Non-zero-sum games ( - games.create_reduction_both_players_payoff_ties_efg(), + games.read_from_file("reduction_both_players_payoff_ties_GTE_survey.efg"), [[[0, 0, 1, 0], [1, 0]], [[0, 1], [0, 1], [0, 1], [0, 1]]], ), ( From 255afa44e291fc0e48517860c92bb064a7c944c2 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:04:18 +0000 Subject: [PATCH 12/24] removed create_3_player_with_internal_outcomes_efg and create_large_payoff_game from games.py --- tests/games.py | 74 ------------------- tests/test_behav.py | 4 +- tests/test_extensive.py | 4 +- tests/test_games/3_player.efg | 24 ++++++ .../3_player_with_nonterm_outcomes.efg | 24 ++++++ tests/test_games/large_payoff_game.efg | 18 +++++ tests/test_nash.py | 8 +- 7 files changed, 74 insertions(+), 82 deletions(-) create mode 100644 tests/test_games/3_player.efg create mode 100644 tests/test_games/3_player_with_nonterm_outcomes.efg create mode 100644 tests/test_games/large_payoff_game.efg diff --git a/tests/games.py b/tests/games.py index af8277498..5847d3c47 100644 --- a/tests/games.py +++ b/tests/games.py @@ -185,80 +185,6 @@ def create_non_zero_sum_lacking_outcome_efg(missing_term_outcome: bool = False) return g -def create_large_payoff_game_efg() -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2"], title="Large payoff game") - g.append_move(g.root, g.players.chance, ["L", "R"]) - for i in range(2): - g.append_move(g.root.children[i], "1", ["A", "B"]) - for i in range(2): - g.append_move(g.root.children[0].children[i], "2", ["X", "Y"]) - g.append_infoset(g.root.children[1].children[i], g.root.children[0].children[i].infoset) - o_large = g.add_outcome([10000000000000000000, -10000000000000000000], label="large payoff") - o_1 = g.add_outcome([1, -1], label="1") - o_m1 = g.add_outcome([-1, 1], label="-1") - o_zero = g.add_outcome([0, 0], label="0") - g.set_outcome(g.root.children[0].children[0].children[0], o_large) - g.set_outcome(g.root.children[0].children[0].children[1], o_1) - g.set_outcome(g.root.children[0].children[1].children[0], o_m1) - g.set_outcome(g.root.children[0].children[1].children[1], o_zero) - g.set_outcome(g.root.children[1].children[0].children[0], o_m1) - g.set_outcome(g.root.children[1].children[0].children[1], o_1) - g.set_outcome(g.root.children[1].children[1].children[0], o_zero) - g.set_outcome(g.root.children[1].children[1].children[1], o_large) - g.to_efg("large_payoff_game.efg") - return g - - -def create_3_player_with_internal_outcomes_efg(nonterm_outcomes: bool = False) -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2", "3"], title="3 player game") - g.append_move(g.root, g.players.chance, ["H", "T"]) - g.set_chance_probs(g.root.infoset, ["1/2", "1/2"]) - g.append_move(g.root.children[0], "1", ["a", "b"]) - g.append_move(g.root.children[1], "1", ["c", "d"]) - g.append_move(g.root.children[0].children[0], "2", ["A", "B"]) - g.append_infoset(g.root.children[1].children[0], g.root.children[0].children[0].infoset) - g.append_move(g.root.children[0].children[1], "3", ["W", "X"]) - g.append_infoset(g.root.children[1].children[1], g.root.children[0].children[1].infoset) - g.append_move(g.root.children[0].children[0].children[0], "3", ["Y", "Z"]) - iset = g.root.children[0].children[0].children[0].infoset - g.append_infoset(g.root.children[0].children[0].children[1], iset) - g.append_move(g.root.children[0].children[1].children[1], "2", ["C", "D"]) - o = g.add_outcome([3, 1, 4]) - g.set_outcome(g.root.children[0].children[0].children[0].children[0], o) - o = g.add_outcome([4, 0, 1]) - g.set_outcome(g.root.children[0].children[0].children[0].children[1], o) - o = g.add_outcome([1, 3, 2]) - g.set_outcome(g.root.children[0].children[1].children[0], o) - o = g.add_outcome([2, 4, 1]) - g.set_outcome(g.root.children[0].children[1].children[1].children[0], o) - o = g.add_outcome([4, 1, 3]) - g.set_outcome(g.root.children[0].children[1].children[1].children[1], o) - if nonterm_outcomes: - o = g.add_outcome([1, 2, 3]) - g.set_outcome(g.root.children[1], o) - o = g.add_outcome([1, 0, 1]) - g.set_outcome(g.root.children[1].children[0].children[0], o) - o = g.add_outcome([2, -1, -2]) - g.set_outcome(g.root.children[1].children[0].children[1], o) - o = g.add_outcome([-1, 2, -1]) - g.set_outcome(g.root.children[1].children[1].children[0], o) - else: - o = g.add_outcome([2, 2, 4]) - g.set_outcome(g.root.children[1].children[0].children[0], o) - o = g.add_outcome([3, 1, 1]) - g.set_outcome(g.root.children[1].children[0].children[1], o) - o = g.add_outcome([0, 4, 2]) - g.set_outcome(g.root.children[1].children[1].children[0], o) - o = g.add_outcome([1, 2, 3]) - g.set_outcome(g.root.children[1].children[1].children[1], o) - o = g.add_outcome([0, 0, 0]) - g.set_outcome(g.root.children[0].children[0].children[1].children[0], o) - g.set_outcome(g.root.children[0].children[0].children[1].children[1], o) - tmp = "_with_nonterm_outcomes" if nonterm_outcomes else "" - g.to_efg(f"3_player{tmp}.efg") - return g - - def create_matching_pennies_efg(with_neutral_outcome: bool = False) -> gbt.Game: """ TODO: use create_efg_corresponding_to_bimatrix_game diff --git a/tests/test_behav.py b/tests/test_behav.py index 77c3f8e43..c24cf5361 100644 --- a/tests/test_behav.py +++ b/tests/test_behav.py @@ -843,8 +843,8 @@ def test_infoset_regret_consistency(game: gbt.Game, rational_flag: bool): (games.create_stripped_down_poker_efg(), True), (games.create_kuhn_poker_efg(), False), (games.create_kuhn_poker_efg(), True), - (games.create_3_player_with_internal_outcomes_efg(), False), - (games.create_3_player_with_internal_outcomes_efg(), True) + (games.read_from_file("3_player.efg"), False), + (games.read_from_file("3_player.efg"), True) ] ) def test_max_regret_consistency(game: gbt.Game, rational_flag: bool): diff --git a/tests/test_extensive.py b/tests/test_extensive.py index b3527765b..638adf49c 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -405,8 +405,8 @@ def test_reduced_strategic_form( games.read_from_file("two_player_perfect_info_win_lose_with_nonterm_outcomes.efg") ), ( - games.create_3_player_with_internal_outcomes_efg(), - games.create_3_player_with_internal_outcomes_efg(nonterm_outcomes=True) + games.read_from_file("3_player.efg"), + games.read_from_file("3_player_with_nonterm_outcomes.efg") ), ( games.read_from_file("chance_in_middle.efg"), diff --git a/tests/test_games/3_player.efg b/tests/test_games/3_player.efg new file mode 100644 index 000000000..c1c89ab57 --- /dev/null +++ b/tests/test_games/3_player.efg @@ -0,0 +1,24 @@ +EFG 2 R "3 player game" { "1" "2" "3" } +"" + +c "" 1 "" { "H" 1/2 "T" 1/2 } 0 +p "" 1 1 "" { "a" "b" } 0 +p "" 2 1 "" { "A" "B" } 0 +p "" 3 2 "" { "Y" "Z" } 0 +t "" 1 "" { 3, 1, 4 } +t "" 2 "" { 4, 0, 1 } +p "" 3 2 "" { "Y" "Z" } 0 +t "" 10 "" { 0, 0, 0 } +t "" 10 "" { 0, 0, 0 } +p "" 3 1 "" { "W" "X" } 0 +t "" 3 "" { 1, 3, 2 } +p "" 2 2 "" { "C" "D" } 0 +t "" 4 "" { 2, 4, 1 } +t "" 5 "" { 4, 1, 3 } +p "" 1 2 "" { "c" "d" } 0 +p "" 2 1 "" { "A" "B" } 0 +t "" 6 "" { 2, 2, 4 } +t "" 7 "" { 3, 1, 1 } +p "" 3 1 "" { "W" "X" } 0 +t "" 8 "" { 0, 4, 2 } +t "" 9 "" { 1, 2, 3 } diff --git a/tests/test_games/3_player_with_nonterm_outcomes.efg b/tests/test_games/3_player_with_nonterm_outcomes.efg new file mode 100644 index 000000000..85c11d24a --- /dev/null +++ b/tests/test_games/3_player_with_nonterm_outcomes.efg @@ -0,0 +1,24 @@ +EFG 2 R "3 player game" { "1" "2" "3" } +"" + +c "" 1 "" { "H" 1/2 "T" 1/2 } 0 +p "" 1 1 "" { "a" "b" } 0 +p "" 2 1 "" { "A" "B" } 0 +p "" 3 2 "" { "Y" "Z" } 0 +t "" 1 "" { 3, 1, 4 } +t "" 2 "" { 4, 0, 1 } +p "" 3 2 "" { "Y" "Z" } 0 +t "" 0 +t "" 0 +p "" 3 1 "" { "W" "X" } 0 +t "" 3 "" { 1, 3, 2 } +p "" 2 2 "" { "C" "D" } 0 +t "" 4 "" { 2, 4, 1 } +t "" 5 "" { 4, 1, 3 } +p "" 1 2 "" { "c" "d" } 6 "" { 1, 2, 3 } +p "" 2 1 "" { "A" "B" } 0 +t "" 7 "" { 1, 0, 1 } +t "" 8 "" { 2, -1, -2 } +p "" 3 1 "" { "W" "X" } 0 +t "" 9 "" { -1, 2, -1 } +t "" 0 diff --git a/tests/test_games/large_payoff_game.efg b/tests/test_games/large_payoff_game.efg new file mode 100644 index 000000000..51d304418 --- /dev/null +++ b/tests/test_games/large_payoff_game.efg @@ -0,0 +1,18 @@ +EFG 2 R "Large payoff game" { "1" "2" } +"" + +c "" 1 "" { "L" 1/2 "R" 1/2 } 0 +p "" 1 1 "" { "A" "B" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 1 "large payoff" { 10000000000000000000, -10000000000000000000 } +t "" 2 "1" { 1, -1 } +p "" 2 2 "" { "X" "Y" } 0 +t "" 3 "-1" { -1, 1 } +t "" 4 "0" { 0, 0 } +p "" 1 2 "" { "A" "B" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 3 "-1" { -1, 1 } +t "" 2 "1" { 1, -1 } +p "" 2 2 "" { "X" "Y" } 0 +t "" 4 "0" { 0, 0 } +t "" 1 "large payoff" { 10000000000000000000, -10000000000000000000 } diff --git a/tests/test_nash.py b/tests/test_nash.py index d0c94c9ff..796fea3d8 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -249,7 +249,7 @@ def test_enummixed_rational(game: gbt.Game, mixed_strategy_prof_data: list): ############################################################################## ############################################################################## ( - games.create_3_player_with_internal_outcomes_efg(), + games.read_from_file("3_player.efg"), [ [[[1, 0], [1, 0]], [[1, 0], ["1/2", "1/2"]], [[1, 0], [0, 1]]], [[[1, 0], [1, 0]], [[1, 0], [0, 1]], @@ -257,7 +257,7 @@ def test_enummixed_rational(game: gbt.Game, mixed_strategy_prof_data: list): 2, ), ( - games.create_3_player_with_internal_outcomes_efg(nonterm_outcomes=True), + games.read_from_file("3_player_with_nonterm_outcomes.efg"), [ [[[1, 0], [1, 0]], [[1, 0], ["1/2", "1/2"]], [[1, 0], [0, 1]]], [[[1, 0], [1, 0]], [[1, 0], [0, 1]], @@ -579,7 +579,7 @@ def test_lcp_behavior_double(): ], ), ( - games.create_large_payoff_game_efg(), + games.read_from_file("large_payoff_game.efg"), [ [[1, 0], [1, 0]], [[0, 1], ["9999999999999999999/10000000000000000000", @@ -784,7 +784,7 @@ def test_lp_behavior_double(): ], ), ( - games.create_large_payoff_game_efg(), + games.read_from_file("large_payoff_game.efg"), [ [[1, 0], [1, 0]], [[0, 1], ["9999999999999999999/10000000000000000000", From f8c32f49a258b9012601594aa6877b1a1593c6c2 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:13:33 +0000 Subject: [PATCH 13/24] removed create_reduction_one_player_generic_payoffs_efg from games.py --- tests/games.py | 13 ------------- tests/test_extensive.py | 2 +- .../reduction_one_player_generic_payoffs.efg | 10 ++++++++++ 3 files changed, 11 insertions(+), 14 deletions(-) create mode 100644 tests/test_games/reduction_one_player_generic_payoffs.efg diff --git a/tests/games.py b/tests/games.py index 5847d3c47..6d4175a65 100644 --- a/tests/games.py +++ b/tests/games.py @@ -645,19 +645,6 @@ def create_reduction_generic_payoffs_efg() -> gbt.Game: return g -def create_reduction_one_player_generic_payoffs_efg() -> gbt.Game: - g = gbt.Game.new_tree(players=["1"], title="One player reduction generic payoffs") - g.append_move(g.root, "1", ["a", "b", "c", "d"]) - g.append_move(g.root.children[0], "1", ["e", "f"]) - g.set_outcome(g.root.children[0].children[0], g.add_outcome([1])) - g.set_outcome(g.root.children[0].children[1], g.add_outcome([2])) - g.set_outcome(g.root.children[1], g.add_outcome([3])) - g.set_outcome(g.root.children[2], g.add_outcome([4])) - g.set_outcome(g.root.children[3], g.add_outcome([5])) - g.to_efg("reduction_one_player_generic_payoffs.efg") - return g - - def create_reduction_both_players_payoff_ties_efg() -> gbt.Game: g = gbt.Game.new_tree(players=["1", "2"], title="From GTE survey") g.append_move(g.root, "1", ["A", "B", "C", "D"]) diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 638adf49c..31cdc2c43 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -123,7 +123,7 @@ def test_outcome_index_exception_label(): ############################################################################### # 1 player; reduction; generic payoffs ( - games.create_reduction_one_player_generic_payoffs_efg(), + games.read_from_file("reduction_one_player_generic_payoffs.efg"), [["11", "12", "2*", "3*", "4*"]], [np.array(range(1, 6))], ), diff --git a/tests/test_games/reduction_one_player_generic_payoffs.efg b/tests/test_games/reduction_one_player_generic_payoffs.efg new file mode 100644 index 000000000..7844ed6c0 --- /dev/null +++ b/tests/test_games/reduction_one_player_generic_payoffs.efg @@ -0,0 +1,10 @@ +EFG 2 R "One player reduction generic payoffs" { "1" } +"" + +p "" 1 1 "" { "a" "b" "c" "d" } 0 +p "" 1 2 "" { "e" "f" } 0 +t "" 1 "" { 1 } +t "" 2 "" { 2 } +t "" 3 "" { 3 } +t "" 4 "" { 4 } +t "" 5 "" { 5 } From ce73a369e3850403257b8c252fe31064dcaa95ae Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:16:23 +0000 Subject: [PATCH 14/24] removed create_reduction_generic_payoffs_efg from games.py --- tests/games.py | 68 ----------------------------------------- tests/test_extensive.py | 2 +- 2 files changed, 1 insertion(+), 69 deletions(-) diff --git a/tests/games.py b/tests/games.py index 6d4175a65..1521477fb 100644 --- a/tests/games.py +++ b/tests/games.py @@ -577,74 +577,6 @@ def create_selten_horse_game_efg() -> gbt.Game: return read_from_file("e01.efg") -def create_reduction_generic_payoffs_efg() -> gbt.Game: - # tree with only root - g = gbt.Game.new_tree( - players=["1", "2"], title="2 player reduction generic payoffs" - ) - - # add four children - g.append_move(g.root, "2", ["a", "b", "c", "d"]) - - # add L and R after a - g.append_move(g.root.children[0], "1", ["L", "R"]) - - # add C and D to single infoset after b and c - nodes = [g.root.children[1], g.root.children[2]] - g.append_move(nodes, "1", ["C", "D"]) - - # add s and t from single infoset after rightmost C and D - g.append_move(g.root.children[2].children, "2", ["s", "t"]) - - # add p and q - g.append_move(g.root.children[0].children[1], "2", ["p", "q"]) - - # add U and V in a single infoset after p and q - g.append_move(g.root.children[0].children[1].children, "1", ["U", "V"]) - - # Set outcomes - - g.set_outcome(g.root.children[0].children[0], g.add_outcome([1, -1], label="aL")) - g.set_outcome( - g.root.children[0].children[1].children[0].children[0], - g.add_outcome([2, -2], label="aRpU"), - ) - g.set_outcome( - g.root.children[0].children[1].children[0].children[1], - g.add_outcome([3, -3], label="aRpV"), - ) - g.set_outcome( - g.root.children[0].children[1].children[1].children[0], - g.add_outcome([4, -4], label="aRqU"), - ) - g.set_outcome( - g.root.children[0].children[1].children[1].children[1], - g.add_outcome([5, -5], label="aRqV"), - ) - - g.set_outcome(g.root.children[1].children[0], g.add_outcome([6, -6], label="bC")) - g.set_outcome(g.root.children[1].children[1], g.add_outcome([7, -7], label="bD")) - - g.set_outcome( - g.root.children[2].children[0].children[0], g.add_outcome([8, -8], label="cCs") - ) - g.set_outcome( - g.root.children[2].children[0].children[1], g.add_outcome([9, -9], label="cCt") - ) - g.set_outcome( - g.root.children[2].children[1].children[0], - g.add_outcome([10, -10], label="cDs"), - ) - g.set_outcome( - g.root.children[2].children[1].children[1], - g.add_outcome([11, -11], label="cDt"), - ) - - g.set_outcome(g.root.children[3], g.add_outcome([12, -12], label="d")) - g.to_efg("reduction_generic_payoffs.efg") - return g - - def create_reduction_both_players_payoff_ties_efg() -> gbt.Game: g = gbt.Game.new_tree(players=["1", "2"], title="From GTE survey") g.append_move(g.root, "1", ["A", "B", "C", "D"]) diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 31cdc2c43..33c06bd6f 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -168,7 +168,7 @@ def test_outcome_index_exception_label(): ), # 2-player (zero-sum) game; reduction for both players; generic payoffs ( - games.create_reduction_generic_payoffs_efg(), + games.read_from_file("reduction_generic_payoffs.efg"), [ ["1*1", "1*2", "211", "212", "221", "222"], ["11*", "12*", "2**", "3*1", "3*2", "4**"], From 9307709422098c854adada107e90263b0a5f585c Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:19:27 +0000 Subject: [PATCH 15/24] removed create_perfect_info_with_chance_efg from games.py --- tests/games.py | 47 ------------------- tests/test_games/perfect_info_with_chance.efg | 12 +++++ .../test_games/reduction_generic_payoffs.efg | 24 ++++++++++ tests/test_nash.py | 4 +- 4 files changed, 38 insertions(+), 49 deletions(-) create mode 100644 tests/test_games/perfect_info_with_chance.efg create mode 100644 tests/test_games/reduction_generic_payoffs.efg diff --git a/tests/games.py b/tests/games.py index 1521477fb..e684b6880 100644 --- a/tests/games.py +++ b/tests/games.py @@ -67,30 +67,6 @@ def create_2x2_zero_sum_efg(missing_term_outcome: bool = False) -> gbt.Game: return g -def create_perfect_info_with_chance_efg() -> gbt.Game: - # Tests case in which sequence profile probabilities don't sum to 1 - g = gbt.Game.new_tree(players=["1", "2"], title="2 player perfect info with chance") - g.append_move(g.root, "1", ["a", "b"]) - g.append_move(g.root.children[0], g.players.chance, ["L", "R"]) - g.append_move(g.root.children[0].children[0], "2", ["A", "B"]) - g.append_move(g.root.children[0].children[1], "2", ["C", "D"]) - g.set_outcome( - g.root.children[0].children[0].children[0], g.add_outcome([-2, 2], label="aLA") - ) - g.set_outcome( - g.root.children[0].children[0].children[1], g.add_outcome([-2, 2], label="aLB") - ) - g.set_outcome( - g.root.children[0].children[1].children[0], g.add_outcome([-2, 2], label="aRC") - ) - g.set_outcome( - g.root.children[0].children[1].children[1], g.add_outcome([-2, 2], label="aRD") - ) - g.set_outcome(g.root.children[1], g.add_outcome([-1, 1], label="b")) - g.to_efg("perfect_info_with_chance.efg") - return g - - def create_three_action_internal_outcomes_efg(nonterm_outcomes: bool = False) -> gbt.Game: """ with nonterm_outcomes there are nonterminal outcomes, and missing outcomes at some leaves @@ -577,29 +553,6 @@ def create_selten_horse_game_efg() -> gbt.Game: return read_from_file("e01.efg") -def create_reduction_both_players_payoff_ties_efg() -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2"], title="From GTE survey") - g.append_move(g.root, "1", ["A", "B", "C", "D"]) - g.append_move(g.root.children[0], "2", ["a", "b"]) - g.append_move(g.root.children[1], "2", ["c", "d"]) - g.append_move(g.root.children[2], "2", ["e", "f"]) - g.append_move(g.root.children[0].children[1], "2", ["g", "h"]) - g.append_move(g.root.children[2].children, "1", ["E", "F"]) - - g.set_outcome(g.root.children[0].children[0], g.add_outcome([2, 8])) - g.set_outcome(g.root.children[0].children[1].children[0], g.add_outcome([0, 1])) - g.set_outcome(g.root.children[0].children[1].children[1], g.add_outcome([5, 2])) - g.set_outcome(g.root.children[1].children[0], g.add_outcome([7, 6])) - g.set_outcome(g.root.children[1].children[1], g.add_outcome([4, 2])) - g.set_outcome(g.root.children[2].children[0].children[0], g.add_outcome([3, 7])) - g.set_outcome(g.root.children[2].children[0].children[1], g.add_outcome([8, 3])) - g.set_outcome(g.root.children[2].children[1].children[0], g.add_outcome([7, 8])) - g.set_outcome(g.root.children[2].children[1].children[1], g.add_outcome([2, 2])) - g.set_outcome(g.root.children[3], g.add_outcome([6, 4])) - g.to_efg("reduction_both_players_payoff_ties_GTE_survey.efg") - return g - - def create_EFG_for_nxn_bimatrix_coordination_game(n: int) -> gbt.Game: A = np.eye(n, dtype=int) B = A diff --git a/tests/test_games/perfect_info_with_chance.efg b/tests/test_games/perfect_info_with_chance.efg new file mode 100644 index 000000000..4b7c58ea0 --- /dev/null +++ b/tests/test_games/perfect_info_with_chance.efg @@ -0,0 +1,12 @@ +EFG 2 R "2 player perfect info with chance" { "1" "2" } +"" + +p "" 1 1 "" { "a" "b" } 0 +c "" 1 "" { "L" 1/2 "R" 1/2 } 0 +p "" 2 1 "" { "A" "B" } 0 +t "" 1 "aLA" { -2, 2 } +t "" 2 "aLB" { -2, 2 } +p "" 2 2 "" { "C" "D" } 0 +t "" 3 "aRC" { -2, 2 } +t "" 4 "aRD" { -2, 2 } +t "" 5 "b" { -1, 1 } diff --git a/tests/test_games/reduction_generic_payoffs.efg b/tests/test_games/reduction_generic_payoffs.efg new file mode 100644 index 000000000..7dcac053a --- /dev/null +++ b/tests/test_games/reduction_generic_payoffs.efg @@ -0,0 +1,24 @@ +EFG 2 R "2 player reduction generic payoffs" { "1" "2" } +"" + +p "" 2 1 "" { "a" "b" "c" "d" } 0 +p "" 1 1 "" { "L" "R" } 0 +t "" 1 "aL" { 1, -1 } +p "" 2 3 "" { "p" "q" } 0 +p "" 1 3 "" { "U" "V" } 0 +t "" 2 "aRpU" { 2, -2 } +t "" 3 "aRpV" { 3, -3 } +p "" 1 3 "" { "U" "V" } 0 +t "" 4 "aRqU" { 4, -4 } +t "" 5 "aRqV" { 5, -5 } +p "" 1 2 "" { "C" "D" } 0 +t "" 6 "bC" { 6, -6 } +t "" 7 "bD" { 7, -7 } +p "" 1 2 "" { "C" "D" } 0 +p "" 2 2 "" { "s" "t" } 0 +t "" 8 "cCs" { 8, -8 } +t "" 9 "cCt" { 9, -9 } +p "" 2 2 "" { "s" "t" } 0 +t "" 10 "cDs" { 10, -10 } +t "" 11 "cDt" { 11, -11 } +t "" 12 "d" { 12, -12 } diff --git a/tests/test_nash.py b/tests/test_nash.py index 796fea3d8..a07bdf5d1 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -553,7 +553,7 @@ def test_lcp_behavior_double(): # In the next test case: # 1/2-1/2 for l/r is determined by MixedBehaviorProfile.UndefinedToCentroid() ( - games.create_perfect_info_with_chance_efg(), + games.read_from_file("perfect_info_with_chance.efg"), [[[0, 1]], [[0, 1], [0, 1]]], ), ( @@ -766,7 +766,7 @@ def test_lp_behavior_double(): ], ), ( - games.create_perfect_info_with_chance_efg(), + games.read_from_file("perfect_info_with_chance.efg"), [[[0, 1]], [[1, 0], [1, 0]]], ), ( From 78e337558cbc0244c5920004e90d10b1a0a3b2b6 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:24:41 +0000 Subject: [PATCH 16/24] removed create_entry_accomodation_efg from games.py --- tests/games.py | 24 ------------------- tests/test_extensive.py | 4 ++-- tests/test_games/entry_accommodation.efg | 14 +++++++++++ ...ry_accommodation_with_nonterm_outcomes.efg | 14 +++++++++++ tests/test_nash.py | 4 ++-- 5 files changed, 32 insertions(+), 28 deletions(-) create mode 100644 tests/test_games/entry_accommodation.efg create mode 100644 tests/test_games/entry_accommodation_with_nonterm_outcomes.efg diff --git a/tests/games.py b/tests/games.py index e684b6880..764ae4df0 100644 --- a/tests/games.py +++ b/tests/games.py @@ -113,30 +113,6 @@ def create_three_action_internal_outcomes_efg(nonterm_outcomes: bool = False) -> return g -def create_entry_accomodation_efg(nonterm_outcomes: bool = False) -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2"], - title="Entry-accomodation game") - g.append_move(g.root, "1", ["S", "T"]) - g.append_move(g.root.children[0], "2", ["E", "O"]) - g.append_infoset(g.root.children[1], g.root.children[0].infoset) - g.append_move(g.root.children[0].children[0], "1", ["A", "F"]) - g.append_move(g.root.children[1].children[0], "1", ["A", "F"]) - if nonterm_outcomes: - g.set_outcome(g.root.children[0], g.add_outcome([3, 2])) - g.set_outcome(g.root.children[0].children[0].children[1], g.add_outcome([-3, -1])) - g.set_outcome(g.root.children[0].children[1], g.add_outcome([-2, 1])) - else: - g.set_outcome(g.root.children[0].children[0].children[0], g.add_outcome([3, 2])) - g.set_outcome(g.root.children[0].children[0].children[1], g.add_outcome([0, 1])) - g.set_outcome(g.root.children[0].children[1], g.add_outcome([1, 3])) - g.set_outcome(g.root.children[1].children[0].children[0], g.add_outcome([2, 3])) - g.set_outcome(g.root.children[1].children[0].children[1], g.add_outcome([1, 0])) - g.set_outcome(g.root.children[1].children[1], g.add_outcome([3, 1])) - tmp = "_with_nonterm_outcomes" if nonterm_outcomes else "" - g.to_efg(f"entry_accomodation{tmp}.efg") - return g - - def create_non_zero_sum_lacking_outcome_efg(missing_term_outcome: bool = False) -> gbt.Game: g = gbt.Game.new_tree(players=["1", "2"], title="Non constant-sum game lacking outcome") g.append_move(g.root, g.players.chance, ["H", "T"]) diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 33c06bd6f..b7b917755 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -417,8 +417,8 @@ def test_reduced_strategic_form( games.create_non_zero_sum_lacking_outcome_efg(missing_term_outcome=True) ), ( - games.create_entry_accomodation_efg(), - games.create_entry_accomodation_efg(nonterm_outcomes=True) + games.read_from_file("entry_accommodation.efg"), + games.read_from_file("entry_accommodation_with_nonterm_outcomes.efg") ), ( games.create_three_action_internal_outcomes_efg(), diff --git a/tests/test_games/entry_accommodation.efg b/tests/test_games/entry_accommodation.efg new file mode 100644 index 000000000..dfd383ba7 --- /dev/null +++ b/tests/test_games/entry_accommodation.efg @@ -0,0 +1,14 @@ +EFG 2 R "Entry-accomodation game" { "1" "2" } +"" + +p "" 1 1 "" { "S" "T" } 0 +p "" 2 1 "" { "E" "O" } 0 +p "" 1 2 "" { "A" "F" } 0 +t "" 1 "" { 3, 2 } +t "" 2 "" { 0, 1 } +t "" 3 "" { 1, 3 } +p "" 2 1 "" { "E" "O" } 0 +p "" 1 3 "" { "A" "F" } 0 +t "" 4 "" { 2, 3 } +t "" 5 "" { 1, 0 } +t "" 6 "" { 3, 1 } diff --git a/tests/test_games/entry_accommodation_with_nonterm_outcomes.efg b/tests/test_games/entry_accommodation_with_nonterm_outcomes.efg new file mode 100644 index 000000000..9453a4ff8 --- /dev/null +++ b/tests/test_games/entry_accommodation_with_nonterm_outcomes.efg @@ -0,0 +1,14 @@ +EFG 2 R "Entry-accomodation game" { "1" "2" } +"" + +p "" 1 1 "" { "S" "T" } 0 +p "" 2 1 "" { "E" "O" } 1 "" { 3, 2 } +p "" 1 2 "" { "A" "F" } 0 +t "" 0 +t "" 2 "" { -3, -1 } +t "" 3 "" { -2, 1 } +p "" 2 1 "" { "E" "O" } 0 +p "" 1 3 "" { "A" "F" } 0 +t "" 4 "" { 2, 3 } +t "" 5 "" { 1, 0 } +t "" 6 "" { 3, 1 } diff --git a/tests/test_nash.py b/tests/test_nash.py index a07bdf5d1..fe97559e9 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -618,11 +618,11 @@ def test_lcp_behavior_double(): [[[0, 0, 0, 1]], [[0, 0, 0, 1]]], ), ( - games.create_entry_accomodation_efg(), + games.read_from_file("entry_accommodation.efg"), [[["2/3", "1/3"], [1, 0], [1, 0]], [["2/3", "1/3"]]] ), ( - games.create_entry_accomodation_efg(nonterm_outcomes=True), + games.read_from_file("entry_accommodation_with_nonterm_outcomes.efg"), [[["2/3", "1/3"], [1, 0], [1, 0]], [["2/3", "1/3"]]], ), ( From 22fafa73811b6a3482f0e21a9939ced90167d4c2 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:35:10 +0000 Subject: [PATCH 17/24] removed create_non_zero_sum_lacking_outcome_efg from games.py --- tests/games.py | 24 ------------------- tests/test_extensive.py | 4 ++-- tests/test_games/2_player_non_zero_sum.efg | 18 ++++++++++++++ ...ayer_non_zero_sum_missing_term_outcome.efg | 18 ++++++++++++++ tests/test_nash.py | 8 +++---- 5 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 tests/test_games/2_player_non_zero_sum.efg create mode 100644 tests/test_games/2_player_non_zero_sum_missing_term_outcome.efg diff --git a/tests/games.py b/tests/games.py index 764ae4df0..b16b4aacb 100644 --- a/tests/games.py +++ b/tests/games.py @@ -113,30 +113,6 @@ def create_three_action_internal_outcomes_efg(nonterm_outcomes: bool = False) -> return g -def create_non_zero_sum_lacking_outcome_efg(missing_term_outcome: bool = False) -> gbt.Game: - g = gbt.Game.new_tree(players=["1", "2"], title="Non constant-sum game lacking outcome") - g.append_move(g.root, g.players.chance, ["H", "T"]) - g.set_chance_probs(g.root.infoset, ["1/2", "1/2"]) - g.append_move(g.root.children[0], "1", ["A", "B"]) - g.append_infoset(g.root.children[1], g.root.children[0].infoset) - g.append_move(g.root.children[0].children[0], "2", ["X", "Y"]) - g.append_infoset(g.root.children[0].children[1], g.root.children[0].children[0].infoset) - g.append_infoset(g.root.children[1].children[0], g.root.children[0].children[0].infoset) - g.append_infoset(g.root.children[1].children[1], g.root.children[0].children[0].infoset) - g.set_outcome(g.root.children[0].children[0].children[0], g.add_outcome([2, 1])) - g.set_outcome(g.root.children[0].children[0].children[1], g.add_outcome([-1, 2])) - g.set_outcome(g.root.children[0].children[1].children[0], g.add_outcome([1, -1])) - if not missing_term_outcome: - g.set_outcome(g.root.children[0].children[1].children[1], g.add_outcome([0, 0])) - g.set_outcome(g.root.children[1].children[0].children[0], g.add_outcome([1, 0])) - g.set_outcome(g.root.children[1].children[0].children[1], g.add_outcome([0, 1])) - g.set_outcome(g.root.children[1].children[1].children[0], g.add_outcome([-1, 1])) - g.set_outcome(g.root.children[1].children[1].children[1], g.add_outcome([2, -1])) - tmp = "_missing_term_outcome" if missing_term_outcome else "" - g.to_efg(f"non_zero_sum_2_player{tmp}.efg") - return g - - def create_matching_pennies_efg(with_neutral_outcome: bool = False) -> gbt.Game: """ TODO: use create_efg_corresponding_to_bimatrix_game diff --git a/tests/test_extensive.py b/tests/test_extensive.py index b7b917755..0f2e1fc28 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -413,8 +413,8 @@ def test_reduced_strategic_form( games.read_from_file("chance_in_middle_with_nonterm_outcomes.efg") ), ( - games.create_non_zero_sum_lacking_outcome_efg(), - games.create_non_zero_sum_lacking_outcome_efg(missing_term_outcome=True) + games.read_from_file("2_player_non_zero_sum.efg"), + games.read_from_file("2_player_non_zero_sum_missing_term_outcome.efg"), ), ( games.read_from_file("entry_accommodation.efg"), diff --git a/tests/test_games/2_player_non_zero_sum.efg b/tests/test_games/2_player_non_zero_sum.efg new file mode 100644 index 000000000..87a9e7adf --- /dev/null +++ b/tests/test_games/2_player_non_zero_sum.efg @@ -0,0 +1,18 @@ +EFG 2 R "Non constant-sum game lacking outcome" { "1" "2" } +"" + +c "" 1 "" { "H" 1/2 "T" 1/2 } 0 +p "" 1 1 "" { "A" "B" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 1 "" { 2, 1 } +t "" 2 "" { -1, 2 } +p "" 2 1 "" { "X" "Y" } 0 +t "" 3 "" { 1, -1 } +t "" 4 "" { 0, 0 } +p "" 1 1 "" { "A" "B" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 5 "" { 1, 0 } +t "" 6 "" { 0, 1 } +p "" 2 1 "" { "X" "Y" } 0 +t "" 7 "" { -1, 1 } +t "" 8 "" { 2, -1 } diff --git a/tests/test_games/2_player_non_zero_sum_missing_term_outcome.efg b/tests/test_games/2_player_non_zero_sum_missing_term_outcome.efg new file mode 100644 index 000000000..a7fb080e1 --- /dev/null +++ b/tests/test_games/2_player_non_zero_sum_missing_term_outcome.efg @@ -0,0 +1,18 @@ +EFG 2 R "Non constant-sum game lacking outcome" { "1" "2" } +"" + +c "" 1 "" { "H" 1/2 "T" 1/2 } 0 +p "" 1 1 "" { "A" "B" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 1 "" { 2, 1 } +t "" 2 "" { -1, 2 } +p "" 2 1 "" { "X" "Y" } 0 +t "" 3 "" { 1, -1 } +t "" 0 +p "" 1 1 "" { "A" "B" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 4 "" { 1, 0 } +t "" 5 "" { 0, 1 } +p "" 2 1 "" { "X" "Y" } 0 +t "" 6 "" { -1, 1 } +t "" 7 "" { 2, -1 } diff --git a/tests/test_nash.py b/tests/test_nash.py index fe97559e9..343d5208e 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -267,12 +267,12 @@ def test_enummixed_rational(game: gbt.Game, mixed_strategy_prof_data: list): ############################################################################## ############################################################################## ( - games.create_non_zero_sum_lacking_outcome_efg(), + games.read_from_file("2_player_non_zero_sum.efg"), [[[["1/3", "2/3"]], [["1/2", "1/2"]]]], 1, ), ( - games.create_non_zero_sum_lacking_outcome_efg(missing_term_outcome=True), + games.read_from_file("2_player_non_zero_sum_missing_term_outcome.efg"), [[[["1/3", "2/3"]], [["1/2", "1/2"]]]], 1, ), @@ -626,11 +626,11 @@ def test_lcp_behavior_double(): [[["2/3", "1/3"], [1, 0], [1, 0]], [["2/3", "1/3"]]], ), ( - games.create_non_zero_sum_lacking_outcome_efg(), + games.read_from_file("2_player_non_zero_sum.efg"), [[["1/3", "2/3"]], [["1/2", "1/2"]]] ), ( - games.create_non_zero_sum_lacking_outcome_efg(missing_term_outcome=True), + games.read_from_file("2_player_non_zero_sum_missing_term_outcome.efg"), [[["1/3", "2/3"]], [["1/2", "1/2"]]], ), ], From e275daf096f982278a52e82bca3177f79b35871c Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:47:09 +0000 Subject: [PATCH 18/24] create_matching_pennies_efg uses create_efg_corresponding_to_bimatrix_game and removed create_three_action_internal_outcomes_efg --- tests/games.py | 67 +++---------------- tests/test_extensive.py | 4 +- tests/test_games/2_player_chance.efg | 24 +++++++ ...erm_outcomes_and_missing_term_outcomes.efg | 24 +++++++ tests/test_nash.py | 8 +-- 5 files changed, 62 insertions(+), 65 deletions(-) create mode 100644 tests/test_games/2_player_chance.efg create mode 100644 tests/test_games/2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg diff --git a/tests/games.py b/tests/games.py index b16b4aacb..40b115d40 100644 --- a/tests/games.py +++ b/tests/games.py @@ -67,71 +67,20 @@ def create_2x2_zero_sum_efg(missing_term_outcome: bool = False) -> gbt.Game: return g -def create_three_action_internal_outcomes_efg(nonterm_outcomes: bool = False) -> gbt.Game: - """ - with nonterm_outcomes there are nonterminal outcomes, and missing outcomes at some leaves - """ - g = gbt.Game.new_tree(players=["1", "2"], title="") - g.append_move(g.root, g.players.chance, ["H", "L"]) - for i in range(2): - g.append_move(g.root.children[i], "1", ["A", "B", "C"]) - for i in range(3): - g.append_move(g.root.children[0].children[i], "2", ["X", "Y"]) - g.append_infoset(g.root.children[1].children[i], g.root.children[0].children[i].infoset) - o_1 = g.add_outcome([1, -1], label="1") - o_m1 = g.add_outcome([-1, 1], label="-1") - o_2 = g.add_outcome([2, -2], label="2") - o_m2 = g.add_outcome([-2, 2], label="-2") - o_z = g.add_outcome([0, 0], label="0") - if nonterm_outcomes: - g.set_outcome(g.root.children[0].children[0], o_1) - g.set_outcome(g.root.children[1].children[2], o_m1) - g.set_outcome(g.root.children[0].children[0].children[1], o_m2) - g.set_outcome(g.root.children[0].children[1].children[0], o_m1) - g.set_outcome(g.root.children[0].children[1].children[1], o_1) - g.set_outcome(g.root.children[0].children[2].children[0], o_1) - g.set_outcome(g.root.children[1].children[0].children[1], o_1) - g.set_outcome(g.root.children[1].children[1].children[0], o_1) - g.set_outcome(g.root.children[1].children[1].children[1], o_m1) - g.set_outcome(g.root.children[1].children[2].children[1], o_2) - else: - g.set_outcome(g.root.children[0].children[0].children[0], o_1) - g.set_outcome(g.root.children[0].children[0].children[1], o_m1) - g.set_outcome(g.root.children[0].children[1].children[0], o_m1) - g.set_outcome(g.root.children[0].children[1].children[1], o_1) - g.set_outcome(g.root.children[0].children[2].children[0], o_1) - g.set_outcome(g.root.children[0].children[2].children[1], o_z) - - g.set_outcome(g.root.children[1].children[0].children[0], o_z) - g.set_outcome(g.root.children[1].children[0].children[1], o_1) - g.set_outcome(g.root.children[1].children[1].children[0], o_1) - g.set_outcome(g.root.children[1].children[1].children[1], o_m1) - g.set_outcome(g.root.children[1].children[2].children[0], o_m1) - g.set_outcome(g.root.children[1].children[2].children[1], o_1) - tmp = "_nonterm_outcomes_and_missing_term_outcomes" if nonterm_outcomes else "" - g.to_efg(f"2_player_chance_3_actions{tmp}.efg") - return g - - def create_matching_pennies_efg(with_neutral_outcome: bool = False) -> gbt.Game: """ - TODO: use create_efg_corresponding_to_bimatrix_game - The version with_neutral_outcome adds a (0,0) payoff outcomes at a non-terminal node. """ - g = gbt.Game.new_tree( - players=["Alice", "Bob"], title="Matching pennies") - g.append_move(g.root, "Alice", ["H", "T"]) - g.append_move(g.root.children, "Bob", ["h", "t"]) - alice_lose = g.add_outcome([-1, 1], label="Alice lose") - alice_win = g.add_outcome([1, -1], label="Alice win") + title = "Matching Pennies" + if with_neutral_outcome: + title += " with nonterminal neutral outcome" + A = np.array([[1, -1], [-1, 1]]) + B = -A + g = create_efg_corresponding_to_bimatrix_game(A, B, title) if with_neutral_outcome: neutral = g.add_outcome([0, 0], label="neutral") - g.set_outcome(g.root.children["H"], neutral) - g.set_outcome(g.root.children["H"].children["h"], alice_win) - g.set_outcome(g.root.children["T"].children["t"], alice_win) - g.set_outcome(g.root.children["H"].children["t"], alice_lose) - g.set_outcome(g.root.children["T"].children["h"], alice_lose) + g.set_outcome(g.root.children[0], neutral) + g.to_efg(f"tmp2_{with_neutral_outcome}.efg") return g diff --git a/tests/test_extensive.py b/tests/test_extensive.py index 0f2e1fc28..f97584844 100644 --- a/tests/test_extensive.py +++ b/tests/test_extensive.py @@ -421,8 +421,8 @@ def test_reduced_strategic_form( games.read_from_file("entry_accommodation_with_nonterm_outcomes.efg") ), ( - games.create_three_action_internal_outcomes_efg(), - games.create_three_action_internal_outcomes_efg(nonterm_outcomes=True) + games.read_from_file("2_player_chance.efg"), + games.read_from_file("2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg"), ), ( games.create_kuhn_poker_efg(), diff --git a/tests/test_games/2_player_chance.efg b/tests/test_games/2_player_chance.efg new file mode 100644 index 000000000..3362390d5 --- /dev/null +++ b/tests/test_games/2_player_chance.efg @@ -0,0 +1,24 @@ +EFG 2 R "" { "1" "2" } +"" + +c "" 1 "" { "H" 1/2 "L" 1/2 } 0 +p "" 1 1 "" { "A" "B" "C" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 2 2 "" { "X" "Y" } 0 +t "" 2 "-1" { -1, 1 } +t "" 1 "1" { 1, -1 } +p "" 2 3 "" { "X" "Y" } 0 +t "" 1 "1" { 1, -1 } +t "" 5 "0" { 0, 0 } +p "" 1 2 "" { "A" "B" "C" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 5 "0" { 0, 0 } +t "" 1 "1" { 1, -1 } +p "" 2 2 "" { "X" "Y" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 2 3 "" { "X" "Y" } 0 +t "" 2 "-1" { -1, 1 } +t "" 1 "1" { 1, -1 } diff --git a/tests/test_games/2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg b/tests/test_games/2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg new file mode 100644 index 000000000..2a9099273 --- /dev/null +++ b/tests/test_games/2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg @@ -0,0 +1,24 @@ +EFG 2 R "" { "1" "2" } +"" + +c "" 1 "" { "H" 1/2 "L" 1/2 } 0 +p "" 1 1 "" { "A" "B" "C" } 0 +p "" 2 1 "" { "X" "Y" } 1 "1" { 1, -1 } +t "" 0 +t "" 4 "-2" { -2, 2 } +p "" 2 2 "" { "X" "Y" } 0 +t "" 2 "-1" { -1, 1 } +t "" 1 "1" { 1, -1 } +p "" 2 3 "" { "X" "Y" } 0 +t "" 1 "1" { 1, -1 } +t "" 0 +p "" 1 2 "" { "A" "B" "C" } 0 +p "" 2 1 "" { "X" "Y" } 0 +t "" 0 +t "" 1 "1" { 1, -1 } +p "" 2 2 "" { "X" "Y" } 0 +t "" 1 "1" { 1, -1 } +t "" 2 "-1" { -1, 1 } +p "" 2 3 "" { "X" "Y" } 2 "-1" { -1, 1 } +t "" 0 +t "" 3 "2" { 2, -2 } diff --git a/tests/test_nash.py b/tests/test_nash.py index 343d5208e..52343490e 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -565,14 +565,14 @@ def test_lcp_behavior_double(): [[[0, 1], [1, 0]], [[0, 1], ["1/2", "1/2"]]], ), ( - games.create_three_action_internal_outcomes_efg(), + games.read_from_file("2_player_chance.efg"), [ [["1/3", 0, "2/3"], ["2/3", 0, "1/3"]], [["2/3", "1/3"], ["1/3", "2/3"], ["1/3", "2/3"]], ] ), ( - games.create_three_action_internal_outcomes_efg(nonterm_outcomes=True), + games.read_from_file("2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg"), [ [["1/3", 0, "2/3"], ["2/3", 0, "1/3"]], [["2/3", "1/3"], ["1/3", "2/3"], ["1/3", "2/3"]], @@ -770,14 +770,14 @@ def test_lp_behavior_double(): [[[0, 1]], [[1, 0], [1, 0]]], ), ( - games.create_three_action_internal_outcomes_efg(), + games.read_from_file("2_player_chance.efg"), [ [["1/3", 0, "2/3"], ["2/3", 0, "1/3"]], [["2/3", "1/3"], ["2/3", "1/3"], ["1/3", "2/3"]], ] ), ( - games.create_three_action_internal_outcomes_efg(nonterm_outcomes=True), + games.read_from_file("2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg"), [ [["1/3", 0, "2/3"], ["2/3", 0, "1/3"]], [["2/3", "1/3"], ["2/3", "1/3"], ["1/3", "2/3"]], From 25b42cd8c5adaf4a8cb195d70875640479443d39 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 18:52:10 +0000 Subject: [PATCH 19/24] removed temp to_efg call --- tests/games.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/games.py b/tests/games.py index 40b115d40..01b5bc2a6 100644 --- a/tests/games.py +++ b/tests/games.py @@ -80,7 +80,6 @@ def create_matching_pennies_efg(with_neutral_outcome: bool = False) -> gbt.Game: if with_neutral_outcome: neutral = g.add_outcome([0, 0], label="neutral") g.set_outcome(g.root.children[0], neutral) - g.to_efg(f"tmp2_{with_neutral_outcome}.efg") return g From 02d1d8646a5e422df1e00a8871fc6c0c84706e20 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 19:00:29 +0000 Subject: [PATCH 20/24] removed create_mixed_behav_game_efg from games.py --- tests/games.py | 13 - tests/test_behav.py | 2464 ++++++++++++++-------- tests/test_games/mixed_behavior_game.efg | 7 +- tests/test_mixed.py | 28 +- tests/test_nash.py | 8 +- 5 files changed, 1626 insertions(+), 894 deletions(-) diff --git a/tests/games.py b/tests/games.py index 01b5bc2a6..da398bf0a 100644 --- a/tests/games.py +++ b/tests/games.py @@ -83,19 +83,6 @@ def create_matching_pennies_efg(with_neutral_outcome: bool = False) -> gbt.Game: return g -def create_mixed_behav_game_efg() -> gbt.Game: - """ - Returns - ------- - Game - Three-player extensive form game: binary tree with 3 infomation sets, one per player, - with 1, 2, and 4 nodes respectively - - Since no information is revealed this is directly equivalent to a simultaneous move game - """ - return read_from_file("mixed_behavior_game.efg") - - def create_stripped_down_poker_efg(nonterm_outcomes: bool = False) -> gbt.Game: """ Returns diff --git a/tests/test_behav.py b/tests/test_behav.py index c24cf5361..6097d342e 100644 --- a/tests/test_behav.py +++ b/tests/test_behav.py @@ -22,20 +22,22 @@ def _set_action_probs(profile: gbt.MixedBehaviorProfile, probs: list, rational_f @pytest.mark.parametrize( "game,player_idx,payoff,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 3.0, False), - (games.create_mixed_behav_game_efg(), 1, 3.0, False), - (games.create_mixed_behav_game_efg(), 2, 3.25, False), - (games.create_mixed_behav_game_efg(), 0, "3", True), - (games.create_mixed_behav_game_efg(), 1, "3", True), - (games.create_mixed_behav_game_efg(), 2, "13/4", True), - (games.create_stripped_down_poker_efg(), 0, -0.25, False), - (games.create_stripped_down_poker_efg(), 1, 0.25, True), - (games.create_stripped_down_poker_efg(), 0, "-1/4", True), - (games.create_stripped_down_poker_efg(), 1, "1/4", True) - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 3.25, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, "3", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, "3", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, "13/4", True), + (games.create_stripped_down_poker_efg(), 0, -0.25, False), + (games.create_stripped_down_poker_efg(), 1, 0.25, True), + (games.create_stripped_down_poker_efg(), 0, "-1/4", True), + (games.create_stripped_down_poker_efg(), 1, "1/4", True), + ], ) -def test_payoff_reference(game: gbt.Game, player_idx: int, payoff: str | float, - rational_flag: bool): +def test_payoff_reference( + game: gbt.Game, player_idx: int, payoff: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) payoff = gbt.Rational(payoff) if rational_flag else payoff assert profile.payoff(game.players[player_idx]) == payoff @@ -43,20 +45,22 @@ def test_payoff_reference(game: gbt.Game, player_idx: int, payoff: str | float, @pytest.mark.parametrize( "game,label,payoff,rational_flag", - [(games.create_mixed_behav_game_efg(), "Player 1", 3.0, False), - (games.create_mixed_behav_game_efg(), "Player 2", 3.0, False), - (games.create_mixed_behav_game_efg(), "Player 3", 3.25, False), - (games.create_mixed_behav_game_efg(), "Player 1", "3", True), - (games.create_mixed_behav_game_efg(), "Player 2", "3", True), - (games.create_mixed_behav_game_efg(), "Player 3", "13/4", True), - (games.create_stripped_down_poker_efg(), "Alice", -0.25, False), - (games.create_stripped_down_poker_efg(), "Bob", 0.25, False), - (games.create_stripped_down_poker_efg(), "Alice", "-1/4", True), - (games.create_stripped_down_poker_efg(), "Bob", "1/4", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 2", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 3", 3.25, False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "Player 2", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "Player 3", "13/4", True), + (games.create_stripped_down_poker_efg(), "Alice", -0.25, False), + (games.create_stripped_down_poker_efg(), "Bob", 0.25, False), + (games.create_stripped_down_poker_efg(), "Alice", "-1/4", True), + (games.create_stripped_down_poker_efg(), "Bob", "1/4", True), + ], ) -def test_payoff_by_label_reference(game: gbt.Game, label: str, payoff: str | float, - rational_flag: bool): +def test_payoff_by_label_reference( + game: gbt.Game, label: str, payoff: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) payoff = gbt.Rational(payoff) if rational_flag else payoff assert profile.payoff(label) == payoff @@ -64,11 +68,12 @@ def test_payoff_by_label_reference(game: gbt.Game, label: str, payoff: str | flo @pytest.mark.parametrize( "game,rational_flag", - [(games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), - (games.create_stripped_down_poker_efg(), False), - (games.create_stripped_down_poker_efg(), True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), + (games.create_stripped_down_poker_efg(), False), + (games.create_stripped_down_poker_efg(), True), + ], ) def test_is_defined_at(game: gbt.Game, rational_flag: bool): """Test to check if infoset are all defined""" @@ -79,19 +84,20 @@ def test_is_defined_at(game: gbt.Game, rational_flag: bool): @pytest.mark.parametrize( "game,label,rational_flag", - [(games.create_mixed_behav_game_efg(), "Infoset 1:1", False), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", False), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", False), - (games.create_mixed_behav_game_efg(), "Infoset 1:1", True), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", True), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", True), - (games.create_stripped_down_poker_efg(), "Alice has King", False), - (games.create_stripped_down_poker_efg(), "Alice has Queen", False), - (games.create_stripped_down_poker_efg(), "Bob's response", False), - (games.create_stripped_down_poker_efg(), "Alice has King", True), - (games.create_stripped_down_poker_efg(), "Alice has Queen", True), - (games.create_stripped_down_poker_efg(), "Bob's response", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", True), + (games.create_stripped_down_poker_efg(), "Alice has King", False), + (games.create_stripped_down_poker_efg(), "Alice has Queen", False), + (games.create_stripped_down_poker_efg(), "Bob's response", False), + (games.create_stripped_down_poker_efg(), "Alice has King", True), + (games.create_stripped_down_poker_efg(), "Alice has Queen", True), + (games.create_stripped_down_poker_efg(), "Bob's response", True), + ], ) def test_is_defined_at_by_label(game: gbt.Game, label: str, rational_flag: bool): """Test to check if an infoset is defined by string labels""" @@ -101,37 +107,41 @@ def test_is_defined_at_by_label(game: gbt.Game, label: str, rational_flag: bool) @pytest.mark.parametrize( "game,player_idx,infoset_idx,action_idx,prob,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 0, 0, 0.5, False), - (games.create_mixed_behav_game_efg(), 0, 0, 1, 0.5, False), - (games.create_mixed_behav_game_efg(), 1, 0, 0, 0.5, False), - (games.create_mixed_behav_game_efg(), 1, 0, 1, 0.5, False), - (games.create_mixed_behav_game_efg(), 2, 0, 0, 0.5, False), - (games.create_mixed_behav_game_efg(), 2, 0, 1, 0.5, False), - (games.create_mixed_behav_game_efg(), 0, 0, 0, "1/2", True), - (games.create_mixed_behav_game_efg(), 0, 0, 1, "1/2", True), - (games.create_mixed_behav_game_efg(), 1, 0, 0, "1/2", True), - (games.create_mixed_behav_game_efg(), 1, 0, 1, "1/2", True), - (games.create_mixed_behav_game_efg(), 2, 0, 0, "1/2", True), - (games.create_mixed_behav_game_efg(), 2, 0, 1, "1/2", True), - (games.create_stripped_down_poker_efg(), 0, 0, 0, 0.5, False), - (games.create_stripped_down_poker_efg(), 0, 0, 1, 0.5, False), - (games.create_stripped_down_poker_efg(), 0, 1, 0, 0.5, False), - (games.create_stripped_down_poker_efg(), 0, 1, 1, 0.5, False), - (games.create_stripped_down_poker_efg(), 1, 0, 0, 0.5, False), - (games.create_stripped_down_poker_efg(), 1, 0, 1, 0.5, False), - (games.create_stripped_down_poker_efg(), 0, 0, 0, "1/2", True), - (games.create_stripped_down_poker_efg(), 0, 0, 1, "1/2", True), - (games.create_stripped_down_poker_efg(), 0, 1, 0, "1/2", True), - (games.create_stripped_down_poker_efg(), 0, 1, 1, "1/2", True), - (games.create_stripped_down_poker_efg(), 1, 0, 0, "1/2", True), - (games.create_stripped_down_poker_efg(), 1, 0, 1, "1/2", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 0, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 1, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 0, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 1, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 0, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 1, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 0, "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 1, "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 0, "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 1, "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 0, "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 1, "1/2", True), + (games.create_stripped_down_poker_efg(), 0, 0, 0, 0.5, False), + (games.create_stripped_down_poker_efg(), 0, 0, 1, 0.5, False), + (games.create_stripped_down_poker_efg(), 0, 1, 0, 0.5, False), + (games.create_stripped_down_poker_efg(), 0, 1, 1, 0.5, False), + (games.create_stripped_down_poker_efg(), 1, 0, 0, 0.5, False), + (games.create_stripped_down_poker_efg(), 1, 0, 1, 0.5, False), + (games.create_stripped_down_poker_efg(), 0, 0, 0, "1/2", True), + (games.create_stripped_down_poker_efg(), 0, 0, 1, "1/2", True), + (games.create_stripped_down_poker_efg(), 0, 1, 0, "1/2", True), + (games.create_stripped_down_poker_efg(), 0, 1, 1, "1/2", True), + (games.create_stripped_down_poker_efg(), 1, 0, 0, "1/2", True), + (games.create_stripped_down_poker_efg(), 1, 0, 1, "1/2", True), + ], ) -def test_profile_indexing_by_player_infoset_action_idx_reference(game: gbt.Game, player_idx: int, - infoset_idx: int, - action_idx: int, - prob: str | float, - rational_flag: bool): +def test_profile_indexing_by_player_infoset_action_idx_reference( + game: gbt.Game, + player_idx: int, + infoset_idx: int, + action_idx: int, + prob: str | float, + rational_flag: bool, +): profile = game.mixed_behavior_profile(rational=rational_flag) action = game.players[player_idx].infosets[infoset_idx].actions[action_idx] prob = gbt.Rational(prob) if rational_flag else prob @@ -140,25 +150,26 @@ def test_profile_indexing_by_player_infoset_action_idx_reference(game: gbt.Game, @pytest.mark.parametrize( "game,action_label,prob,rational_flag", - [(games.create_mixed_behav_game_efg(), "U1", 0.5, False), - (games.create_mixed_behav_game_efg(), "D1", 0.5, False), - (games.create_mixed_behav_game_efg(), "U2", 0.5, False), - (games.create_mixed_behav_game_efg(), "D2", 0.5, False), - (games.create_mixed_behav_game_efg(), "U3", 0.5, False), - (games.create_mixed_behav_game_efg(), "D3", 0.5, False), - (games.create_mixed_behav_game_efg(), "U1", "1/2", True), - (games.create_mixed_behav_game_efg(), "D1", "1/2", True), - (games.create_mixed_behav_game_efg(), "U2", "1/2", True), - (games.create_mixed_behav_game_efg(), "D2", "1/2", True), - (games.create_mixed_behav_game_efg(), "U3", "1/2", True), - (games.create_mixed_behav_game_efg(), "D3", "1/2", True), - (games.create_stripped_down_poker_efg(), "Call", 0.5, False), - (games.create_stripped_down_poker_efg(), "Call", "1/2", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "U1", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "D1", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "U2", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "D2", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "U3", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "D3", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "U1", "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), "D1", "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), "U2", "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), "D2", "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), "U3", "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), "D3", "1/2", True), + (games.create_stripped_down_poker_efg(), "Call", 0.5, False), + (games.create_stripped_down_poker_efg(), "Call", "1/2", True), + ], ) -def test_profile_indexing_by_action_label_reference(game: gbt.Game, action_label: str, - prob: str | float, - rational_flag: bool): +def test_profile_indexing_by_action_label_reference( + game: gbt.Game, action_label: str, prob: str | float, rational_flag: bool +): """Here we only use the action label, which are all valid""" profile = game.mixed_behavior_profile(rational=rational_flag) prob = gbt.Rational(prob) if rational_flag else prob @@ -167,36 +178,33 @@ def test_profile_indexing_by_action_label_reference(game: gbt.Game, action_label @pytest.mark.parametrize( "game,action_label,rational_flag,error", - [(games.create_mixed_behav_game_efg(), "U4", True, KeyError), - (games.create_mixed_behav_game_efg(), "U4", False, KeyError), - (games.create_stripped_down_poker_efg(), "Bet", True, ValueError), - (games.create_stripped_down_poker_efg(), "Bet", False, ValueError), - (games.create_stripped_down_poker_efg(), "Fold", True, ValueError), - (games.create_stripped_down_poker_efg(), "Fold", False, ValueError), - (games.create_stripped_down_poker_efg(), "BetFold", True, KeyError), - (games.create_stripped_down_poker_efg(), "BetFold", False, KeyError), - (games.create_stripped_down_poker_efg(), "MISSING", True, KeyError), - (games.create_stripped_down_poker_efg(), "MISSING", False, KeyError), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "U4", True, KeyError), + (games.read_from_file("mixed_behavior_game.efg"), "U4", False, KeyError), + (games.create_stripped_down_poker_efg(), "Bet", True, ValueError), + (games.create_stripped_down_poker_efg(), "Bet", False, ValueError), + (games.create_stripped_down_poker_efg(), "Fold", True, ValueError), + (games.create_stripped_down_poker_efg(), "Fold", False, ValueError), + (games.create_stripped_down_poker_efg(), "BetFold", True, KeyError), + (games.create_stripped_down_poker_efg(), "BetFold", False, KeyError), + (games.create_stripped_down_poker_efg(), "MISSING", True, KeyError), + (games.create_stripped_down_poker_efg(), "MISSING", False, KeyError), + ], ) -def test_profile_indexing_by_invalid_action_label(game: gbt.Game, action_label: str, - rational_flag: bool, - error: ValueError | KeyError): - """Test that we get a KeyError for a missing label, and a ValueError for an ambigiuous label - """ +def test_profile_indexing_by_invalid_action_label( + game: gbt.Game, action_label: str, rational_flag: bool, error: ValueError | KeyError +): + """Test that we get a KeyError for a missing label, and a ValueError for an ambigiuous label""" with pytest.raises(error): game.mixed_behavior_profile(rational=rational_flag)[action_label] -@pytest.mark.parametrize( - "rational_flag", - [True, False] - ) +@pytest.mark.parametrize("rational_flag", [True, False]) def test_profile_indexing_by_invalid_infoset_label(rational_flag: bool): """Create a duplicate infoset label and check we get a ValueError for this ambiguous label, and a KeyError for the now missing label that was overwritten """ - game = games.create_mixed_behav_game_efg() + game = games.read_from_file("mixed_behavior_game.efg") profile = game.mixed_behavior_profile(rational=rational_flag) assert profile["Infoset 1:1"] game.infosets["Infoset 1:1"].label = "Infoset 2:1" @@ -208,25 +216,24 @@ def test_profile_indexing_by_invalid_infoset_label(rational_flag: bool): @pytest.mark.parametrize( "game,infoset_label,action_label,prob,rational_flag", - [(games.create_mixed_behav_game_efg(), "Infoset 1:1", "U1", 0.5, False), - (games.create_mixed_behav_game_efg(), "Infoset 1:1", "D1", 0.5, False), - (games.create_mixed_behav_game_efg(), "Infoset 1:1", "U1", "1/2", True), - (games.create_mixed_behav_game_efg(), "Infoset 1:1", "D1", "1/2", True), - (games.create_stripped_down_poker_efg(), "Alice has King", "Bet", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice has King", "Fold", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice has Queen", "Bet", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice has Queen", "Fold", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob's response", "Call", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob's response", "Fold", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob's response", "Call", "1/2", True), - (games.create_stripped_down_poker_efg(), "Bob's response", "Fold", "1/2", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", "U1", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", "D1", 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", "U1", "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", "D1", "1/2", True), + (games.create_stripped_down_poker_efg(), "Alice has King", "Bet", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice has King", "Fold", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice has Queen", "Bet", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice has Queen", "Fold", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob's response", "Call", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob's response", "Fold", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob's response", "Call", "1/2", True), + (games.create_stripped_down_poker_efg(), "Bob's response", "Fold", "1/2", True), + ], ) -def test_profile_indexing_by_infoset_and_action_labels_reference(game: gbt.Game, - infoset_label: str, - action_label: str, - prob: str | float, - rational_flag: bool): +def test_profile_indexing_by_infoset_and_action_labels_reference( + game: gbt.Game, infoset_label: str, action_label: str, prob: str | float, rational_flag: bool +): """Here we use the infoset label and action label, with some examples where the action label alone throws a ValueError (checked in a separate test) """ @@ -237,26 +244,57 @@ def test_profile_indexing_by_infoset_and_action_labels_reference(game: gbt.Game, @pytest.mark.parametrize( "game,player_label,infoset_label,action_label,prob,rational_flag", - [(games.create_mixed_behav_game_efg(), "Player 1", "Infoset 1:1", "U1", 0.5, False), - (games.create_mixed_behav_game_efg(), "Player 1", "Infoset 1:1", "D1", 0.5, False), - (games.create_mixed_behav_game_efg(), "Player 1", "Infoset 1:1", "U1", "1/2", True), - (games.create_mixed_behav_game_efg(), "Player 1", "Infoset 1:1", "D1", "1/2", True), - (games.create_stripped_down_poker_efg(), "Alice", "Alice has King", "Bet", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice", "Alice has King", "Fold", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice", "Alice has Queen", "Bet", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice", "Alice has Queen", "Fold", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Call", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Fold", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Call", "1/2", True), - (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Fold", "1/2", True), - ] + [ + ( + games.read_from_file("mixed_behavior_game.efg"), + "Player 1", + "Infoset 1:1", + "U1", + 0.5, + False, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + "Player 1", + "Infoset 1:1", + "D1", + 0.5, + False, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + "Player 1", + "Infoset 1:1", + "U1", + "1/2", + True, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + "Player 1", + "Infoset 1:1", + "D1", + "1/2", + True, + ), + (games.create_stripped_down_poker_efg(), "Alice", "Alice has King", "Bet", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice", "Alice has King", "Fold", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice", "Alice has Queen", "Bet", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice", "Alice has Queen", "Fold", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Call", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Fold", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Call", "1/2", True), + (games.create_stripped_down_poker_efg(), "Bob", "Bob's response", "Fold", "1/2", True), + ], ) -def test_profile_indexing_by_player_infoset_action_labels_reference(game: gbt.Game, - player_label: str, - infoset_label: str, - action_label: str, - prob: str | float, - rational_flag: bool): +def test_profile_indexing_by_player_infoset_action_labels_reference( + game: gbt.Game, + player_label: str, + infoset_label: str, + action_label: str, + prob: str | float, + rational_flag: bool, +): """Here we use the infoset label and action label, with some examples where the action label alone throws a ValueError (checked in a separate test) """ @@ -267,41 +305,52 @@ def test_profile_indexing_by_player_infoset_action_labels_reference(game: gbt.Ga @pytest.mark.parametrize( "game,infoset_label,action_label,rational_flag", - [(games.create_mixed_behav_game_efg(), "1:1", "U2", True), # U2 is at a different iset - (games.create_mixed_behav_game_efg(), "1:1", "U2", False), - (games.create_mixed_behav_game_efg(), "1:1", "U4", True), # U4 isn't in the game - (games.create_mixed_behav_game_efg(), "1:1", "U4", False), - (games.create_stripped_down_poker_efg(), "Alice has King", "MEET", True), - (games.create_stripped_down_poker_efg(), "Alice has King", "MEET", False), - ] + [ + ( + games.read_from_file("mixed_behavior_game.efg"), + "1:1", + "U2", + True, + ), # U2 is at a different iset + (games.read_from_file("mixed_behavior_game.efg"), "1:1", "U2", False), + ( + games.read_from_file("mixed_behavior_game.efg"), + "1:1", + "U4", + True, + ), # U4 isn't in the game + (games.read_from_file("mixed_behavior_game.efg"), "1:1", "U4", False), + (games.create_stripped_down_poker_efg(), "Alice has King", "MEET", True), + (games.create_stripped_down_poker_efg(), "Alice has King", "MEET", False), + ], ) -def test_profile_indexing_by_invalid_infoset_or_action_label(game: gbt.Game, infoset_label: str, - action_label: str, - rational_flag: bool): +def test_profile_indexing_by_invalid_infoset_or_action_label( + game: gbt.Game, infoset_label: str, action_label: str, rational_flag: bool +): with pytest.raises(KeyError): game.mixed_behavior_profile(rational=rational_flag)[infoset_label][action_label] @pytest.mark.parametrize( "game,player_idx,infoset_idx,probs,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 0, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), 1, 0, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), 2, 0, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), 0, 0, ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), 1, 0, ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), 2, 0, ["1/2", "1/2"], True), - (games.create_stripped_down_poker_efg(), 0, 0, [0.5, 0.5], False), - (games.create_stripped_down_poker_efg(), 0, 1, [0.5, 0.5], False), - (games.create_stripped_down_poker_efg(), 1, 0, [0.5, 0.5], False), - (games.create_stripped_down_poker_efg(), 0, 0, ["1/2", "1/2"], True), - (games.create_stripped_down_poker_efg(), 0, 1, ["1/2", "1/2"], True), - (games.create_stripped_down_poker_efg(), 1, 0, ["1/2", "1/2"], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, ["1/2", "1/2"], True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, ["1/2", "1/2"], True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, ["1/2", "1/2"], True), + (games.create_stripped_down_poker_efg(), 0, 0, [0.5, 0.5], False), + (games.create_stripped_down_poker_efg(), 0, 1, [0.5, 0.5], False), + (games.create_stripped_down_poker_efg(), 1, 0, [0.5, 0.5], False), + (games.create_stripped_down_poker_efg(), 0, 0, ["1/2", "1/2"], True), + (games.create_stripped_down_poker_efg(), 0, 1, ["1/2", "1/2"], True), + (games.create_stripped_down_poker_efg(), 1, 0, ["1/2", "1/2"], True), + ], ) -def test_profile_indexing_by_player_and_infoset_idx_reference(game: gbt.Game, - player_idx: int, - infoset_idx: int, - probs: list, rational_flag: bool): +def test_profile_indexing_by_player_and_infoset_idx_reference( + game: gbt.Game, player_idx: int, infoset_idx: int, probs: list, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) infoset = game.players[player_idx].infosets[infoset_idx] probs = [gbt.Rational(prob) for prob in probs] if rational_flag else probs @@ -310,23 +359,24 @@ def test_profile_indexing_by_player_and_infoset_idx_reference(game: gbt.Game, @pytest.mark.parametrize( "game,player_idx,infoset_label,probs,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, "Infoset 1:1", [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), 1, "Infoset 2:1", [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), 2, "Infoset 3:1", [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), 0, "Infoset 1:1", ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), 1, "Infoset 2:1", ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), 2, "Infoset 3:1", ["1/2", "1/2"], True), - (games.create_stripped_down_poker_efg(), 0, "Alice has King", [0.5, 0.5], False), - (games.create_stripped_down_poker_efg(), 0, "Alice has Queen", [0.5, 0.5], False), - (games.create_stripped_down_poker_efg(), 1, "Bob's response", [0.5, 0.5], False), - (games.create_stripped_down_poker_efg(), 0, "Alice has King", ["1/2", "1/2"], True), - (games.create_stripped_down_poker_efg(), 0, "Alice has Queen", ["1/2", "1/2"], True), - (games.create_stripped_down_poker_efg(), 1, "Bob's response", ["1/2", "1/2"], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, "Infoset 1:1", [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), 1, "Infoset 2:1", [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), 2, "Infoset 3:1", [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), 0, "Infoset 1:1", ["1/2", "1/2"], True), + (games.read_from_file("mixed_behavior_game.efg"), 1, "Infoset 2:1", ["1/2", "1/2"], True), + (games.read_from_file("mixed_behavior_game.efg"), 2, "Infoset 3:1", ["1/2", "1/2"], True), + (games.create_stripped_down_poker_efg(), 0, "Alice has King", [0.5, 0.5], False), + (games.create_stripped_down_poker_efg(), 0, "Alice has Queen", [0.5, 0.5], False), + (games.create_stripped_down_poker_efg(), 1, "Bob's response", [0.5, 0.5], False), + (games.create_stripped_down_poker_efg(), 0, "Alice has King", ["1/2", "1/2"], True), + (games.create_stripped_down_poker_efg(), 0, "Alice has Queen", ["1/2", "1/2"], True), + (games.create_stripped_down_poker_efg(), 1, "Bob's response", ["1/2", "1/2"], True), + ], ) -def test_profile_indexing_by_player_idx_infoset_label_reference(game: gbt.Game, player_idx: int, - infoset_label: str, probs: list, - rational_flag: bool): +def test_profile_indexing_by_player_idx_infoset_label_reference( + game: gbt.Game, player_idx: int, infoset_label: str, probs: list, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) player = game.players[player_idx] probs = [gbt.Rational(prob) for prob in probs] if rational_flag else probs @@ -336,16 +386,21 @@ def test_profile_indexing_by_player_idx_infoset_label_reference(game: gbt.Game, @pytest.mark.parametrize( "game,player_label,infoset_label,rational_flag", - [(games.create_mixed_behav_game_efg(), "Player 1", "1:1", True), # correct: "Infoset 1:1" - (games.create_mixed_behav_game_efg(), "Player 1", "1:1", False), - (games.create_stripped_down_poker_efg(), "Player 1", "(2,1)", True), # wrong player - (games.create_stripped_down_poker_efg(), "Player 1", "(2,1)", False), - ] + [ + ( + games.read_from_file("mixed_behavior_game.efg"), + "Player 1", + "1:1", + True, + ), # correct: "Infoset 1:1" + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", "1:1", False), + (games.create_stripped_down_poker_efg(), "Player 1", "(2,1)", True), # wrong player + (games.create_stripped_down_poker_efg(), "Player 1", "(2,1)", False), + ], ) -def test_profile_indexing_by_player_and_invalid_infoset_label(game: gbt.Game, - player_label: str, - infoset_label: str, - rational_flag: bool): +def test_profile_indexing_by_player_and_invalid_infoset_label( + game: gbt.Game, player_label: str, infoset_label: str, rational_flag: bool +): """Test that we get a KeyError and that "player" appears in the error message""" with pytest.raises(KeyError, match="player"): game.mixed_behavior_profile(rational=rational_flag)[player_label][infoset_label] @@ -353,16 +408,16 @@ def test_profile_indexing_by_player_and_invalid_infoset_label(game: gbt.Game, @pytest.mark.parametrize( "game,player_label,action_label,rational_flag", - [(games.create_mixed_behav_game_efg(), "Player 1", "U2", True), - (games.create_mixed_behav_game_efg(), "Player 1", "U2", False), - (games.create_stripped_down_poker_efg(), "Player 1", "MEET", True), - (games.create_stripped_down_poker_efg(), "Player 1", "MEET", False), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", "U2", True), + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", "U2", False), + (games.create_stripped_down_poker_efg(), "Player 1", "MEET", True), + (games.create_stripped_down_poker_efg(), "Player 1", "MEET", False), + ], ) -def test_profile_indexing_by_player_and_invalid_action_label(game: gbt.Game, - player_label: str, - action_label: str, - rational_flag: bool): +def test_profile_indexing_by_player_and_invalid_action_label( + game: gbt.Game, player_label: str, action_label: str, rational_flag: bool +): """Test that we get a KeyError and that "player" appears in the error message""" with pytest.raises(KeyError, match="player"): game.mixed_behavior_profile(rational=rational_flag)[player_label][action_label] @@ -370,21 +425,22 @@ def test_profile_indexing_by_player_and_invalid_action_label(game: gbt.Game, @pytest.mark.parametrize( "game,player_idx,behav_data,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, [[0.5, 0.5]], False), - (games.create_mixed_behav_game_efg(), 1, [[0.5, 0.5]], False), - (games.create_mixed_behav_game_efg(), 2, [[0.5, 0.5]], False), - (games.create_mixed_behav_game_efg(), 0, [["1/2", "1/2"]], True), - (games.create_mixed_behav_game_efg(), 1, [["1/2", "1/2"]], True), - (games.create_mixed_behav_game_efg(), 2, [["1/2", "1/2"]], True), - (games.create_stripped_down_poker_efg(), 0, [[0.5, 0.5], [0.5, 0.5]], False), - (games.create_stripped_down_poker_efg(), 1, [[0.5, 0.5]], False), - (games.create_stripped_down_poker_efg(), 0, [["1/2", "1/2"], ["1/2", "1/2"]], True), - (games.create_stripped_down_poker_efg(), 1, [["1/2", "1/2"]], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, [[0.5, 0.5]], False), + (games.read_from_file("mixed_behavior_game.efg"), 1, [[0.5, 0.5]], False), + (games.read_from_file("mixed_behavior_game.efg"), 2, [[0.5, 0.5]], False), + (games.read_from_file("mixed_behavior_game.efg"), 0, [["1/2", "1/2"]], True), + (games.read_from_file("mixed_behavior_game.efg"), 1, [["1/2", "1/2"]], True), + (games.read_from_file("mixed_behavior_game.efg"), 2, [["1/2", "1/2"]], True), + (games.create_stripped_down_poker_efg(), 0, [[0.5, 0.5], [0.5, 0.5]], False), + (games.create_stripped_down_poker_efg(), 1, [[0.5, 0.5]], False), + (games.create_stripped_down_poker_efg(), 0, [["1/2", "1/2"], ["1/2", "1/2"]], True), + (games.create_stripped_down_poker_efg(), 1, [["1/2", "1/2"]], True), + ], ) -def test_profile_indexing_by_player_idx_reference(game: gbt.Game, player_idx: int, - behav_data: list, - rational_flag: bool): +def test_profile_indexing_by_player_idx_reference( + game: gbt.Game, player_idx: int, behav_data: list, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) player = game.players[player_idx] if rational_flag: @@ -394,21 +450,22 @@ def test_profile_indexing_by_player_idx_reference(game: gbt.Game, player_idx: in @pytest.mark.parametrize( "game,player_label,behav_data,rational_flag", - [(games.create_mixed_behav_game_efg(), "Player 1", [[0.5, 0.5]], False), - (games.create_mixed_behav_game_efg(), "Player 2", [[0.5, 0.5]], False), - (games.create_mixed_behav_game_efg(), "Player 3", [[0.5, 0.5]], False), - (games.create_mixed_behav_game_efg(), "Player 1", [["1/2", "1/2"]], True), - (games.create_mixed_behav_game_efg(), "Player 2", [["1/2", "1/2"]], True), - (games.create_mixed_behav_game_efg(), "Player 3", [["1/2", "1/2"]], True), - (games.create_stripped_down_poker_efg(), "Alice", [[0.5, 0.5], [0.5, 0.5]], False), - (games.create_stripped_down_poker_efg(), "Bob", [[0.5, 0.5]], False), - (games.create_stripped_down_poker_efg(), "Alice", [["1/2", "1/2"], ["1/2", "1/2"]], - True), - (games.create_stripped_down_poker_efg(), "Bob", [["1/2", "1/2"]], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", [[0.5, 0.5]], False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 2", [[0.5, 0.5]], False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 3", [[0.5, 0.5]], False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", [["1/2", "1/2"]], True), + (games.read_from_file("mixed_behavior_game.efg"), "Player 2", [["1/2", "1/2"]], True), + (games.read_from_file("mixed_behavior_game.efg"), "Player 3", [["1/2", "1/2"]], True), + (games.create_stripped_down_poker_efg(), "Alice", [[0.5, 0.5], [0.5, 0.5]], False), + (games.create_stripped_down_poker_efg(), "Bob", [[0.5, 0.5]], False), + (games.create_stripped_down_poker_efg(), "Alice", [["1/2", "1/2"], ["1/2", "1/2"]], True), + (games.create_stripped_down_poker_efg(), "Bob", [["1/2", "1/2"]], True), + ], ) -def test_profile_indexing_by_player_label_reference(game: gbt.Game, player_label: str, - behav_data: list, rational_flag: bool): +def test_profile_indexing_by_player_label_reference( + game: gbt.Game, player_label: str, behav_data: list, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) if rational_flag: behav_data = [[gbt.Rational(prob) for prob in probs] for probs in behav_data] @@ -417,34 +474,36 @@ def test_profile_indexing_by_player_label_reference(game: gbt.Game, player_label @pytest.mark.parametrize( "game,action_idx,prob,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 0.72, False), - (games.create_mixed_behav_game_efg(), 1, 0.28, False), - (games.create_mixed_behav_game_efg(), 2, 0.42, False), - (games.create_mixed_behav_game_efg(), 3, 0.58, False), - (games.create_mixed_behav_game_efg(), 4, 0.02, False), - (games.create_mixed_behav_game_efg(), 5, 0.98, False), - (games.create_mixed_behav_game_efg(), 0, "2/9", True), - (games.create_mixed_behav_game_efg(), 1, "7/9", True), - (games.create_mixed_behav_game_efg(), 2, "4/13", True), - (games.create_mixed_behav_game_efg(), 3, "9/13", True), - (games.create_mixed_behav_game_efg(), 4, "1/98", True), - (games.create_mixed_behav_game_efg(), 5, "97/98", True), - (games.create_stripped_down_poker_efg(), 0, 0.1, False), - (games.create_stripped_down_poker_efg(), 1, 0.2, False), - (games.create_stripped_down_poker_efg(), 2, 0.3, False), - (games.create_stripped_down_poker_efg(), 3, 0.4, False), - (games.create_stripped_down_poker_efg(), 4, 0.5, False), - (games.create_stripped_down_poker_efg(), 5, 0.6, False), - (games.create_stripped_down_poker_efg(), 0, "1/10", True), - (games.create_stripped_down_poker_efg(), 1, "2/10", True), - (games.create_stripped_down_poker_efg(), 2, "3/10", True), - (games.create_stripped_down_poker_efg(), 3, "4/10", True), - (games.create_stripped_down_poker_efg(), 4, "5/10", True), - (games.create_stripped_down_poker_efg(), 5, "6/10", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 0.72, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0.28, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0.42, False), + (games.read_from_file("mixed_behavior_game.efg"), 3, 0.58, False), + (games.read_from_file("mixed_behavior_game.efg"), 4, 0.02, False), + (games.read_from_file("mixed_behavior_game.efg"), 5, 0.98, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, "2/9", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, "7/9", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, "4/13", True), + (games.read_from_file("mixed_behavior_game.efg"), 3, "9/13", True), + (games.read_from_file("mixed_behavior_game.efg"), 4, "1/98", True), + (games.read_from_file("mixed_behavior_game.efg"), 5, "97/98", True), + (games.create_stripped_down_poker_efg(), 0, 0.1, False), + (games.create_stripped_down_poker_efg(), 1, 0.2, False), + (games.create_stripped_down_poker_efg(), 2, 0.3, False), + (games.create_stripped_down_poker_efg(), 3, 0.4, False), + (games.create_stripped_down_poker_efg(), 4, 0.5, False), + (games.create_stripped_down_poker_efg(), 5, 0.6, False), + (games.create_stripped_down_poker_efg(), 0, "1/10", True), + (games.create_stripped_down_poker_efg(), 1, "2/10", True), + (games.create_stripped_down_poker_efg(), 2, "3/10", True), + (games.create_stripped_down_poker_efg(), 3, "4/10", True), + (games.create_stripped_down_poker_efg(), 4, "5/10", True), + (games.create_stripped_down_poker_efg(), 5, "6/10", True), + ], ) -def test_set_probabilities_action(game: gbt.Game, action_idx: int, prob: str | float, - rational_flag: bool): +def test_set_probabilities_action( + game: gbt.Game, action_idx: int, prob: str | float, rational_flag: bool +): """Test to set probabilities of actions by action index""" profile = game.mixed_behavior_profile(rational=rational_flag) prob = gbt.Rational(prob) if rational_flag else prob @@ -455,24 +514,26 @@ def test_set_probabilities_action(game: gbt.Game, action_idx: int, prob: str | f @pytest.mark.parametrize( "game,label,prob,rational_flag", - [(games.create_mixed_behav_game_efg(), "U1", 0.72, False), - (games.create_mixed_behav_game_efg(), "D1", 0.28, False), - (games.create_mixed_behav_game_efg(), "U2", 0.42, False), - (games.create_mixed_behav_game_efg(), "D2", 0.58, False), - (games.create_mixed_behav_game_efg(), "U3", 0.02, False), - (games.create_mixed_behav_game_efg(), "D3", 0.98, False), - (games.create_mixed_behav_game_efg(), "U1", "2/9", True), - (games.create_mixed_behav_game_efg(), "D1", "7/9", True), - (games.create_mixed_behav_game_efg(), "U2", "4/13", True), - (games.create_mixed_behav_game_efg(), "D2", "9/13", True), - (games.create_mixed_behav_game_efg(), "U3", "1/98", True), - (games.create_mixed_behav_game_efg(), "D3", "97/98", True), - (games.create_stripped_down_poker_efg(), "Call", 0.3, False), - (games.create_stripped_down_poker_efg(), "Call", "3/10", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "U1", 0.72, False), + (games.read_from_file("mixed_behavior_game.efg"), "D1", 0.28, False), + (games.read_from_file("mixed_behavior_game.efg"), "U2", 0.42, False), + (games.read_from_file("mixed_behavior_game.efg"), "D2", 0.58, False), + (games.read_from_file("mixed_behavior_game.efg"), "U3", 0.02, False), + (games.read_from_file("mixed_behavior_game.efg"), "D3", 0.98, False), + (games.read_from_file("mixed_behavior_game.efg"), "U1", "2/9", True), + (games.read_from_file("mixed_behavior_game.efg"), "D1", "7/9", True), + (games.read_from_file("mixed_behavior_game.efg"), "U2", "4/13", True), + (games.read_from_file("mixed_behavior_game.efg"), "D2", "9/13", True), + (games.read_from_file("mixed_behavior_game.efg"), "U3", "1/98", True), + (games.read_from_file("mixed_behavior_game.efg"), "D3", "97/98", True), + (games.create_stripped_down_poker_efg(), "Call", 0.3, False), + (games.create_stripped_down_poker_efg(), "Call", "3/10", True), + ], ) -def test_set_probabilities_action_by_label(game: gbt.Game, label: str, - prob: str | float, rational_flag: bool): +def test_set_probabilities_action_by_label( + game: gbt.Game, label: str, prob: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) prob = gbt.Rational(prob) if rational_flag else prob profile[label] = prob @@ -481,22 +542,24 @@ def test_set_probabilities_action_by_label(game: gbt.Game, label: str, @pytest.mark.parametrize( "game,player_idx,infoset_idx,probs,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 0, [0.72, 0.28], False), - (games.create_mixed_behav_game_efg(), 1, 0, [0.42, 0.58], False), - (games.create_mixed_behav_game_efg(), 2, 0, [0.02, 0.98], False), - (games.create_mixed_behav_game_efg(), 0, 0, ["7/9", "2/9"], True), - (games.create_mixed_behav_game_efg(), 1, 0, ["4/13", "9/13"], True), - (games.create_mixed_behav_game_efg(), 2, 0, ["1/98", "97/98"], True), - (games.create_stripped_down_poker_efg(), 0, 0, [0.1, 0.9], False), - (games.create_stripped_down_poker_efg(), 0, 1, [0.2, 0.8], False), - (games.create_stripped_down_poker_efg(), 1, 0, [0.3, 0.7], False), - (games.create_stripped_down_poker_efg(), 0, 0, ["1/10", "9/10"], True), - (games.create_stripped_down_poker_efg(), 0, 1, ["2/10", "8/10"], True), - (games.create_stripped_down_poker_efg(), 1, 0, ["3/10", "7/10"], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, [0.72, 0.28], False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, [0.42, 0.58], False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, [0.02, 0.98], False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, ["7/9", "2/9"], True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, ["4/13", "9/13"], True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, ["1/98", "97/98"], True), + (games.create_stripped_down_poker_efg(), 0, 0, [0.1, 0.9], False), + (games.create_stripped_down_poker_efg(), 0, 1, [0.2, 0.8], False), + (games.create_stripped_down_poker_efg(), 1, 0, [0.3, 0.7], False), + (games.create_stripped_down_poker_efg(), 0, 0, ["1/10", "9/10"], True), + (games.create_stripped_down_poker_efg(), 0, 1, ["2/10", "8/10"], True), + (games.create_stripped_down_poker_efg(), 1, 0, ["3/10", "7/10"], True), + ], ) -def test_set_probabilities_infoset(game: gbt.Game, player_idx: int, infoset_idx: int, probs: list, - rational_flag: bool): +def test_set_probabilities_infoset( + game: gbt.Game, player_idx: int, infoset_idx: int, probs: list, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) if rational_flag: probs = [gbt.Rational(p) for p in probs] @@ -507,22 +570,24 @@ def test_set_probabilities_infoset(game: gbt.Game, player_idx: int, infoset_idx: @pytest.mark.parametrize( "game,infoset_label,probs,rational_flag", - [(games.create_mixed_behav_game_efg(), "Infoset 1:1", [0.72, 0.28], False), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", [0.42, 0.58], False), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", [0.02, 0.98], False), - (games.create_mixed_behav_game_efg(), "Infoset 1:1", ["7/9", "2/9"], True), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", ["4/13", "9/13"], True), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", ["1/98", "97/98"], True), - (games.create_stripped_down_poker_efg(), "Alice has King", [0.1, 0.9], False), - (games.create_stripped_down_poker_efg(), "Alice has Queen", [0.2, 0.8], False), - (games.create_stripped_down_poker_efg(), "Bob's response", [0.3, 0.7], False), - (games.create_stripped_down_poker_efg(), "Alice has King", ["1/10", "9/10"], True), - (games.create_stripped_down_poker_efg(), "Alice has Queen", ["2/10", "8/10"], True), - (games.create_stripped_down_poker_efg(), "Bob's response", ["3/10", "7/10"], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", [0.72, 0.28], False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", [0.42, 0.58], False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", [0.02, 0.98], False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", ["7/9", "2/9"], True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", ["4/13", "9/13"], True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", ["1/98", "97/98"], True), + (games.create_stripped_down_poker_efg(), "Alice has King", [0.1, 0.9], False), + (games.create_stripped_down_poker_efg(), "Alice has Queen", [0.2, 0.8], False), + (games.create_stripped_down_poker_efg(), "Bob's response", [0.3, 0.7], False), + (games.create_stripped_down_poker_efg(), "Alice has King", ["1/10", "9/10"], True), + (games.create_stripped_down_poker_efg(), "Alice has Queen", ["2/10", "8/10"], True), + (games.create_stripped_down_poker_efg(), "Bob's response", ["3/10", "7/10"], True), + ], ) -def test_set_probabilities_infoset_by_label(game: gbt.Game, infoset_label: str, probs: list, - rational_flag: bool): +def test_set_probabilities_infoset_by_label( + game: gbt.Game, infoset_label: str, probs: list, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) if rational_flag: probs = [gbt.Rational(p) for p in probs] @@ -532,20 +597,22 @@ def test_set_probabilities_infoset_by_label(game: gbt.Game, infoset_label: str, @pytest.mark.parametrize( "game,player_idx,behav_data,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, [[0.72, 0.28]], False), - (games.create_mixed_behav_game_efg(), 1, [[0.42, 0.58]], False), - (games.create_mixed_behav_game_efg(), 2, [[0.02, 0.98]], False), - (games.create_mixed_behav_game_efg(), 0, [["7/9", "2/9"]], True), - (games.create_mixed_behav_game_efg(), 1, [["4/13", "9/13"]], True), - (games.create_mixed_behav_game_efg(), 2, [["1/98", "97/98"]], True), - (games.create_stripped_down_poker_efg(), 0, [[0.1, 0.9], [0.5, 0.5]], False), - (games.create_stripped_down_poker_efg(), 1, [[0.6, 0.4]], False), - (games.create_stripped_down_poker_efg(), 0, [["1/3", "2/3"], ["1/2", "1/2"]], True), - (games.create_stripped_down_poker_efg(), 1, [["2/3", "1/3"]], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, [[0.72, 0.28]], False), + (games.read_from_file("mixed_behavior_game.efg"), 1, [[0.42, 0.58]], False), + (games.read_from_file("mixed_behavior_game.efg"), 2, [[0.02, 0.98]], False), + (games.read_from_file("mixed_behavior_game.efg"), 0, [["7/9", "2/9"]], True), + (games.read_from_file("mixed_behavior_game.efg"), 1, [["4/13", "9/13"]], True), + (games.read_from_file("mixed_behavior_game.efg"), 2, [["1/98", "97/98"]], True), + (games.create_stripped_down_poker_efg(), 0, [[0.1, 0.9], [0.5, 0.5]], False), + (games.create_stripped_down_poker_efg(), 1, [[0.6, 0.4]], False), + (games.create_stripped_down_poker_efg(), 0, [["1/3", "2/3"], ["1/2", "1/2"]], True), + (games.create_stripped_down_poker_efg(), 1, [["2/3", "1/3"]], True), + ], ) -def test_set_probabilities_player(game: gbt.Game, player_idx: int, behav_data: list, - rational_flag: bool): +def test_set_probabilities_player( + game: gbt.Game, player_idx: int, behav_data: list, rational_flag: bool +): player = game.players[player_idx] profile = game.mixed_behavior_profile(rational=rational_flag) if rational_flag: @@ -556,21 +623,22 @@ def test_set_probabilities_player(game: gbt.Game, player_idx: int, behav_data: l @pytest.mark.parametrize( "game,player_label,behav_data,rational_flag", - [(games.create_mixed_behav_game_efg(), "Player 1", [[0.72, 0.28]], False), - (games.create_mixed_behav_game_efg(), "Player 2", [[0.42, 0.58]], False), - (games.create_mixed_behav_game_efg(), "Player 3", [[0.02, 0.98]], False), - (games.create_mixed_behav_game_efg(), "Player 1", [["7/9", "2/9"]], True), - (games.create_mixed_behav_game_efg(), "Player 2", [["4/13", "9/13"]], True), - (games.create_mixed_behav_game_efg(), "Player 3", [["1/98", "97/98"]], True), - (games.create_stripped_down_poker_efg(), "Alice", [[0.1, 0.9], [0.5, 0.5]], False), - (games.create_stripped_down_poker_efg(), "Bob", [[0.6, 0.4]], False), - (games.create_stripped_down_poker_efg(), "Alice", [["1/3", "2/3"], ["1/2", "1/2"]], - True), - (games.create_stripped_down_poker_efg(), "Bob", [["2/3", "1/3"]], True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", [[0.72, 0.28]], False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 2", [[0.42, 0.58]], False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 3", [[0.02, 0.98]], False), + (games.read_from_file("mixed_behavior_game.efg"), "Player 1", [["7/9", "2/9"]], True), + (games.read_from_file("mixed_behavior_game.efg"), "Player 2", [["4/13", "9/13"]], True), + (games.read_from_file("mixed_behavior_game.efg"), "Player 3", [["1/98", "97/98"]], True), + (games.create_stripped_down_poker_efg(), "Alice", [[0.1, 0.9], [0.5, 0.5]], False), + (games.create_stripped_down_poker_efg(), "Bob", [[0.6, 0.4]], False), + (games.create_stripped_down_poker_efg(), "Alice", [["1/3", "2/3"], ["1/2", "1/2"]], True), + (games.create_stripped_down_poker_efg(), "Bob", [["2/3", "1/3"]], True), + ], ) -def test_set_probabilities_player_by_label(game: gbt.Game, player_label: str, behav_data: list, - rational_flag: bool): +def test_set_probabilities_player_by_label( + game: gbt.Game, player_label: str, behav_data: list, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) if rational_flag: behav_data = [[gbt.Rational(prob) for prob in probs] for probs in behav_data] @@ -580,85 +648,90 @@ def test_set_probabilities_player_by_label(game: gbt.Game, player_label: str, be @pytest.mark.parametrize( "game,node_idx,realiz_prob,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, "1", True), - (games.create_mixed_behav_game_efg(), 1, "1/2", True), - (games.create_mixed_behav_game_efg(), 2, "1/4", True), - (games.create_mixed_behav_game_efg(), 3, "1/8", True), - (games.create_mixed_behav_game_efg(), 4, "1/8", True), - (games.create_mixed_behav_game_efg(), 5, "1/4", True), - (games.create_mixed_behav_game_efg(), 6, "1/8", True), - (games.create_mixed_behav_game_efg(), 7, "1/8", True), - (games.create_mixed_behav_game_efg(), 8, "1/2", True), - (games.create_mixed_behav_game_efg(), 9, "1/4", True), - (games.create_mixed_behav_game_efg(), 10, "1/8", True), - (games.create_mixed_behav_game_efg(), 11, "1/8", True), - (games.create_mixed_behav_game_efg(), 12, "1/4", True), - (games.create_mixed_behav_game_efg(), 13, "1/8", True), - (games.create_mixed_behav_game_efg(), 14, "1/8", True), - (games.create_mixed_behav_game_efg(), 0, 1.0, False), - (games.create_mixed_behav_game_efg(), 1, 0.5, False), - (games.create_mixed_behav_game_efg(), 2, 0.25, False), - (games.create_mixed_behav_game_efg(), 3, 0.125, False), - (games.create_mixed_behav_game_efg(), 4, 0.125, False), - (games.create_mixed_behav_game_efg(), 5, 0.25, False), - (games.create_mixed_behav_game_efg(), 6, 0.125, False), - (games.create_mixed_behav_game_efg(), 7, 0.125, False), - (games.create_mixed_behav_game_efg(), 8, 0.5, False), - (games.create_mixed_behav_game_efg(), 9, 0.25, False), - (games.create_mixed_behav_game_efg(), 10, 0.125, False), - (games.create_mixed_behav_game_efg(), 11, 0.125, False), - (games.create_mixed_behav_game_efg(), 12, 0.25, False), - (games.create_mixed_behav_game_efg(), 13, 0.125, False), - (games.create_mixed_behav_game_efg(), 14, 0.125, False), - (games.create_stripped_down_poker_efg(), 0, "1", True), - (games.create_stripped_down_poker_efg(), 1, "1/2", True), - (games.create_stripped_down_poker_efg(), 2, "1/4", True), - (games.create_stripped_down_poker_efg(), 3, "1/8", True), - (games.create_stripped_down_poker_efg(), 4, "1/8", True), - (games.create_stripped_down_poker_efg(), 5, "1/4", True), - (games.create_stripped_down_poker_efg(), 6, "1/2", True), - (games.create_stripped_down_poker_efg(), 7, "1/4", True), - (games.create_stripped_down_poker_efg(), 8, "1/8", True), - (games.create_stripped_down_poker_efg(), 9, "1/8", True), - (games.create_stripped_down_poker_efg(), 10, "1/4", True), - (games.create_stripped_down_poker_efg(), 0, 1.0, False), - (games.create_stripped_down_poker_efg(), 1, 0.5, False), - (games.create_stripped_down_poker_efg(), 2, 0.25, False), - (games.create_stripped_down_poker_efg(), 3, 0.125, False), - (games.create_stripped_down_poker_efg(), 4, 0.125, False), - (games.create_stripped_down_poker_efg(), 5, 0.25, False), - (games.create_stripped_down_poker_efg(), 6, 0.5, False), - (games.create_stripped_down_poker_efg(), 7, 0.25, False), - (games.create_stripped_down_poker_efg(), 8, 0.125, False), - (games.create_stripped_down_poker_efg(), 9, 0.125, False), - (games.create_stripped_down_poker_efg(), 10, 0.25, False)] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, "1", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, "1/4", True), + (games.read_from_file("mixed_behavior_game.efg"), 3, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 4, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 5, "1/4", True), + (games.read_from_file("mixed_behavior_game.efg"), 6, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 7, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 8, "1/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 9, "1/4", True), + (games.read_from_file("mixed_behavior_game.efg"), 10, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 11, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 12, "1/4", True), + (games.read_from_file("mixed_behavior_game.efg"), 13, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 14, "1/8", True), + (games.read_from_file("mixed_behavior_game.efg"), 0, 1.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0.25, False), + (games.read_from_file("mixed_behavior_game.efg"), 3, 0.125, False), + (games.read_from_file("mixed_behavior_game.efg"), 4, 0.125, False), + (games.read_from_file("mixed_behavior_game.efg"), 5, 0.25, False), + (games.read_from_file("mixed_behavior_game.efg"), 6, 0.125, False), + (games.read_from_file("mixed_behavior_game.efg"), 7, 0.125, False), + (games.read_from_file("mixed_behavior_game.efg"), 8, 0.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 9, 0.25, False), + (games.read_from_file("mixed_behavior_game.efg"), 10, 0.125, False), + (games.read_from_file("mixed_behavior_game.efg"), 11, 0.125, False), + (games.read_from_file("mixed_behavior_game.efg"), 12, 0.25, False), + (games.read_from_file("mixed_behavior_game.efg"), 13, 0.125, False), + (games.read_from_file("mixed_behavior_game.efg"), 14, 0.125, False), + (games.create_stripped_down_poker_efg(), 0, "1", True), + (games.create_stripped_down_poker_efg(), 1, "1/2", True), + (games.create_stripped_down_poker_efg(), 2, "1/4", True), + (games.create_stripped_down_poker_efg(), 3, "1/8", True), + (games.create_stripped_down_poker_efg(), 4, "1/8", True), + (games.create_stripped_down_poker_efg(), 5, "1/4", True), + (games.create_stripped_down_poker_efg(), 6, "1/2", True), + (games.create_stripped_down_poker_efg(), 7, "1/4", True), + (games.create_stripped_down_poker_efg(), 8, "1/8", True), + (games.create_stripped_down_poker_efg(), 9, "1/8", True), + (games.create_stripped_down_poker_efg(), 10, "1/4", True), + (games.create_stripped_down_poker_efg(), 0, 1.0, False), + (games.create_stripped_down_poker_efg(), 1, 0.5, False), + (games.create_stripped_down_poker_efg(), 2, 0.25, False), + (games.create_stripped_down_poker_efg(), 3, 0.125, False), + (games.create_stripped_down_poker_efg(), 4, 0.125, False), + (games.create_stripped_down_poker_efg(), 5, 0.25, False), + (games.create_stripped_down_poker_efg(), 6, 0.5, False), + (games.create_stripped_down_poker_efg(), 7, 0.25, False), + (games.create_stripped_down_poker_efg(), 8, 0.125, False), + (games.create_stripped_down_poker_efg(), 9, 0.125, False), + (games.create_stripped_down_poker_efg(), 10, 0.25, False), + ], ) -def test_realiz_prob_nodes_reference(game: gbt.Game, node_idx: int, - realiz_prob: str | float, rational_flag: bool): +def test_realiz_prob_nodes_reference( + game: gbt.Game, node_idx: int, realiz_prob: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) - realiz_prob = (gbt.Rational(realiz_prob) if rational_flag else realiz_prob) + realiz_prob = gbt.Rational(realiz_prob) if rational_flag else realiz_prob node = list(game.nodes)[node_idx] assert profile.realiz_prob(node) == realiz_prob @pytest.mark.parametrize( "game,player_idx,infoset_idx,prob,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 0, 1.0, False), - (games.create_mixed_behav_game_efg(), 1, 0, 1.0, False), - (games.create_mixed_behav_game_efg(), 2, 0, 1.0, False), - (games.create_mixed_behav_game_efg(), 0, 0, "1", True), - (games.create_mixed_behav_game_efg(), 1, 0, "1", True), - (games.create_mixed_behav_game_efg(), 2, 0, "1", True), - (games.create_stripped_down_poker_efg(), 0, 0, 0.5, False), - (games.create_stripped_down_poker_efg(), 0, 1, 0.5, False), - (games.create_stripped_down_poker_efg(), 1, 0, 0.5, False), - (games.create_stripped_down_poker_efg(), 0, 0, "1/2", True), - (games.create_stripped_down_poker_efg(), 0, 1, "1/2", True), - (games.create_stripped_down_poker_efg(), 1, 0, "1/2", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 1.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 1.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 1.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, "1", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, "1", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, "1", True), + (games.create_stripped_down_poker_efg(), 0, 0, 0.5, False), + (games.create_stripped_down_poker_efg(), 0, 1, 0.5, False), + (games.create_stripped_down_poker_efg(), 1, 0, 0.5, False), + (games.create_stripped_down_poker_efg(), 0, 0, "1/2", True), + (games.create_stripped_down_poker_efg(), 0, 1, "1/2", True), + (games.create_stripped_down_poker_efg(), 1, 0, "1/2", True), + ], ) -def test_infoset_prob_reference(game: gbt.Game, player_idx: int, infoset_idx: int, - prob: str | float, rational_flag: bool): +def test_infoset_prob_reference( + game: gbt.Game, player_idx: int, infoset_idx: int, prob: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) ip = profile.infoset_prob(game.players[player_idx].infosets[infoset_idx]) assert ip == (gbt.Rational(prob) if rational_flag else prob) @@ -666,44 +739,48 @@ def test_infoset_prob_reference(game: gbt.Game, player_idx: int, infoset_idx: in @pytest.mark.parametrize( "game,label,prob,rational_flag,", - [(games.create_mixed_behav_game_efg(), "Infoset 1:1", 1.0, False), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", 1.0, False), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", 1.0, False), - (games.create_mixed_behav_game_efg(), "Infoset 1:1", "1", True), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", "1", True), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", "1", True), - (games.create_stripped_down_poker_efg(), "Alice has King", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice has Queen", 0.5, False), - (games.create_stripped_down_poker_efg(), "Bob's response", 0.5, False), - (games.create_stripped_down_poker_efg(), "Alice has King", "1/2", True), - (games.create_stripped_down_poker_efg(), "Alice has Queen", "1/2", True), - (games.create_stripped_down_poker_efg(), "Bob's response", "1/2", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", 1.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", 1.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", 1.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", "1", True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", "1", True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", "1", True), + (games.create_stripped_down_poker_efg(), "Alice has King", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice has Queen", 0.5, False), + (games.create_stripped_down_poker_efg(), "Bob's response", 0.5, False), + (games.create_stripped_down_poker_efg(), "Alice has King", "1/2", True), + (games.create_stripped_down_poker_efg(), "Alice has Queen", "1/2", True), + (games.create_stripped_down_poker_efg(), "Bob's response", "1/2", True), + ], ) -def test_infoset_prob_by_label_reference(game: gbt.Game, label: str, - prob: str | float, rational_flag: bool): +def test_infoset_prob_by_label_reference( + game: gbt.Game, label: str, prob: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) assert profile.infoset_prob(label) == (gbt.Rational(prob) if rational_flag else prob) @pytest.mark.parametrize( "game,player_idx,infoset_idx,payoff,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 0, 3.0, False), - (games.create_mixed_behav_game_efg(), 1, 0, 3.0, False), - (games.create_mixed_behav_game_efg(), 2, 0, 3.25, False), - (games.create_mixed_behav_game_efg(), 0, 0, "3", True), - (games.create_mixed_behav_game_efg(), 1, 0, "3", True), - (games.create_mixed_behav_game_efg(), 2, 0, "13/4", True), - (games.create_stripped_down_poker_efg(), 0, 0, 0.25, False), - (games.create_stripped_down_poker_efg(), 0, 1, -0.75, False), - (games.create_stripped_down_poker_efg(), 1, 0, -0.5, False), - (games.create_stripped_down_poker_efg(), 0, 0, "1/4", True), - (games.create_stripped_down_poker_efg(), 0, 1, "-3/4", True), - (games.create_stripped_down_poker_efg(), 1, 0, "-1/2", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 3.25, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, "3", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, "3", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, "13/4", True), + (games.create_stripped_down_poker_efg(), 0, 0, 0.25, False), + (games.create_stripped_down_poker_efg(), 0, 1, -0.75, False), + (games.create_stripped_down_poker_efg(), 1, 0, -0.5, False), + (games.create_stripped_down_poker_efg(), 0, 0, "1/4", True), + (games.create_stripped_down_poker_efg(), 0, 1, "-3/4", True), + (games.create_stripped_down_poker_efg(), 1, 0, "-1/2", True), + ], ) -def test_infoset_payoff_reference(game: gbt.Game, player_idx: int, infoset_idx: int, - payoff: str | float, rational_flag: bool): +def test_infoset_payoff_reference( + game: gbt.Game, player_idx: int, infoset_idx: int, payoff: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) iv = profile.infoset_value(game.players[player_idx].infosets[infoset_idx]) assert iv == (gbt.Rational(payoff) if rational_flag else payoff) @@ -711,58 +788,66 @@ def test_infoset_payoff_reference(game: gbt.Game, player_idx: int, infoset_idx: @pytest.mark.parametrize( "game,label,payoff,rational_flag", - [(games.create_mixed_behav_game_efg(), "Infoset 1:1", 3.0, False), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", 3.0, False), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", 3.25, False), - (games.create_mixed_behav_game_efg(), "Infoset 1:1", "3", True), - (games.create_mixed_behav_game_efg(), "Infoset 2:1", "3", True), - (games.create_mixed_behav_game_efg(), "Infoset 3:1", "13/4", True), - (games.create_stripped_down_poker_efg(), "Alice has King", 0.25, False), - (games.create_stripped_down_poker_efg(), "Alice has Queen", -0.75, False), - (games.create_stripped_down_poker_efg(), "Bob's response", -0.5, False), - (games.create_stripped_down_poker_efg(), "Alice has King", "1/4", True), - (games.create_stripped_down_poker_efg(), "Alice has Queen", "-3/4", True), - (games.create_stripped_down_poker_efg(), "Bob's response", "-1/2", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", 3.25, False), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 1:1", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 2:1", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "Infoset 3:1", "13/4", True), + (games.create_stripped_down_poker_efg(), "Alice has King", 0.25, False), + (games.create_stripped_down_poker_efg(), "Alice has Queen", -0.75, False), + (games.create_stripped_down_poker_efg(), "Bob's response", -0.5, False), + (games.create_stripped_down_poker_efg(), "Alice has King", "1/4", True), + (games.create_stripped_down_poker_efg(), "Alice has Queen", "-3/4", True), + (games.create_stripped_down_poker_efg(), "Bob's response", "-1/2", True), + ], ) -def test_infoset_payoff_by_label_reference(game: gbt.Game, label: str, - payoff: str | float, rational_flag: bool): +def test_infoset_payoff_by_label_reference( + game: gbt.Game, label: str, payoff: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) assert profile.infoset_value(label) == (gbt.Rational(payoff) if rational_flag else payoff) @pytest.mark.parametrize( "game,player_idx,infoset_idx,action_idx,payoff,rational_flag", - [(games.create_mixed_behav_game_efg(), 0, 0, 0, 3.0, False), - (games.create_mixed_behav_game_efg(), 0, 0, 1, 3.0, False), - (games.create_mixed_behav_game_efg(), 1, 0, 0, 3.0, False), - (games.create_mixed_behav_game_efg(), 1, 0, 1, 3.0, False), - (games.create_mixed_behav_game_efg(), 2, 0, 0, 3.5, False), - (games.create_mixed_behav_game_efg(), 2, 0, 1, 3.0, False), - (games.create_mixed_behav_game_efg(), 2, 0, 1, 3.0, False), - (games.create_mixed_behav_game_efg(), 0, 0, 0, "3/1", True), - (games.create_mixed_behav_game_efg(), 0, 0, 1, "3/1", True), - (games.create_mixed_behav_game_efg(), 1, 0, 0, "3/1", True), - (games.create_mixed_behav_game_efg(), 1, 0, 1, "3/1", True), - (games.create_mixed_behav_game_efg(), 2, 0, 0, "7/2", True), - (games.create_mixed_behav_game_efg(), 2, 0, 1, "3/1", True), - (games.create_stripped_down_poker_efg(), 0, 0, 0, 1.5, False), - (games.create_stripped_down_poker_efg(), 0, 0, 1, -1, False), - (games.create_stripped_down_poker_efg(), 0, 1, 0, -0.5, False), - (games.create_stripped_down_poker_efg(), 0, 1, 1, -1, False), - (games.create_stripped_down_poker_efg(), 1, 0, 0, 0, False), - (games.create_stripped_down_poker_efg(), 1, 0, 1, -1, False), - (games.create_stripped_down_poker_efg(), 0, 0, 0, "3/2", True), - (games.create_stripped_down_poker_efg(), 0, 0, 1, -1, True), - (games.create_stripped_down_poker_efg(), 0, 1, 0, "-1/2", True), - (games.create_stripped_down_poker_efg(), 0, 1, 1, -1, True), - (games.create_stripped_down_poker_efg(), 1, 0, 0, 0, True), - (games.create_stripped_down_poker_efg(), 1, 0, 1, -1, True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 0, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 1, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 0, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 1, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 0, 3.5, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 1, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 1, 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 0, "3/1", True), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 1, "3/1", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 0, "3/1", True), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 1, "3/1", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 0, "7/2", True), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 1, "3/1", True), + (games.create_stripped_down_poker_efg(), 0, 0, 0, 1.5, False), + (games.create_stripped_down_poker_efg(), 0, 0, 1, -1, False), + (games.create_stripped_down_poker_efg(), 0, 1, 0, -0.5, False), + (games.create_stripped_down_poker_efg(), 0, 1, 1, -1, False), + (games.create_stripped_down_poker_efg(), 1, 0, 0, 0, False), + (games.create_stripped_down_poker_efg(), 1, 0, 1, -1, False), + (games.create_stripped_down_poker_efg(), 0, 0, 0, "3/2", True), + (games.create_stripped_down_poker_efg(), 0, 0, 1, -1, True), + (games.create_stripped_down_poker_efg(), 0, 1, 0, "-1/2", True), + (games.create_stripped_down_poker_efg(), 0, 1, 1, -1, True), + (games.create_stripped_down_poker_efg(), 1, 0, 0, 0, True), + (games.create_stripped_down_poker_efg(), 1, 0, 1, -1, True), + ], ) -def test_action_payoff_reference(game: gbt.Game, player_idx: int, infoset_idx: int, - action_idx: int, payoff: str | float, - rational_flag: bool): +def test_action_payoff_reference( + game: gbt.Game, + player_idx: int, + infoset_idx: int, + action_idx: int, + payoff: str | float, + rational_flag: bool, +): profile = game.mixed_behavior_profile(rational=rational_flag) av = profile.action_value(game.players[player_idx].infosets[infoset_idx].actions[action_idx]) assert av == (gbt.Rational(payoff) if rational_flag else payoff) @@ -770,82 +855,83 @@ def test_action_payoff_reference(game: gbt.Game, player_idx: int, infoset_idx: i @pytest.mark.parametrize( "game,label,payoff,rational_flag", - [(games.create_mixed_behav_game_efg(), "U1", 3.0, False), - (games.create_mixed_behav_game_efg(), "D1", 3.0, False), - (games.create_mixed_behav_game_efg(), "U2", 3.0, False), - (games.create_mixed_behav_game_efg(), "D2", 3.0, False), - (games.create_mixed_behav_game_efg(), "U3", 3.5, False), - (games.create_mixed_behav_game_efg(), "D3", 3.0, False), - (games.create_mixed_behav_game_efg(), "U1", "3", True), - (games.create_mixed_behav_game_efg(), "D1", "3", True), - (games.create_mixed_behav_game_efg(), "U2", "3", True), - (games.create_mixed_behav_game_efg(), "D2", "3", True), - (games.create_mixed_behav_game_efg(), "U3", "7/2", True), - (games.create_mixed_behav_game_efg(), "D3", "3", True), - (games.create_stripped_down_poker_efg(), "Call", 0, False), - (games.create_stripped_down_poker_efg(), "Call", "0", True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), "U1", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "D1", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "U2", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "D2", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "U3", 3.5, False), + (games.read_from_file("mixed_behavior_game.efg"), "D3", 3.0, False), + (games.read_from_file("mixed_behavior_game.efg"), "U1", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "D1", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "U2", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "D2", "3", True), + (games.read_from_file("mixed_behavior_game.efg"), "U3", "7/2", True), + (games.read_from_file("mixed_behavior_game.efg"), "D3", "3", True), + (games.create_stripped_down_poker_efg(), "Call", 0, False), + (games.create_stripped_down_poker_efg(), "Call", "0", True), + ], ) -def test_action_value_by_label_reference(game: gbt.Game, label: str, - payoff: str | float, rational_flag: bool): +def test_action_value_by_label_reference( + game: gbt.Game, label: str, payoff: str | float, rational_flag: bool +): profile = game.mixed_behavior_profile(rational=rational_flag) assert profile.action_value(label) == (gbt.Rational(payoff) if rational_flag else payoff) @pytest.mark.parametrize( "game,rational_flag", - [(games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), - (games.create_stripped_down_poker_efg(), False), - (games.create_stripped_down_poker_efg(), True), - (games.create_kuhn_poker_efg(), False), - (games.create_kuhn_poker_efg(), True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), + (games.create_stripped_down_poker_efg(), False), + (games.create_stripped_down_poker_efg(), True), + (games.create_kuhn_poker_efg(), False), + (games.create_kuhn_poker_efg(), True), + ], ) def test_action_regret_consistency(game: gbt.Game, rational_flag: bool): profile = game.mixed_behavior_profile(rational=rational_flag) for player in game.players: for infoset in player.infosets: for action in infoset.actions: - assert ( - profile.action_regret(action) == - max(profile.action_value(a) for a in infoset.actions) - - profile.action_value(action) - ) + assert profile.action_regret(action) == max( + profile.action_value(a) for a in infoset.actions + ) - profile.action_value(action) @pytest.mark.parametrize( "game,rational_flag", - [(games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), - (games.create_stripped_down_poker_efg(), False), - (games.create_stripped_down_poker_efg(), True), - (games.create_kuhn_poker_efg(), False), - (games.create_kuhn_poker_efg(), True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), + (games.create_stripped_down_poker_efg(), False), + (games.create_stripped_down_poker_efg(), True), + (games.create_kuhn_poker_efg(), False), + (games.create_kuhn_poker_efg(), True), + ], ) def test_infoset_regret_consistency(game: gbt.Game, rational_flag: bool): profile = game.mixed_behavior_profile(rational=rational_flag) for player in game.players: for infoset in player.infosets: - assert ( - profile.infoset_regret(infoset) == - max(profile.action_value(a) for a in infoset.actions) - - profile.infoset_value(infoset) - ) + assert profile.infoset_regret(infoset) == max( + profile.action_value(a) for a in infoset.actions + ) - profile.infoset_value(infoset) @pytest.mark.parametrize( "game,rational_flag", - [(games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), - (games.create_stripped_down_poker_efg(), False), - (games.create_stripped_down_poker_efg(), True), - (games.create_kuhn_poker_efg(), False), - (games.create_kuhn_poker_efg(), True), - (games.read_from_file("3_player.efg"), False), - (games.read_from_file("3_player.efg"), True) - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), + (games.create_stripped_down_poker_efg(), False), + (games.create_stripped_down_poker_efg(), True), + (games.create_kuhn_poker_efg(), False), + (games.create_kuhn_poker_efg(), True), + (games.read_from_file("3_player.efg"), False), + (games.read_from_file("3_player.efg"), True), + ], ) def test_max_regret_consistency(game: gbt.Game, rational_flag: bool): profile = game.mixed_behavior_profile(rational=rational_flag) @@ -854,71 +940,223 @@ def test_max_regret_consistency(game: gbt.Game, rational_flag: bool): @pytest.mark.parametrize( "game,rational_flag", - [(games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), - (games.create_stripped_down_poker_efg(), False), - (games.create_stripped_down_poker_efg(), True), - (games.create_kuhn_poker_efg(), False), - (games.create_kuhn_poker_efg(), True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), + (games.create_stripped_down_poker_efg(), False), + (games.create_stripped_down_poker_efg(), True), + (games.create_kuhn_poker_efg(), False), + (games.create_kuhn_poker_efg(), True), + ], ) def test_agent_max_regret_consistency(game: gbt.Game, rational_flag: bool): profile = game.mixed_behavior_profile(rational=rational_flag) - assert ( - profile.agent_max_regret() == - max([profile.infoset_regret(infoset) for infoset in game.infosets]) + assert profile.agent_max_regret() == max( + [profile.infoset_regret(infoset) for infoset in game.infosets] ) @pytest.mark.parametrize( "game,player_idx,infoset_idx,action_idx,action_probs,rational_flag,tol,value", [ - # uniform - (games.create_mixed_behav_game_efg(), 0, 0, 0, None, False, TOL, 0), - (games.create_mixed_behav_game_efg(), 0, 0, 1, None, False, TOL, 0), - (games.create_mixed_behav_game_efg(), 1, 0, 0, None, False, TOL, 0), - (games.create_mixed_behav_game_efg(), 1, 0, 1, None, False, TOL, 0), - (games.create_mixed_behav_game_efg(), 2, 0, 0, None, False, TOL, 0), - (games.create_mixed_behav_game_efg(), 2, 0, 1, None, False, TOL, 0.5), # 3.5 - 3 - # U1 U2 U3 - (games.create_mixed_behav_game_efg(), 0, 0, 0, [1, 0, 1, 0, 1, 0], False, TOL, 0), - (games.create_mixed_behav_game_efg(), 0, 0, 0, [1, 0, 1, 0, 1, 0], True, ZERO, 0), - (games.create_mixed_behav_game_efg(), 0, 0, 1, [1, 0, 1, 0, 1, 0], False, TOL, 9), - (games.create_mixed_behav_game_efg(), 0, 0, 1, [1, 0, 1, 0, 1, 0], True, ZERO, 9), - (games.create_mixed_behav_game_efg(), 1, 0, 0, [1, 0, 1, 0, 1, 0], False, TOL, 0), - (games.create_mixed_behav_game_efg(), 1, 0, 0, [1, 0, 1, 0, 1, 0], True, ZERO, 0), - (games.create_mixed_behav_game_efg(), 1, 0, 1, [1, 0, 1, 0, 1, 0], False, TOL, 8), - (games.create_mixed_behav_game_efg(), 1, 0, 1, [1, 0, 1, 0, 1, 0], True, ZERO, 8), - # Mixed Nash equilibrium - (games.create_mixed_behav_game_efg(), 0, 0, 0, ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], - True, ZERO, 0), - (games.create_mixed_behav_game_efg(), 0, 0, 1, ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], - True, ZERO, 0), - (games.create_mixed_behav_game_efg(), 1, 0, 0, ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], - True, ZERO, 0), - (games.create_mixed_behav_game_efg(), 1, 0, 1, ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], - True, ZERO, 0), - (games.create_mixed_behav_game_efg(), 2, 0, 0, ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], - True, ZERO, 0), - (games.create_mixed_behav_game_efg(), 2, 0, 1, ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], - True, ZERO, 0), - # uniform - (games.create_stripped_down_poker_efg(), 0, 0, 0, None, False, TOL, 0), - (games.create_stripped_down_poker_efg(), 0, 0, 1, None, False, TOL, 2.5), # 1.5 - (-1) - (games.create_stripped_down_poker_efg(), 0, 1, 0, None, False, TOL, 0), - (games.create_stripped_down_poker_efg(), 0, 1, 1, None, False, TOL, 0.5), # -0.5 - (-1) - (games.create_stripped_down_poker_efg(), 1, 0, 0, None, False, TOL, 0), - (games.create_stripped_down_poker_efg(), 1, 0, 1, None, False, TOL, 1), # -0 - (-1) - # mixed Nash equilibrium - (games.create_stripped_down_poker_efg(), 0, 0, 0, ["1", "0", "1/3", "2/3", "2/3", "1/3"], - True, ZERO, 0), - (games.create_stripped_down_poker_efg(), 0, 0, 1, ["1", "0", "1/3", "2/3", "2/3", "1/3"], - True, ZERO, "8/3"), # (2/3*2 + 1/3*1) - (-1) - ] + # uniform + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 0, None, False, TOL, 0), + (games.read_from_file("mixed_behavior_game.efg"), 0, 0, 1, None, False, TOL, 0), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 0, None, False, TOL, 0), + (games.read_from_file("mixed_behavior_game.efg"), 1, 0, 1, None, False, TOL, 0), + (games.read_from_file("mixed_behavior_game.efg"), 2, 0, 0, None, False, TOL, 0), + ( + games.read_from_file("mixed_behavior_game.efg"), + 2, + 0, + 1, + None, + False, + TOL, + 0.5, + ), # 3.5 - 3 + # U1 U2 U3 + ( + games.read_from_file("mixed_behavior_game.efg"), + 0, + 0, + 0, + [1, 0, 1, 0, 1, 0], + False, + TOL, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 0, + 0, + 0, + [1, 0, 1, 0, 1, 0], + True, + ZERO, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 0, + 0, + 1, + [1, 0, 1, 0, 1, 0], + False, + TOL, + 9, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 0, + 0, + 1, + [1, 0, 1, 0, 1, 0], + True, + ZERO, + 9, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 1, + 0, + 0, + [1, 0, 1, 0, 1, 0], + False, + TOL, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 1, + 0, + 0, + [1, 0, 1, 0, 1, 0], + True, + ZERO, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 1, + 0, + 1, + [1, 0, 1, 0, 1, 0], + False, + TOL, + 8, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 1, + 0, + 1, + [1, 0, 1, 0, 1, 0], + True, + ZERO, + 8, + ), + # Mixed Nash equilibrium + ( + games.read_from_file("mixed_behavior_game.efg"), + 0, + 0, + 0, + ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], + True, + ZERO, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 0, + 0, + 1, + ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], + True, + ZERO, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 1, + 0, + 0, + ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], + True, + ZERO, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 1, + 0, + 1, + ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], + True, + ZERO, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 2, + 0, + 0, + ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], + True, + ZERO, + 0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + 2, + 0, + 1, + ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], + True, + ZERO, + 0, + ), + # uniform + (games.create_stripped_down_poker_efg(), 0, 0, 0, None, False, TOL, 0), + (games.create_stripped_down_poker_efg(), 0, 0, 1, None, False, TOL, 2.5), # 1.5 - (-1) + (games.create_stripped_down_poker_efg(), 0, 1, 0, None, False, TOL, 0), + (games.create_stripped_down_poker_efg(), 0, 1, 1, None, False, TOL, 0.5), # -0.5 - (-1) + (games.create_stripped_down_poker_efg(), 1, 0, 0, None, False, TOL, 0), + (games.create_stripped_down_poker_efg(), 1, 0, 1, None, False, TOL, 1), # -0 - (-1) + # mixed Nash equilibrium + ( + games.create_stripped_down_poker_efg(), + 0, + 0, + 0, + ["1", "0", "1/3", "2/3", "2/3", "1/3"], + True, + ZERO, + 0, + ), + ( + games.create_stripped_down_poker_efg(), + 0, + 0, + 1, + ["1", "0", "1/3", "2/3", "2/3", "1/3"], + True, + ZERO, + "8/3", + ), # (2/3*2 + 1/3*1) - (-1) + ], ) -def test_action_regret_reference(game: gbt.Game, player_idx: int, infoset_idx: int, - action_idx: int, action_probs: None | list, rational_flag: bool, - tol: gbt.Rational | float, value: str | float): +def test_action_regret_reference( + game: gbt.Game, + player_idx: int, + infoset_idx: int, + action_idx: int, + action_probs: None | list, + rational_flag: bool, + tol: gbt.Rational | float, + value: str | float, +): action = game.players[player_idx].infosets[infoset_idx].actions[action_idx] profile = game.mixed_behavior_profile(rational=rational_flag) if action_probs: @@ -930,11 +1168,12 @@ def test_action_regret_reference(game: gbt.Game, player_idx: int, infoset_idx: i @pytest.mark.parametrize( "game,rational_flag", - [(games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), - (games.create_stripped_down_poker_efg(), False), - (games.create_stripped_down_poker_efg(), True), - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), + (games.create_stripped_down_poker_efg(), False), + (games.create_stripped_down_poker_efg(), True), + ], ) def test_martingale_property_of_node_value(game: gbt.Game, rational_flag: bool): """Loops over all nodes and for non-chance, non-terminal nodes, this checks that the node @@ -955,10 +1194,12 @@ def test_martingale_property_of_node_value(game: gbt.Game, rational_flag: bool): @pytest.mark.parametrize( "game,rational_flag", - [(games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), - (games.create_stripped_down_poker_efg(), False), - (games.create_stripped_down_poker_efg(), True)] + [ + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), + (games.create_stripped_down_poker_efg(), False), + (games.create_stripped_down_poker_efg(), True), + ], ) def test_node_value_consistency(game: gbt.Game, rational_flag: bool): """Test that the profile's node value at the root for each player matches the profile's payoff @@ -971,114 +1212,281 @@ def test_node_value_consistency(game: gbt.Game, rational_flag: bool): @pytest.mark.parametrize( "game,action_probs,rational_flag,expected_value", [ - # uniform (non-Nash): - (games.create_mixed_behav_game_efg(), None, True, "1/16"), - (games.create_mixed_behav_game_efg(), None, False, 0.0625), - # four pure Nash equilibria: - (games.create_mixed_behav_game_efg(), [1.0, 0.0, 1.0, 0.0, 1.0, 0.0], False, 0), # U1 U2 U3 - (games.create_mixed_behav_game_efg(), ["1", "0", "1", "0", "1", "0"], True, 0), - (games.create_mixed_behav_game_efg(), ["1", "0", "0", "1", "0", "1"], True, 0), # U1 D2 D3 - (games.create_mixed_behav_game_efg(), [1.0, 0.0, 0.0, 1.0, 0, 1.0], False, 0), - (games.create_mixed_behav_game_efg(), ["0", "1", "1", "0", "0", "1"], True, 0), # D1 U2 D3 - (games.create_mixed_behav_game_efg(), [0.0, 1.0, 1.0, 0.0, 0, 1.0], False, 0), - (games.create_mixed_behav_game_efg(), ["0", "1", "0", "1", "1", "0"], True, 0), # D1 D2 U3 - (games.create_mixed_behav_game_efg(), [0.0, 1.0, 0.0, 1.0, 1.0, 0], False, 0), - # mixed Nash equilibrium (only rational tested): - (games.create_mixed_behav_game_efg(), ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], True, 0), - # non-Nash pure profile: D1 D2 D3 - (games.create_mixed_behav_game_efg(), [0.0, 1.0, 0.0, 1.0, 0.0, 1.0], False, 29.0), - (games.create_mixed_behav_game_efg(), ["0", "1", "0", "1", "0", "1"], True, "29"), - # uniform (non-Nash): - (games.create_stripped_down_poker_efg(), None, True, "15/8"), - (games.create_stripped_down_poker_efg(), None, False, 1.875), - # mixed Nash equilibrium (only rational tested): - (games.create_stripped_down_poker_efg(), ["1", "0", "1/3", "2/3", "2/3", "1/3"], True, 0), - # non-Nash pure profile: - # Raise at 1:1, Raise at 1:2, Meet at 2:1 - (games.create_stripped_down_poker_efg(), ["1", "0", "1", "0", "1", "0"], True, 1), - (games.create_stripped_down_poker_efg(), [1.0, 0.0, 1.0, 0.0, 1.0, 0.0], False, 1.0), - ] + # uniform (non-Nash): + (games.read_from_file("mixed_behavior_game.efg"), None, True, "1/16"), + (games.read_from_file("mixed_behavior_game.efg"), None, False, 0.0625), + # four pure Nash equilibria: + ( + games.read_from_file("mixed_behavior_game.efg"), + [1.0, 0.0, 1.0, 0.0, 1.0, 0.0], + False, + 0, + ), # U1 U2 U3 + (games.read_from_file("mixed_behavior_game.efg"), ["1", "0", "1", "0", "1", "0"], True, 0), + ( + games.read_from_file("mixed_behavior_game.efg"), + ["1", "0", "0", "1", "0", "1"], + True, + 0, + ), # U1 D2 D3 + (games.read_from_file("mixed_behavior_game.efg"), [1.0, 0.0, 0.0, 1.0, 0, 1.0], False, 0), + ( + games.read_from_file("mixed_behavior_game.efg"), + ["0", "1", "1", "0", "0", "1"], + True, + 0, + ), # D1 U2 D3 + (games.read_from_file("mixed_behavior_game.efg"), [0.0, 1.0, 1.0, 0.0, 0, 1.0], False, 0), + ( + games.read_from_file("mixed_behavior_game.efg"), + ["0", "1", "0", "1", "1", "0"], + True, + 0, + ), # D1 D2 U3 + (games.read_from_file("mixed_behavior_game.efg"), [0.0, 1.0, 0.0, 1.0, 1.0, 0], False, 0), + # mixed Nash equilibrium (only rational tested): + ( + games.read_from_file("mixed_behavior_game.efg"), + ["2/5", "3/5", "1/2", "1/2", "1/3", "2/3"], + True, + 0, + ), + # non-Nash pure profile: D1 D2 D3 + ( + games.read_from_file("mixed_behavior_game.efg"), + [0.0, 1.0, 0.0, 1.0, 0.0, 1.0], + False, + 29.0, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + ["0", "1", "0", "1", "0", "1"], + True, + "29", + ), + # uniform (non-Nash): + (games.create_stripped_down_poker_efg(), None, True, "15/8"), + (games.create_stripped_down_poker_efg(), None, False, 1.875), + # mixed Nash equilibrium (only rational tested): + (games.create_stripped_down_poker_efg(), ["1", "0", "1/3", "2/3", "2/3", "1/3"], True, 0), + # non-Nash pure profile: + # Raise at 1:1, Raise at 1:2, Meet at 2:1 + (games.create_stripped_down_poker_efg(), ["1", "0", "1", "0", "1", "0"], True, 1), + (games.create_stripped_down_poker_efg(), [1.0, 0.0, 1.0, 0.0, 1.0, 0.0], False, 1.0), + ], ) -def test_agent_liap_value_reference(game: gbt.Game, action_probs: None | list, - rational_flag: bool, expected_value: str | float): +def test_agent_liap_value_reference( + game: gbt.Game, action_probs: None | list, rational_flag: bool, expected_value: str | float +): """Tests agent_liap_value under profile given by action_probs (which will be uniform if action_probs is None) """ profile = game.mixed_behavior_profile(rational=rational_flag) if action_probs: _set_action_probs(profile, action_probs, rational_flag) - assert ( - profile.agent_liap_value() == (gbt.Rational(expected_value) - if rational_flag else expected_value) + assert profile.agent_liap_value() == ( + gbt.Rational(expected_value) if rational_flag else expected_value ) @pytest.mark.parametrize( "game,action_probs,rational_flag,max_regret,agent_max_regret,liap_value,agent_liap_value", [ - # uniform (non-Nash): - (games.create_mixed_behav_game_efg(), None, True, "1/4", "1/4", "1/16", "1/16"), - (games.create_mixed_behav_game_efg(), None, False, 0.25, 0.25, 0.0625, 0.0625), - # Myerson fig 4.2 - (games.read_from_file("myerson_fig_4_2.efg"), [0, 1, 0, 1, 1, 0], True, 1, 0, 1, 0), - ] + # uniform (non-Nash): + ( + games.read_from_file("mixed_behavior_game.efg"), + None, + True, + "1/4", + "1/4", + "1/16", + "1/16", + ), + (games.read_from_file("mixed_behavior_game.efg"), None, False, 0.25, 0.25, 0.0625, 0.0625), + # Myerson fig 4.2 + (games.read_from_file("myerson_fig_4_2.efg"), [0, 1, 0, 1, 1, 0], True, 1, 0, 1, 0), + ], ) -def test_agent_max_regret_versus_non_agent(game: gbt.Game, action_probs: None | list, - rational_flag: bool, - max_regret: str | float, - agent_max_regret: str | float, - agent_liap_value: str | float, - liap_value: str | float, - ): +def test_agent_max_regret_versus_non_agent( + game: gbt.Game, + action_probs: None | list, + rational_flag: bool, + max_regret: str | float, + agent_max_regret: str | float, + agent_liap_value: str | float, + liap_value: str | float, +): profile = game.mixed_behavior_profile(rational=rational_flag) if action_probs: _set_action_probs(profile, action_probs, rational_flag) - assert (profile.max_regret() == (gbt.Rational(max_regret) if rational_flag else max_regret)) - assert ( - profile.agent_max_regret() == (gbt.Rational(agent_max_regret) - if rational_flag else agent_max_regret) + assert profile.max_regret() == (gbt.Rational(max_regret) if rational_flag else max_regret) + assert profile.agent_max_regret() == ( + gbt.Rational(agent_max_regret) if rational_flag else agent_max_regret ) - assert (profile.liap_value() == (gbt.Rational(liap_value) if rational_flag else liap_value)) - assert ( - profile.agent_liap_value() == (gbt.Rational(agent_liap_value) - if rational_flag else agent_liap_value) + assert profile.liap_value() == (gbt.Rational(liap_value) if rational_flag else liap_value) + assert profile.agent_liap_value() == ( + gbt.Rational(agent_liap_value) if rational_flag else agent_liap_value ) @pytest.mark.parametrize( "game,tol,probs,infoset_idx,member_idx,value,rational_flag", - [(games.create_mixed_behav_game_efg(), TOL, [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], 0, 0, 1.0, False), - (games.create_mixed_behav_game_efg(), TOL, [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], 1, 0, 0.8, False), - (games.create_mixed_behav_game_efg(), TOL, [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], 1, 1, 0.2, False), - (games.create_mixed_behav_game_efg(), TOL, [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], 2, 0, 0.32, False), - (games.create_mixed_behav_game_efg(), TOL, [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], 2, 1, 0.48, False), - (games.create_mixed_behav_game_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], 0, 0, "1", - True), - (games.create_mixed_behav_game_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], 1, 0, - "4/5", True), - (games.create_mixed_behav_game_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], 1, 1, - "1/5", True), - (games.create_mixed_behav_game_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], 2, 0, - "8/25", True), - (games.create_mixed_behav_game_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], 2, 1, - "12/25", True), - (games.create_stripped_down_poker_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], - 0, 0, "1", True), - (games.create_stripped_down_poker_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], - 1, 0, "1", True), - (games.create_stripped_down_poker_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], - 2, 0, "2/3", True), - (games.create_stripped_down_poker_efg(), ZERO, ["4/5", "1/5", "2/5", "3/5", "0", "1"], - 2, 1, "1/3", True), - (games.create_stripped_down_poker_efg(), ZERO, ["1", "0", "2/5", "3/5", "0", "1"], - 2, 0, "5/7", True), - (games.create_stripped_down_poker_efg(), ZERO, ["1", "0", "2/5", "3/5", "0", "1"], - 2, 1, "2/7", True), - ] - ) -def test_node_belief_reference(game: gbt.Game, tol: gbt.Rational | float, - probs: list, infoset_idx: int, member_idx: int, - value: str | float, rational_flag: bool): + [ + ( + games.read_from_file("mixed_behavior_game.efg"), + TOL, + [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], + 0, + 0, + 1.0, + False, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + TOL, + [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], + 1, + 0, + 0.8, + False, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + TOL, + [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], + 1, + 1, + 0.2, + False, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + TOL, + [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], + 2, + 0, + 0.32, + False, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + TOL, + [0.8, 0.2, 0.4, 0.6, 0.0, 1.0], + 2, + 1, + 0.48, + False, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 0, + 0, + "1", + True, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 1, + 0, + "4/5", + True, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 1, + 1, + "1/5", + True, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 2, + 0, + "8/25", + True, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 2, + 1, + "12/25", + True, + ), + ( + games.create_stripped_down_poker_efg(), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 0, + 0, + "1", + True, + ), + ( + games.create_stripped_down_poker_efg(), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 1, + 0, + "1", + True, + ), + ( + games.create_stripped_down_poker_efg(), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 2, + 0, + "2/3", + True, + ), + ( + games.create_stripped_down_poker_efg(), + ZERO, + ["4/5", "1/5", "2/5", "3/5", "0", "1"], + 2, + 1, + "1/3", + True, + ), + ( + games.create_stripped_down_poker_efg(), + ZERO, + ["1", "0", "2/5", "3/5", "0", "1"], + 2, + 0, + "5/7", + True, + ), + ( + games.create_stripped_down_poker_efg(), + ZERO, + ["1", "0", "2/5", "3/5", "0", "1"], + 2, + 1, + "2/7", + True, + ), + ], +) +def test_node_belief_reference( + game: gbt.Game, + tol: gbt.Rational | float, + probs: list, + infoset_idx: int, + member_idx: int, + value: str | float, + rational_flag: bool, +): profile = game.mixed_behavior_profile(rational=rational_flag) _set_action_probs(profile, probs, rational_flag) node = game.infosets[infoset_idx].members[member_idx] @@ -1088,9 +1496,10 @@ def test_node_belief_reference(game: gbt.Game, tol: gbt.Rational | float, @pytest.mark.parametrize( "game,rational_flag", - [(games.create_stripped_down_poker_efg(), True), - (games.create_stripped_down_poker_efg(), False), - ] + [ + (games.create_stripped_down_poker_efg(), True), + (games.create_stripped_down_poker_efg(), False), + ], ) def test_payoff_value_error_with_chance_player(game: gbt.Game, rational_flag: bool): """Ensure a value error is thrown when we call payoff for a chance player""" @@ -1101,9 +1510,10 @@ def test_payoff_value_error_with_chance_player(game: gbt.Game, rational_flag: bo @pytest.mark.parametrize( "game,rational_flag", - [(games.create_stripped_down_poker_efg(), True), - (games.create_stripped_down_poker_efg(), False), - ] + [ + (games.create_stripped_down_poker_efg(), True), + (games.create_stripped_down_poker_efg(), False), + ], ) def test_infoset_value_error_with_chance_player_infoset(game: gbt.Game, rational_flag: bool): """Ensure a value error is raised when we call action value for a chance action""" @@ -1114,9 +1524,10 @@ def test_infoset_value_error_with_chance_player_infoset(game: gbt.Game, rational @pytest.mark.parametrize( "game,rational_flag", - [(games.create_stripped_down_poker_efg(), True), - (games.create_stripped_down_poker_efg(), False), - ] + [ + (games.create_stripped_down_poker_efg(), True), + (games.create_stripped_down_poker_efg(), False), + ], ) def test_action_value_error_with_chance_player_action(game: gbt.Game, rational_flag: bool): """Ensure a value error is raised when we call action value for a chance action""" @@ -1125,9 +1536,14 @@ def test_action_value_error_with_chance_player_action(game: gbt.Game, rational_f game.mixed_behavior_profile(rational=rational_flag).action_value(chance_action) -def _get_answers_one_order(game: gbt.Game, action_probs_1st: tuple, action_probs_2nd: tuple, - rational_flag: bool, func_to_test: typing.Callable, - object_to_test_on: typing.Any): +def _get_answers_one_order( + game: gbt.Game, + action_probs_1st: tuple, + action_probs_2nd: tuple, + rational_flag: bool, + func_to_test: typing.Callable, + object_to_test_on: typing.Any, +): """helper function for the 'profile_order' caching tests""" ret = dict() profile = game.mixed_behavior_profile(rational=rational_flag) @@ -1138,14 +1554,27 @@ def _get_answers_one_order(game: gbt.Game, action_probs_1st: tuple, action_probs return ret -def _get_and_check_answers(game: gbt.Game, action_probs1: tuple, action_probs2: tuple, - rational_flag: bool, func_to_test: typing.Callable, - objects_to_test_on: typing.Collection): +def _get_and_check_answers( + game: gbt.Game, + action_probs1: tuple, + action_probs2: tuple, + rational_flag: bool, + func_to_test: typing.Callable, + objects_to_test_on: typing.Collection, +): """helper function for the 'profile_order' caching tests""" - order1_answers = {o: _get_answers_one_order(game, action_probs1, action_probs2, rational_flag, - func_to_test, o) for o in objects_to_test_on} - order2_answers = {o: _get_answers_one_order(game, action_probs2, action_probs1, rational_flag, - func_to_test, o) for o in objects_to_test_on} + order1_answers = { + o: _get_answers_one_order( + game, action_probs1, action_probs2, rational_flag, func_to_test, o + ) + for o in objects_to_test_on + } + order2_answers = { + o: _get_answers_one_order( + game, action_probs2, action_probs1, rational_flag, func_to_test, o + ) + for o in objects_to_test_on + } assert order1_answers == order2_answers @@ -1162,177 +1591,481 @@ def _get_and_check_answers(game: gbt.Game, action_probs1: tuple, action_probs2: @pytest.mark.parametrize( "game,action_probs1,action_probs2,rational_flag,func_to_test,objects_to_test", [ - ###################################################################################### - # belief (at nodes) - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.belief(y), lambda x: x.nodes), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.belief(y), lambda x: x.nodes), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.belief(y), lambda x: x.nodes), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.belief(y), lambda x: x.nodes), - ###################################################################################### - # realiz_prob (at nodes) - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.realiz_prob(y), lambda x: x.nodes), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.realiz_prob(y), lambda x: x.nodes), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.realiz_prob(y), lambda x: x.nodes), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.realiz_prob(y), lambda x: x.nodes), - ###################################################################################### - # infoset_prob - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.infoset_prob(y), lambda x: x.infosets), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.infoset_prob(y), lambda x: x.infosets), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.infoset_prob(y), lambda x: x.infosets), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.infoset_prob(y), lambda x: x.infosets), - ###################################################################################### - # infoset_value - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.infoset_value(y), lambda x: x.infosets), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.infoset_value(y), lambda x: x.infosets), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.infoset_value(y), lambda x: x.infosets), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.infoset_value(y), lambda x: x.infosets), - ###################################################################################### - # action_value - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.action_value(y), lambda x: x.actions), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.action_value(y), lambda x: x.actions), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.action_value(y), lambda x: x.actions), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.action_value(y), lambda x: x.actions), - ###################################################################################### - # regret (for actions) - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.action_regret(y), lambda x: x.actions), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.action_regret(y), lambda x: x.actions), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.action_regret(y), lambda x: x.actions), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.action_regret(y), lambda x: x.actions), - ###################################################################################### - # node_value - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.node_value(player=y[0], node=y[1]), - lambda x: list(product(x.players, x.nodes))), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.node_value(player=y[0], node=y[1]), - lambda x: list(product(x.players, x.nodes))), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.node_value(player=y[0], node=y[1]), - lambda x: list(product(x.players, x.nodes))), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.node_value(player=y[0], node=y[1]), - lambda x: list(product(x.players, x.nodes))), - ###################################################################################### - # agent_liap_value (of profile, hence [1] for objects_to_test, - # any singleton collection would do) - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.agent_liap_value(), lambda x: [1]), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.agent_liap_value(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.agent_liap_value(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.agent_liap_value(), lambda x: [1]), - ###################################################################################### - # liap_value (of profile, hence [1] for objects_to_test, - # any singleton collection would do) - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.liap_value(), lambda x: [1]), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.liap_value(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.liap_value(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.liap_value(), lambda x: [1]), - ###################################################################################### - # agent_max_regret (of profile, hence [1] for objects_to_test, - # any singleton collection would do) - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.agent_max_regret(), lambda x: [1]), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.agent_max_regret(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.agent_max_regret(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.agent_max_regret(), lambda x: [1]), - ###################################################################################### - # max_regret (of profile, hence [1] for objects_to_test, - # any singleton collection would do) - (games.create_mixed_behav_game_efg(), PROBS_1A_doub, PROBS_2A_doub, False, - lambda x, y: x.max_regret(), lambda x: [1]), - (games.create_mixed_behav_game_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.max_regret(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1B_doub, PROBS_2B_doub, False, - lambda x, y: x.max_regret(), lambda x: [1]), - (games.create_stripped_down_poker_efg(), PROBS_1A_rat, PROBS_2A_rat, True, - lambda x, y: x.max_regret(), lambda x: [1]), - ] + ###################################################################################### + # belief (at nodes) + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.belief(y), + lambda x: x.nodes, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.belief(y), + lambda x: x.nodes, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.belief(y), + lambda x: x.nodes, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.belief(y), + lambda x: x.nodes, + ), + ###################################################################################### + # realiz_prob (at nodes) + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.realiz_prob(y), + lambda x: x.nodes, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.realiz_prob(y), + lambda x: x.nodes, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.realiz_prob(y), + lambda x: x.nodes, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.realiz_prob(y), + lambda x: x.nodes, + ), + ###################################################################################### + # infoset_prob + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.infoset_prob(y), + lambda x: x.infosets, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.infoset_prob(y), + lambda x: x.infosets, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.infoset_prob(y), + lambda x: x.infosets, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.infoset_prob(y), + lambda x: x.infosets, + ), + ###################################################################################### + # infoset_value + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.infoset_value(y), + lambda x: x.infosets, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.infoset_value(y), + lambda x: x.infosets, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.infoset_value(y), + lambda x: x.infosets, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.infoset_value(y), + lambda x: x.infosets, + ), + ###################################################################################### + # action_value + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.action_value(y), + lambda x: x.actions, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.action_value(y), + lambda x: x.actions, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.action_value(y), + lambda x: x.actions, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.action_value(y), + lambda x: x.actions, + ), + ###################################################################################### + # regret (for actions) + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.action_regret(y), + lambda x: x.actions, + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.action_regret(y), + lambda x: x.actions, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.action_regret(y), + lambda x: x.actions, + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.action_regret(y), + lambda x: x.actions, + ), + ###################################################################################### + # node_value + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.node_value(player=y[0], node=y[1]), + lambda x: list(product(x.players, x.nodes)), + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.node_value(player=y[0], node=y[1]), + lambda x: list(product(x.players, x.nodes)), + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.node_value(player=y[0], node=y[1]), + lambda x: list(product(x.players, x.nodes)), + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.node_value(player=y[0], node=y[1]), + lambda x: list(product(x.players, x.nodes)), + ), + ###################################################################################### + # agent_liap_value (of profile, hence [1] for objects_to_test, + # any singleton collection would do) + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.agent_liap_value(), + lambda x: [1], + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.agent_liap_value(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.agent_liap_value(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.agent_liap_value(), + lambda x: [1], + ), + ###################################################################################### + # liap_value (of profile, hence [1] for objects_to_test, + # any singleton collection would do) + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.liap_value(), + lambda x: [1], + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.liap_value(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.liap_value(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.liap_value(), + lambda x: [1], + ), + ###################################################################################### + # agent_max_regret (of profile, hence [1] for objects_to_test, + # any singleton collection would do) + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.agent_max_regret(), + lambda x: [1], + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.agent_max_regret(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.agent_max_regret(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.agent_max_regret(), + lambda x: [1], + ), + ###################################################################################### + # max_regret (of profile, hence [1] for objects_to_test, + # any singleton collection would do) + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_doub, + PROBS_2A_doub, + False, + lambda x, y: x.max_regret(), + lambda x: [1], + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.max_regret(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1B_doub, + PROBS_2B_doub, + False, + lambda x, y: x.max_regret(), + lambda x: [1], + ), + ( + games.create_stripped_down_poker_efg(), + PROBS_1A_rat, + PROBS_2A_rat, + True, + lambda x, y: x.max_regret(), + lambda x: [1], + ), + ], ) -def test_profile_order_consistency(game: gbt.Game, - action_probs1: tuple, - action_probs2: tuple, rational_flag: bool, - func_to_test: typing.Callable, - objects_to_test: typing.Callable): - _get_and_check_answers(game, action_probs1, action_probs2, rational_flag, func_to_test, - objects_to_test(game)) +def test_profile_order_consistency( + game: gbt.Game, + action_probs1: tuple, + action_probs2: tuple, + rational_flag: bool, + func_to_test: typing.Callable, + objects_to_test: typing.Callable, +): + _get_and_check_answers( + game, action_probs1, action_probs2, rational_flag, func_to_test, objects_to_test(game) + ) @pytest.mark.parametrize( "game,rational_flag,data", - [(games.create_mixed_behav_game_efg(), True, [[[0, 1]], [[0, 1]], [[1, 0]]]), - (games.create_mixed_behav_game_efg(), True, [[["1/5", "4/5"]], [["1/4", "3/4"]], [[1, 0]]]), - (games.create_stripped_down_poker_efg(), True, [[[1/5, 4/5], [3/5, 2/5]], [[1/4, 3/4]]]), - (games.create_mixed_behav_game_efg(), False, [[[0, 1]], [[1, 0]], [[1, 0]]]), - (games.create_mixed_behav_game_efg(), False, [[[1/5, 4/5]], [[1/4, 3/4]], [[1, 0]]]), - (games.create_stripped_down_poker_efg(), False, [[[1/5, 4/5], [3/5, 2/5]], [[1/4, 3/4]]]) - ] + [ + (games.read_from_file("mixed_behavior_game.efg"), True, [[[0, 1]], [[0, 1]], [[1, 0]]]), + ( + games.read_from_file("mixed_behavior_game.efg"), + True, + [[["1/5", "4/5"]], [["1/4", "3/4"]], [[1, 0]]], + ), + ( + games.create_stripped_down_poker_efg(), + True, + [[[1 / 5, 4 / 5], [3 / 5, 2 / 5]], [[1 / 4, 3 / 4]]], + ), + (games.read_from_file("mixed_behavior_game.efg"), False, [[[0, 1]], [[1, 0]], [[1, 0]]]), + ( + games.read_from_file("mixed_behavior_game.efg"), + False, + [[[1 / 5, 4 / 5]], [[1 / 4, 3 / 4]], [[1, 0]]], + ), + ( + games.create_stripped_down_poker_efg(), + False, + [[[1 / 5, 4 / 5], [3 / 5, 2 / 5]], [[1 / 4, 3 / 4]]], + ), + ], ) def test_specific_profile(game: gbt.Game, rational_flag: bool, data: list): """Test that the mixed behavior profile is initialized from a specific distribution for each player over his actions. """ profile = game.mixed_behavior_profile(rational=rational_flag, data=data) - for (action, prob) in zip(game.actions, [k for i in data for j in i for k in j], strict=True): + for action, prob in zip(game.actions, [k for i in data for j in i for k in j], strict=True): assert profile[action] == (gbt.Rational(prob) if rational_flag else prob) @pytest.mark.parametrize( "game,rational_flag,data", - [(games.create_mixed_behav_game_efg(), True, - [[[0, 1, 0]], [[1, 0]], [["1/2", "1/2"]]]), - (games.create_mixed_behav_game_efg(), True, - [[[0, 1]], [[1, 0]], [[1, 0]], [[0, 1]]]), - (games.create_stripped_down_poker_efg(), True, - [[["1/5", "4/5"], ["3/5", "2/5"]], [["1/4", "3/4"], ["1/4", "3/4"]]]), - (games.create_el_farol_bar_game_efg(), True, - [[4/9, 5/9], [0], [1/2, 1/2], [11/12, 1/12], [1/2, 1/2]]), - (games.create_el_farol_bar_game_efg(), True, - [[1/2, 1/2]]), - (games.create_mixed_behav_game_efg(), False, - [[[0, 1, 0]], [[1, 0]], [[1, 0]]]), - (games.create_mixed_behav_game_efg(), False, - [[[0, 1]], [[1, 0]], [[1, 0]], [[0, 1]]]), - (games.create_stripped_down_poker_efg(), False, - [[[1/5, 4/5], [3/5, 2/5]], [[1/4, 3/4], [1/4, 3/4]]]), - (games.create_el_farol_bar_game_efg(), False, - [[4/9, 5/9], [0], [1/2, 1/2], [11/12, 1/12], [1/2, 1/2]]), - (games.create_el_farol_bar_game_efg(), False, - [[1/2, 1/2]]) - ] + [ + ( + games.read_from_file("mixed_behavior_game.efg"), + True, + [[[0, 1, 0]], [[1, 0]], [["1/2", "1/2"]]], + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + True, + [[[0, 1]], [[1, 0]], [[1, 0]], [[0, 1]]], + ), + ( + games.create_stripped_down_poker_efg(), + True, + [[["1/5", "4/5"], ["3/5", "2/5"]], [["1/4", "3/4"], ["1/4", "3/4"]]], + ), + ( + games.create_el_farol_bar_game_efg(), + True, + [[4 / 9, 5 / 9], [0], [1 / 2, 1 / 2], [11 / 12, 1 / 12], [1 / 2, 1 / 2]], + ), + (games.create_el_farol_bar_game_efg(), True, [[1 / 2, 1 / 2]]), + ( + games.read_from_file("mixed_behavior_game.efg"), + False, + [[[0, 1, 0]], [[1, 0]], [[1, 0]]], + ), + ( + games.read_from_file("mixed_behavior_game.efg"), + False, + [[[0, 1]], [[1, 0]], [[1, 0]], [[0, 1]]], + ), + ( + games.create_stripped_down_poker_efg(), + False, + [[[1 / 5, 4 / 5], [3 / 5, 2 / 5]], [[1 / 4, 3 / 4], [1 / 4, 3 / 4]]], + ), + ( + games.create_el_farol_bar_game_efg(), + False, + [[4 / 9, 5 / 9], [0], [1 / 2, 1 / 2], [11 / 12, 1 / 12], [1 / 2, 1 / 2]], + ), + (games.create_el_farol_bar_game_efg(), False, [[1 / 2, 1 / 2]]), + ], ) def test_profile_data_error(game: gbt.Game, rational_flag: bool, data: list): """Test to ensure a pygambit.ValueError is raised when the data do not @@ -1345,11 +2078,18 @@ def test_profile_data_error(game: gbt.Game, rational_flag: bool, data: list): @pytest.mark.parametrize( "game,rational_flag,data", - [(games.read_from_file("coordination_4x4_payoff.nfg"), True, - [["1/5", "2/5", 0, "2/5"], ["1/4", "3/8", "1/4", "3/8"]]), - (games.read_from_file("coordination_4x4_payoff.nfg"), False, - [[1/5, 2/5, 0/5, 2/5], [1/4, 3/8, 1/4, 3/8]]), - ] + [ + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + True, + [["1/5", "2/5", 0, "2/5"], ["1/4", "3/8", "1/4", "3/8"]], + ), + ( + games.read_from_file("coordination_4x4_payoff.nfg"), + False, + [[1 / 5, 2 / 5, 0 / 5, 2 / 5], [1 / 4, 3 / 8, 1 / 4, 3 / 8]], + ), + ], ) def test_tree_representation_error(game: gbt.Game, rational_flag: bool, data: list): """Test to ensure a pygambit.UndefinedOperationError is raised when the game diff --git a/tests/test_games/mixed_behavior_game.efg b/tests/test_games/mixed_behavior_game.efg index d6de35662..ff93b5732 100644 --- a/tests/test_games/mixed_behavior_game.efg +++ b/tests/test_games/mixed_behavior_game.efg @@ -1,5 +1,10 @@ EFG 2 R "Test Extensive Form Game" { "Player 1" "Player 2" "Player 3" } -"" +" +Three-player extensive form game: binary tree with 3 infomation sets, one per player, +with 1, 2, and 4 nodes respectively. + +Since no information is revealed this is directly equivalent to a simultaneous move game. +" p "" 1 1 "Infoset 1:1" { "U1" "D1" } 0 p "" 2 1 "Infoset 2:1" { "U2" "D2" } 0 diff --git a/tests/test_mixed.py b/tests/test_mixed.py index 731f6f35f..f82535cb2 100644 --- a/tests/test_mixed.py +++ b/tests/test_mixed.py @@ -358,12 +358,12 @@ def test_profile_indexing_by_strategy_label_reference( [ ############################################################################ # mixed behav efg - (games.create_mixed_behav_game_efg(), P1, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), P2, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), P3, [0.5, 0.5], False), - (games.create_mixed_behav_game_efg(), P1, ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), P2, ["1/2", "1/2"], True), - (games.create_mixed_behav_game_efg(), P3, ["1/2", "1/2"], True), + (games.read_from_file("mixed_behavior_game.efg"), P1, [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), P2, [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), P3, [0.5, 0.5], False), + (games.read_from_file("mixed_behavior_game.efg"), P1, ["1/2", "1/2"], True), + (games.read_from_file("mixed_behavior_game.efg"), P2, ["1/2", "1/2"], True), + (games.read_from_file("mixed_behavior_game.efg"), P3, ["1/2", "1/2"], True), ############################################################################ # stripped-down poker efg (games.create_stripped_down_poker_efg(), "Alice", [0.25, 0.25, 0.25, 0.25], False), @@ -493,12 +493,12 @@ def test_profile_indexing_by_player_label_reference( ), (games.create_stripped_down_poker_efg(), True, [[0, 0, 0, 1], ["1/2", "1/2"]], "Bob", 1), ######################################################################### - (games.create_mixed_behav_game_efg(), False, None, P1, 3.0), - (games.create_mixed_behav_game_efg(), False, None, P2, 3.0), - (games.create_mixed_behav_game_efg(), False, None, P3, 3.25), - (games.create_mixed_behav_game_efg(), True, None, P1, 3), - (games.create_mixed_behav_game_efg(), True, None, P2, 3), - (games.create_mixed_behav_game_efg(), True, None, P3, "13/4"), + (games.read_from_file("mixed_behavior_game.efg"), False, None, P1, 3.0), + (games.read_from_file("mixed_behavior_game.efg"), False, None, P2, 3.0), + (games.read_from_file("mixed_behavior_game.efg"), False, None, P3, 3.25), + (games.read_from_file("mixed_behavior_game.efg"), True, None, P1, 3), + (games.read_from_file("mixed_behavior_game.efg"), True, None, P2, 3), + (games.read_from_file("mixed_behavior_game.efg"), True, None, P3, "13/4"), ], ) def test_payoff_by_label_reference( @@ -542,8 +542,8 @@ def test_strategy_value_by_label_reference( @pytest.mark.parametrize( "game,rational_flag", [ - (games.create_mixed_behav_game_efg(), False), - (games.create_mixed_behav_game_efg(), True), + (games.read_from_file("mixed_behavior_game.efg"), False), + (games.read_from_file("mixed_behavior_game.efg"), True), (games.create_centipede_game_with_chance_efg(), False), (games.create_centipede_game_with_chance_efg(), True), ], diff --git a/tests/test_nash.py b/tests/test_nash.py index 52343490e..f47801d61 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -44,7 +44,7 @@ (games.create_EFG_for_6x6_bimatrix_with_long_LH_paths_and_unique_eq(), []), # 3-player game ( - games.create_mixed_behav_game_efg(), + games.read_from_file("mixed_behavior_game.efg"), [ [[1, 0], [1, 0], [1, 0]], [[0, 1], [0, 1], [1, 0]], @@ -101,7 +101,7 @@ def test_enumpure_strategy(game: gbt.Game, pure_strategy_prof_data: list): (games.create_EFG_for_6x6_bimatrix_with_long_LH_paths_and_unique_eq(), []), # 3-player game ( - games.create_mixed_behav_game_efg(), + games.read_from_file("mixed_behavior_game.efg"), [ [[[1, 0]], [[1, 0]], [[1, 0]]], [[[1, 0]], [[0, 1]], [[0, 1]]], @@ -239,7 +239,7 @@ def test_enummixed_rational(game: gbt.Game, mixed_strategy_prof_data: list): ), # 3-player game # ( - # games.create_mixed_behav_game_efg(), + # games.read_from_file("mixed_behavior_game.efg"), # [ # [[["1/2", "1/2"]], [["2/5", "3/5"]], [["1/4", "3/4"]]], # [[["2/5", "3/5"]], [["1/2", "1/2"]], [["1/3", "2/3"]]], @@ -335,7 +335,7 @@ def test_enumpoly_ordered_behavior( [ # 3-player game ( - games.create_mixed_behav_game_efg(), + games.read_from_file("mixed_behavior_game.efg"), [ [[["2/5", "3/5"]], [["1/2", "1/2"]], [["1/3", "2/3"]]], [[["1/2", "1/2"]], [["2/5", "3/5"]], [["1/4", "3/4"]]], From 0e5aabdd742caa11505e417711c8e1f625695252 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 19:04:53 +0000 Subject: [PATCH 21/24] create_2x2_zero_sum_efg uses create_efg_corresponding_to_bimatrix_game --- tests/games.py | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/tests/games.py b/tests/games.py index da398bf0a..f37caade2 100644 --- a/tests/games.py +++ b/tests/games.py @@ -44,26 +44,17 @@ def create_efg_corresponding_to_bimatrix_game( def create_2x2_zero_sum_efg(missing_term_outcome: bool = False) -> gbt.Game: """ - TODO: use create_efg_corresponding_to_bimatrix_game - EFG corresponding to 2x2 zero-sum game (I,-I). - If missing_term_outcome, the terminal node after "T" then "r" does not have an outcome. + If missing_term_outcome, the terminal node after action 0 then 1 does not have an outcome. """ - g = gbt.Game.new_tree( - players=["Alice", "Bob"], title="2x2 matrix games (I,-I)") - g.append_move(g.root, "Alice", ["T", "B"]) - g.append_move(g.root.children, "Bob", ["l", "r"]) - - alice_win = g.add_outcome([1, -1], label="Alice win") - draw = g.add_outcome([0, 0], label="Draw") - - g.set_outcome(g.root.children["T"].children["l"], alice_win) - g.set_outcome(g.root.children["B"].children["r"], alice_win) - g.set_outcome(g.root.children["B"].children["l"], draw) - - if not missing_term_outcome: - g.set_outcome(g.root.children["T"].children["r"], draw) - + title = "EFG for 2x2 zero-sum game (I,-I)" + if missing_term_outcome: + title += " with missing terminal outcome" + A = np.eye(2) + B = -A + g = create_efg_corresponding_to_bimatrix_game(A, B, title) + if missing_term_outcome: + g.delete_outcome(g.root.children[0].children[1].outcome) return g From 9548e67ccbaec387c1d022273b3738aa917880c4 Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 19:08:11 +0000 Subject: [PATCH 22/24] removed create_selten_horse_game_efg from games.py --- tests/games.py | 10 ---------- tests/test_io.py | 2 +- tests/test_mixed.py | 8 ++++---- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/tests/games.py b/tests/games.py index f37caade2..bb980da87 100644 --- a/tests/games.py +++ b/tests/games.py @@ -421,16 +421,6 @@ def create_el_farol_bar_game_efg() -> gbt.Game: return read_from_file("el_farol_bar.efg") -def create_selten_horse_game_efg() -> gbt.Game: - """ - Returns - ------- - Game - 5-player Selten's Horse Game - """ - return read_from_file("e01.efg") - - def create_EFG_for_nxn_bimatrix_coordination_game(n: int) -> gbt.Game: A = np.eye(n, dtype=int) B = A diff --git a/tests/test_io.py b/tests/test_io.py index c0bf876ec..3016c224b 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -112,7 +112,7 @@ def test_write_latex(): def test_read_write_efg(): - efg_game = games.create_selten_horse_game_efg() + efg_game = games.read_from_file("e01.efg") serialized_efg_game = efg_game.to_efg() deserialized_efg_game = gbt.read_efg(io.BytesIO(serialized_efg_game.encode())) double_serialized_efg_game = deserialized_efg_game.to_efg() diff --git a/tests/test_mixed.py b/tests/test_mixed.py index f82535cb2..25941127b 100644 --- a/tests/test_mixed.py +++ b/tests/test_mixed.py @@ -1359,9 +1359,9 @@ def test_player_regret_max_regret_consistency( False, ), ################################################################################# - # Selten's horse game + # Selten's horse ( - games.create_selten_horse_game_efg(), + games.read_from_file("e01.efg"), [["4/9", "5/9"], ["1/11", "10/11"], ["8/9", "1/9"]], [["4/9", "5/9"], ["10/11", "1/11"], ["8/9", "1/9"]], gbt.Rational("4/9"), @@ -1459,13 +1459,13 @@ def test_linearity_payoff_property( ################################################################################# # Selten's horse ( - games.create_selten_horse_game_efg(), + games.read_from_file("e01.efg"), [["4/9", "5/9"], ["6/11", "5/11"], ["4/7", "3/7"]], ZERO, True, ), ( - games.create_selten_horse_game_efg(), + games.read_from_file("e01.efg"), [[4 / 9, 5 / 9], [6 / 11, 5 / 11], [4 / 7, 3 / 7]], TOL, False, From cdb6201032233106020d8ff22ced67a34eabb2be Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 19:13:47 +0000 Subject: [PATCH 23/24] removed create_el_farol_bar_game_efg and create_centipede_game_with_chance_efg from games.py --- tests/games.py | 20 ------------- tests/test_behav.py | 8 ++--- tests/test_mixed.py | 72 ++++++++++++++++++++++----------------------- 3 files changed, 40 insertions(+), 60 deletions(-) diff --git a/tests/games.py b/tests/games.py index bb980da87..e01e9f335 100644 --- a/tests/games.py +++ b/tests/games.py @@ -401,26 +401,6 @@ def create_one_shot_trust_efg(unique_NE_variant: bool = False) -> gbt.Game: return g -def create_centipede_game_with_chance_efg() -> gbt.Game: - """ - Returns - ------- - Game - 2-player Centipede Game with 3 innings and a probability of altruism - """ - return read_from_file("cent3.efg") - - -def create_el_farol_bar_game_efg() -> gbt.Game: - """ - Returns - ------- - Game - 5-player El Farol Bar Game - """ - return read_from_file("el_farol_bar.efg") - - def create_EFG_for_nxn_bimatrix_coordination_game(n: int) -> gbt.Game: A = np.eye(n, dtype=int) B = A diff --git a/tests/test_behav.py b/tests/test_behav.py index 6097d342e..62ec7bbf3 100644 --- a/tests/test_behav.py +++ b/tests/test_behav.py @@ -2039,11 +2039,11 @@ def test_specific_profile(game: gbt.Game, rational_flag: bool, data: list): [[["1/5", "4/5"], ["3/5", "2/5"]], [["1/4", "3/4"], ["1/4", "3/4"]]], ), ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), True, [[4 / 9, 5 / 9], [0], [1 / 2, 1 / 2], [11 / 12, 1 / 12], [1 / 2, 1 / 2]], ), - (games.create_el_farol_bar_game_efg(), True, [[1 / 2, 1 / 2]]), + (games.read_from_file("el_farol_bar.efg"), True, [[1 / 2, 1 / 2]]), ( games.read_from_file("mixed_behavior_game.efg"), False, @@ -2060,11 +2060,11 @@ def test_specific_profile(game: gbt.Game, rational_flag: bool, data: list): [[[1 / 5, 4 / 5], [3 / 5, 2 / 5]], [[1 / 4, 3 / 4], [1 / 4, 3 / 4]]], ), ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), False, [[4 / 9, 5 / 9], [0], [1 / 2, 1 / 2], [11 / 12, 1 / 12], [1 / 2, 1 / 2]], ), - (games.create_el_farol_bar_game_efg(), False, [[1 / 2, 1 / 2]]), + (games.read_from_file("el_farol_bar.efg"), False, [[1 / 2, 1 / 2]]), ], ) def test_profile_data_error(game: gbt.Game, rational_flag: bool, data: list): diff --git a/tests/test_mixed.py b/tests/test_mixed.py index 25941127b..287ee9eac 100644 --- a/tests/test_mixed.py +++ b/tests/test_mixed.py @@ -46,10 +46,10 @@ def _set_action_probs(profile: gbt.MixedStrategyProfile, probs: list, rational_f ), ############################################################################### # centipede with chance efg - (games.create_centipede_game_with_chance_efg(), [[0, 0, 0, 0], [1, 0, 0, 0]], True), - (games.create_centipede_game_with_chance_efg(), [[1, 0, 0, 0], [0, 0, 0, 0]], True), - (games.create_centipede_game_with_chance_efg(), [[0, 0, 0, 0], [1, 0, 0, 0]], False), - (games.create_centipede_game_with_chance_efg(), [[1, 0, 0, 0], [0, 0, 0, 0]], False), + (games.read_from_file("cent3.efg"), [[0, 0, 0, 0], [1, 0, 0, 0]], True), + (games.read_from_file("cent3.efg"), [[1, 0, 0, 0], [0, 0, 0, 0]], True), + (games.read_from_file("cent3.efg"), [[0, 0, 0, 0], [1, 0, 0, 0]], False), + (games.read_from_file("cent3.efg"), [[1, 0, 0, 0], [0, 0, 0, 0]], False), ], ) def test_normalize_zero_value_error(game, profile_data, rational_flag): @@ -83,10 +83,10 @@ def test_normalize_zero_value_error(game, profile_data, rational_flag): ), ############################################################################### # centipede with chance efg - (games.create_centipede_game_with_chance_efg(), [[-1, 0, 0, 0], [1, 0, 0, 0]], True), - (games.create_centipede_game_with_chance_efg(), [[1, 0, 0, 0], [-1, 0, 0, 0]], True), - (games.create_centipede_game_with_chance_efg(), [[-1, 0, 0, 0], [1, 0, 0, 0]], False), - (games.create_centipede_game_with_chance_efg(), [[1, 0, 0, 0], [-1, 0, 0, 0]], False), + (games.read_from_file("cent3.efg"), [[-1, 0, 0, 0], [1, 0, 0, 0]], True), + (games.read_from_file("cent3.efg"), [[1, 0, 0, 0], [-1, 0, 0, 0]], True), + (games.read_from_file("cent3.efg"), [[-1, 0, 0, 0], [1, 0, 0, 0]], False), + (games.read_from_file("cent3.efg"), [[1, 0, 0, 0], [-1, 0, 0, 0]], False), ], ) def test_normalize_neg_entry_value_error(game, profile_data, rational_flag): @@ -115,13 +115,13 @@ def test_normalize_neg_entry_value_error(game, profile_data, rational_flag): ############################################################################### # centipede with chance efg ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [[1, 2, 3, 14], [1, 1, 1, 1]], [["1/20", "2/20", "3/20", "14/20"], ["1/4", "1/4", "1/4", "1/4"]], True, ), ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [[1.0, 2.0, 3.0, 14.0], [1, 1, 1, 1]], [[1 / 20, 2 / 20, 3 / 20, 14 / 20], [0.25, 0.25, 0.25, 0.25]], False, @@ -544,8 +544,8 @@ def test_strategy_value_by_label_reference( [ (games.read_from_file("mixed_behavior_game.efg"), False), (games.read_from_file("mixed_behavior_game.efg"), True), - (games.create_centipede_game_with_chance_efg(), False), - (games.create_centipede_game_with_chance_efg(), True), + (games.read_from_file("cent3.efg"), False), + (games.read_from_file("cent3.efg"), True), ], ) def test_as_behavior_roundtrip(game: gbt.Game, rational_flag: bool): @@ -774,14 +774,14 @@ def test_strategy_value_reference( ############################################################################## # El Farol bar game efg ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"]], 0, ZERO, True, ), ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [[1, 0], [1, 0], [0, 1], [0, 1], [0, 1]], 0, ZERO, @@ -972,14 +972,14 @@ def test_liap_value_reference( ############################################################################## # El Farol bar game efg ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"], ["1/2", "1/2"]], [0] * 5, ZERO, True, ), ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [[1, 0], [1, 0], [0, 1], [0, 1], [0, 1]], [0] * 5, ZERO, @@ -1104,12 +1104,12 @@ def test_player_regret_max_regret_reference( (games.read_from_file("2x2_bimatrix_all_zero_payoffs.nfg"), True), ################################################################################# # El Farol bar game efg - (games.create_el_farol_bar_game_efg(), False), - (games.create_el_farol_bar_game_efg(), True), + (games.read_from_file("el_farol_bar.efg"), False), + (games.read_from_file("el_farol_bar.efg"), True), ################################################################################# # Centipede with chance efg - (games.create_centipede_game_with_chance_efg(), False), - (games.create_centipede_game_with_chance_efg(), True), + (games.read_from_file("cent3.efg"), False), + (games.read_from_file("cent3.efg"), True), ################################################################################# # 2x2x2 nfg (games.read_from_file("2x2x2_nfg_from_local_max_cut_2_pure_1_mixed_eq.nfg"), False), @@ -1146,13 +1146,13 @@ def test_strategy_regret_consistency(game: gbt.Game, rational_flag: bool): ################################################################################# # Centipede with chance efg ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", 0]], ZERO, True, ), ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [[1 / 3, 1 / 3, 1 / 3, 0], [0.10, 3 / 5, 0.3, 0]], TOL, False, @@ -1160,13 +1160,13 @@ def test_strategy_regret_consistency(game: gbt.Game, rational_flag: bool): ################################################################################# # El Farol bar game efg ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [[1, 0], ["1/2", "1/2"], ["1/3", "2/3"], ["1/5", "4/5"], ["1/8", "7/8"]], ZERO, True, ), ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [[1, 0], [1 / 2, 1 / 2], [1 / 3, 2 / 3], [1 / 5, 4 / 5], [1 / 8, 7 / 8]], TOL, False, @@ -1239,13 +1239,13 @@ def test_liap_value_consistency( ################################################################################# # Centipede with chance efg ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", 0]], ZERO, True, ), ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [[1 / 3, 1 / 3, 1 / 3, 0], [0.10, 3 / 5, 0.3, 0]], TOL, False, @@ -1253,13 +1253,13 @@ def test_liap_value_consistency( ################################################################################# # El Farol bar game efg ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [[1, 0], ["1/2", "1/2"], ["1/3", "2/3"], ["1/5", "4/5"], ["1/8", "7/8"]], ZERO, True, ), ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [[1, 0], [1 / 2, 1 / 2], [1 / 3, 2 / 3], [1 / 5, 4 / 5], [1 / 8, 7 / 8]], TOL, False, @@ -1343,7 +1343,7 @@ def test_player_regret_max_regret_consistency( ################################################################################# # Centipede game with chance ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [["1/3", "1/3", "1/3", "0/1"], ["1/10", "3/5", "3/10", "0/1"]], [["1/3", "1/3", "1/3", "0/1"], ["1/5", "2/5", "1/5", "1/5"]], gbt.Rational("1/12"), @@ -1351,7 +1351,7 @@ def test_player_regret_max_regret_consistency( True, ), ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [[1 / 3, 1 / 3, 1 / 3, 0 / 1], [1 / 10, 3 / 5, 3 / 10, 0 / 1]], [[1 / 3, 1 / 3, 1 / 3, 0 / 1], [1 / 5, 2 / 5, 1 / 5, 1 / 5]], 1 / 12, @@ -1371,7 +1371,7 @@ def test_player_regret_max_regret_consistency( ################################################################################# # El Farol bar game ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [["4/9", "5/9"], ["1/3", "2/3"], ["1/2", "1/2"], ["11/12", "1/12"], ["1/2", "1/2"]], [["4/9", "5/9"], ["1/3", "2/3"], ["1/2", "1/2"], ["1/12", "11/12"], ["1/2", "1/2"]], gbt.Rational("1/2"), @@ -1445,13 +1445,13 @@ def test_linearity_payoff_property( ################################################################################# # Centipede game with chance ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [["1/5", "2/5", "1/5", "1/5"], ["1/10", "3/5", "3/10", "0/1"]], ZERO, True, ), ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [[1 / 3, 1 / 3, 1 / 3, 0 / 1], [1 / 10, 3 / 5, 3 / 10, 0 / 1]], TOL, False, @@ -1473,7 +1473,7 @@ def test_linearity_payoff_property( ################################################################################# # El Farol bar game ( - games.create_el_farol_bar_game_efg(), + games.read_from_file("el_farol_bar.efg"), [["4/9", "5/9"], ["1/3", "2/3"], ["0/1", "1/1"], ["11/12", "1/12"], ["1/3", "2/3"]], ZERO, True, @@ -1523,7 +1523,7 @@ def test_payoff_and_strategy_value_consistency( ################################################################################# # centipede game with chance ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [["1/3", "1/3", "1/3", "0"], ["1/10", "3/5", "3/10", "0"]], [["1/3", "1/3", "1/3", "0"], ["1/10", "3/5", "3/10", "0"]], "82943/62500", @@ -1531,7 +1531,7 @@ def test_payoff_and_strategy_value_consistency( ZERO, ), ( - games.create_centipede_game_with_chance_efg(), + games.read_from_file("cent3.efg"), [[1 / 3, 1 / 3, 1 / 3, 0], [1 / 10, 3 / 5, 3 / 10, 0]], [[1 / 3, 1 / 3, 1 / 3, 0], [1 / 10, 3 / 5, 3 / 10, 0]], 82943 / 62500, From 2394420ecc300fa7ccac1b8c99914e0252a219cd Mon Sep 17 00:00:00 2001 From: Rahul Savani Date: Wed, 14 Jan 2026 19:15:30 +0000 Subject: [PATCH 24/24] comment in create_one_shot_trust_efg, which could be removed in due course --- tests/games.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/games.py b/tests/games.py index e01e9f335..450282a52 100644 --- a/tests/games.py +++ b/tests/games.py @@ -373,6 +373,8 @@ def kuhn_poker_lcp_first_mixed_strategy_prof(): def create_one_shot_trust_efg(unique_NE_variant: bool = False) -> gbt.Game: """ + TODO: this could be replaced with two .efg files + One-shot trust game, after Kreps (1990) The unique_NE_variant makes Trust a dominant strategy, replacing the