Skip to content

Commit 1282c3d

Browse files
authored
Merge pull request #137 from bashtage/patch-maintenance
Patch maintenance
2 parents 5e2f2da + b2315a5 commit 1282c3d

18 files changed

+480
-105
lines changed

doc/source/brng/dsfmt.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Double SIMD Mersenne Twister (dSFMT)
1+
Double SIMD Mersenne Twister (dSFMT)
22
------------------------------------
33

44
.. module:: randomgen.dsfmt

doc/source/brng/index.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Basic Random Number Generators
22
------------------------------
33

4-
The random values produced by :class:`~randomgen.generator.RandomGenerator`
4+
The random values produced by :class:`~randomgen.generator.RandomGenerator`
55
are produced by a basic RNG. These basic RNGs do not directly provide
66
random numbers and only contains methods used for seeding, getting or
7-
setting the state, jumping or advancing the state, and for accessing
8-
low-level wrappers for consumption by code that can efficiently
7+
setting the state, jumping or advancing the state, and for accessing
8+
low-level wrappers for consumption by code that can efficiently
99
access the functions provided, e.g., `numba <https://numba.pydata.org>`_.
1010

1111
Stable RNGs

doc/source/brng/mt19937.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Mersenne Twister (MT19937)
1+
Mersenne Twister (MT19937)
22
--------------------------
33

44
.. module:: randomgen.mt19937

doc/source/change-log.rst

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33
Change Log
44
----------
55

6+
v1.16.6
7+
=======
8+
- Changed the default jump step size to phi times the period of the generator for
9+
:class:`~randomgen.pcg32.PCG32` and :class:`~randomgen.pcg64.PCG64`.
10+
- Improved the performance of :class:`~randomgen.pcg64.PCG64` on Windows.
11+
- Improved performance of :func:`~randomgen.dsfmt.DSFMT.jump` and
12+
:func:`~randomgen.dsfmt.DSFMT.jumped`.
13+
- Improves backward compatability of :class:`~randomgen.mtrand.RandomState`
14+
15+
616
v1.16.5
717
=======
818
- Fixed bugs in :func:`~randomgen.mtrand.RandomState.laplace`,

doc/source/generator.rst

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
Random Generator
22
----------------
3-
The :class:`~randomgen.generator.RandomGenerator` provides access to
4-
a wide range of distributions, and served as a replacement for
5-
:class:`~numpy.random.RandomState`. The main difference between
3+
The :class:`~randomgen.generator.RandomGenerator` provides access to
4+
a wide range of distributions, and served as a replacement for
5+
:class:`~numpy.random.RandomState`. The main difference between
66
the two is that :class:`~randomgen.generator.RandomGenerator` relies
7-
on an additional basic RNG to manage state and generate the random
8-
bits which are then transformed into random values from useful
9-
distributions. The default basic RNG used by
10-
:class:`~randomgen.generator.RandomGenerator` is
11-
:class:`~randomgen.xoroshiro128.Xoroshiro128`. The basic RNG can be
12-
changed by passing an instantized basic RNG to
13-
:class:`~randomgen.generator.RandomGenerator`.
7+
on an additional basic RNG to manage state and generate the random
8+
bits which are then transformed into random values from useful
9+
distributions. The default basic RNG used by
10+
:class:`~randomgen.generator.RandomGenerator` is
11+
:class:`~randomgen.xoroshiro128.Xoroshiro128`. The basic RNG can be
12+
changed by passing an instantized basic RNG to
13+
:class:`~randomgen.generator.RandomGenerator`.
1414

1515
.. currentmodule:: randomgen.generator
1616

doc/source/index.rst

+10-10
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ generator be be changed.
77
Quick Start
88
-----------
99

10-
Like :mod:`numpy.random`, RandomGen can be used at the module level.
11-
This uses the default :class:`~randomgen.generator.RandomGenerator` which
10+
Like :mod:`numpy.random`, RandomGen can be used at the module level.
11+
This uses the default :class:`~randomgen.generator.RandomGenerator` which
1212
uses normals provided by :class:`~randomgen.xoroshiro128.Xoroshiro128`.
1313

1414
.. code-block:: python
@@ -17,10 +17,10 @@ uses normals provided by :class:`~randomgen.xoroshiro128.Xoroshiro128`.
1717
import randomgen.generator as random
1818
random.standard_normal()
1919
20-
:class:`~randomgen.generator.RandomGenerator` can also be used as a
20+
:class:`~randomgen.generator.RandomGenerator` can also be used as a
2121
replacement for :class:`~numpy.random.RandomState`, although the random
22-
values are generated by :class:`~randomgen.xoroshiro128.Xoroshiro128`. It
23-
also isn't possible to directly seed a
22+
values are generated by :class:`~randomgen.xoroshiro128.Xoroshiro128`. It
23+
also isn't possible to directly seed a
2424
:class:`~randomgen.generator.RandomGenerator`.
2525

