Skip to content

Commit d9ada31

Browse files
authored
Merge pull request #56 from bashtage/add-dtypes-uniform
ENH: Add single precision uniforms
2 parents 17edf82 + e34e8e4 commit d9ada31

File tree

12 files changed

+187
-27
lines changed

12 files changed

+187
-27
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ version of the MT19937 generator that is especially fast at generating doubles
5353
support an additional `method` keyword argument which can be `bm` or
5454
`zig` where `bm` corresponds to the current method using the Box-Muller
5555
transformation and `zig` uses the much faster (100%+) ziggurat method.
56+
* `random_sample` can produce either single precision (`np.float32`) or
57+
double precision (`np.float64`, the default) using an the optional keyword
58+
argument `dtype`.
5659

5760
### New Functions
5861

README.rst

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This is a library and generic interface for alternative random
77
generators in Python and Numpy.
88

99
Features
10+
--------
1011

1112
- Immediate drop in replacement for NumPy's RandomState
1213

doc/source/change-log.rst

+15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
Change Log
44
==========
5+
Version 1.11.2
6+
--------------
7+
* Added keyword argument `dtype` to `random_sample` which allows for single
8+
precision as well as double precision uniforms to be generated.
9+
10+
.. ipython:: python
11+
12+
import numpy as np
13+
import randomstate as rs
14+
rs.seed(23456)
15+
rs.random_sample(3, dtype=np.float64)
16+
17+
rs.seed(23456)
18+
rs.random_sample(3, dtype=np.float32)
19+
520
621
Version 1.11.1
722
--------------

doc/source/conf.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
'sphinx.ext.mathjax',
3838
'sphinx.ext.napoleon',
3939
'sphinx.ext.autosummary',
40+
'IPython.sphinxext.ipython_console_highlighting',
41+
'IPython.sphinxext.ipython_directive'
4042
]
4143

4244
# Add any paths that contain templates here, relative to this directory.
@@ -65,7 +67,7 @@
6567
# The short X.Y version.
6668
version = '1.11'
6769
# The full version, including alpha/beta/rc tags.
68-
release = '1.11.1'
70+
release = '1.11.2'
6971

7072
# The language for content autogenerated by Sphinx. Refer to documentation
7173
# for a list of supported languages.

doc/source/index.rst

+20-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ What's New or Different
1010
* ``randomstate.entropy.random_entropy`` provides access to the system
1111
source of randomness that is used in cryptographic applications (e.g.,
1212
``/dev/urandom`` on Unix).
13-
* The normal generator supports a 256-step ziggurat method which is 2-6 times
14-
faster than NumPy's ``standard_normal``. This generator can be accessed using
13+
* The normal generator supports a 256-step Ziggurat method which is 2-6 times
14+
faster than NumPy's ``standard_normal``. This generator can be accessed
15+
by passing the keyword argument ``method='zig'``.
16+
* ``random_sample`` accepts the optional keyword argument ``dtype`` which
17+
accepts ``np.float32`` or ``np.float64`` to produce either single or
18+
double prevision uniform random variables
1519
* For changes since the previous release, see the :ref:`change-log`
1620

1721
.. code-block:: python
@@ -69,6 +73,14 @@ generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are
6973
.. _`wiki page on Fibonacci generators`: https://en.wikipedia.org/wiki/Lagged_Fibonacci_generator
7074
.. _`MRG32K3A author's page`: http://simul.iro.umontreal.ca/
7175

76+
New Features
77+
~~~~~~~~~~~~
78+
.. toctree::
79+
:maxdepth: 2
80+
81+
Using in Parallel Applications <parallel>
82+
Reading System Entropy <entropy>
83+
7284

7385
Individual Pseudo Random Number Generators
7486
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -85,8 +97,13 @@ Individual Pseudo Random Number Generators
8597
PCG-64 <pcg64>
8698
MLFG <mlfg>
8799
MRG32K3A <mrg32k3a>
88-
Reading System Entropy <entropy>
89100

101+
Changes
102+
~~~~~~~
103+
.. toctree::
104+
:maxdepth: 2
105+
106+
Change Log <change-log>
90107

