Skip to content

Commit

Permalink
Merge pull request #654 from QuantEcon/np-random-generator
Browse files Browse the repository at this point in the history
ENH: check_random_state: Accept `np.random.Generator`
  • Loading branch information
oyamad authored Nov 27, 2022
2 parents c20ea25 + 46b2bd3 commit 366c558
Show file tree
Hide file tree
Showing 29 changed files with 303 additions and 226 deletions.
4 changes: 2 additions & 2 deletions docs/rtd-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ sphinx
ipython
numpydoc
numba>=0.38
numpy>=1.2
numpy>=1.17
sympy
scipy>=1.0
scipy>=1.5
requests
matplotlib
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ dynamic = ["description", "version"]
requires-python = ">=3.7"
dependencies = [
'numba',
'numpy',
'numpy>=1.17.0',
'requests',
'scipy>=1.0.0',
'scipy>=1.5.0',
'sympy',
]

Expand Down
10 changes: 5 additions & 5 deletions quantecon/arma.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,11 @@ def simulation(self, ts_length=90, random_state=None):
ts_length : scalar(int), optional(default=90)
Number of periods to simulate for
random_state : int or np.random.RandomState, optional
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.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number
generator for reproducibility. If None, a randomly
initialized RandomState is used.
Returns
-------
Expand Down
10 changes: 5 additions & 5 deletions quantecon/discrete_rv.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ def draw(self, k=1, random_state=None):
k : scalar(int), optional
Number of draws to be returned
random_state : int or np.random.RandomState, optional
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.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number
generator for reproducibility. If None, a randomly
initialized RandomState is used.
Returns
-------
Expand Down
4 changes: 2 additions & 2 deletions quantecon/game_theory/brd.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
from .normal_form_game import Player
from ..util import check_random_state
from ..util import check_random_state, rng_integers
from .random import random_pure_actions


Expand Down Expand Up @@ -112,7 +112,7 @@ def time_series(self, ts_length, init_action_dist=None, **options):

out = np.empty((ts_length, self.num_actions), dtype=int)
random_state = check_random_state(random_state)
player_ind_seq = random_state.randint(self.N, size=ts_length)
player_ind_seq = rng_integers(random_state, self.N, size=ts_length)
action_dist = np.asarray(init_action_dist)
for t in range(ts_length):
out[t, :] = action_dist[:]
Expand Down
52 changes: 26 additions & 26 deletions quantecon/game_theory/game_generators/bimatrix_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
import scipy.special
from numba import jit
from ..normal_form_game import Player, NormalFormGame
from ...util import check_random_state
from ...util import check_random_state, rng_integers
from ...gridtools import simplex_grid
from ...graph_tools import random_tournament_graph
from ...util.combinatorics import next_k_array, k_array_rank_jit
Expand Down Expand Up @@ -129,11 +129,11 @@ def blotto_game(h, t, rho, mu=0, random_state=None):
[-1, 1].
mu : scalar(float), optional(default=0)
Mean of the players' values of each hill.
random_state : int or np.random.RandomState, optional
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.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number generator
for reproducibility. If None, a randomly initialized RandomState
is used.
Returns
-------
Expand Down Expand Up @@ -225,11 +225,11 @@ def ranking_game(n, steps=10, random_state=None):
the costs are multiples of `1/(n*steps)`, where the cost of
effort level `0` is 0, and the maximum possible cost of effort
level `n-1` is less than or equal to 1.
random_state : int or np.random.RandomState, optional
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.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number generator
for reproducibility. If None, a randomly initialized RandomState
is used.
Returns
-------
Expand All @@ -255,11 +255,11 @@ def ranking_game(n, steps=10, random_state=None):
payoff_arrays = tuple(np.empty((n, n)) for i in range(2))
random_state = check_random_state(random_state)

scores = random_state.randint(1, steps+1, size=(2, n))
scores = rng_integers(random_state, 1, steps+1, size=(2, n))
scores.cumsum(axis=1, out=scores)

costs = np.empty((2, n-1))
costs[:] = random_state.randint(1, steps+1, size=(2, n-1))
costs[:] = rng_integers(random_state, 1, steps+1, size=(2, n-1))
costs.cumsum(axis=1, out=costs)
costs[:] /= (n * steps)

