Skip to content

Commit f1b0769

Browse files
committed
ENH: Add jump for MRG32K3A
Add jump that will jump the state as-if 2**127 samples have been drawn
1 parent 3d554a8 commit f1b0769

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

randomstate/shims/mrg32k3a/mrg32k3a.pxi

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
DEF RS_RNG_NAME = 'mrg32k3a'
2+
DEF RS_RNG_JUMPABLE = 1
23

34
cdef extern from "distributions.h":
45

@@ -41,6 +42,48 @@ cdef object _set_state(aug_state *state, object state_info):
4142
state.rng.s21 = state_info[4]
4243
state.rng.s22 = state_info[5]
4344

45+
cdef object matrix_power_127(x, m):
46+
n = x.shape[0]
47+
# Start at power 1
48+
out = x.copy()
49+
current_pow = x.copy()
50+
for i in range(7):
51+
current_pow = np.mod(current_pow.dot(current_pow), m)
52+
out = np.mod(out.dot(current_pow), m)
53+
return out
54+
55+
m1 = np.int64(4294967087)
56+
a12 = np.int64(1403580)
57+
a13n = np.int64(810728)
58+
A1 = np.array([[0, 1, 0], [0, 0, 1], [-a13n, a12, 0]], dtype=np.int64)
59+
A1p = np.mod(A1, m1).astype(np.uint64)
60+
A1_127 = matrix_power_127(A1p, m1)
61+
62+
a21 = np.int64(527612)
63+
a23n = np.int64(1370589)
64+
A2 = np.array([[0, 1, 0], [0, 0, 1], [-a23n, 0, a21]], dtype=np.int64)
65+
m2 = np.int64(4294944443)
66+
A2p = np.mod(A2, m2).astype(np.uint64)
67+
A2_127 = matrix_power_127(A2p, m2)
68+
69+
cdef void jump_state(aug_state* state):
70+
# vectors s1 and s2
71+
s1 = np.array([state.rng.s10,state.rng.s11,state.rng.s12], dtype=np.uint64)
72+
s2 = np.array([state.rng.s20,state.rng.s21,state.rng.s22], dtype=np.uint64)
73+
74+
# Advance the state
75+
s1 = np.mod(A1_127.dot(s1), m1)
76+
s2 = np.mod(A1_127.dot(s2), m2)
77+
78+
# Restore state
79+
state.rng.s10 = s1[0]
80+
state.rng.s11 = s1[1]
81+
state.rng.s12 = s1[2]
82+
83+
state.rng.s20 = s2[0]
84+
state.rng.s21 = s2[1]
85+
state.rng.s22 = s2[2]
86+
4487
DEF CLASS_DOCSTRING = """
4588
RandomState(seed=None)
4689
@@ -83,11 +126,30 @@ The state of the MRG32KA PRNG is represented by 6 64-bit integers.
83126
This implementation is integer based and produces integers in the interval
84127
:math:`[0, 2^{32}-209+1]`. These are treated as if they 32-bit random integers.
85128
129+
**Parallel Features**
130+
131+
``mrg32k3a.RandomState`` can be used in parallel applications by
132+
calling the method ``jump`` which advances the
133+
the state as-if :math:`2^{127}` random numbers have been generated [3]_. This
134+
allow the original sequence to be split so that distinct segments can be used
135+
on each worker process. All generators should be initialized with the same
136+
seed to ensure that the segments come from the same sequence.
137+
138+
>>> import randomstate.prng.mrg32k3a as rnd
139+
>>> rs = [rnd.RandomState(12345) for _ in range(10)]
140+
# Advance rs[i] by i jumps
141+
>>> for i in range(10):
142+
rs[i].jump(i)
143+
144+
86145
References
87146
----------
88147
.. [1] "Software developed by the Canada Research Chair in Stochastic
89148
Simulation and Optimization", http://simul.iro.umontreal.ca/
90149
.. [2] Pierre L'Ecuyer, (1999) "Good Parameters and Implementations for
91150
Combined Multiple Recursive Random Number Generators.", Operations
92151
Research 47(1):159-164
152+
.. [3] L'ecuyer, Pierre, Richard Simard, E. Jack Chen, and W. David Kelton.
153+
"An object-oriented random-number package with many long streams
154+
and substreams." Operations research 50, no. 6, pp. 1073-1075, 2002.
93155
"""

0 commit comments

Comments
 (0)