91108
Indices and tables
92109
~~~~~~~~~~~~~~~~~~

randomstate/array_utilities.pxi

+21
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ ctypedef uint32_t (* random_uint_1_i_32)(aug_state* state, uint32_t a) nogil
1616
ctypedef int32_t (* random_int_2_i_32)(aug_state* state, int32_t a, int32_t b) nogil
1717
ctypedef int64_t (* random_int_2_i)(aug_state* state, int64_t a, int64_t b) nogil
1818

19+
ctypedef void (* random_float_fill)(aug_state* state, np.npy_intp count, float *out) nogil
1920
ctypedef void (* random_double_fill)(aug_state* state, np.npy_intp count, double *out) nogil
2021

22+
2123
cdef np.npy_intp compute_numel(size):
2224
cdef np.npy_intp i, n = 1
2325
if isinstance(size, tuple):
@@ -613,6 +615,25 @@ cdef object double_fill(aug_state* state, void *func, object size, object lock):
613615
out_array = <np.ndarray>np.empty(size, np.float64)
614616
n = np.PyArray_SIZE(out_array)
615617
out_array_data = <double *>np.PyArray_DATA(out_array)
618+
with lock, nogil:
619+
f(state, n, out_array_data)
620+
return out_array
621+
622+
cdef object float_fill(aug_state* state, void *func, object size, object lock):
623+
cdef random_float_fill f = <random_float_fill>func
624+
cdef float out
625+
cdef float *out_array_data
626+
cdef np.ndarray out_array
627+
cdef np.npy_intp n
628+
629+
if size is None:
630+
with lock:
631+
f(state, 1, &out)
632+
return out
633+
else:
634+
out_array = <np.ndarray>np.empty(size, np.float32)
635+
n = np.PyArray_SIZE(out_array)
636+
out_array_data = <float *>np.PyArray_DATA(out_array)
616637
with lock, nogil:
617638
f(state, n, out_array_data)
618639
return out_array

randomstate/distributions.c

+14-2
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,25 @@ unsigned long random_uint(aug_state* state)
3030
}
3131

3232

33-
double random_standard_uniform(aug_state* state)
33+
float random_standard_uniform32(aug_state* state)
34+
{
35+
return (random_uint32(state) >> 9) * (1.0 / 8388608.0);
36+
}
37+
38+
double random_standard_uniform64(aug_state* state)
3439
{
3540
return random_double(state);
3641
}
3742

43+
void random_uniform_fill32(aug_state* state, npy_intp count, float *out)
44+
{
45+
int i;
46+
for (i=0; i < count; i++) {
47+
out[i] = (random_uint32(state) >> 9) * (float)(1.0 / 8388608.0);
48+
}
49+
}
3850