Expand Down Expand Up @@ -415,11 +415,11 @@ def tournament_game(n, k, random_state=None):
Number of nodes in the tournament graph.
k : scalar(int)
Size of subsets of nodes in the tournament graph.
random_state : int or np.random.RandomState, optional
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.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number generator
for reproducibility. If None, a randomly initialized RandomState
is used.
Returns
-------
Expand Down Expand Up @@ -548,11 +548,11 @@ def unit_vector_game(n, avoid_pure_nash=False, random_state=None):
If True, player 0's payoffs will be placed in order to avoid
pure Nash equilibria. (If necessary, the payoffs for player 1
are redrawn so as not to have a dominant action.)
random_state : int or np.random.RandomState, optional
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.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number generator
for reproducibility. If None, a randomly initialized RandomState
is used.
Returns
-------
Expand Down Expand Up @@ -593,7 +593,7 @@ def unit_vector_game(n, avoid_pure_nash=False, random_state=None):
payoff_arrays = (np.zeros((n, n)), random_state.random((n, n)))

if not avoid_pure_nash:
ones_ind = random_state.randint(n, size=n)
ones_ind = rng_integers(random_state, n, size=n)
payoff_arrays[0][ones_ind, np.arange(n)] = 1
else:
if n == 1:
Expand All @@ -609,9 +609,9 @@ def unit_vector_game(n, avoid_pure_nash=False, random_state=None):
is_suboptimal.sum(axis=1, out=nums_suboptimal)

for i in range(n):
one_ind = random_state.randint(n)
one_ind = rng_integers(random_state, n)
while not is_suboptimal[i, one_ind]:
one_ind = random_state.randint(n)
one_ind = rng_integers(random_state, n)
payoff_arrays[0][one_ind, i] = 1

