.. currentmodule:: numpy.random .. _extending: 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 gaussian samples using a pure Python implementation which is then compiled. The random numbers are provided by ``ctypes.next_double``. .. literalinclude:: ../../../../numpy/random/_examples/numba/extending.py :language: python :end-before: example 2 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`_ section below. .. _random_cython: Cython ------ Cython can be used to unpack the ``PyCapsule`` provided by a BitGenerator. This example uses `PCG64` and the example from above. The usual caveats for writing high-performance code using Cython -- removing bounds checks and wrap around, providing array alignment information -- still apply. .. literalinclude:: ../../../../numpy/random/_examples/cython/extending_distributions.pyx :language: cython :end-before: example 2 The BitGenerator can also be directly accessed using the members of the ``bitgen_t`` struct. .. literalinclude:: ../../../../numpy/random/_examples/cython/extending_distributions.pyx :language: cython :start-after: example 2 :end-before: example 3 Cython can be used to directly access the functions in ``numpy/random/c_distributions.pxd``. This requires linking with the ``npyrandom`` library located in ``numpy/random/lib``. .. literalinclude:: ../../../../numpy/random/_examples/cython/extending_distributions.pyx :language: cython :start-after: example 3 See :ref:`extending_cython_example` for the complete listings of these examples and a minimal ``setup.py`` to build the c-extension modules. CFFI ---- CFFI can be used to directly access the functions in ``include/numpy/random/distributions.h``. Some "massaging" of the header file is required: .. literalinclude:: ../../../../numpy/random/_examples/cffi/extending.py :language: python :end-before: dlopen Once the header is parsed by ``ffi.cdef``, the functions can be accessed directly from the ``_generator`` shared object, using the `BitGenerator.cffi` interface. .. literalinclude:: ../../../../numpy/random/_examples/cffi/extending.py :language: python :start-after: dlopen New Bit Generators ------------------ `~Generator` can be used with user-provided `~BitGenerator`\ s. 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) Examples -------- .. toctree:: Numba CFFI + Numba Cython CFFI