Skip to content

Commit 8ecbf26

Browse files
committed
Merge pull request #20 from bashtage/dSFMT
ENH: Add initial support for dSFMT generator
2 parents fd6c16e + 232ad01 commit 8ecbf26

23 files changed

+3954
-13
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ The RNGs include:
99

1010
* [MT19937](https://github.com/numpy/numpy/blob/master/numpy/random/mtrand/),
1111
the NumPy rng
12+
* [dSFMT](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/) a SSE2-aware
13+
version of the MT19937 generator that is especially fast at generating doubles
1214
* [xorshift128+](http://xorshift.di.unimi.it/) and
1315
[xorshift1024*](http://xorshift.di.unimi.it/)
1416
* [PCG32](http://www.pcg-random.org/) and [PCG64](http:w//www.pcg-random.org/)

randomstate/distributions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ typedef int bool;
3131
#include "shims/mrg32k3a/mrg32k3a-shim.h"
3232
#elif defined(MLFG_1279_861_RNG)
3333
#include "shims/mlfg-1279-861/mlfg-1279-861-shim.h"
34+
#elif defined(DSFMT_RNG)
35+
#include "shims/dSFMT/dSFMT-shim.h"
3436
#else
3537
#error Unknown RNG!!! Unknown RNG!!! Unknown RNG!!!
3638
#endif

randomstate/interface.pyx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ IF RNG_MOD_NAME == 'mrg32k3a':
3939
include "shims/mrg32k3a/mrg32k3a.pxi"
4040
IF RNG_MOD_NAME == 'mlfg_1279_861':
4141
include "shims/mlfg-1279-861/mlfg-1279-861.pxi"
42+
IF RNG_MOD_NAME == 'dsfmt':
43+
include "shims/dSFMT/dSFMT.pxi"
4244

4345
IF NORMAL_METHOD == 'inv':
4446
__normal_method = 'inv'

randomstate/performance.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
scale_64 = 2
2222

2323
RNGS = ['mlfg_1279_861', 'mrg32k3a', 'pcg64', 'pcg32', 'mt19937', 'xorshift128', 'xorshift1024',
24-
'random']
24+
'dsfmt', 'random']
2525

2626

2727
def timer(code, setup):

randomstate/prng/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .mrg32k3a import mrg32k3a
66
from .pcg32 import pcg32
77
from .pcg64 import pcg64
8+
from .dsfmt import dsfmt
89

910
def __generic_ctor(mod_name='mt19937'):
1011
"""
@@ -42,6 +43,8 @@ def __generic_ctor(mod_name='mt19937'):
4243
mod = xorshift128
4344
elif mod_name == 'xorshift1024':
4445
mod = xorshift1024
46+
elif mod_name == 'dsfmt':
47+
mod = dsfmt
4548
else:
4649
raise ValueError(str(mod_name) + ' is not a known PRNG module.')
4750

randomstate/prng/dsfmt/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .dsfmt import *

randomstate/shims/dSFMT/dSFMT-shim.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "dSFMT-shim.h"
2+
3+
extern inline uint32_t random_uint32(aug_state* state);
4+
5+
extern inline uint64_t random_uint64(aug_state* state);
6+
7+
extern inline double random_double(aug_state* state);
8+
9+
extern void set_seed_by_array(aug_state* state, uint32_t init_key[], int key_length)
10+
{
11+
dsfmt_init_by_array(state->rng, init_key, key_length);
12+
}
13+
14+
void set_seed(aug_state* state, uint32_t seed)
15+
{
16+
dsfmt_init_gen_rand(state->rng, seed);
17+
}
18+
19+
void entropy_init(aug_state* state)
20+
{
21+
uint32_t seeds[1];
22+
entropy_fill((void*) seeds, sizeof(seeds));
23+
set_seed(state, seeds[0]);
24+
}

randomstate/shims/dSFMT/dSFMT-shim.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#define RNG_TYPE rk_state
2+
3+
#ifdef _WIN32
4+
#include "../../src/common/stdint.h"
5+
#define inline __inline
6+
#else
7+
#include <stdint.h>
8+
#endif
9+
10+
#include "../../src/common/binomial.h"
11+
#include "../../src/common/entropy.h"
12+
#include "../../src/dSFMT/dSFMT.h"
13+
14+
typedef struct s_aug_state {
15+
dsfmt_t *rng;
16+
binomial_t *binomial;
17+
18+
int has_gauss, shift_zig_random_int, has_uint32;
19+
double gauss;
20+
uint32_t uinteger;
21+
uint64_t zig_random_int;
22+
} aug_state;
23+
24+
static inline uint32_t random_uint32(aug_state* state)
25+
{
26+
double d = dsfmt_genrand_close1_open2(state->rng);
27+
uint64_t *out = (uint64_t *)&d;
28+
return (uint32_t)(*out & 0xffffffff);
29+
}
30+
31+
static inline uint64_t random_uint64(aug_state* state)
32+
{
33+
double d = dsfmt_genrand_close1_open2(state->rng);
34+
uint64_t out;
35+
uint64_t *tmp;
36+
tmp = (uint64_t *)&d;
37+
out = *tmp << 32;
38+
d = dsfmt_genrand_close1_open2(state->rng);
39+
tmp = (uint64_t *)&d;
40+
out |= *tmp & 0xffffffff;
41+
return out;
42+
}
43+
44+
static inline double random_double(aug_state* state)
45+
{
46+
return dsfmt_genrand_close1_open2(state->rng) - 1.0;
47+
}
48+
49+
extern void entropy_init(aug_state* state);
50+
51+
extern void set_seed_by_array(aug_state* state, uint32_t init_key[], int key_length);
52+
53+
extern void set_seed(aug_state* state, uint32_t seed);
54+

randomstate/shims/dSFMT/dSFMT.pxi

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
DEF RNG_NAME = 'dSFMT'
2+
DEF RNG_ADVANCEABLE = 0
3+
DEF RNG_SEED = 1
4+
DEF RNG_JUMPABLE = 0
5+
DEF RNG_STATE_LEN = 4
6+
DEF NORMAL_METHOD = 'zig'
7+
DEF DSFMT_MEXP = 19937
8+
DEF DSFMT_N = 191 # ((DSFMT_MEXP - 128) / 104 + 1)
9+
DEF DSFMT_N_PLUS_1 = 192 # DSFMT_N + 1
10+
11+
ctypedef uint32_t rng_state_t
12+
13+
cdef extern from "distributions.h":
14+
15+
cdef union W128_T:
16+
uint64_t u[2];
17+
uint32_t u32[4];
18+
double d[2];
19+
20+
ctypedef W128_T w128_t;
21+
22+
cdef struct DSFMT_T:
23+
w128_t status[DSFMT_N_PLUS_1];
24+
int idx;
25+
26+
ctypedef DSFMT_T dsfmt_t;
27+
28+
cdef struct s_aug_state:
29+
dsfmt_t *rng
30+
binomial_t *binomial
31+
32+
int has_gauss, shift_zig_random_int, has_uint32
33+
double gauss
34+
uint64_t zig_random_int
35+
uint32_t uinteger
36+
37+
ctypedef s_aug_state aug_state
38+
39+
cdef void set_seed(aug_state* state, uint32_t seed)
40+
41+
cdef void set_seed_by_array(aug_state* state, uint32_t init_key[], int key_length)
42+
43+
ctypedef dsfmt_t rng_t
44+
45+
cdef object _get_state(aug_state state):
46+
cdef uint32_t [:] key = np.zeros(4 * DSFMT_N_PLUS_1, dtype=np.uint32)
47+
cdef Py_ssize_t i, j, key_loc = 0
48+
cdef w128_t state_val
49+
for i in range(DSFMT_N_PLUS_1):
50+
state_val = state.rng.status[i]
51+
for j in range(4):
52+
key[key_loc] = state_val.u32[j]
53+
key_loc += 1
54+
return (np.asarray(key), state.rng.idx)
55+
56+
cdef object _set_state(aug_state state, object state_info):
57+
cdef uint32_t [:] key = state_info[0]
58+
cdef Py_ssize_t i, j, key_loc = 0
59+
for i in range(DSFMT_N_PLUS_1):
60+
for j in range(4):
61+
state.rng.status[i].u32[j] = key[key_loc]
62+
key_loc += 1
63+
64+
state.rng.idx = state_info[1]
65+
66+
DEF CLASS_DOCSTRING = """
67+
RandomState(seed=None)
68+
69+
Container for the SIMD-based Mersenne Twister pseudo-random number generator.
70+
71+
`dSFMT.RandomState` exposes a number of methods for generating random
72+
numbers drawn from a variety of probability distributions. In addition to the
73+
distribution-specific arguments, each method takes a keyword argument
74+
`size` that defaults to ``None``. If `size` is ``None``, then a single
75+
value is generated and returned. If `size` is an integer, then a 1-D
76+
array filled with generated values is returned. If `size` is a tuple,
77+
then an array with that shape is filled and returned.
78+
79+
*No Compatibility Guarantee*
80+
'dSFMT.RandomState' does not make a guarantee that a fixed seed and a
81+
fixed series of calls to 'dSFMT.RandomState' methods using the same
82+
parameters will always produce the same results. This is different from
83+
'numpy.random.RandomState' guarantee. This is done to simplify improving
84+
random number generators. To ensure identical results, you must use the
85+
same release version.
86+
87+
Parameters
88+
----------
89+
seed : {None, int}, optional
90+
Random seed initializing the pseudo-random number generator.
91+
Can be an integer in [0, 2**32] or ``None`` (the default).
92+
If `seed` is ``None``, then `dSFMT.RandomState` will try to read
93+
entropy from ``/dev/urandom`` (or the Windows analogue) if available to
94+
produce a 64-bit seed. If unavailable, the a 64-bit hash of the time
95+
and process ID is used.
96+
97+
Notes
98+
-----
99+
The Python stdlib module "random" also contains a Mersenne Twister
100+
pseudo-random number generator with a number of methods that are similar
101+
to the ones available in `RandomState`. `RandomState`, besides being
102+
NumPy-aware, has the advantage that it provides a much larger number
103+
of probability distributions to choose from.
104+
"""

randomstate/src/dSFMT/LICENSE.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
Copyright (c) 2007, 2008, 2009 Mutsuo Saito, Makoto Matsumoto
2+
and Hiroshima University.
3+
Copyright (c) 2011, 2002 Mutsuo Saito, Makoto Matsumoto, Hiroshima
4+
University and The University of Tokyo.
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are
9+
met:
10+
11+
* Redistributions of source code must retain the above copyright
12+
notice, this list of conditions and the following disclaimer.
13+
* Redistributions in binary form must reproduce the above
14+
copyright notice, this list of conditions and the following
15+
disclaimer in the documentation and/or other materials provided
16+
with the distribution.
17+
* Neither the name of the Hiroshima University nor the names of
18+
its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written
20+
permission.
21+
22+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

0 commit comments

Comments
 (0)