-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add random_game, covariance_game (#270)
- Loading branch information
Showing
3 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
""" | ||
Filename: random.py | ||
Author: Daisuke Oyama | ||
Generate random NormalFormGame instances. | ||
""" | ||
import numpy as np | ||
|
||
from .normal_form_game import Player, NormalFormGame | ||
from ..util import check_random_state | ||
|
||
|
||
def random_game(nums_actions, random_state=None): | ||
""" | ||
Return a random NormalFormGame instance where the payoffs are drawn | ||
independently from the uniform distribution on [0, 1). | ||
Parameters | ||
---------- | ||
nums_actions : tuple(int) | ||
Tuple of the numbers of actions, one for each player. | ||
random_state : scalar(int) or np.random.RandomState, | ||
optional(default=None) | ||
Random seed (integer) or np.random.RandomState instance to set | ||
the initial state of the random number generator for | ||
reproducibility. If None, a randomly initialized RandomState is | ||
used. | ||
Returns | ||
------- | ||
g : NormalFormGame | ||
""" | ||
N = len(nums_actions) | ||
if N == 0: | ||
raise ValueError('nums_actions must be non-empty') | ||
|
||
random_state = check_random_state(random_state) | ||
players = [ | ||
Player(random_state.random_sample(nums_actions[i:]+nums_actions[:i])) | ||
for i in range(N) | ||
] | ||
g = NormalFormGame(players) | ||
return g | ||
|
||
|
||
def covariance_game(nums_actions, rho, random_state=None): | ||
""" | ||
Return a random NormalFormGame instance where the payoff profiles | ||
are drawn independently from the standard multi-normal with the | ||
covariance of any pair of payoffs equal to `rho`, as studied in | ||
[1]_. | ||
Parameters | ||
---------- | ||
nums_actions : tuple(int) | ||
Tuple of the numbers of actions, one for each player. | ||
rho : scalar(float) | ||
Covariance of a pair of payoff values. Must be in [-1/(N-1), 1], | ||
where N is the number of players. | ||
random_state : scalar(int) or np.random.RandomState, | ||
optional(default=None) | ||
Random seed (integer) or np.random.RandomState instance to set | ||
the initial state of the random number generator for | ||
reproducibility. If None, a randomly initialized RandomState is | ||
used. | ||
Returns | ||
------- | ||
g : NormalFormGame | ||
References | ||
---------- | ||
.. [1] Y. Rinott and M. Scarsini, "On the Number of Pure Strategy | ||
Nash Equilibria in Random Games," Games and Economic Behavior | ||
(2000), 274-293. | ||
""" | ||
N = len(nums_actions) | ||
if N <= 1: | ||
raise ValueError('length of nums_actions must be at least 2') | ||
if not (-1 / (N - 1) <= rho <= 1): | ||
lb = '-1' if N == 2 else '-1/{0}'.format(N-1) | ||
raise ValueError('rho must be in [{0}, 1]'.format(lb)) | ||
|
||
mean = np.zeros(N) | ||
cov = np.empty((N, N)) | ||
cov.fill(rho) | ||
cov[range(N), range(N)] = 1 | ||
|
||
random_state = check_random_state(random_state) | ||
payoff_profile_array = \ | ||
random_state.multivariate_normal(mean, cov, nums_actions) | ||
g = NormalFormGame(payoff_profile_array) | ||
return g |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
""" | ||
Filename: test_random.py | ||
Author: Daisuke Oyama | ||
Tests for game_theory/random.py | ||
""" | ||
import numpy as np | ||
from numpy.testing import assert_allclose, assert_raises | ||
from nose.tools import eq_ | ||
|
||
from quantecon.game_theory import random_game, covariance_game | ||
|
||
|
||
def test_random_game(): | ||
nums_actions = (2, 3, 4) | ||
g = random_game(nums_actions) | ||
eq_(g.nums_actions, nums_actions) | ||
|
||
|
||
def test_covariance_game(): | ||
nums_actions = (2, 3, 4) | ||
N = len(nums_actions) | ||
|
||
rho = 0.5 | ||
g = covariance_game(nums_actions, rho=rho) | ||
eq_(g.nums_actions, nums_actions) | ||
|
||
rho = 1 | ||
g = covariance_game(nums_actions, rho=rho) | ||
for a in np.ndindex(*nums_actions): | ||
for i in range(N-1): | ||
payoff_profile = g.payoff_profile_array[a] | ||
assert_allclose(payoff_profile[i], payoff_profile[-1]) | ||
|
||
rho = -1 / (N - 1) | ||
g = covariance_game(nums_actions, rho=rho) | ||
for a in np.ndindex(*nums_actions): | ||
assert_allclose(g.payoff_profile_array.sum(axis=-1), | ||
np.zeros(nums_actions), | ||
atol=1e-10) | ||
|
||
|
||
def test_random_game_value_error(): | ||
nums_actions = () # empty | ||
assert_raises(ValueError, random_game, nums_actions) | ||
|
||
|
||
def test_covariance_game_value_error(): | ||
nums_actions = () # empty | ||
assert_raises(ValueError, covariance_game, nums_actions, rho=0) | ||
|
||
nums_actions = (2,) # length one | ||
assert_raises(ValueError, covariance_game, nums_actions, rho=0) | ||
|
||
nums_actions = (2, 3, 4) | ||
|
||
rho = 1.1 # > 1 | ||
assert_raises(ValueError, covariance_game, nums_actions, rho) | ||
|
||
rho = -1 # < -1/(N-1) | ||
assert_raises(ValueError, covariance_game, nums_actions, rho) | ||
|
||
|
||
if __name__ == '__main__': | ||
import sys | ||
import nose | ||
|
||
argv = sys.argv[:] | ||
argv.append('--verbose') | ||
argv.append('--nocapture') | ||
nose.main(argv=argv, defaultTest=__file__) |