diff --git a/quantecon/game_theory/polymatrix_game.py b/quantecon/game_theory/polymatrix_game.py index 7ec0efbc..f071c280 100644 --- a/quantecon/game_theory/polymatrix_game.py +++ b/quantecon/game_theory/polymatrix_game.py @@ -14,7 +14,7 @@ >>> matching_pennies_bimatrix = [ ... [(1, -1), (-1, 1)], [(-1, 1), (1, -1)]] >>> nfg = NormalFormGame(matching_pennies_bimatrix) ->>> polymg = PolymatrixGame.from_nf(nfg) +>>> polymg = PolymatrixGame.from_normal_form_game(nfg) >>> print(polymg) 2-player PolymatrixGame with payoff matrices: (0, 1): @@ -31,6 +31,7 @@ """ +import warnings import numpy as np from itertools import product from math import isqrt @@ -220,7 +221,7 @@ def __init__( self.polymatrix[(p1, p2)] = matrix_builder @classmethod - def from_nf( + def from_normal_form_game( cls, nf: NormalFormGame, is_polymatrix: bool = True @@ -263,6 +264,24 @@ def from_nf( return cls(polymatrix_builder) + @classmethod + def from_nf(cls, nf: NormalFormGame, is_polymatrix: bool = True): + """ + Creates a Polymatrix from a Normal Form Game. + + .. deprecated:: 0.13.0 + + Use `from_normal_form_game` instead. + + """ + warnings.warn( + "`PolymatrixGame.from_nf` is deprecated. " + "Use `PolymatrixGame.from_normal_form_game` instead.", + DeprecationWarning, + stacklevel=2, + ) + return cls.from_normal_form_game(nf, is_polymatrix=is_polymatrix) + def get_player(self, player_idx: int) -> Player: """ Calculates the payoff function of a player. @@ -288,7 +307,7 @@ def get_player(self, player_idx: int) -> Player: ]) return Player(payoff_array) - def to_nfg(self) -> NormalFormGame: + def to_normal_form_game(self) -> NormalFormGame: """ Creates a Normal Form Game from the Polymatrix Game. @@ -301,6 +320,23 @@ def to_nfg(self) -> NormalFormGame: return nfg + def to_nfg(self) -> NormalFormGame: + """ + Creates a Normal Form Game from the Polymatrix Game. + + .. deprecated:: 0.13.0 + + Use `to_normal_form_game` instead. + + """ + warnings.warn( + "`PolymatrixGame.to_nfg` is deprecated. " + "Use `PolymatrixGame.to_normal_form_game` instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.to_normal_form_game() + def range_of_payoffs(self) -> tuple[float, float]: """ The lowest and highest components of payoff from diff --git a/quantecon/game_theory/tests/test_howson_lcp.py b/quantecon/game_theory/tests/test_howson_lcp.py index de30fd5b..c394c807 100644 --- a/quantecon/game_theory/tests/test_howson_lcp.py +++ b/quantecon/game_theory/tests/test_howson_lcp.py @@ -23,7 +23,7 @@ def test_polym_lcp_solver_where_solution_is_pure_NE(): filename = "big_polym.gam" nfg = from_gam(os.path.join(data_dir, filename)) - polymg = PolymatrixGame.from_nf(nfg) + polymg = PolymatrixGame.from_normal_form_game(nfg) ne = polym_lcp_solver(polymg) worked = nfg.is_nash(ne) assert_(worked) @@ -32,7 +32,7 @@ def test_polym_lcp_solver_where_solution_is_pure_NE(): def test_polym_lcp_solver_where_lcp_solver_must_backtrack(): filename = "triggers_back_case.gam" nfg = from_gam(os.path.join(data_dir, filename)) - polymg = PolymatrixGame.from_nf(nfg) + polymg = PolymatrixGame.from_normal_form_game(nfg) ne = polym_lcp_solver(polymg) worked = nfg.is_nash(ne) assert_(worked) @@ -54,7 +54,7 @@ def test_solves_rock_paper_scissors(): polymg = PolymatrixGame( polymatrix ) - nfg = polymg.to_nfg() + nfg = polymg.to_normal_form_game() ne = polym_lcp_solver(polymg) worked = nfg.is_nash(ne) assert_(worked) @@ -98,7 +98,7 @@ def test_solves_rps_with_scissorless_third_player(): polymg = PolymatrixGame( polymatrix ) - nfg = polymg.to_nfg() + nfg = polymg.to_normal_form_game() ne = polym_lcp_solver(polymg) worked = nfg.is_nash(ne) assert_(worked) @@ -144,7 +144,7 @@ def test_solves_rps_with_rocking_third_player(): polymg = PolymatrixGame( polymatrix ) - nfg = polymg.to_nfg() + nfg = polymg.to_normal_form_game() ne = polym_lcp_solver(polymg) worked = nfg.is_nash(ne) assert_(worked) @@ -297,7 +297,7 @@ def test_solves_multiplayer_rps_like(): polymatrix, nums_actions=[3, 2, 2, 2, 3, 2], ) - nfg = polymg.to_nfg() + nfg = polymg.to_normal_form_game() ne = polym_lcp_solver(polymg) worked = nfg.is_nash(ne, tol=1e-5) assert_(worked) @@ -306,7 +306,7 @@ def test_solves_multiplayer_rps_like(): def test_different_starting(): filename = "triggers_back_case.gam" nfg = from_gam(os.path.join(data_dir, filename)) - polymg = PolymatrixGame.from_nf(nfg) + polymg = PolymatrixGame.from_normal_form_game(nfg) starting = [3, 2, 2, 0, 3] # We also notice that changing the start # can avoid the backrtrack @@ -361,7 +361,7 @@ def test_howson_lcp_degenerate(self): for d in self.game_dicts: for k in d['NEs_dict'].keys(): NE_computed, res = polym_lcp_solver( - PolymatrixGame.from_nf(d['g']), + PolymatrixGame.from_normal_form_game(d['g']), full_output=True ) for action_computed, action in zip(NE_computed, diff --git a/quantecon/game_theory/tests/test_polymatrix_game.py b/quantecon/game_theory/tests/test_polymatrix_game.py index 56523b4d..031ed090 100644 --- a/quantecon/game_theory/tests/test_polymatrix_game.py +++ b/quantecon/game_theory/tests/test_polymatrix_game.py @@ -2,6 +2,7 @@ Tests for polymatrix_game.py """ +import pytest from numpy.testing import assert_, assert_raises from quantecon.game_theory.game_converters import from_gam from quantecon.game_theory import NormalFormGame, PolymatrixGame @@ -61,23 +62,24 @@ def test_same_games_are_close(self): assert_(are_close) def test_normal_form_to_polymatrix_to_normal_form_multiplayer(self): - polymg = PolymatrixGame.from_nf(self.pmg1, is_polymatrix=True) - back_in_nf = polymg.to_nfg() + polymg = PolymatrixGame.from_normal_form_game( + self.pmg1, is_polymatrix=True) + back_in_nf = polymg.to_normal_form_game() are_close = close_normal_form_games(self.pmg1, back_in_nf) assert_(are_close) def test_normal_form_to_polymatrix_to_normal_form_bimatrix(self): - polymg = PolymatrixGame.from_nf( + polymg = PolymatrixGame.from_normal_form_game( self.bimatrix_game, is_polymatrix=True) - back_in_nf = polymg.to_nfg() + back_in_nf = polymg.to_normal_form_game() are_close = close_normal_form_games( self.bimatrix_game, back_in_nf) assert_(are_close) def test_comes_up_with_approximation(self): - polymg = PolymatrixGame.from_nf( + polymg = PolymatrixGame.from_normal_form_game( self.non_pmg, is_polymatrix=False) - back_in_nf = polymg.to_nfg() + back_in_nf = polymg.to_normal_form_game() assert_(not close_normal_form_games( self.non_pmg, back_in_nf @@ -85,11 +87,18 @@ def test_comes_up_with_approximation(self): def test_nonpolymatrix_gets_error_if_is_polymatrix_flag(self): with assert_raises(AssertionError): - PolymatrixGame.from_nf( + PolymatrixGame.from_normal_form_game( self.non_pmg, is_polymatrix=True ) + def test_deprecated_names_warn(self): + with pytest.warns(DeprecationWarning, match="from_nf"): + polymg = PolymatrixGame.from_nf(self.pmg1, is_polymatrix=True) + with pytest.warns(DeprecationWarning, match="to_nfg"): + back_in_nf = polymg.to_nfg() + assert_(close_normal_form_games(self.pmg1, back_in_nf)) + def test_matchups_get_filled_with_zeros(self): polymatrix = { (0, 1): [