|
1 | 1 | DEF RS_RNG_NAME = 'mrg32k3a'
|
| 2 | +DEF RS_RNG_JUMPABLE = 1 |
2 | 3 |
|
3 | 4 | cdef extern from "distributions.h":
|
4 | 5 |
|
@@ -41,6 +42,48 @@ cdef object _set_state(aug_state *state, object state_info):
|
41 | 42 | state.rng.s21 = state_info[4]
|
42 | 43 | state.rng.s22 = state_info[5]
|
43 | 44 |
|
| 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 | + |
44 | 87 | DEF CLASS_DOCSTRING = """
|
45 | 88 | RandomState(seed=None)
|
46 | 89 |
|
@@ -83,11 +126,30 @@ The state of the MRG32KA PRNG is represented by 6 64-bit integers.
|
83 | 126 | This implementation is integer based and produces integers in the interval
|
84 | 127 | :math:`[0, 2^{32}-209+1]`. These are treated as if they 32-bit random integers.
|
85 | 128 |
|
| 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 | +
|
86 | 145 | References
|
87 | 146 | ----------
|
88 | 147 | .. [1] "Software developed by the Canada Research Chair in Stochastic
|
89 | 148 | Simulation and Optimization", http://simul.iro.umontreal.ca/
|
90 | 149 | .. [2] Pierre L'Ecuyer, (1999) "Good Parameters and Implementations for
|
91 | 150 | Combined Multiple Recursive Random Number Generators.", Operations
|
92 | 151 | 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. |
93 | 155 | """
|
0 commit comments