Skip to content

Commit f443577

Browse files
committed
Merge pull request #35 from bashtage/seed-doc
ENH: Add vector initializers
2 parents 4e816b3 + afceee3 commit f443577

24 files changed

+414
-145
lines changed

randomstate/defaults.pxi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ DEF RS_RNG_SEED = 1
33
DEF RS_RNG_ADVANCEABLE = 0
44
DEF RS_RNG_JUMPABLE = 0
55
DEF RS_RNG_STATE_LEN = 4
6-
DEF RS_SEED_NBYTES = 2
6+
DEF RS_SEED_NBYTES = 2
7+
DEF RS_SEED_ARRAY_BITS = 64

randomstate/interface.pyx

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ cimport numpy as np
1313
cimport cython
1414

1515
from libc cimport string
16-
from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t,
17-
int16_t, int32_t, int64_t, intptr_t)
16+
from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t,
17+
int8_t, int16_t, int32_t, int64_t, intptr_t)
18+
1819
from cpython cimport Py_INCREF
19-
from cpython.mem cimport PyMem_Malloc, PyMem_Free
2020

2121
import randomstate
2222
from binomial cimport binomial_t
23-
from cython_overrides cimport PyFloat_AsDouble, PyInt_AsLong, PyErr_Occurred, PyErr_Clear
23+
from cython_overrides cimport PyFloat_AsDouble, PyInt_AsLong
2424
from randomstate.entropy import random_entropy
2525

2626
np.import_array()
@@ -234,7 +234,9 @@ cdef class RandomState:
234234
raise ValueError("Seed must be between 0 and 4294967295")
235235
obj = obj.astype('L', casting='unsafe')
236236
with self.lock:
237-
set_seed_by_array(&self.rng_state, <unsigned long *>np.PyArray_DATA(obj), np.PyArray_DIM(obj, 0))
237+
set_seed_by_array(&self.rng_state,
238+
<unsigned long *>np.PyArray_DATA(obj),
239+
np.PyArray_DIM(obj, 0))
238240
self._reset_state_variables()
239241

