From bda1bb31fd879723e73ba53c6b3987011d2e1eff Mon Sep 17 00:00:00 2001 From: Daisuke Oyama Date: Sat, 3 Oct 2026 15:05:46 +0900 Subject: [PATCH 1/2] MAINT: Rename PolymatrixGame.from_nf and to_nfg Rename them to `from_normal_form_game` and `to_normal_form_game`, as "nfg" now refers to the Gambit .nfg format in `game_converters`. The old names remain as deprecated aliases that emit a DeprecationWarning. Co-Authored-By: Claude Fable 5.1 --- quantecon/game_theory/polymatrix_game.py | 42 +++++++++++++++++-- .../game_theory/tests/test_howson_lcp.py | 16 +++---- .../game_theory/tests/test_polymatrix_game.py | 23 ++++++---- 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/quantecon/game_theory/polymatrix_game.py b/quantecon/game_theory/polymatrix_game.py index 7ec0efbc5..deca66b15 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.12.1 + + 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.12.1 + + 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 de30fd5b7..c394c8074 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 56523b4d1..031ed0903 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): [ From d17a0f1cafee78a14c4710fc9d3ef8a37f0b1565 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 8 Oct 2026 10:24:55 +1100 Subject: [PATCH 2/2] DOC: Set the deprecation version of from_nf and to_nfg to 0.13.0 The next release is 0.13.0, matching the version used in #953. Co-Authored-By: Claude Fable 5.1 --- quantecon/game_theory/polymatrix_game.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quantecon/game_theory/polymatrix_game.py b/quantecon/game_theory/polymatrix_game.py index deca66b15..f071c2802 100644 --- a/quantecon/game_theory/polymatrix_game.py +++ b/quantecon/game_theory/polymatrix_game.py @@ -269,7 +269,7 @@ def from_nf(cls, nf: NormalFormGame, is_polymatrix: bool = True): """ Creates a Polymatrix from a Normal Form Game. - .. deprecated:: 0.12.1 + .. deprecated:: 0.13.0 Use `from_normal_form_game` instead. @@ -324,7 +324,7 @@ def to_nfg(self) -> NormalFormGame: """ Creates a Normal Form Game from the Polymatrix Game. - .. deprecated:: 0.12.1 + .. deprecated:: 0.13.0 Use `to_normal_form_game` instead.