2626

@@ -33,7 +33,7 @@ also isn't possible to directly seed a
3333
3434
3535
Seeds can be passed to any of the basic RNGs. Here :class:`~randomgen.mt19937.MT19937`
36-
is used and the :class:`~randomgen.generator.RandomGenerator` is accessed via
36+
is used and the :class:`~randomgen.generator.RandomGenerator` is accessed via
3737
the property :attr:`~randomgen.mt19937.MT19937.generator`.
3838

3939
.. code-block:: python
@@ -93,13 +93,13 @@ What's New or Different
9393
.. warning::
9494

9595
The Box-Muller method used to produce NumPy's normals is no longer available
96-
in :class:`~randomgen.generator.RandomGenerator`. It is not possible to
97-
reproduce the random values using :class:`~randomgen.generator.RandomGenerator`
96+
in :class:`~randomgen.generator.RandomGenerator`. It is not possible to
97+
reproduce the random values using :class:`~randomgen.generator.RandomGenerator`
9898
for the normal distribution or any other distribution that relies on the
99-
normal such as the gamma or student's t. If you require backward compatibility, a
99+
normal such as the gamma or student's t. If you require backward compatibility, a
100100
legacy generator, :class:`~randomgen.mtrand.RandomState`, has been created
101101
which can fully reproduce the sequence produced by NumPy.
102-
102+
103103
* The normal, exponential and gamma generators use 256-step Ziggurat
104104
methods which are 2-10 times faster than NumPy's Box-Muller or inverse CDF
105105
implementations.

doc/source/legacy.rst

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
Legacy Random Generation
22
------------------------
3-
The :class:`~randomgen.mtrand.RandomState` provides access to
3+
The :class:`~randomgen.mtrand.RandomState` provides access to
44
legacy generators. These all depend on normals produced using a
55
polar transformation or inverse CDF exponentials or gammas. This
66
class should only be used if it is essential to have randoms that
77
are identical to what would have been produced by NumPy.
88

99
:class:`~randomgen.mtrand.RandomState` add additional information
1010
to the state which is required when using Box-Muller normals since these
11-
are produced in pairs. It is important to use
11+
are produced in pairs. It is important to use
1212
:attr:`~randomgen.mtrand.RandomState.get_state()`
13-
when accessing the state so that these extra values are saved.
13+
when accessing the state so that these extra values are saved.
1414

1515
.. code-block:: python
16-
16+
1717
from randomgen import MT19937
1818
from randomgen.mtrand import RandomState
1919
from numpy.random import RandomState
@@ -31,7 +31,7 @@ when accessing the state so that these extra values are saved.
3131
3232
rs.standard_exponential()
3333
lg.standard_exponential()
34-
34+
3535
3636
.. currentmodule:: randomgen.mtrand
3737

@@ -46,7 +46,7 @@ Seeding and State
4646

4747
~RandomState.get_state
4848
~RandomState.set_state
49-
49+
5050
Simple random data
5151
==================
5252
.. autosummary::

doc/source/multithreading.rst

