Skip to content

Commit

Permalink
Merge pull request #137 from bashtage/patch-maintenance
Browse files Browse the repository at this point in the history
Patch maintenance
  • Loading branch information
bashtage authored Jun 2, 2019
2 parents 5e2f2da + b2315a5 commit 1282c3d
Show file tree
Hide file tree
Showing 18 changed files with 480 additions and 105 deletions.
2 changes: 1 addition & 1 deletion doc/source/brng/dsfmt.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Double SIMD Mersenne Twister (dSFMT)
Double SIMD Mersenne Twister (dSFMT)
------------------------------------

.. module:: randomgen.dsfmt
Expand Down
6 changes: 3 additions & 3 deletions doc/source/brng/index.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Basic Random Number Generators
------------------------------

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

Stable RNGs
Expand Down
2 changes: 1 addition & 1 deletion doc/source/brng/mt19937.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Mersenne Twister (MT19937)
Mersenne Twister (MT19937)
--------------------------

.. module:: randomgen.mt19937
Expand Down
10 changes: 10 additions & 0 deletions doc/source/change-log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
Change Log
----------

v1.16.6
=======
- Changed the default jump step size to phi times the period of the generator for
:class:`~randomgen.pcg32.PCG32` and :class:`~randomgen.pcg64.PCG64`.
- Improved the performance of :class:`~randomgen.pcg64.PCG64` on Windows.
- Improved performance of :func:`~randomgen.dsfmt.DSFMT.jump` and
:func:`~randomgen.dsfmt.DSFMT.jumped`.
- Improves backward compatability of :class:`~randomgen.mtrand.RandomState`


v1.16.5
=======
- Fixed bugs in :func:`~randomgen.mtrand.RandomState.laplace`,
Expand Down
20 changes: 10 additions & 10 deletions doc/source/generator.rst
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
Random Generator
----------------
The :class:`~randomgen.generator.RandomGenerator` provides access to
a wide range of distributions, and served as a replacement for
:class:`~numpy.random.RandomState`. The main difference between
The :class:`~randomgen.generator.RandomGenerator` provides access to
a wide range of distributions, and served as a replacement for
:class:`~numpy.random.RandomState`. The main difference between
the two is that :class:`~randomgen.generator.RandomGenerator` relies
on an additional basic RNG to manage state and generate the random
bits which are then transformed into random values from useful
distributions. The default basic RNG used by
:class:`~randomgen.generator.RandomGenerator` is
:class:`~randomgen.xoroshiro128.Xoroshiro128`. The basic RNG can be
changed by passing an instantized basic RNG to
:class:`~randomgen.generator.RandomGenerator`.
on an additional basic RNG to manage state and generate the random
bits which are then transformed into random values from useful
distributions. The default basic RNG used by
:class:`~randomgen.generator.RandomGenerator` is
:class:`~randomgen.xoroshiro128.Xoroshiro128`. The basic RNG can be
changed by passing an instantized basic RNG to
:class:`~randomgen.generator.RandomGenerator`.

.. currentmodule:: randomgen.generator

Expand Down
20 changes: 10 additions & 10 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ generator be be changed.
Quick Start
-----------

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

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


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

.. code-block:: python
Expand Down Expand Up @@ -93,13 +93,13 @@ What's New or Different
.. warning::

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

* The normal, exponential and gamma generators use 256-step Ziggurat
methods which are 2-10 times faster than NumPy's Box-Muller or inverse CDF
implementations.
Expand Down
12 changes: 6 additions & 6 deletions doc/source/legacy.rst
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
Legacy Random Generation
------------------------
The :class:`~randomgen.mtrand.RandomState` provides access to
The :class:`~randomgen.mtrand.RandomState` provides access to
legacy generators. These all depend on normals produced using a
polar transformation or inverse CDF exponentials or gammas. This
class should only be used if it is essential to have randoms that
are identical to what would have been produced by NumPy.

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

.. code-block:: python
from randomgen import MT19937
from randomgen.mtrand import RandomState
from numpy.random import RandomState
Expand All @@ -31,7 +31,7 @@ when accessing the state so that these extra values are saved.
rs.standard_exponential()
lg.standard_exponential()
.. currentmodule:: randomgen.mtrand

Expand All @@ -46,7 +46,7 @@ Seeding and State

~RandomState.get_state
~RandomState.set_state

