Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions quantecon/game_theory/polymatrix_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -31,6 +31,7 @@

"""

import warnings
import numpy as np
from itertools import product
from math import isqrt
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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.

Expand All @@ -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
Expand Down
16 changes: 8 additions & 8 deletions quantecon/game_theory/tests/test_howson_lcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down
23 changes: 16 additions & 7 deletions quantecon/game_theory/tests/test_polymatrix_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -61,35 +62,43 @@ 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
))

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): [
Expand Down
Loading