+10-10
Original file line numberDiff line numberDiff line change
@@ -20,41 +20,41 @@ that the same seed will produce the same outputs.
2020
import multiprocessing
2121
import concurrent.futures
2222
import numpy as np
23-
23+
2424
class MultithreadedRNG(object):
2525
def __init__(self, n, seed=None, threads=None):
2626
rg = Xorshift1024(seed)
2727
if threads is None:
2828
threads = multiprocessing.cpu_count()
2929
self.threads = threads
30-
30+
3131
self._random_generators = []
3232
for _ in range(0, threads-1):
3333
_rg = Xorshift1024()
3434
_rg.state = rg.state
3535
self._random_generators.append(_rg.generator)
3636
rg.jump()
3737
self._random_generators.append(rg.generator)
38-
38+
3939
self.n = n
4040
self.executor = concurrent.futures.ThreadPoolExecutor(threads)
4141
self.values = np.empty(n)
4242
self.step = np.ceil(n / threads).astype(np.int)
43-
43+
4444
def fill(self):
4545
def _fill(random_state, out, first, last):
4646
random_state.standard_normal(out=out[first:last])
47-
47+
4848
futures = {}
4949
for i in range(self.threads):
50-
args = (_fill,
50+
args = (_fill,
5151
self._random_generators[i],
52-
self.values,
53-
i * self.step,
52+
self.values,
53+
i * self.step,
5454
(i + 1) * self.step)
5555
futures[self.executor.submit(*args)] = i
5656
concurrent.futures.wait(futures)
57-
57+
5858
def __del__(self):
5959
self.executor.shutdown(False)
6060
@@ -80,7 +80,7 @@ the time required to generate using a single thread.
8080
8181
In [4]: print(mrng.threads)
8282
...: %timeit mrng.fill()
83-
83+
8484
4
8585
32.8 ms ± 2.71 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
8686

doc/source/new-or-different.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ What's New or Different
66
.. warning::
77

88
The Box-Muller method used to produce NumPy's normals is no longer available
9-
in :class:`~randomgen.generator.RandomGenerator`. It is not possible to
10-
reproduce the random values using :class:`~randomgen.generator.RandomGenerator`
9+
in :class:`~randomgen.generator.RandomGenerator`. It is not possible to
10+
reproduce the random values using :class:`~randomgen.generator.RandomGenerator`
1111
for the normal distribution or any other distribution that relies on the
12-
normal such as the gamma or student's t. If you require backward compatibility, a
12+
normal such as the gamma or student's t. If you require backward compatibility, a
1313
legacy generator, :class:`~randomgen.mtrand.RandomState`, has been created
1414
which can fully reproduce the sequence produced by NumPy.
1515

doc/source/performance.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ percentage. The overall performance was computed using a geometric mean.
5656
.. csv-table::
5757
:header: ,Xoroshiro128,Xoshiro256**,Xorshift1024,PCG64,MT19937,Philox,ThreeFry
5858
:widths: 14,14,14,14,14,14,14,14
59-
59+
6060
64-bit Unsigned Ints,353,309,283,263,233,191,162
6161
Uniforms,271,283,276,288,232,188,173
6262
32-bit Unsigned Ints,83,76,78,70,76,64,56

randomgen/common.pxd

+2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ cdef object float_fill(void *func, brng_t *state, object size, object lock, obje
7474

7575
cdef object float_fill_from_double(void *func, brng_t *state, object size, object lock, object out)
7676

77+
cdef object wrap_int(object val, object bits)
78+
7779
cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size)
7880

7981
cdef object cont(void *func, void *state, object size, object lock, int narg,

randomgen/common.pyx

+10
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,16 @@ cdef double kahan_sum(double *darr, np.npy_intp n):
172172
sum = t
173173
return sum
174174

175+
176+
cdef object wrap_int(object val, object bits):
177+
"""Wraparound to place an integer into the interval [0, 2**bits)"""
178+
upper = int(2)**int(bits)
179+
if not 0<= val < upper:
180+
divisor = val // upper
181+
val = val - upper * divisor
182+
return val
183+
184+
175185
cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size):
176186
"""Convert a large integer to an array of unsigned integers"""
177187
len = bits // uint_size

randomgen/pcg32.pyx

+7-2
Original file line numberDiff line numberDiff line change
@@ -297,14 +297,18 @@ cdef class PCG32:
297297
RNG. For example, two 16-bit integer values can be simulated
298298
from a single draw of a 32-bit RNG.
299299
"""
300+
delta = wrap_int(delta, 64)
300301
pcg32_advance_state(&self.rng_state, <uint64_t>delta)
301302
return self
302303

303304
def jump(self, np.npy_intp iter=1):
304305
"""
305306
jump(iter=1)
306307
307-
Jumps the state as-if 2**32 random numbers have been generated
308+
Jump the state a fixed increment
309+
310+
Jumps the state as-if 11400714819323198486 random numbers have been
311+
generated.
308312
309313
Parameters
310314
----------
@@ -316,7 +320,8 @@ cdef class PCG32:
316320
self : PCG32
317321
RNG jumped iter times
318322
"""
319-
return self.advance(iter * 2**32)
323+
step = int(0x9e3779b97f4a7c16)
324+
return self.advance(iter * step)
320325

321326
@property
322327
def ctypes(self):

randomgen/pcg64.pyx

+9-2
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ cdef class PCG64:
326326
Advancing the RNG state resets any pre-computed random numbers.
327327
This is required to ensure exact reproducibility.
328328
"""
329+
delta = wrap_int(delta, 128)
330+
329331
cdef np.ndarray d = np.empty(2, dtype=np.uint64)
330332
d[0] = delta // 2**64
331333
d[1] = delta % 2**64
@@ -337,7 +339,10 @@ cdef class PCG64:
337339
"""
338340
jump(iter=1)
339341
340-
Jumps the state as-if 2**64 random numbers have been generated
342+
Jump the state a fixed increment
343+
344+
Jumps the state as-if 210306068529402873165736369884012333108 random
345+
numbers have been generated.
341346
342347
Parameters
343348
----------
@@ -354,7 +359,9 @@ cdef class PCG64:
354359
Jumping the rng state resets any pre-computed random numbers. This is required
355360
to ensure exact reproducibility.
356361
"""
357-
return self.advance(iter * 2**64)
362+
step = 0x9e3779b97f4a7c15f39cc0605cedc834
363+
step *= int(iter)
364+
return self.advance(step)
358365

359366
@property
360367
def ctypes(self):

0 commit comments

Comments
 (0)