Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ repos:
rev: v1.10.0
hooks:
- id: python-check-blanket-noqa
exclude: ^docs/source/conf\.py$
- id: python-check-blanket-type-ignore
- id: python-check-mock-methods
- id: python-no-eval
Expand Down
12 changes: 12 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,15 @@

html_theme = "furo"
html_static_path = ["_static"]

# remove linter flags from rendered docstrings


def remove_linter_flags(app, what, name, obj, options, lines):
for index, line in enumerate(lines):
if "# noqa" in line or "# no-cython-lint" in line:
lines[index] = line.split("#")[0].rstrip()


def setup(app):
app.connect("autodoc-process-docstring", remove_linter_flags)
86 changes: 82 additions & 4 deletions docs/source/how_to.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ How-to Guides
How to save and resume long computation
---------------------------------------

:class:`RandomState` is pickleable. Pickling allows to save and restore
:class:`MKLRandomState` is pickleable. Pickling allows to save and restore
the internal state of the pseudo-random number generators.

.. code-block:: python
Expand All @@ -14,7 +14,7 @@ the internal state of the pseudo-random number generators.
import mkl_random
import pickle

rs = mkl_random.RandomState(seed=777, brng="r250")
rs = mkl_random.MKLRandomState(seed=777, brng="r250")
draw = rs.standard_normal(size=1357913)

# pickle random state
Expand Down Expand Up @@ -45,7 +45,7 @@ from such family, initialized equally, produce streams of randomness statistical
indistinguishable from independent.

.. py:method:: skipahead(nskips)
:canonical: mkl_random.RandomState.skipahead
:canonical: mkl_random.MKLRandomState.skipahead

Advance the state of the generator using skip-ahead method, or raise :code:`ValueError`
exception if not supported.
Expand All @@ -63,7 +63,7 @@ indistinguishable from independent.
independence breaks down.

.. py:method:: leapfrog(k, nstreams)
:canonical: mkl_random.RandomState.leapfrog
:canonical: mkl_random.MKLRandomState.leapfrog

Initialize the state of the generator using leap-frog method, or raise :code:`ValueError`
exception if not supported.
Expand All @@ -85,3 +85,81 @@ indistinguishable from independent.
randomness stasistically indistunguishable from independent. To use such families in parallel computation, assign
difference family generators to different parallel workers and sample those assigned generators in each parallel worker.
Please refer to "examples/" folder in the `GitHub repo <https://github.com/IntelPython/mkl_random>`_ for more details.


Using :mod:`mkl_random` as a drop-in replacement for `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_
-----------------------------------------------------------------

The :mod:`mkl_random.interfaces.numpy_random` module is aligned to the legacy
portion of the `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ legacy API.
You can import it in place of `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_
without changing the rest of your code:

.. code-block:: python
:caption: Drop-in replacement for numpy.random

from mkl_random.interfaces import numpy_random as rng

rng.seed(1234)
x = rng.standard_normal(size=100)
y = rng.uniform(0, 1, size=100)

See :ref:`interfaces` for a full list of available functions.

.. note::
While the API is the same, :mod:`mkl_random.interfaces.numpy_random` is **not** seed-compatible
with `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_. Given the same seed,
the two modules will produce different sequences. There also may be differences in some edge cases, such as
behavior of functions when given specific inputs.


How to patch `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ with :mod:`mkl_random`
-------------------------------------------------------------

Existing code that calls `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_
directly can be patched to use :mod:`mkl_random.interfaces.numpy_random` at runtime.

The recommended approach is to use the :class:`mkl_random.mkl_random` context manager:

.. code-block:: python
:caption: Temporarily patch numpy.random using context manager

import numpy as np
import mkl_random

with mkl_random.mkl_random():
x = np.random.standard_normal(100) # uses mkl_random
y = np.random.uniform(0, 1, size=100) # uses mkl_random

:mod:`mkl_random` also exposes the explicit patching functions:

.. code-block:: python
:caption: Patch numpy.random for the duration of a script

