diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2020-12-31 09:38:40 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2020-12-31 09:38:40 +0900 |
commit | 295fa02e974b890f98bb7bf6a94045c2cd3f5f68 (patch) | |
tree | 2a59dc21aeb4953eb6cbde947296aebbad4f93ba /doc/source/reference | |
parent | e0fb9413a32fd2fa984710d904d4f776555a6b5c (diff) | |
download | python-numpy-295fa02e974b890f98bb7bf6a94045c2cd3f5f68.tar.gz python-numpy-295fa02e974b890f98bb7bf6a94045c2cd3f5f68.tar.bz2 python-numpy-295fa02e974b890f98bb7bf6a94045c2cd3f5f68.zip |
Imported Upstream version 1.17.5upstream/1.17.5
Diffstat (limited to 'doc/source/reference')
-rw-r--r-- | doc/source/reference/random/extending.rst | 165 | ||||
-rw-r--r-- | doc/source/reference/random/index.rst | 5 | ||||
-rw-r--r-- | doc/source/reference/random/new-or-different.rst | 7 |
3 files changed, 3 insertions, 174 deletions
diff --git a/doc/source/reference/random/extending.rst b/doc/source/reference/random/extending.rst deleted file mode 100644 index 22f9cb7e4..000000000 --- a/doc/source/reference/random/extending.rst +++ /dev/null @@ -1,165 +0,0 @@ -.. currentmodule:: numpy.random - -Extending ---------- -The BitGenerators have been designed to be extendable using standard tools for -high-performance Python -- numba and Cython. The `~Generator` object can also -be used with user-provided BitGenerators as long as these export a small set of -required functions. - -Numba -===== -Numba can be used with either CTypes or CFFI. The current iteration of the -BitGenerators all export a small set of functions through both interfaces. - -This example shows how numba can be used to produce Box-Muller normals using -a pure Python implementation which is then compiled. The random numbers are -provided by ``ctypes.next_double``. - -.. code-block:: python - - from numpy.random import PCG64 - import numpy as np - import numba as nb - - x = PCG64() - f = x.ctypes.next_double - s = x.ctypes.state - state_addr = x.ctypes.state_address - - def normals(n, state): - out = np.empty(n) - for i in range((n+1)//2): - x1 = 2.0*f(state) - 1.0 - x2 = 2.0*f(state) - 1.0 - r2 = x1*x1 + x2*x2 - while r2 >= 1.0 or r2 == 0.0: - x1 = 2.0*f(state) - 1.0 - x2 = 2.0*f(state) - 1.0 - r2 = x1*x1 + x2*x2 - g = np.sqrt(-2.0*np.log(r2)/r2) - out[2*i] = g*x1 - if 2*i+1 < n: - out[2*i+1] = g*x2 - return out - - # Compile using Numba - print(normals(10, s).var()) - # Warm up - normalsj = nb.jit(normals, nopython=True) - # Must use state address not state with numba - normalsj(1, state_addr) - %timeit normalsj(1000000, state_addr) - print('1,000,000 Box-Muller (numba/PCG64) randoms') - %timeit np.random.standard_normal(1000000) - print('1,000,000 Box-Muller (NumPy) randoms') - - -Both CTypes and CFFI allow the more complicated distributions to be used -directly in Numba after compiling the file distributions.c into a DLL or so. -An example showing the use of a more complicated distribution is in the -examples folder. - -.. _randomgen_cython: - -Cython -====== - -Cython can be used to unpack the ``PyCapsule`` provided by a BitGenerator. -This example uses `~pcg64.PCG64` 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 --- still apply. - -.. code-block:: cython - - import numpy as np - cimport numpy as np - cimport cython - 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 PCG64 - - - @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 = PCG64() - 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 = PCG64() - 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. - -New Basic RNGs -============== -`~Generator` can be used with other user-provided BitGenerators. The simplest -way to write a new BitGenerator is to examine the pyx file of one of the -existing BitGenerators. The key structure that must be provided is the -``capsule`` which contains a ``PyCapsule`` to a struct pointer of type -``bitgen_t``, - -.. code-block:: c - - typedef struct bitgen { - void *state; - uint64_t (*next_uint64)(void *st); - uint32_t (*next_uint32)(void *st); - double (*next_double)(void *st); - uint64_t (*next_raw)(void *st); - } bitgen_t; - -which provides 5 pointers. The first is an opaque pointer to the data structure -used by the BitGenerators. The next three are function pointers which return -the next 64- and 32-bit unsigned integers, the next random double and the next -raw value. This final function is used for testing and so can be set to -the next 64-bit unsigned integer function if not needed. Functions inside -``Generator`` use this structure as in - -.. code-block:: c - - bitgen_state->next_uint64(bitgen_state->state) diff --git a/doc/source/reference/random/index.rst b/doc/source/reference/random/index.rst index b0283f3a7..641c2164a 100644 --- a/doc/source/reference/random/index.rst +++ b/doc/source/reference/random/index.rst @@ -152,10 +152,6 @@ What's New or Different * Optional ``out`` argument that allows existing arrays to be filled for select distributions * All BitGenerators can produce doubles, uint64s and uint32s via CTypes - (`~.PCG64.ctypes`) and CFFI (`~.PCG64.cffi`). This allows the bit generators - to be used in numba. -* The bit generators can be used in downstream projects via - :ref:`Cython <randomgen_cython>`. * `~.Generator.integers` is now the canonical way to generate integer random numbers from a discrete uniform distribution. The ``rand`` and ``randn`` methods are only available through the legacy `~.RandomState`. @@ -199,7 +195,6 @@ Features Multithreaded Generation <multithreading> new-or-different Comparing Performance <performance> - extending Original Source ~~~~~~~~~~~~~~~ diff --git a/doc/source/reference/random/new-or-different.rst b/doc/source/reference/random/new-or-different.rst index c8815f98f..402f24ab0 100644 --- a/doc/source/reference/random/new-or-different.rst +++ b/doc/source/reference/random/new-or-different.rst @@ -56,13 +56,12 @@ And in more detail: ``randn`` methods are only available through the legacy `~.RandomState`. This replaces both ``randint`` and the deprecated ``random_integers``. * The Box-Muller method used to produce NumPy's normals is no longer available. -* All bit generators can produce doubles, uint64s and - uint32s via CTypes (`~PCG64.ctypes`) and CFFI (`~PCG64.cffi`). - This allows these bit generators to be used in numba. +* All bit generators can produce doubles, uint64s and uint32s via CTypes + (`~PCG64.ctypes`) and CFFI (`~PCG64.cffi`). This allows these bit generators + to be used in numba. * The bit generators can be used in downstream projects via Cython. - .. ipython:: python from numpy.random import Generator, PCG64 |