39-
void random_uniform_fill(aug_state* state, npy_intp count, double *out)
51+
void random_uniform_fill64(aug_state* state, npy_intp count, double *out)
4052
{
4153
int i;
4254
for (i=0; i < count; i++) {

randomstate/distributions.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ extern int64_t random_positive_int64(aug_state* state);
4848

4949
extern int32_t random_positive_int32(aug_state* state);
5050

51-
extern double random_standard_uniform(aug_state* state);
51+
extern float random_standard_uniform32(aug_state* state);
52+
53+
extern double random_standard_uniform64(aug_state* state);
5254

5355
extern double random_standard_exponential(aug_state* state);
5456

@@ -138,7 +140,9 @@ extern void random_bounded_uint8_fill(aug_state *state, uint8_t off, uint8_t rng
138140

139141
extern void random_bounded_bool_fill(aug_state *state, npy_bool off, npy_bool rng, npy_intp cnt, npy_bool *out);
140142

141-
extern void random_uniform_fill(aug_state* state, npy_intp count, double *out);
143+
extern void random_uniform_fill32(aug_state* state, npy_intp count, float *out);
144+
145+
extern void random_uniform_fill64(aug_state* state, npy_intp count, double *out);
142146

143147
extern void random_standard_exponential_fill(aug_state* state, npy_intp count, double *out);
144148

randomstate/interface/dSFMT/dSFMT-shim.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,16 @@ static inline double random_double_from_buffer(aug_state *state)
3939

4040
static inline uint32_t random_uint32(aug_state* state)
4141
{
42+
/* TODO: This can be improved to use upper bits */
4243
double d = random_double_from_buffer(state);//dsfmt_genrand_close1_open2(state->rng);
4344
uint64_t *out = (uint64_t *)&d;
4445
return (uint32_t)(*out & 0xffffffff);
4546
}
4647

4748
static inline uint64_t random_uint64(aug_state* state)
4849
{
49-
double d = random_double_from_buffer(state);//dsfmt_genrand_close1_open2(state->rng);
50+
/* TODO: This can be improved to use upper bits */
51+
double d = random_double_from_buffer(state); //dsfmt_genrand_close1_open2(state->rng);
5052
uint64_t out;
5153
uint64_t *tmp;
5254
tmp = (uint64_t *)&d;

randomstate/randomstate.pyx

+15-4
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ cdef extern from "distributions.h":
6868

6969
cdef void entropy_init(aug_state* state) nogil
7070

71-
cdef double random_standard_uniform(aug_state* state) nogil
71+
cdef float random_standard_uniform32(aug_state* state) nogil
72+
73+
cdef double random_standard_uniform64(aug_state* state) nogil
7274
cdef double random_gauss(aug_state* state) nogil
7375
cdef double random_gauss_zig(aug_state* state) nogil
7476
cdef double random_gauss_zig_julia(aug_state* state) nogil
@@ -114,7 +116,8 @@ cdef extern from "distributions.h":
114116
cdef void random_bounded_uint16_fill(aug_state *state, uint16_t off, uint16_t rng, intptr_t cnt, uint16_t *out) nogil
115117
cdef void random_bounded_uint8_fill(aug_state *state, uint8_t off, uint8_t rng, intptr_t cnt, uint8_t *out) nogil
116118
cdef void random_bounded_bool_fill(aug_state *state, np.npy_bool off, np.npy_bool rng, intptr_t cnt, np.npy_bool *out) nogil
117-
cdef void random_uniform_fill(aug_state *state, intptr_t cnt, double *out) nogil
119+
cdef void random_uniform_fill32(aug_state *state, intptr_t cnt, double *out) nogil
120+
cdef void random_uniform_fill64(aug_state *state, intptr_t cnt, double *out) nogil
118121
cdef void random_standard_exponential_fill(aug_state* state, intptr_t count, double *out) nogil
119122
cdef void random_gauss_fill(aug_state* state, intptr_t count, double *out) nogil
120123
cdef void random_gauss_zig_julia_fill(aug_state* state, intptr_t count, double *out) nogil
@@ -680,7 +683,7 @@ cdef class RandomState:
680683
self.get_state())
681684

682685
# Basic distributions:
683-
def random_sample(self, size=None):
686+
def random_sample(self, size=None, dtype=np.float64):
684687
"""
685688
random_sample(size=None)
686689
@@ -698,6 +701,9 @@ cdef class RandomState:
698701
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
699702
``m * n * k`` samples are drawn. Default is None, in which case a
700703
single value is returned.
704+
dtype : dtype, optional
705+
Desired dtype of the result, either np.float64 (default)
706+
or np.float32.
701707
702708
Returns
703709
-------
@@ -722,7 +728,12 @@ cdef class RandomState:
722728
[-1.23204345, -1.75224494]])
723729
724730
"""
725-
return double_fill(&self.rng_state, &random_uniform_fill, size, self.lock)
731+
if dtype is np.float64:
732+
return double_fill(&self.rng_state, &random_uniform_fill64, size, self.lock)
733+
elif dtype is np.float32:
734+
return float_fill(&self.rng_state, &random_uniform_fill32, size, self.lock)
735+
else:
736+
raise ValueError('Unknown dtype')
726737

727738
def tomaxint(self, size=None):
728739
"""

0 commit comments

Comments
 (0)