import mkl_random
mkl_random.patch_numpy_random() # subsequent numpy.random calls use mkl_random

import numpy as np
data = np.random.normal(0, 1, size=100)

.. note::
The patching functions are provided for users' convenience, but they are not recommended
for new code. It is instead recommended to use :mod:`mkl_random` directly for new code.
For existing code where patching may be desirable, it is also suggested to prefer the
context manager, as it scopes the patch to blocks and thus, prevents user error of
forgetting to restore the original state, calling the patch multiple times, or
creating undefined behavior when patching in a multi-threaded program.

You can also use :class:`mkl_random.mkl_random` as a decorator:

.. code-block:: python
:caption: Patch numpy.random as a decorator

import numpy as np
import mkl_random

@mkl_random.mkl_random()
def get_data():
return np.random.standard_normal(100)

See :ref:`patching` for details.
3 changes: 2 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ Intel(R) oneAPI Math Kernel Library

.. grid-item-card:: Reference Guide

The reference guide contains a detailed description of class :class:`mkl_random.RandomState` and its methods.
The reference guide contains the detailed documentation of the :mod:`mkl_random` API and its
submodules.

+++

Expand Down
8 changes: 8 additions & 0 deletions docs/source/reference/api.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
.. _fullapi:

Class MKLRandomState
====================

.. autoclass:: mkl_random.MKLRandomState
:members:
:inherited-members:

Class RandomState
=================

.. autoclass:: mkl_random.RandomState
:members:
:inherited-members:
22 changes: 19 additions & 3 deletions docs/source/reference/index.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
:mod:`mkl_random` APIs
:mod:`mkl_random` Overview
======================

The class :doc:`mkl_random.RandomState <./api>` exposes sampling from probability distributions while supporting
The class :doc:`mkl_random.MKLRandomState <./api>` exposes sampling from probability distributions while supporting
different streams of randomness, also known as basic random number generators.

The basic random number generator is chosen by specifying :code:`brng` keyword argument to the constructor of :code:`mkl.RandomState` class.
The basic random number generator is chosen by specifying :code:`brng` keyword argument to the constructor of :code:`mkl.MKLRandomState` class.

The list of supported basic random number generators is as follows (also see `oneMKL Engines <oneMKLBRNG_>`_):

