diff options
| author | Kevin Sheppard <kevin.k.sheppard@gmail.com> | 2019-05-23 15:28:22 +0100 |
|---|---|---|
| committer | mattip <matti.picus@gmail.com> | 2019-05-27 22:58:35 +0300 |
| commit | dabf42be29208a59bbacffd40d9d8dca6e200f49 (patch) | |
| tree | 929ddc66702b257a8ffa372939d38bb42c041414 /doc/source/reference | |
| parent | 7c52c2810e20a9e483e564751b8e2342c97f56c2 (diff) | |
| download | numpy-dabf42be29208a59bbacffd40d9d8dca6e200f49.tar.gz | |
MAINT: Remove remnants of bit generators
Remove traces of the three removed bit generators
Add lock to Cython examples
Diffstat (limited to 'doc/source/reference')
| -rw-r--r-- | doc/source/reference/random/extending.rst | 95 | ||||
| -rw-r--r-- | doc/source/reference/random/generator.rst | 2 | ||||
| -rw-r--r-- | doc/source/reference/random/multithreading.rst | 12 | ||||
| -rw-r--r-- | doc/source/reference/random/parallel.rst | 8 | ||||
| -rw-r--r-- | doc/source/reference/random/performance.py | 7 | ||||
| -rw-r--r-- | doc/source/reference/random/performance.rst | 67 |
6 files changed, 93 insertions, 98 deletions
diff --git a/doc/source/reference/random/extending.rst b/doc/source/reference/random/extending.rst index f65d7708f..28db4021c 100644 --- a/doc/source/reference/random/extending.rst +++ b/doc/source/reference/random/extending.rst @@ -18,11 +18,11 @@ provided by ``ctypes.next_double``. .. code-block:: python - from numpy.random import Xoroshiro128 + from numpy.random import Xoshiro256 import numpy as np import numba as nb - x = Xoroshiro128() + x = Xoshiro256() f = x.ctypes.next_double s = x.ctypes.state state_addr = x.ctypes.state_address @@ -50,7 +50,7 @@ provided by ``ctypes.next_double``. # Must use state address not state with numba normalsj(1, state_addr) %timeit normalsj(1000000, state_addr) - print('1,000,000 Box-Muller (numba/Xoroshiro128) randoms') + print('1,000,000 Box-Muller (numba/Xoshiro256) randoms') %timeit np.random.standard_normal(1000000) print('1,000,000 Box-Muller (NumPy) randoms') @@ -66,7 +66,7 @@ Cython ====== Cython can be used to unpack the ``PyCapsule`` provided by a BitGenerator. -This example uses `~xoroshiro128.Xoroshiro128` and +This example uses `~xoshiro256.Xoshiro256` and ``random_gauss_zig``, the Ziggurat-based generator for normals, to fill an array. The usual caveats for writing high-performance code using Cython -- removing bounds checks and wrap around, providing array alignment information @@ -80,54 +80,57 @@ removing bounds checks and wrap around, providing array alignment information from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from numpy.random.common cimport * from numpy.random.distributions cimport random_gauss_zig - from numpy.random import Xoroshiro128 - - - @cython.boundscheck(False) - @cython.wraparound(False) - def normals_zig(Py_ssize_t n): - cdef Py_ssize_t i - cdef bitgen_t *rng - cdef const char *capsule_name = "BitGenerator" - cdef double[::1] random_values - - x = Xoroshiro128() - capsule = x.capsule - if not PyCapsule_IsValid(capsule, capsule_name): - raise ValueError("Invalid pointer to anon_func_state") - rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name) - random_values = np.empty(n) - for i in range(n): - random_values[i] = random_gauss_zig(rng) - randoms = np.asarray(random_values) - return randoms + from numpy.random import Xoshiro256 + + + @cython.boundscheck(False) + @cython.wraparound(False) + def normals_zig(Py_ssize_t n): + cdef Py_ssize_t i + cdef bitgen_t *rng + cdef const char *capsule_name = "BitGenerator" + cdef double[::1] random_values + + x = Xoshiro256() + capsule = x.capsule + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + # Best practice is to release GIL and acquire the lock + with x.lock, nogil: + for i in range(n): + random_values[i] = random_gauss_zig(rng) + randoms = np.asarray(random_values) + return randoms The BitGenerator can also be directly accessed using the members of the basic RNG structure. .. code-block:: cython - @cython.boundscheck(False) - @cython.wraparound(False) - def uniforms(Py_ssize_t n): - cdef Py_ssize_t i - cdef bitgen_t *rng - cdef const char *capsule_name = "BitGenerator" - cdef double[::1] random_values - - x = Xoroshiro128() - capsule = x.capsule - # Optional check that the capsule if from a Basic RNG - if not PyCapsule_IsValid(capsule, capsule_name): - raise ValueError("Invalid pointer to anon_func_state") - # Cast the pointer - rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name) - random_values = np.empty(n) - for i in range(n): - # Call the function - random_values[i] = rng.next_double(rng.state) - randoms = np.asarray(random_values) - return randoms + @cython.boundscheck(False) + @cython.wraparound(False) + def uniforms(Py_ssize_t n): + cdef Py_ssize_t i + cdef bitgen_t *rng + cdef const char *capsule_name = "BitGenerator" + cdef double[::1] random_values + + x = Xoshiro256() + capsule = x.capsule + # Optional check that the capsule if from a BitGenerator + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + # Cast the pointer + rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + with x.lock, nogil: + for i in range(n): + # Call the function + random_values[i] = rng.next_double(rng.state) + randoms = np.asarray(random_values) + return randoms These functions along with a minimal setup file are included in the examples folder. diff --git a/doc/source/reference/random/generator.rst b/doc/source/reference/random/generator.rst index ee70725e7..8b086e901 100644 --- a/doc/source/reference/random/generator.rst +++ b/doc/source/reference/random/generator.rst @@ -8,7 +8,7 @@ a wide range of distributions, and served as a replacement for the two is that ``Generator`` relies on an additional BitGenerator to manage state and generate the random bits, which are then transformed into random values from useful distributions. The default BitGenerator used by -``Generator`` is :class:`~xoroshiro128.Xoroshiro128`. The BitGenerator +``Generator`` is :class:`~xoshiro256.Xoshiro256`. The BitGenerator can be changed by passing an instantized BitGenerator to ``Generator``. diff --git a/doc/source/reference/random/multithreading.rst b/doc/source/reference/random/multithreading.rst index 718fe05f1..871425e6d 100644 --- a/doc/source/reference/random/multithreading.rst +++ b/doc/source/reference/random/multithreading.rst @@ -10,21 +10,21 @@ these requirements. This example makes use of Python 3 :mod:`concurrent.futures` to fill an array using multiple threads. Threads are long-lived so that repeated calls do not require any additional overheads from thread creation. The underlying -BitGenerator is `Xorshift1024` which is fast, has a long period and supports -using `Xorshift1024.jumped` to return a new generator while advancing the +BitGenerator is `Xoshiro256` which is fast, has a long period and supports +using `Xoshiro256.jumped` to return a new generator while advancing the state. The random numbers generated are reproducible in the sense that the same seed will produce the same outputs. .. code-block:: ipython - from numpy.random import Generator, Xorshift1024 + from numpy.random import Generator, Xoshiro256 import multiprocessing import concurrent.futures import numpy as np class MultithreadedRNG(object): def __init__(self, n, seed=None, threads=None): - rg = Xorshift1024(seed) + rg = Xoshiro256(seed) if threads is None: threads = multiprocessing.cpu_count() self.threads = threads @@ -89,7 +89,7 @@ The single threaded call directly uses the BitGenerator. .. code-block:: ipython In [5]: values = np.empty(10000000) - ...: rg = Generator(Xorshift1024()) + ...: rg = Generator(Xoshiro256()) ...: %timeit rg.standard_normal(out=values) 99.6 ms ± 222 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) @@ -100,7 +100,7 @@ that does not use an existing array due to array creation overhead. .. code-block:: ipython - In [6]: rg = Generator(Xorshift1024()) + In [6]: rg = Generator(Xoshiro256()) ...: %timeit rg.standard_normal(10000000) 125 ms ± 309 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) diff --git a/doc/source/reference/random/parallel.rst b/doc/source/reference/random/parallel.rst index 8bdc3f23f..40f0bce63 100644 --- a/doc/source/reference/random/parallel.rst +++ b/doc/source/reference/random/parallel.rst @@ -72,10 +72,6 @@ are listed below. +-----------------+-------------------------+-------------------------+-------------------------+ | ThreeFry | :math:`2^{256}` | :math:`2^{128}` | 64 | +-----------------+-------------------------+-------------------------+-------------------------+ -| Xoroshiro128 | :math:`2^{128}` | :math:`2^{64}` | 64 | -+-----------------+-------------------------+-------------------------+-------------------------+ -| Xorshift1024 | :math:`2^{1024}` | :math:`2^{512}` | 64 | -+-----------------+-------------------------+-------------------------+-------------------------+ | Xoshiro256** | :math:`2^{256}` | :math:`2^{128}` | 64 | +-----------------+-------------------------+-------------------------+-------------------------+ | Xoshiro512** | :math:`2^{512}` | :math:`2^{256}` | 64 | @@ -87,13 +83,13 @@ overlap. .. code-block:: python from numpy.random.entropy import random_entropy - from numpy.random import Xorshift1024 + from numpy.random import Xoshiro256 entropy = random_entropy(2).astype(np.uint64) # 64-bit number as a seed seed = entropy[0] * 2**32 + entropy[1] blocked_rng = [] - rng = Xorshift1024(seed) + rng = Xoshiro256(seed) for i in range(10): blocked_rng.append(rng.jumped(i)) diff --git a/doc/source/reference/random/performance.py b/doc/source/reference/random/performance.py index a29e09c41..bbf17b1d0 100644 --- a/doc/source/reference/random/performance.py +++ b/doc/source/reference/random/performance.py @@ -4,11 +4,10 @@ from timeit import repeat import numpy as np import pandas as pd -from numpy.random import MT19937, DSFMT, ThreeFry, Xoroshiro128, \ - Xorshift1024, Philox, Xoshiro256, Xoshiro512 +from numpy.random import MT19937, DSFMT, ThreeFry, Philox, Xoshiro256, \ + Xoshiro512 -PRNGS = [DSFMT, MT19937, Philox, ThreeFry, Xoroshiro128, Xorshift1024, - Xoshiro256, Xoshiro512] +PRNGS = [DSFMT, MT19937, Philox, ThreeFry, Xoshiro256, Xoshiro512] funcs = {'32-bit Unsigned Ints': 'integers(0, 2**32,size=1000000, dtype="uint32")', '64-bit Unsigned Ints': 'integers(0, 2**64,size=1000000, dtype="uint64")', diff --git a/doc/source/reference/random/performance.rst b/doc/source/reference/random/performance.rst index 61898ac89..395744eb8 100644 --- a/doc/source/reference/random/performance.rst +++ b/doc/source/reference/random/performance.rst @@ -8,25 +8,22 @@ Performance Recommendation ************** The recommended generator for single use is -:class:`~xoroshiro128.Xoroshiro128`. The recommended generator +:class:`~.xoshiro256.Xoshiro256`. The recommended generator for use in large-scale parallel applications is -:class:`~.xoshiro256.Xoshiro256` -where the `jumped` method is used to advance the state. For very large scale -applications -- requiring 1,000+ independent streams, -:class:`~.philox.Philox` is the best choice. +:class:`~.xoshiro512.Xoshiro512` where the `jumped` method is used to advance +the state. For very large scale applications -- requiring 1,000+ independent +streams -- :class:`~.philox.Philox` is the best choice. Timings ******* The timings below are the time in ns to produce 1 random value from a -specific distribution. :class:`~xoroshiro128.Xoroshiro128` is the -fastest, followed by :class:`~xorshift1024.Xorshift1024`. The original -:class:`~mt19937.MT19937` generator is much slower since it requires 2 32-bit -values to equal the output of the faster generators. +specific distribution. The original :class:`~mt19937.MT19937` generator is +much slower since it requires 2 32-bit values to equal the output of the +faster generators. Integer performance has a similar ordering although `dSFMT` is slower since -it generates 53-bit floating point values rather than integer values. On the -other hand, it is very fast for uniforms, although slower than `xoroshiro128+`. +it generates 53-bit floating point values rather than integer values. The pattern is similar for other, more complex generators. The normal performance of NumPy's MT19937 is much lower than the other since it @@ -35,38 +32,38 @@ performance gap for Exponentials is also large due to the cost of computing the log function to invert the CDF. .. csv-table:: - :header: ,Xoroshiro128,Xoshiro256**,Xorshift1024,MT19937,Philox,ThreeFry,NumPy + :header: ,Xoshiro256**,Xoshiro512**,DSFMT,MT19937,Philox,NumPy,ThreeFry :widths: 14,14,14,14,14,14,14,14 - 64-bit Unsigned Ints,11.9,13.6,14.9,18.0,22.0,25.9,42.0 - Uniforms,16.3,15.6,16.0,19.1,23.5,25.5,44.1 - 32-bit Unsigned Ints,21.6,23.7,23.1,23.6,27.9,32.3,17.9 - Exponentials,21.2,22.4,23.8,26.7,30.8,33.0,115.3 - Normals,25.1,26.9,26.2,31.7,32.6,37.8,106.8 - Binomials,72.4,73.0,71.9,77.4,80.0,83.1,101.9 - Complex Normals,80.4,86.4,81.1,93.4,96.3,105.5, - Laplaces,97.0,97.4,99.6,109.8,102.3,105.1,125.3 - Gammas,91.3,91.2,94.8,101.7,108.7,113.8,187.9 - Poissons,136.7,137.6,139.7,161.9,171.0,181.0,265.1 + 32-bit Unsigned Ints,2.6,2.9,3.4,3.2,5.0,3.3,7.6 + 64-bit Unsigned Ints,3.1,4.0,5.6,5.7,6.6,8.1,13.4 + Uniforms,3.7,4.2,3.2,7.4,9.1,8.9,13.5 + Exponentials,4.3,5.3,7.3,8.2,9.7,42.4,14.9 + Normals,8.2,8.9,11.7,13.4,15.0,37.3,18.6 + Binomials,20.0,20.8,19.8,26.4,28.2,26.6,31.0 + Gammas,26.4,28.7,30.4,37.1,38.8,62.9,49.0 + Laplaces,40.2,40.0,39.4,48.7,51.2,47.4,51.4 + Poissons,48.8,51.6,47.8,73.6,82.3,74.0,90.6 -The next table presents the performance relative to `xoroshiro128+` in -percentage. The overall performance was computed using a geometric mean. +The next table presents the performance in percentage relative to values +generated by the legagy generator, `RandomState(MT19937())`. The overall +performance was computed using a geometric mean. .. csv-table:: - :header: ,Xoroshiro128,Xoshiro256**,Xorshift1024,MT19937,Philox,ThreeFry + :header: ,Xoshiro256**,Xoshiro512**,DSFMT,MT19937,Philox,ThreeFry :widths: 14,14,14,14,14,14,14 - 64-bit Unsigned Ints,353,309,283,233,191,162 - Uniforms,271,283,276,232,188,173 - 32-bit Unsigned Ints,83,76,78,76,64,56 - Exponentials,544,514,485,432,375,350 - Normals,425,397,407,337,328,283 - Binomials,141,140,142,132,127,123 - Laplaces,129,129,126,114,123,119 - Gammas,206,206,198,185,173,165 - Poissons,194,193,190,164,155,146 - Overall,223,215,210,186,170,156 + 32-bit Unsigned Ints,129,113,98,103,66,44 + 64-bit Unsigned Ints,258,202,145,142,122,61 + Uniforms,244,214,283,121,98,66 + Exponentials,981,796,580,518,436,285 + Normals,453,417,319,278,249,200 + Binomials,133,128,134,101,94,86 + Gammas,238,219,207,170,162,129 + Laplaces,118,118,120,97,93,92 + Poissons,152,144,155,101,90,82 + Overall,233,209,194,152,130,98 .. note:: |