Simple random data
==================
.. autosummary::
Expand Down
20 changes: 10 additions & 10 deletions doc/source/multithreading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,41 @@ that the same seed will produce the same outputs.
import multiprocessing
import concurrent.futures
import numpy as np
class MultithreadedRNG(object):
def __init__(self, n, seed=None, threads=None):
rg = Xorshift1024(seed)
if threads is None:
threads = multiprocessing.cpu_count()
self.threads = threads
self._random_generators = []
for _ in range(0, threads-1):
_rg = Xorshift1024()
_rg.state = rg.state
self._random_generators.append(_rg.generator)
rg.jump()
self._random_generators.append(rg.generator)
self.n = n
self.executor = concurrent.futures.ThreadPoolExecutor(threads)
self.values = np.empty(n)
self.step = np.ceil(n / threads).astype(np.int)
def fill(self):
def _fill(random_state, out, first, last):
random_state.standard_normal(out=out[first:last])
futures = {}
for i in range(self.threads):
args = (_fill,
args = (_fill,
self._random_generators[i],
self.values,
i * self.step,
self.values,
i * self.step,
(i + 1) * self.step)
futures[self.executor.submit(*args)] = i
concurrent.futures.wait(futures)
def __del__(self):
self.executor.shutdown(False)
Expand All @@ -80,7 +80,7 @@ the time required to generate using a single thread.
In [4]: print(mrng.threads)
...: %timeit mrng.fill()
4
32.8 ms ± 2.71 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Expand Down
6 changes: 3 additions & 3 deletions doc/source/new-or-different.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ What's New or Different
.. warning::

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

Expand Down
2 changes: 1 addition & 1 deletion doc/source/performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ percentage. The overall performance was computed using a geometric mean.
.. csv-table::
:header: ,Xoroshiro128,Xoshiro256**,Xorshift1024,PCG64,MT19937,Philox,ThreeFry
:widths: 14,14,14,14,14,14,14,14

64-bit Unsigned Ints,353,309,283,263,233,191,162
Uniforms,271,283,276,288,232,188,173
32-bit Unsigned Ints,83,76,78,70,76,64,56
Expand Down
2 changes: 2 additions & 0 deletions randomgen/common.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ cdef object float_fill(void *func, brng_t *state, object size, object lock, obje

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

cdef object wrap_int(object val, object bits)

cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size)

cdef object cont(void *func, void *state, object size, object lock, int narg,
Expand Down
10 changes: 10 additions & 0 deletions randomgen/common.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ cdef double kahan_sum(double *darr, np.npy_intp n):
sum = t
return sum
cdef object wrap_int(object val, object bits):
"""Wraparound to place an integer into the interval [0, 2**bits)"""
upper = int(2)**int(bits)
if not 0<= val < upper:
divisor = val // upper
val = val - upper * divisor
return val
cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size):
"""Convert a large integer to an array of unsigned integers"""
len = bits // uint_size
Expand Down
9 changes: 7 additions & 2 deletions randomgen/pcg32.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -297,14 +297,18 @@ cdef class PCG32:
RNG. For example, two 16-bit integer values can be simulated
from a single draw of a 32-bit RNG.
"""
delta = wrap_int(delta, 64)
pcg32_advance_state(&self.rng_state, <uint64_t>delta)
return self

def jump(self, np.npy_intp iter=1):
"""
jump(iter=1)
Jumps the state as-if 2**32 random numbers have been generated
Jump the state a fixed increment
Jumps the state as-if 11400714819323198486 random numbers have been
generated.
Parameters
----------
Expand All @@ -316,7 +320,8 @@ cdef class PCG32:
self : PCG32
RNG jumped iter times
"""
return self.advance(iter * 2**32)
step = int(0x9e3779b97f4a7c16)
return self.advance(iter * step)

@property
def ctypes(self):
Expand Down
11 changes: 9 additions & 2 deletions randomgen/pcg64.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ cdef class PCG64:
Advancing the RNG state resets any pre-computed random numbers.
This is required to ensure exact reproducibility.
"""
delta = wrap_int(delta, 128)

cdef np.ndarray d = np.empty(2, dtype=np.uint64)
d[0] = delta // 2**64
d[1] = delta % 2**64
Expand All @@ -337,7 +339,10 @@ cdef class PCG64:
"""
jump(iter=1)
Jumps the state as-if 2**64 random numbers have been generated
Jump the state a fixed increment
Jumps the state as-if 210306068529402873165736369884012333108 random
numbers have been generated.
Parameters
----------
Expand All @@ -354,7 +359,9 @@ cdef class PCG64:
Jumping the rng state resets any pre-computed random numbers. This is required
to ensure exact reproducibility.
"""
return self.advance(iter * 2**64)
step = 0x9e3779b97f4a7c15f39cc0605cedc834
step *= int(iter)
return self.advance(step)

@property
def ctypes(self):
Expand Down
Loading

0 comments on commit 1282c3d

Please sign in to comment.