g = NormalFormGame(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ def test_seed(self):
seed = 0
h, t = 3, 4
rho = -0.5
g0 = blotto_game(h, t, rho, random_state=seed)
g1 = blotto_game(h, t, rho, random_state=seed)
assert_array_equal(g1.payoff_profile_array, g0.payoff_profile_array)
for gen in [lambda x: x, np.random.default_rng]:
gs = [
blotto_game(h, t, rho, random_state=gen(seed))
for i in range(2)
]
assert_array_equal(*[g.payoff_profile_array for g in gs])


class TestRankingGame:
Expand All @@ -59,9 +62,9 @@ def test_elements_first_row(self):
def test_seed(self):
seed = 0
n = 100
g0 = ranking_game(n, random_state=seed)
g1 = ranking_game(n, random_state=seed)
assert_array_equal(g1.payoff_profile_array, g0.payoff_profile_array)
for gen in [lambda x: x, np.random.default_rng]:
gs = [ranking_game(n, random_state=gen(seed)) for i in range(2)]
assert_array_equal(*[g.payoff_profile_array for g in gs])


def test_sgc_game():
Expand Down Expand Up @@ -106,9 +109,12 @@ def test_payoff_values(self):

def test_seed(self):
seed = 0
g0 = tournament_game(self.n, self.k, random_state=seed)
g1 = tournament_game(self.n, self.k, random_state=seed)
assert_array_equal(g1.payoff_profile_array, g0.payoff_profile_array)
for gen in [lambda x: x, np.random.default_rng]:
gs = [
tournament_game(self.n, self.k, random_state=gen(seed))
for i in range(2)
]
assert_array_equal(*[g.payoff_profile_array for g in gs])

def test_raises_value_error_too_large_inputs(self):
n, k = 100, 50
Expand All @@ -135,9 +141,11 @@ def test_avoid_pure_nash(self):
def test_seed(self):
seed = 0
n = 100
g0 = unit_vector_game(n, random_state=seed)
g1 = unit_vector_game(n, random_state=seed)
assert_array_equal(g1.payoff_profile_array, g0.payoff_profile_array)
for gen in [lambda x: x, np.random.default_rng]:
gs = [
unit_vector_game(n, random_state=gen(seed)) for i in range(2)
]
assert_array_equal(*[g.payoff_profile_array for g in gs])

def test_redraw(self):
seed = 1
Expand Down
8 changes: 5 additions & 3 deletions quantecon/game_theory/localint.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np
import numbers
from scipy import sparse
from ..util import check_random_state
from ..util import check_random_state, rng_integers
from .random import random_pure_actions
from .normal_form_game import Player

Expand Down Expand Up @@ -112,7 +112,8 @@ def play(self, revision='simultaneous', actions=None,
elif revision == 'asynchronous':
if player_ind_seq is None:
random_state = check_random_state(random_state)
player_ind_seq = random_state.randint(self.N, size=num_reps)
player_ind_seq = rng_integers(random_state, self.N,
size=num_reps)
elif isinstance(player_ind_seq, numbers.Integral):
player_ind_seq = [player_ind_seq]
else:
Expand Down Expand Up @@ -176,7 +177,8 @@ def time_series(self, ts_length, revision='simultaneous',
elif revision == 'asynchronous':
if player_ind_seq is None:
random_state = check_random_state(random_state)
player_ind_seq = random_state.randint(self.N, size=ts_length)
player_ind_seq = rng_integers(random_state, self.N,
size=ts_length)
else:
raise ValueError(
"revision must be `simultaneous` or `asynchronous`"
Expand Down
10 changes: 5 additions & 5 deletions quantecon/game_theory/logitdyn.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np
import numbers
from .normal_form_game import NormalFormGame
from ..util import check_random_state
from ..util import check_random_state, rng_integers
from .random import random_pure_actions


Expand Down Expand Up @@ -92,7 +92,7 @@ def play(self, init_actions=None, player_ind_seq=None, num_reps=1,
num_reps : scalar(int), optional(default=1)
The number of iterations.
random_state : np.random.RandomState, optional(default=None)
random_state : int or np.random.RandomState/Generator, optional
Random number generator used.
Returns
Expand All @@ -109,7 +109,7 @@ def play(self, init_actions=None, player_ind_seq=None, num_reps=1,

if player_ind_seq is None:
random_state = check_random_state(random_state)
player_ind_seq = random_state.randint(self.N, size=num_reps)
player_ind_seq = rng_integers(random_state, self.N, size=num_reps)

if isinstance(player_ind_seq, numbers.Integral):
player_ind_seq = [player_ind_seq]
Expand All @@ -134,7 +134,7 @@ def time_series(self, ts_length, init_actions=None, random_state=None):
The action profile in the initial period. If None, selected
randomly.
random_state : np.random.RandomState, optional(default=None)
random_state : int or np.random.RandomState/Generator, optional
Random number generator used.
Returns
Expand All @@ -150,7 +150,7 @@ def time_series(self, ts_length, init_actions=None, random_state=None):

out = np.empty((ts_length, self.N), dtype=int)
random_state = check_random_state(random_state)
player_ind_seq = random_state.randint(self.N, size=ts_length)
player_ind_seq = rng_integers(random_state, self.N, size=ts_length)

for t, player_ind in enumerate(player_ind_seq):
out[t, :] = actions[:]
Expand Down
25 changes: 13 additions & 12 deletions quantecon/game_theory/normal_form_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
import numpy as np
from numba import jit

from ..util import check_random_state
from ..util import check_random_state, rng_integers


class Player:
Expand Down Expand Up @@ -339,11 +339,12 @@ def best_response(self, opponents_actions, tie_breaking='smallest',
Tolerance level used in determining best responses. If None,
default to the value of the `tol` attribute.
random_state : int or np.random.RandomState, optional
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. Relevant only when tie_breaking='random'.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number
generator for reproducibility. If None, a randomly
initialized RandomState is used. Relevant only when
tie_breaking='random'.
Returns
-------
Expand Down Expand Up @@ -388,11 +389,11 @@ def random_choice(self, actions=None, random_state=None):
actions : array_like(int), optional(default=None)
An array of integers representing pure actions.
random_state : int or np.random.RandomState, optional
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.
random_state : int or np.random.RandomState/Generator, optional
Random seed (integer) or np.random.RandomState or Generator
instance to set the initial state of the random number
generator for reproducibility. If None, a randomly
initialized RandomState is used.
Returns
-------
Expand All @@ -412,7 +413,7 @@ def random_choice(self, actions=None, random_state=None):
if n == 1:
idx = 0
else:
idx = random_state.randint(n)
idx = rng_integers(random_state, n)

if actions is not None:
return actions[idx]
Expand Down
Loading

0 comments on commit 366c558

Please sign in to comment.