240242
ELIF RS_RNG_SEED==1:
@@ -263,12 +265,36 @@ cdef class RandomState:
263265
--------
264266
RandomState
265267
"""
266-
if seed is not None:
267-
if seed < 0:
268-
raise ValueError('seed < 0')
269-
else:
270-
self.__seed = seed = _generate_seed(RS_SEED_NBYTES)
271-
set_seed(&self.rng_state, seed)
268+
try:
269+
if seed is not None:
270+
idx = operator.index(seed)
271+
if idx < 0:
272+
raise ValueError('seed < 0')
273+
else:
274+
self.__seed = seed = _generate_seed(RS_SEED_NBYTES)
275+
set_seed(&self.rng_state, seed)
276+
except TypeError:
277+
IF RS_SEED_ARRAY_BITS == 32:
278+
seed = np.asarray(seed).astype(np.int64, casting='safe')
279+
if ((seed > int(2**32 - 1)) | (seed < 0)).any():
280+
raise ValueError("Seed values must be between 0 and "
281+
"4294967295 (2**32-1)")
282+
seed = seed.astype(np.uint32, casting='unsafe')
283+
with self.lock:
284+
set_seed_by_array(&self.rng_state,
285+
<uint32_t *>np.PyArray_DATA(seed),
286+
np.PyArray_DIM(seed, 0))
287+
ELSE:
288+
seed = np.asarray(seed).astype(np.object, casting='safe')
289+
if ((seed > int(2**64 - 1)) | (seed < 0)).any():
290+
raise ValueError("Seed values must be between 0 and "
291+
"18446744073709551616 (2**64-1)")
292+
seed = seed.astype(np.uint64, casting='unsafe')
293+
with self.lock:
294+
set_seed_by_array(&self.rng_state,
295+
<uint64_t *>np.PyArray_DATA(seed),
296+
np.PyArray_DIM(seed, 0))
297+
self.__seed = seed
272298
self._reset_state_variables()
273299

274300
ELSE:

randomstate/shims/dSFMT/dSFMT.pxi

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ DEF DSFMT_MEXP = 19937
44
DEF DSFMT_N = 191 # ((DSFMT_MEXP - 128) / 104 + 1)
55
DEF DSFMT_N_PLUS_1 = 192 # DSFMT_N + 1
66
DEF RS_SEED_NBYTES = 1
7+
DEF RS_SEED_ARRAY_BITS = 32
8+
79

810
ctypedef uint32_t rng_state_t
911

@@ -103,11 +105,12 @@ same release version.
103105
104106
Parameters
105107
----------
106-
seed : {None, int}, optional
108+
seed : {None, int, array_like}, optional
107109
Random seed initializing the pseudo-random number generator.
108-
Can be an integer in [0, 2**32] or ``None`` (the default).
109-
If `seed` is ``None``, then ``dSFMT.RandomState`` will try to read
110-
entropy from ``/dev/urandom`` (or the Windows analogue) if available to
110+
Can be an integer in [0, 2**32-1], array of integers in
111+
[0, 2**32-1] or ``None`` (the default). If `seed` is ``None``,
112+
then ``dSFMT.RandomState`` will try to read entropy from
113+
``/dev/urandom`` (or the Windows analogue) if available to
111114
produce a 64-bit seed. If unavailable, the a 64-bit hash of the time
112115
and process ID is used.
113116
@@ -136,6 +139,20 @@ segments come from the same sequence.
136139
>>> for i in range(10):
137140
rs[i].jump(i)
138141
142+
**State and Seeding**
143+
The ``dsfmt.RandomState`` state vector consists of a 764 element array of
144+
32-bit unsigned integers plus a single integer value between 0 and 382
145+
indicating the current position within the main array. The implementation
146+
used here augments this with a 384 element array of doubles which are used
147+
to efficiently access the random numbers produced by the dSFMT generator.
148+
149+
``dsfmt.RandomState`` is seeded using either a single 32-bit unsigned integer
150+
or a vector of 32-bit unsigned integers. In either case the input seed is
151+
used as an input (or inputs) for a hashing function, and the output of the
152+
hashing function is used as the initial state. Using a single 32-bit value
153+
for the seed can only initialize a small range of the possible initial
154+
state values.
155+
139156
.. [1] Mutsuo Saito and Makoto Matsumoto, "SIMD-oriented Fast Mersenne
140157
Twister: a 128-bit Pseudorandom Number Generator." Monte Carlo
141158
and Quasi-Monte Carlo Methods 2006, Springer, pp. 607 -- 622, 2008.

randomstate/shims/mlfg-1279-861/mlfg-1279-861-shim.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ void set_seed(aug_state* state, uint64_t val)
1111
mlfg_seed(state->rng, val);
1212
}
1313

14+
void set_seed_by_array(aug_state* state, uint64_t *vals, int count)
15+
{
16+
mlfg_seed_by_array(state->rng, vals, count);
17+
}
18+
1419
void entropy_init(aug_state* state)
1520
{
1621
uint64_t seeds[1];

randomstate/shims/mlfg-1279-861/mlfg-1279-861-shim.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,6 @@ inline double random_double(aug_state* state)
4545

4646
extern void set_seed(aug_state* state, uint64_t seed);
4747

48+
extern void set_seed_by_array(aug_state* state, uint64_t *vals, int count);
49+
4850
extern void entropy_init(aug_state* state);

randomstate/shims/mlfg-1279-861/mlfg-1279-861.pxi

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ cdef extern from "distributions.h":
2222

2323
cdef void set_seed(aug_state* state, uint64_t seed)
2424

25+
cdef void set_seed_by_array(aug_state* state, uint64_t *seed, int count)
26+
2527
ctypedef uint64_t rng_state_t
2628

2729
ctypedef mlfg_state rng_t
@@ -76,17 +78,35 @@ same release version.
7678
7779
Parameters
7880
----------
79-
seed : {None, int}, optional
81+
seed : {None, int, array_like}, optional
8082
Random seed initializing the pseudo-random number generator.
81-
Can be an integer in [0, 2**64] or ``None`` (the default).
82-
If ``seed`` is ``None``, then ``mlfg_1279_861.RandomState`` will try to
83-
read entropy from ``/dev/urandom`` (or the Windows analogue) if available
84-
to produce a 64-bit seed. If unavailable, a 64-bit hash of the time
83+
Can be an integer in [0, 2**64-1], array of integers in
84+
[0, 2**64-1] or ``None`` (the default). If `seed` is ``None``,
85+
then ``mlfg_1279_861.RandomState`` will try to read entropy from
86+
``/dev/urandom`` (or the Windows analogue) if available to
87+
produce a 64-bit seed. If unavailable, a 64-bit hash of the time
8588
and process ID is used.
8689
8790
Notes
8891
-----
8992
The state of the MLFG(1279,861,*) PRNG is represented by 1279 64-bit unsigned
9093
integers as well as a two 32-bit integers representing the location in the
9194
state array of the current and lagged values.
95+
96+
**State and Seeding**
97+
The ``dsfmt.mlfg_1279_861`` state vector consists of a 1279 element array of
98+
64-bit unsigned integers plus a two integers value between 0 and 1278
99+
indicating the current position and the lagged value within the main array
100+
required to produce the next random.
101+
102+
``dsfmt.mlfg_1279_861`` is seeded using either a single 64-bit unsigned integer
103+
or a vector of 64-bit unsigned integers. In either case the input seed is
104+
used as an input (or inputs) for another simple random number generator,
105+
Splitmix64, and the output of this PRNG function is used as the initial state.
106+
Using a single 64-bit value for the seed can only initialize a small range of
107+
the possible initial state values. When using an array, the SplitMix64 state
108+
for producing the ith component of the initial state is XORd with the ith
109+
value of the seed array until the seed array is exhausted. When using an array
110+
the initial state for the SplitMix64 state is 0 so that using a single element
111+
array and using a single scalar value will produce the same initial state.
92112
"""

