Skip to content

Commit 120ab73

Browse files
oyamadmmcky
authored andcommitted
Add random_game, covariance_game (#270)
1 parent 43ecfa3 commit 120ab73

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

quantecon/game_theory/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
"""
55
from .normal_form_game import Player, NormalFormGame
66
from .normal_form_game import pure2mixed, best_response_2p
7+
from .random import random_game, covariance_game

quantecon/game_theory/random.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
"""
2+
Filename: random.py
3+
4+
Author: Daisuke Oyama
5+
6+
Generate random NormalFormGame instances.
7+
8+
"""
9+
import numpy as np
10+
11+
from .normal_form_game import Player, NormalFormGame
12+
from ..util import check_random_state
13+
14+
15+
def random_game(nums_actions, random_state=None):
16+
"""
17+
Return a random NormalFormGame instance where the payoffs are drawn
18+
independently from the uniform distribution on [0, 1).
19+
20+
Parameters
21+
----------
22+
nums_actions : tuple(int)
23+
Tuple of the numbers of actions, one for each player.
24+
25+
random_state : scalar(int) or np.random.RandomState,
26+
optional(default=None)
27+
Random seed (integer) or np.random.RandomState instance to set
28+
the initial state of the random number generator for
29+
reproducibility. If None, a randomly initialized RandomState is
30+
used.
31+
32+
Returns
33+
-------
34+
g : NormalFormGame
35+
36+
"""
37+
N = len(nums_actions)
38+
if N == 0:
39+
raise ValueError('nums_actions must be non-empty')
40+
41+
random_state = check_random_state(random_state)
42+
players = [
43+
Player(random_state.random_sample(nums_actions[i:]+nums_actions[:i]))
44+
for i in range(N)
45+
]
46+
g = NormalFormGame(players)
47+
return g
48+
49+
50+
def covariance_game(nums_actions, rho, random_state=None):
51+
"""
52+
Return a random NormalFormGame instance where the payoff profiles
53+
are drawn independently from the standard multi-normal with the
54+
covariance of any pair of payoffs equal to `rho`, as studied in
55+
[1]_.
56+
57+
Parameters
58+
----------
59+
nums_actions : tuple(int)
60+
Tuple of the numbers of actions, one for each player.
61+
62+
rho : scalar(float)
63+
Covariance of a pair of payoff values. Must be in [-1/(N-1), 1],
64+
where N is the number of players.
65+
66+
random_state : scalar(int) or np.random.RandomState,
67+
optional(default=None)
68+
Random seed (integer) or np.random.RandomState instance to set
69+
the initial state of the random number generator for
70+
reproducibility. If None, a randomly initialized RandomState is
71+
used.
72+
73+
Returns
74+
-------
75+
g : NormalFormGame
76+
77+
References
78+
----------
79+
.. [1] Y. Rinott and M. Scarsini, "On the Number of Pure Strategy
80+
Nash Equilibria in Random Games," Games and Economic Behavior
81+
(2000), 274-293.
82+
83+
"""
84+
N = len(nums_actions)
85+
if N <= 1:
86+
raise ValueError('length of nums_actions must be at least 2')
87+
if not (-1 / (N - 1) <= rho <= 1):
88+
lb = '-1' if N == 2 else '-1/{0}'.format(N-1)
89+
raise ValueError('rho must be in [{0}, 1]'.format(lb))
90+
91+
mean = np.zeros(N)
92+
cov = np.empty((N, N))
93+
cov.fill(rho)
94+
cov[range(N), range(N)] = 1
95+
96+
random_state = check_random_state(random_state)
97+
payoff_profile_array = \
98+
random_state.multivariate_normal(mean, cov, nums_actions)
99+
g = NormalFormGame(payoff_profile_array)
100+
return g
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Filename: test_random.py
3+
Author: Daisuke Oyama
4+
5+
Tests for game_theory/random.py
6+
7+
"""
8+
import numpy as np
9+
from numpy.testing import assert_allclose, assert_raises
10+
from nose.tools import eq_
11+
12+
from quantecon.game_theory import random_game, covariance_game
13+
14+
15+
def test_random_game():
16+
nums_actions = (2, 3, 4)
17+
g = random_game(nums_actions)
18+
eq_(g.nums_actions, nums_actions)
19+
20+
21+
def test_covariance_game():
22+
nums_actions = (2, 3, 4)
23+
N = len(nums_actions)
24+
25+
rho = 0.5
26+
g = covariance_game(nums_actions, rho=rho)
27+
eq_(g.nums_actions, nums_actions)
28+
29+
rho = 1
30+
g = covariance_game(nums_actions, rho=rho)
31+
for a in np.ndindex(*nums_actions):
32+
for i in range(N-1):
33+
payoff_profile = g.payoff_profile_array[a]
34+
assert_allclose(payoff_profile[i], payoff_profile[-1])
35+
36+
rho = -1 / (N - 1)
37+
g = covariance_game(nums_actions, rho=rho)
38+
for a in np.ndindex(*nums_actions):
39+
assert_allclose(g.payoff_profile_array.sum(axis=-1),
40+
np.zeros(nums_actions),
41+
atol=1e-10)
42+
43+
44+
def test_random_game_value_error():
45+
nums_actions = () # empty
46+
assert_raises(ValueError, random_game, nums_actions)
47+
48+
49+
def test_covariance_game_value_error():
50+
nums_actions = () # empty
51+
assert_raises(ValueError, covariance_game, nums_actions, rho=0)
52+
53+
nums_actions = (2,) # length one
54+
assert_raises(ValueError, covariance_game, nums_actions, rho=0)
55+
56+
nums_actions = (2, 3, 4)
57+
58+
rho = 1.1 # > 1
59+
assert_raises(ValueError, covariance_game, nums_actions, rho)
60+
61+
rho = -1 # < -1/(N-1)
62+
assert_raises(ValueError, covariance_game, nums_actions, rho)
63+
64+
65+
if __name__ == '__main__':
66+
import sys
67+
import nose
68+
69+
argv = sys.argv[:]
70+
argv.append('--verbose')
71+
argv.append('--nocapture')
72+
nose.main(argv=argv, defaultTest=__file__)

0 commit comments

Comments
 (0)