diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml new file mode 100644 index 0000000..ae990c4 --- /dev/null +++ b/.github/workflows/build-docs.yml @@ -0,0 +1,93 @@ +name: Build mkl_random documentation +on: + pull_request: + push: + branches: [master] + +permissions: read-all + +jobs: + build-and-deploy: + name: Build and Deploy Documentation + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.12.1 + with: + access_token: ${{ github.token }} + - name: Add Intel repository + if: ${{ !github.event.pull_request || github.event.action != 'closed' }} + run: | + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" + sudo apt-get update + - name: Install Intel OneAPI + if: ${{ !github.event.pull_request || github.event.action != 'closed' }} + run: | + sudo apt-get install intel-oneapi-compiler-dpcpp-cpp intel-oneapi-mkl-devel + - name: Setup Python + if: ${{ !github.event.pull_request || github.event.action != 'closed' }} + uses: actions/setup-python@v5 + with: + python-version: '3.11' + architecture: x64 + - name: Install sphinx dependencies + if: ${{ !github.event.pull_request || github.event.action != 'closed' }} + shell: bash -l {0} + run: | + pip install numpy cython setuptools scikit-build cmake sphinx sphinx_rtd_theme furo pydot graphviz sphinxcontrib-programoutput sphinxcontrib-googleanalytics sphinx_design + - name: Checkout repo + uses: actions/checkout@v4.1.1 + with: + fetch-depth: 0 + persist-credentials: false + - name: Build mkl_random+docs + if: ${{ !github.event.pull_request || github.event.action != 'closed' }} + shell: bash -l {0} + run: | + # Ensure that SYCL libraries are on LD_LIBRARY_PATH + source /opt/intel/oneapi/setvars.sh + python setup.py develop + python -c "import mkl_random; print(mkl_random.__version__)" || exit 1 + sphinx-build -M html docs/source docs/build + mkdir -p ~/rendered_docs + cp -r docs/build/html/* ~/rendered_docs/ + git clean -dfx + - name: Save built docs as an artifact + if: ${{ github.event.pull_request && github.event.action != 'closed'}} + uses: actions/upload-artifact@v4 + with: + name: ${{ env.PACKAGE_NAME }} rendered documentation + path: ~/rendered_docs + - name: Configure git + if: ${{ !github.event.pull_request && github.event.action != 'closed'}} + run: | + git config --local user.email "scripting@intel.com" + git config --local user.name "mkl_random-doc-bot" + timeout-minutes: 5 + - name: Checkout gh-pages + if: ${{ !github.event.pull_request && github.event.action != 'closed'}} + run: | + git fetch --all + git checkout gh-pages + - name: 'Copy build to root' + if: ${{ !github.event.pull_request && github.event.action != 'closed'}} + run: | + cp -R ~/rendered_docs/* . + timeout-minutes: 10 + - name: 'Commit changes' + if: ${{ !github.event.pull_request && github.event.action != 'closed'}} + run: | + git add . && git commit -m "Deploy: ${{ github.sha }}" + continue-on-error: true + timeout-minutes: 10 + - name: Publish changes + if: ${{ success() && !github.event.pull_request && github.event.action != 'closed'}} + run: | + git push origin gh-pages + timeout-minutes: 10 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f65eca4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*~ +build/ +mkl_random/__pycache__/ +mkl_random/tests/__pycache__/ +mkl_random/mklrand.cpp +mkl_random/mklrand.cpython*.so +mkl_random.egg-info/ diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..747ffb7 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..faf2b40 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,41 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'mkl_random' +copyright = '2017-2024, Intel Corp.' +author = 'Intel Corp.' +release = '1.2.5' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.coverage", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", + "sphinx.ext.githubpages", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "sphinxcontrib.programoutput", + # "sphinxcontrib.googleanalytics", + 'sphinx_design', +] + +templates_path = ['_templates'] +exclude_patterns = [] + + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'furo' +html_static_path = ['_static'] diff --git a/docs/source/how_to.rst b/docs/source/how_to.rst new file mode 100644 index 0000000..809a47f --- /dev/null +++ b/docs/source/how_to.rst @@ -0,0 +1,4 @@ +How-to Guides +============= + +To be written. \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..33149a8 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,73 @@ +Random sampling powered by Intel(R) Math Kernel Library +======================================================= + +:mod:`mkl_random` is Python package exposing pseudo-random and non-deterministic random +number generators with continuous and discrete distribution available in +Intel(R) Math Kernel Library (MKL). + +.. grid:: 2 + :gutter: 3 + + .. grid-item-card:: Beginner Guides + + New to :mod:`mkl_random`? Check out the Tutorials. + They are a hands-on introduction for beginners. + + +++ + + .. button-ref:: tutorials + :expand: + :color: secondary + :click-parent: + + To the beginner guides + + .. grid-item-card:: User Guides + + The user guides are recipes for key tasks and common problems. + + +++ + + .. button-ref:: how_to + :expand: + :color: secondary + :click-parent: + + To the user guides + + .. grid-item-card:: Reference Guide + + The reference guide contains a detailed description of class :class:`mkl_random.RandomState` and its methods. + + +++ + + .. button-ref:: reference/index + :expand: + :color: secondary + :click-parent: + + To the reference guide + + .. grid-item-card:: Contributor Guides + + Want to add to the codebase? + The contributing guidelines will guide you through the + process of improving :mod:`mkl_random`. + + +++ + + .. button-ref:: maintenance/index + :expand: + :color: secondary + :click-parent: + + To the contributor guides + + +.. toctree:: + :hidden: + + tutorials + how_to + reference/index + maintenance/index diff --git a/docs/source/maintenance/index.rst b/docs/source/maintenance/index.rst new file mode 100644 index 0000000..2611957 --- /dev/null +++ b/docs/source/maintenance/index.rst @@ -0,0 +1,50 @@ +Contributing +============ + +:mod:`mkl_random` is an free and open source project. +We welcome and appreciate your contributions. + +To contribute, fork the repo https://github.com/IntelPython/mkl_random.git, +clone it: + +.. code-block:: + :caption: How to clone the repo + + git clone https://github.com//mkl_random.git + + +A working compiler is needed build :mod:`mkl_random`. +Both Gnu :code:`g++` and Intel LLVM :code:`icpx` are supported. + +Make sure to install Python packages required to build :mod:`mkl_random`: + +* :mod:`python` +* :mod:`numpy` +* :mod:`cython` +* :mod:`setuptools` + +You would also need Intel(R) MKL library and its headers. Set :code:`MKLROOT` environment +variable so that :code:`${MKLROOT}/include/mkl.h` and :code:`${MKLROOT}/lib/libmkl_rt.so` +can be found. + +.. code-block:: bash + :caption: Building mkl_random + + $ export MKLROOT= + python setup.py develop + +To run test suite, install :mod:`pytest`, and run + +.. code-block:: bash + :caption: Running mkl_random test suite + + python -m pytest mkl_random/tests + +To build documentation, install dependencies and running + +.. code-block:: bash + :caption: Building mkl_random documentation + + $ sphinx-build -M html docs/source docs/build + +Rendered documentation can be found in "docs/build/html". \ No newline at end of file diff --git a/docs/source/reference/api.rst b/docs/source/reference/api.rst new file mode 100644 index 0000000..cf2f084 --- /dev/null +++ b/docs/source/reference/api.rst @@ -0,0 +1,7 @@ +.. _fullapi: + +Class RandomState +================= + +.. autoclass:: mkl_random.RandomState + :members: diff --git a/docs/source/reference/ars5.rst b/docs/source/reference/ars5.rst new file mode 100644 index 0000000..0a91c02 --- /dev/null +++ b/docs/source/reference/ars5.rst @@ -0,0 +1,37 @@ +ARS5 brng +========= + +The ARS5 counter-based pseudorandom number generator based on AES encryption algorithm can be +initialized with either an integral seed, a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for ARS5 basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="ars5") + + # Use random state instance to generate 1000 random numbers from + # Uniform(0, 1) distribution + esample = rs.uniform(0, 1, size=1000) + +.. code-block:: python + :caption: Construction for ARS5 basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="ars5") + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for ARS5 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="ars5") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst new file mode 100644 index 0000000..c66d54b --- /dev/null +++ b/docs/source/reference/index.rst @@ -0,0 +1,39 @@ +:mod:`mkl_random` APIs +====================== + +The class :doc:`mkl_random.RandomState <./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 list of supported basic random number generators is as follows (also see `oneMKL Engines `_): + +* :code:`'MT19937'` - the Mersenne Twister pseudo-random number generator (default), :doc:`example ` +* :code:`'SFMT19937'` - the SIMD-oriented Mersenne Twister pseudo-random number generator, :doc:`example ` +* :code:`'MT2203'` - the set of 6024 Mersenne Twister pseudorandom number generators, :doc:`example ` +* :code:`'R250'` - the 32-bit generalized feedback shift register pseudorandom number generator GFSR(250,103), :doc:`example ` +* :code:`'WH'` - the set of 273 Wichmann-Hill’s combined multiplicative congruential generators, :doc:`example ` +* :code:`'MCG31'` - the 31-bit multiplicative congruential pseudorandom number generator, :doc:`example ` +* :code:`'MCG59'` - the 59-bit multiplicative congruential pseudorandom number generator, :doc:`example ` +* :code:`'MRG32K3A'` - the combined multiple recursive pseudorandom number generator MRG32k3a, :doc:`example ` +* :code:`'PHILOX4X32X10'` - the Philox4x32x10 counter-based pseudorandom number generator, :doc:`example ` +* :code:`'NONDETERM'` - the generator with non-deterministic source of randomness (for example, a hardware device), :doc:`example ` +* :code:`'ARS5'` - the ARS5 counter-based pseudorandom number generator based on AES encryption algorithm, :doc:`example ` + +.. _oneMKLBRNG: https://spec.oneapi.io/versions/1.0-rev-2/elements/oneMKL/source/domains/rng/engines-basic-random-number-generators.html + +.. toctree:: + :hidden: + + api + mt19937 + sfmt19937 + r250 + mt2203 + wichmann_hill + mcg31 + mcg59 + mrg32k3a + philox4x32x10 + nondeterministic + ars5 diff --git a/docs/source/reference/mcg31.rst b/docs/source/reference/mcg31.rst new file mode 100644 index 0000000..87ee301 --- /dev/null +++ b/docs/source/reference/mcg31.rst @@ -0,0 +1,37 @@ +MCG31 brng +========== + +The 31-bit multiplicative congruential pseudorandom number generator MCG(1132489760, 2**31 -1) can be +initialized with either an integral seed, a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for MCG31 basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="MCG31") + + # Use random state instance to generate 1000 random numbers from + # Uniform(0, 1) distribution + esample = rs.uniform(0, 1, size=1000) + +.. code-block:: python + :caption: Construction for MCG31 basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="MCG31") + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for MCG31 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="MCG31") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) diff --git a/docs/source/reference/mcg59.rst b/docs/source/reference/mcg59.rst new file mode 100644 index 0000000..314361a --- /dev/null +++ b/docs/source/reference/mcg59.rst @@ -0,0 +1,37 @@ +MCG59 brng +========== + +The 59-bit multiplicative congruential pseudorandom number generator can be +initialized with either an integral seed, a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for MCG31 basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="MCG59") + + # Use random state instance to generate 1000 random numbers from + # Uniform(0, 1) distribution + esample = rs.uniform(0, 1, size=1000) + +.. code-block:: python + :caption: Construction for MCG31 basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="MCG59") + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for MCG31 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="MCG59") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) diff --git a/docs/source/reference/mrg32k3a.rst b/docs/source/reference/mrg32k3a.rst new file mode 100644 index 0000000..54c5c7e --- /dev/null +++ b/docs/source/reference/mrg32k3a.rst @@ -0,0 +1,37 @@ +MRG32k3a brng +============= + +The combined multiple recursive pseudorandom number generator MRG32k3a can be +initialized with either an integral seed, a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for MRG32k3a basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="MRG32k3a") + + # Use random state instance to generate 1000 random numbers from + # Uniform(0, 1) distribution + esample = rs.uniform(0, 1, size=1000) + +.. code-block:: python + :caption: Construction for MRG32k3a basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="MRG32k3a") + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for MRG32k3a basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="MRG32k3a") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) diff --git a/docs/source/reference/mt19937.rst b/docs/source/reference/mt19937.rst new file mode 100644 index 0000000..6b32777 --- /dev/null +++ b/docs/source/reference/mt19937.rst @@ -0,0 +1,35 @@ +MT19937 brng +============ + +The Mersenne Twister random number generator can be initialized with either an integral seed, +a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for MT19937 basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="MT19937") + + # Use random state instance to generate 1000 uniform random numbers + usample = rs.uniform(0, 1, size=1000) + +.. code-block:: python + :caption: Construction for MT19937 basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="MT19937") + + # Use random state instance to generate 1000 Gaussian random numbers + nsample = rs_vec.normal(0, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for MT19937 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="MT19937") + + # Use random state instance to generate 1000 random numbers + # from Binomial(10, 0.4) + bsample = rs_def.binomial(10, 0.4, size=1000) diff --git a/docs/source/reference/mt2203.rst b/docs/source/reference/mt2203.rst new file mode 100644 index 0000000..6bf43a5 --- /dev/null +++ b/docs/source/reference/mt2203.rst @@ -0,0 +1,53 @@ +MT2203 brng +=========== + +Each generator from the set of `6024 Mersenne Twister pseudorandom number generators `_ can be +initialized with either an integral seed, a list of integral seeds, or automatically. + +An individual member of the set can be addressed by using a tuple to specify the generator +:code:`brng=("MT2203", set_id)` where :math:`0 \leq \text{set_id} < 6024`. + +.. code-block:: python + :caption: Construction for MT2203 basic random number generator with scalar seed + + import mkl_random + seed = 777 + # initialize representative generator from the set + rs0 = mkl_random.RandomState(seed, brng="MT2203") + + # initialize 0-th member of the set + rs0 = mkl_random.RandomState(seed, brng=("MT2203", 0)) + + # initialize 5-th member of the set + rs5 = mkl_random.RandomState(seed, brng=("MT2203", 5)) + + sample = rs5.uniform(0, 1, size=1_000_000) + +.. code-block:: python + :caption: Construction for MT2203 basic random number generator with vector seed + + import mkl_random + rs = mkl_random.RandomState([1234, 567, 89, 0], brng=("MT2203", 6023)) + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for MT2203 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="MT2203") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) + +Different members of the set of generators initialized with the same seed are designed to generate +statistically independent streams of randomness. This property makes MT2203 generator suitable for +parallelizing stochastic algorithms. Please refer to "examples/" folder in the `GitHub repo +`_. + +.. _philoxrng: https://spec.oneapi.io/versions/1.0-rev-2/elements/oneMKL/source/domains/rng/mkl-rng-philox4x32x10.html \ No newline at end of file diff --git a/docs/source/reference/nondeterministic.rst b/docs/source/reference/nondeterministic.rst new file mode 100644 index 0000000..a3b2212 --- /dev/null +++ b/docs/source/reference/nondeterministic.rst @@ -0,0 +1,18 @@ +Nondeterm brng +============== + +The generator with non-deterministic source of randomness, such as a hardware device, requires no seeding. +This basic random number generator should not be used if reproducibility of stochastic simulation is required. + +.. code-block:: python + :caption: Construction for non-deterministic basic random number generator + + import mkl_random + rs = mkl_random.RandomState(brng="nondeterm") + + # Use random state instance to generate 1000 random numbers from + # Uniform(0, 1) distribution + esample = rs.uniform(0, 1, size=1000) + +Seed parameter provided to the constructor of :class:`mkl_random.RandomState`, +or :meth:`mkl_random.RandomState.seed` is ignored. \ No newline at end of file diff --git a/docs/source/reference/philox4x32x10.rst b/docs/source/reference/philox4x32x10.rst new file mode 100644 index 0000000..9eb5ae1 --- /dev/null +++ b/docs/source/reference/philox4x32x10.rst @@ -0,0 +1,37 @@ +Philox4x32x10 brng +================== + +The Philox 4x32x10 counter-based pseudorandom number generator can be +initialized with either an integral seed, a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for Philox4x32x10 basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="philox4x32x10") + + # Use random state instance to generate 1000 random numbers from + # Uniform(0, 1) distribution + esample = rs.uniform(0, 1, size=1000) + +.. code-block:: python + :caption: Construction for Philox4x32x10 basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="philox4x32x10") + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for Philox4x32x10 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="philox4x32x10") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) diff --git a/docs/source/reference/r250.rst b/docs/source/reference/r250.rst new file mode 100644 index 0000000..5f1c5a5 --- /dev/null +++ b/docs/source/reference/r250.rst @@ -0,0 +1,37 @@ +R250 brng +========= + +The 32-bit generalized feedback shift register pseudorandom number generator GFSR(250,103) can be +initialized with either an integral seed, a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for R250 basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="R250") + + # Use random state instance to generate 1000 random numbers from + # Uniform(0, 1) distribution + esample = rs.uniform(0, 1, size=1000) + +.. code-block:: python + :caption: Construction for R250 basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="R250") + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for R250 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="R250") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) diff --git a/docs/source/reference/sfmt19937.rst b/docs/source/reference/sfmt19937.rst new file mode 100644 index 0000000..db6c53f --- /dev/null +++ b/docs/source/reference/sfmt19937.rst @@ -0,0 +1,37 @@ +SFMT19937 brng +============== + +The SIMD-oriented Mersenne Twister random number generator can be initialized with +either an integral seed, a list of integral seeds, or automatically. + +.. code-block:: python + :caption: Construction for SFMT19937 basic random number generator with scalar seed + + import mkl_random + rs = mkl_random.RandomState(1234, brng="SFMT19937") + + # Use random state instance to generate 1000 random numbers from + # Exponential distribution + esample = rs.exponential(2.3, size=1000) + +.. code-block:: python + :caption: Construction for SFMT19937 basic random number generator with vector seed + + import mkl_random + rs_vec = mkl_random.RandomState([1234, 567, 89, 0], brng="SFMT19937") + + # Use random state instance to generate 1000 random numbers from + # Gamma distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for SFMT19937 basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="SFMT19937") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) diff --git a/docs/source/reference/wichmann_hill.rst b/docs/source/reference/wichmann_hill.rst new file mode 100644 index 0000000..b0128dc --- /dev/null +++ b/docs/source/reference/wichmann_hill.rst @@ -0,0 +1,54 @@ +Wichmann-Hill brng +================== + +Each generator from the set of 273 Wichmann-Hill’s combined multiplicative congruential +`generators `_ can be initialized with either an integral seed, a list of integral seeds, +or automatically. + +An individual member of the set can be addressed by using a tuple to specify the generator as +:code:`brng=("WH", set_id)` where :math:`0 \leq \text{set_id} < 273`. + +.. code-block:: python + :caption: Construction for WH basic random number generator with scalar seed + + import mkl_random + seed = 777 + # initialize representative generator from the set + rs0 = mkl_random.RandomState(seed, brng="WH") + + # initialize 0-th member of the set + rs0 = mkl_random.RandomState(seed, brng=("WH", 0)) + + # initialize 5-th member of the set + rs5 = mkl_random.RandomState(seed, brng=("WH", 5)) + + sample = rs5.uniform(0, 1, size=1_000_000) + +.. code-block:: python + :caption: Construction for WH basic random number generator with vector seed + + import mkl_random + rs = mkl_random.RandomState([1234, 567, 89, 0], brng=("WH", 200)) + + # Use random state instance to generate 1000 random numbers from + # Gamma(3, 1) distibution + gsample = rs_vec.gamma(3, 1, size=1000) + +When seed is not specified, the generator is initialized using system clock, e.g.: + +.. code-block:: python + :caption: Construction for WH basic random number generator automatic seed + + import mkl_random + rs_def = mkl_random.RandomState(brng="WH") + + # Use random state instance to generate 1000 random numbers + # from discrete uniform distribution [1, 6] + isample = rs_def.randint(1, 6 + 1, size=1000) + +Different members of the set of generators initialized with the same seed are designed to generate +statistically independent streams of randomness. This property makes MT2203 generator suitable for +parallelizing stochastic algorithms. Please refer to "examples/" folder in the `GitHub repo +`_. + +.. _whrng: https://spec.oneapi.io/versions/1.0-rev-2/elements/oneMKL/source/domains/rng/mkl-rng-wichmann_hill.html \ No newline at end of file diff --git a/docs/source/tutorials.rst b/docs/source/tutorials.rst new file mode 100644 index 0000000..faeb59a --- /dev/null +++ b/docs/source/tutorials.rst @@ -0,0 +1,93 @@ +Installation +============ + +Package :mod:`mkl_random` is available in conda ecosystem on "conda-forge", default, and "intel" channels. + +.. code-block:: bash + :caption: Install mkl_random from conda-forge channel + + $ conda install -c conda-forge mkl_random + +.. code-block:: bash + :caption: Install mkl_random from intel channel + + $ conda install -c intel mkl_random + +.. code-block:: bash + :caption: Install mkl_random from default + + $ conda install mkl_random + +The package can also be installed via :code:`pip`, either from PyPI, or from + +.. code-block:: bash + :caption: Install mkl_random using pip from intel channel on Anaconda + + $ pip install -i https://pypi.anaconda.org/intel/simple mkl_random + +.. code-block:: bash + :caption: Install mkl_random using pip from PyPI + + $ pip install mkl_random + +The :mod:`mkl_random` is also distributed as part of `Intel(R) Distribution for Python* `_. + +Beginner's guide +================ + +The :mod:`mkl_random` package was designed following :class:`numpy.random.RandomState` class to +make use of :mod:`mkl_random` easy for current uses of :mod:`numpy.random` module. + +.. note:: + Since the first release of `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. + +The state of pseudo-random number generator is stored in :class:`mkl_random.RandomState` 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) + +Sampling from difference probability distribution is done by calling class methods on the constructed instance: + +.. code-block:: python + :caption: Generate one million variates from standard continuous uniform distribution + + s = rs.uniform(0, 1, size=1_000_000) + +Drawing samples updates the state of pseudo-random number generator so that next sample is statistically +independent from the previous one (with caveats of using pseudo-random generators implied). + +Here is an example of estimating value of :math:`\pi` by using Monte-Carlo method: + +.. code-block:: python + :caption: Using Monte-Carlo method to estimate value of pi + + import numpy as np + import mkl_random + + rs = mkl_random.RandomState(seed=1234) + + n = 10**8 + batch_size = 10**6 + accepted = 0 + sampled = 0 + while sampled < n: + sampled += batch_size + x = rs.uniform(0, 1, size=batch_size) + y = rs.uniform(0, 1, size=batch_size) + accepted += np.sum(x*x + y*y < 1.0) + + print("Pi estimate: ", 4. * (accepted / n)) + +Sample output of running such an example: + +.. code-block:: bash + :caption: Sample output after executing above script + + $ python pi.py + Pi estimate: 3.14167732 \ No newline at end of file