From 87037106b23e9289844eeed73c787122c56df7ac Mon Sep 17 00:00:00 2001 From: Daisuke Oyama Date: Sun, 4 Nov 2018 14:02:43 +0900 Subject: [PATCH] Add NormalFormGame.delete_action --- quantecon/game_theory/normal_form_game.py | 58 +++++++++++++++++++ .../tests/test_normal_form_game.py | 33 +++++++++++ 2 files changed, 91 insertions(+) diff --git a/quantecon/game_theory/normal_form_game.py b/quantecon/game_theory/normal_form_game.py index 409f6ff09..fcb4a4681 100644 --- a/quantecon/game_theory/normal_form_game.py +++ b/quantecon/game_theory/normal_form_game.py @@ -727,6 +727,64 @@ def __setitem__(self, action_profile, payoff_profile): tuple(action_profile[i:]) + tuple(action_profile[:i]) ] = payoff_profile[i] + def delete_action(self, player_idx, action): + """ + Return a new `NormalFormGame` instance with the action(s) + specified by `action` deleted from the action set of the player + specified by `player_idx`. Deletion is not performed in place. + + Parameters + ---------- + player_idx : scalar(int) + Index of the player to delete action(s) for. + + action : scalar(int) or array_like(int) + Integer or array like of integers representing the action(s) + to be deleted. + + Returns + ------- + NormalFormGame + Copy of `self` with the action(s) deleted as specified. + + Examples + -------- + >>> g = NormalFormGame( + ... [[(3, 0), (0, 1)], [(0, 0), (3, 1)], [(1, 1), (1, 0)]] + ... ) + >>> print(g) + 2-player NormalFormGame with payoff profile array: + [[[3, 0], [0, 1]], + [[0, 0], [3, 1]], + [[1, 1], [1, 0]]] + + Delete player `0`'s action `2` from `g`: + + >>> g1 = g.delete_action(0, 2) + >>> print(g1) + 2-player NormalFormGame with payoff profile array: + [[[3, 0], [0, 1]], + [[0, 0], [3, 1]]] + + Then delete player `1`'s action `0` from `g1`: + + >>> g2 = g1.delete_action(1, 0) + >>> print(g2) + 2-player NormalFormGame with payoff profile array: + [[[0, 1]], + [[3, 1]]] + + """ + # Allow negative indexing + if -self.N <= player_idx < 0: + player_idx = player_idx + self.N + + players_new = tuple( + player.delete_action(action, player_idx-i) + for i, player in enumerate(self.players) + ) + return NormalFormGame(players_new) + def is_nash(self, action_profile, tol=None): """ Return True if `action_profile` is a Nash equilibrium. diff --git a/quantecon/game_theory/tests/test_normal_form_game.py b/quantecon/game_theory/tests/test_normal_form_game.py index f64f2a634..057f36bf9 100644 --- a/quantecon/game_theory/tests/test_normal_form_game.py +++ b/quantecon/game_theory/tests/test_normal_form_game.py @@ -209,6 +209,17 @@ def test_getitem(self): assert_array_equal(self.g[action_profile], self.BoS_bimatrix[action_profile]) + def test_delete_action(self): + action_to_delete = 0 + for i, player in enumerate(self.g.players): + g_new = self.g.delete_action(i, action_to_delete) + actions_to_remain = \ + np.setdiff1d(np.arange(player.num_actions), action_to_delete) + assert_array_equal( + g_new.payoff_profile_array, + self.g.payoff_profile_array.take(actions_to_remain, axis=i) + ) + def test_is_nash_pure(self): ok_(not self.g.is_nash((1, 0))) @@ -239,6 +250,17 @@ def setUp(self): def test_getitem(self): assert_array_equal(self.g[0, 0, 1], [6, 4, 1]) + def test_delete_action(self): + action_to_delete = 0 + for i, player in enumerate(self.g.players): + g_new = self.g.delete_action(i, action_to_delete) + actions_to_remain = \ + np.setdiff1d(np.arange(player.num_actions), action_to_delete) + assert_array_equal( + g_new.payoff_profile_array, + self.g.payoff_profile_array.take(actions_to_remain, axis=i) + ) + def test_is_nash_pure(self): ok_(self.g.is_nash((0, 0, 0))) ok_(not self.g.is_nash((0, 0, 1))) @@ -382,6 +404,17 @@ def test_getitem(self): """Trivial game: __getitem__""" eq_(self.g[0], 0) + def test_delete_action(self): + actions_to_delete = [1, 2] + for i, player in enumerate(self.g.players): + g_new = self.g.delete_action(i, actions_to_delete) + actions_to_remain = \ + np.setdiff1d(np.arange(player.num_actions), actions_to_delete) + assert_array_equal( + g_new.payoff_profile_array, + self.g.payoff_profile_array.take(actions_to_remain, axis=i) + ) + def test_is_nash_pure(self): """Trivial game: is_nash with pure action""" ok_(self.g.is_nash((1,)))