Skip to content

Commit

Permalink
Add random_game, covariance_game (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
oyamad authored and mmcky committed Nov 14, 2016
1 parent 43ecfa3 commit 120ab73
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
1 change: 1 addition & 0 deletions quantecon/game_theory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
"""
from .normal_form_game import Player, NormalFormGame
from .normal_form_game import pure2mixed, best_response_2p
from .random import random_game, covariance_game
100 changes: 100 additions & 0 deletions quantecon/game_theory/random.py
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
72 changes: 72 additions & 0 deletions quantecon/game_theory/tests/test_random.py
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__)

0 comments on commit 120ab73

Please sign in to comment.