Expand All @@ -22,10 +22,26 @@ The list of supported basic random number generators is as follows (also see `on

.. _oneMKLBRNG: https://spec.oneapi.io/versions/1.0-rev-2/elements/oneMKL/source/domains/rng/engines-basic-random-number-generators.html


Drop-in interfaces
------------------

The :mod:`mkl_random.interfaces` submodule provides drop-in replacements for standard random modules:

* :ref:`mkl_random.interfaces.numpy_random <numpy_random_interface>` - a drop-in replacement for the legacy `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ module


Patching
--------

:mod:`mkl_random` can :ref:`patch numpy.random <patching>` so that existing code calling `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ functions can use :mod:`mkl_random` implementations.

.. toctree::
:hidden:

api
interfaces
patching
mt19937
sfmt19937
r250
Expand Down
104 changes: 104 additions & 0 deletions docs/source/reference/interfaces.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
.. _interfaces:

:mod:`mkl_random.interfaces`
====================================================

:mod:`mkl_random.interfaces` provides drop-in replacements for supported random number generation
modules using :mod:`mkl_random` implementations. Currently, only a NumPy interface is provided,
but more may be added in the future.


.. _numpy_random_interface:

NumPy interface --- :mod:`mkl_random.interfaces.numpy_random`
-------------------------------------------------------------

:mod:`mkl_random.interfaces.numpy_random` is a drop-in replacement for the legacy portion of
`numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_.

.. currentmodule:: mkl_random.interfaces.numpy_random

.. note::
While the API is the same, :mod:`mkl_random.interfaces.numpy_random` is **not** seed-compatible
with `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_. Given the same seed, the two modules
will produce different sequences. The output of :func:`get_state` and accepted input to :func:`set_state` may also differ.
It is not recommended to provide the output of :func:`get_state` from one module to :func:`set_state` of the other.
There also may be differences in some edge cases, such as behavior of functions when given specific inputs.


RandomState class
^^^^^^^^^^^^^^^^^

.. autoclass:: mkl_random.interfaces.numpy_random.RandomState
:members:
:undoc-members:


Functions
^^^^^^^^^^^^^^^^^^^^^^

**Seeding and state functions:**

.. autofunction:: mkl_random.interfaces.numpy_random.seed
.. autofunction:: mkl_random.interfaces.numpy_random.get_state
.. autofunction:: mkl_random.interfaces.numpy_random.set_state

**Simple random data:**

Similar to NumPy, the methods of :class:`RandomState` are exported as functions in the module.
Their usage is discouraged, as they are implemented from a global instance of :class:`RandomState`,
which means results may change across calls.

.. autofunction:: mkl_random.interfaces.numpy_random.rand
.. autofunction:: mkl_random.interfaces.numpy_random.randn
.. autofunction:: mkl_random.interfaces.numpy_random.randint
.. autofunction:: mkl_random.interfaces.numpy_random.random_integers
.. autofunction:: mkl_random.interfaces.numpy_random.random_sample
.. autofunction:: mkl_random.interfaces.numpy_random.random
.. autofunction:: mkl_random.interfaces.numpy_random.ranf
.. autofunction:: mkl_random.interfaces.numpy_random.choice
.. autofunction:: mkl_random.interfaces.numpy_random.bytes
.. autofunction:: mkl_random.interfaces.numpy_random.sample

**Permutations:**

.. autofunction:: mkl_random.interfaces.numpy_random.shuffle
.. autofunction:: mkl_random.interfaces.numpy_random.permutation

**Distributions:**

.. autofunction:: mkl_random.interfaces.numpy_random.beta
.. autofunction:: mkl_random.interfaces.numpy_random.binomial
.. autofunction:: mkl_random.interfaces.numpy_random.chisquare
.. autofunction:: mkl_random.interfaces.numpy_random.dirichlet
.. autofunction:: mkl_random.interfaces.numpy_random.exponential
.. autofunction:: mkl_random.interfaces.numpy_random.f
.. autofunction:: mkl_random.interfaces.numpy_random.gamma
.. autofunction:: mkl_random.interfaces.numpy_random.geometric
.. autofunction:: mkl_random.interfaces.numpy_random.gumbel
.. autofunction:: mkl_random.interfaces.numpy_random.hypergeometric
.. autofunction:: mkl_random.interfaces.numpy_random.laplace
.. autofunction:: mkl_random.interfaces.numpy_random.logistic
.. autofunction:: mkl_random.interfaces.numpy_random.lognormal
.. autofunction:: mkl_random.interfaces.numpy_random.logseries
.. autofunction:: mkl_random.interfaces.numpy_random.multinomial
.. autofunction:: mkl_random.interfaces.numpy_random.multivariate_normal
.. autofunction:: mkl_random.interfaces.numpy_random.negative_binomial
.. autofunction:: mkl_random.interfaces.numpy_random.noncentral_chisquare
.. autofunction:: mkl_random.interfaces.numpy_random.noncentral_f
.. autofunction:: mkl_random.interfaces.numpy_random.normal
.. autofunction:: mkl_random.interfaces.numpy_random.pareto
.. autofunction:: mkl_random.interfaces.numpy_random.poisson
.. autofunction:: mkl_random.interfaces.numpy_random.power
.. autofunction:: mkl_random.interfaces.numpy_random.rayleigh
.. autofunction:: mkl_random.interfaces.numpy_random.standard_cauchy
.. autofunction:: mkl_random.interfaces.numpy_random.standard_exponential
.. autofunction:: mkl_random.interfaces.numpy_random.standard_gamma
.. autofunction:: mkl_random.interfaces.numpy_random.standard_normal
.. autofunction:: mkl_random.interfaces.numpy_random.standard_t
.. autofunction:: mkl_random.interfaces.numpy_random.triangular
.. autofunction:: mkl_random.interfaces.numpy_random.uniform
.. autofunction:: mkl_random.interfaces.numpy_random.vonmises
.. autofunction:: mkl_random.interfaces.numpy_random.wald
.. autofunction:: mkl_random.interfaces.numpy_random.weibull
.. autofunction:: mkl_random.interfaces.numpy_random.zipf
27 changes: 27 additions & 0 deletions docs/source/reference/patching.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.. _patching:

Patching `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_
============================

:mod:`mkl_random` can temporarily replace functions and classes in `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ with
:mod:`mkl_random` implementations from the :ref:`numpy interface <numpy_random_interface>`.


Functions
---------

.. autofunction:: mkl_random.patch_numpy_random

.. autofunction:: mkl_random.restore_numpy_random

.. autofunction:: mkl_random.is_patched


Context manager
---------------

.. autoclass:: mkl_random.mkl_random
:members:

:class:`mkl_random.mkl_random` is both a context manager and a decorator, making it possible to
scope the patch to a block of code or a function.
20 changes: 14 additions & 6 deletions docs/source/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,31 @@ The :mod:`mkl_random` is also distributed as part of `Intel® Distribution for P
First steps
-----------

The :mod:`mkl_random` package has followed the design of :class:`numpy.random` package to
make :mod:`mkl_random` easy to use for those already familiar with the :mod:`numpy.random` module.
The :mod:`mkl_random` package has followed the design of `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_
package to make :mod:`mkl_random` easy to use for those already familiar with the
`numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ module.

.. note::
Since the first release of :mod:`mkl_random`, NumPy introduced new classes :class:`numpy.random.Generator` and
:class:`numpy.random.BitGenerator`, while also retaining :class:`numpy.random.RandomState` for backwards
compatibility. :mod:`mkl_random`, at present, does not provide classes mirroring :class:`Generator` or
:class:`BitGenerators`.

The state of pseudo-random number generator is stored in :class:`mkl_random.RandomState` class,
.. tip::
If you want a drop-in replacement for the `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ legacy interface,
see :ref:`interfaces`. While it is recommended users rewrite code to use :mod:`mkl_random` or :mod:`mkl_random.interfaces.numpy_random`
directly, :mod:`mkl_random` provides tools to patch `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_ so that
existing code transparently uses the MKL-backed implementations in `numpy.random <https://numpy.org/doc/stable/reference/random/legacy.html>`_.
See :ref:`patching` for details.

The state of pseudo-random number generator is stored in :class:`mkl_random.MKLRandomState` class,
so using :mod:`mkl_random` begins with creating an instance of this class:

.. code-block:: python
:caption: Construct random number generator

import mkl_random
rs = mkl_random.RandomState(seed=1234)
rs = mkl_random.MKLRandomState(seed=1234)

Sampling from difference probability distribution is done by calling the class methods on the constructed instance:

Expand All @@ -75,7 +83,7 @@ Here is an example of estimating value of :math:`\pi` by using Monte-Carlo metho
import numpy as np
import mkl_random

rs = mkl_random.RandomState(seed=1234)
rs = mkl_random.MKLRandomState(seed=1234)

sample_size = 10**8
batch_size = 10**6
Expand Down Expand Up @@ -110,7 +118,7 @@ distributions of interest.
`True random generator <https://en.wikipedia.org/wiki/Hardware_random_number_generator>`_ relies on
laws of physics to provide those, leveraging dedicated hardware providing a source of entropy.

`Psuedo-random generator <https://en.wikipedia.org/wiki/Pseudorandom_number_generator>`_ is an algorithm that outputs a sequence that emulates true randomness.
`Pseudo-random generator <https://en.wikipedia.org/wiki/Pseudorandom_number_generator>`_ is an algorithm that outputs a sequence that emulates true randomness.
The quality of emulation is tested statistically through a battery of test, e.g. `Diehard tests <https://en.wikipedia.org/wiki/Diehard_tests>`_.
These tests check if various statistical tests can separate the pseudo-random sequence from a true random one.

Expand Down
Loading
Loading