randomstate/shims/mrg32k3a/mrg32k3a-shim.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ void set_seed(aug_state* state, uint64_t val)
3030
mrg32k3a_seed(state->rng, val);
3131
}
3232

33+
void set_seed_by_array(aug_state* state, uint64_t *vals, int count)
34+
{
35+
mrg32k3a_seed_by_array(state->rng, vals, count);
36+
}
37+
38+
3339
void init_state(aug_state* state, int64_t vals[6])
3440
{
3541
state->rng->s1[0] = vals[0];

randomstate/shims/mrg32k3a/mrg32k3a-shim.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ inline double random_double(aug_state* state)
3939

4040
extern void set_seed(aug_state* state, uint64_t val);
4141

42+
extern void set_seed_by_array(aug_state* state, uint64_t *vals, int count);
43+
4244
extern void init_state(aug_state* state, int64_t vals[6]);
4345

4446
extern void entropy_init(aug_state* state);

randomstate/shims/mrg32k3a/mrg32k3a.pxi

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ cdef extern from "distributions.h":
2323

2424
cdef void set_seed(aug_state* state, uint64_t seed)
2525

26+
cdef void set_seed_by_array(aug_state* state, uint64_t *seed, int count)
27+
2628
ctypedef mrg32k3a_state rng_t
2729

2830
ctypedef uint64_t rng_state_t
@@ -129,11 +131,12 @@ same release version.
129131
130132
Parameters
131133
----------
132-
seed : {None, int}, optional
134+
seed : {None, int, array_like}, optional
133135
Random seed initializing the pseudo-random number generator.
134-
Can be an integer in [0, 2**64] or ``None`` (the default).
135-
If `seed` is ``None``, then ``mrg32k3a.RandomState`` will try to read data
136-
from ``/dev/urandom`` (or the Windows analogue) if available. If
136+
Can be an integer in [0, 2**64-1], array of integers in
137+
[0, 2**64-1] or ``None`` (the default). If `seed` is ``None``,
138+
then ``mrg32k3a.RandomState`` will try to read data from
139+
``/dev/urandom`` (or the Windows analogue) if available. If
137140
unavailable, a 64-bit hash of the time and process ID is used.
138141
139142
Notes

randomstate/shims/xorshift1024/xorshift1024-shim.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ void set_seed(aug_state* state, uint64_t seed)
1111
xorshift1024_seed(state->rng, seed);
1212
}
1313

14+
void set_seed_by_array(aug_state* state, uint64_t *vals, int count)
15+
{
16+
xorshift1024_seed_by_array(state->rng, vals, count);
17+
}
18+
1419
void entropy_init(aug_state* state)
1520
{
1621
uint64_t seed[1];

0 commit comments

Comments
 (0)