diff options
Diffstat (limited to 'doc/source/reference/random')
-rw-r--r-- | doc/source/reference/random/bit_generators/index.rst | 14 | ||||
-rw-r--r-- | doc/source/reference/random/compatibility.rst | 87 | ||||
-rw-r--r-- | doc/source/reference/random/extending.rst | 4 | ||||
-rw-r--r-- | doc/source/reference/random/generator.rst | 5 | ||||
-rw-r--r-- | doc/source/reference/random/index.rst | 309 | ||||
-rw-r--r-- | doc/source/reference/random/legacy.rst | 15 | ||||
-rw-r--r-- | doc/source/reference/random/new-or-different.rst | 56 | ||||
-rw-r--r-- | doc/source/reference/random/parallel.rst | 27 |
8 files changed, 275 insertions, 242 deletions
diff --git a/doc/source/reference/random/bit_generators/index.rst b/doc/source/reference/random/bit_generators/index.rst index d93f38d0b..e523b4339 100644 --- a/doc/source/reference/random/bit_generators/index.rst +++ b/doc/source/reference/random/bit_generators/index.rst @@ -1,5 +1,7 @@ .. currentmodule:: numpy.random +.. _random-bit-generators: + Bit Generators ============== @@ -50,6 +52,8 @@ The included BitGenerators are: Philox <philox> SFC64 <sfc64> +.. _seeding_and_entropy: + Seeding and Entropy =================== @@ -127,6 +131,16 @@ of 12 instances: .. end_block +If you already have an initial random generator instance, you can shorten +the above by using the `~BitGenerator.spawn` method: + +.. code-block:: python + + from numpy.random import PCG64, SeedSequence + # High quality initial entropy + entropy = 0x87351080e25cb0fad77a44a3be03b491 + base_bitgen = PCG64(entropy) + generators = base_bitgen.spawn(12) An alternative way is to use the fact that a `~SeedSequence` can be initialized by a tuple of elements. Here we use a base entropy value and an integer diff --git a/doc/source/reference/random/compatibility.rst b/doc/source/reference/random/compatibility.rst new file mode 100644 index 000000000..138f03ca3 --- /dev/null +++ b/doc/source/reference/random/compatibility.rst @@ -0,0 +1,87 @@ +.. _random-compatibility: + +.. currentmodule:: numpy.random + +Compatibility Policy +==================== + +`numpy.random` has a somewhat stricter compatibility policy than the rest of +NumPy. Users of pseudorandomness often have use cases for being able to +reproduce runs in fine detail given the same seed (so-called "stream +compatibility"), and so we try to balance those needs with the flexibility to +enhance our algorithms. :ref:`NEP 19 <NEP19>` describes the evolution of this +policy. + +The main kind of compatibility that we enforce is stream-compatibility from run +to run under certain conditions. If you create a `Generator` with the same +`BitGenerator`, with the same seed, perform the same sequence of method calls +with the same arguments, on the same build of ``numpy``, in the same +environment, on the same machine, you should get the same stream of numbers. +Note that these conditions are very strict. There are a number of factors +outside of NumPy's control that limit our ability to guarantee much more than +this. For example, different CPUs implement floating point arithmetic +differently, and this can cause differences in certain edge cases that cascade +to the rest of the stream. `Generator.multivariate_normal`, for another +example, uses a matrix decomposition from ``numpy.linalg``. Even on the same +platform, a different build of ``numpy`` may use a different version of this +matrix decomposition algorithm from the LAPACK that it links to, causing +`Generator.multivariate_normal` to return completely different (but equally +valid!) results. We strive to prefer algorithms that are more resistant to +these effects, but this is always imperfect. + +.. note:: + + Most of the `Generator` methods allow you to draw multiple values from + a distribution as arrays. The requested size of this array is a parameter, + for the purposes of the above policy. Calling ``rng.random()`` 5 times is + not *guaranteed* to give the same numbers as ``rng.random(5)``. We reserve + the ability to decide to use different algorithms for different-sized + blocks. In practice, this happens rarely. + +Like the rest of NumPy, we generally maintain API source +compatibility from version to version. If we *must* make an API-breaking +change, then we will only do so with an appropriate deprecation period and +warnings, according to :ref:`general NumPy policy <NEP23>`. + +Breaking stream-compatibility in order to introduce new features or +improve performance in `Generator` or `default_rng` will be *allowed* with +*caution*. Such changes will be considered features, and as such will be no +faster than the standard release cadence of features (i.e. on ``X.Y`` releases, +never ``X.Y.Z``). Slowness will not be considered a bug for this purpose. +Correctness bug fixes that break stream-compatibility can happen on bugfix +releases, per usual, but developers should consider if they can wait until the +next feature release. We encourage developers to strongly weight user’s pain +from the break in stream-compatibility against the improvements. One example +of a worthwhile improvement would be to change algorithms for a significant +increase in performance, for example, moving from the `Box-Muller transform +<https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform>`_ method of +Gaussian variate generation to the faster `Ziggurat algorithm +<https://en.wikipedia.org/wiki/Ziggurat_algorithm>`_. An example of +a discouraged improvement would be tweaking the Ziggurat tables just a little +bit for a small performance improvement. + +.. note:: + + In particular, `default_rng` is allowed to change the default + `BitGenerator` that it uses (again, with *caution* and plenty of advance + warning). + +In general, `BitGenerator` classes have stronger guarantees of +version-to-version stream compatibility. This allows them to be a firmer +building block for downstream users that need it. Their limited API surface +makes it easier for them to maintain this compatibility from version to version. See +the docstrings of each `BitGenerator` class for their individual compatibility +guarantees. + +The legacy `RandomState` and the :ref:`associated convenience functions +<functions-in-numpy-random>` have a stricter version-to-version +compatibility guarantee. For reasons outlined in :ref:`NEP 19 <NEP19>`, we had made +stronger promises about their version-to-version stability early in NumPy's +development. There are still some limited use cases for this kind of +compatibility (like generating data for tests), so we maintain as much +compatibility as we can. There will be no more modifications to `RandomState`, +not even to fix correctness bugs. There are a few gray areas where we can make +minor fixes to keep `RandomState` working without segfaulting as NumPy's +internals change, and some docstring fixes. However, the previously-mentioned +caveats about the variability from machine to machine and build to build still +apply to `RandomState` just as much as it does to `Generator`. diff --git a/doc/source/reference/random/extending.rst b/doc/source/reference/random/extending.rst index 6bb941496..998faf80a 100644 --- a/doc/source/reference/random/extending.rst +++ b/doc/source/reference/random/extending.rst @@ -25,7 +25,7 @@ provided by ``ctypes.next_double``. 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. +the `Examples`_ section below. .. _random_cython: @@ -113,6 +113,6 @@ Examples .. toctree:: Numba <examples/numba> - CFFI + Numba <examples/numba_cffi> + CFFI + Numba <examples/numba_cffi> Cython <examples/cython/index> CFFI <examples/cffi> diff --git a/doc/source/reference/random/generator.rst b/doc/source/reference/random/generator.rst index dc71cb1f9..e08395b17 100644 --- a/doc/source/reference/random/generator.rst +++ b/doc/source/reference/random/generator.rst @@ -18,12 +18,13 @@ can be changed by passing an instantized BitGenerator to ``Generator``. :members: __init__ :exclude-members: __init__ -Accessing the BitGenerator --------------------------- +Accessing the BitGenerator and Spawning +--------------------------------------- .. autosummary:: :toctree: generated/ ~numpy.random.Generator.bit_generator + ~numpy.random.Generator.spawn Simple random data ------------------ diff --git a/doc/source/reference/random/index.rst b/doc/source/reference/random/index.rst index 83a27d80c..38555b133 100644 --- a/doc/source/reference/random/index.rst +++ b/doc/source/reference/random/index.rst @@ -7,210 +7,124 @@ Random sampling (:mod:`numpy.random`) ===================================== -Numpy's random number routines produce pseudo random numbers using -combinations of a `BitGenerator` to create sequences and a `Generator` -to use those sequences to sample from different statistical distributions: - -* BitGenerators: Objects that generate random numbers. These are typically - unsigned integer words filled with sequences of either 32 or 64 random bits. -* Generators: Objects that transform sequences of random bits from a - BitGenerator into sequences of numbers that follow a specific probability - distribution (such as uniform, Normal or Binomial) within a specified - interval. - -Since Numpy version 1.17.0 the Generator can be initialized with a -number of different BitGenerators. It exposes many different probability -distributions. See `NEP 19 <https://www.numpy.org/neps/ -nep-0019-rng-policy.html>`_ for context on the updated random Numpy number -routines. The legacy `RandomState` random number routines are still -available, but limited to a single BitGenerator. See :ref:`new-or-different` -for a complete list of improvements and differences from the legacy -``RandomState``. - -For convenience and backward compatibility, a single `RandomState` -instance's methods are imported into the numpy.random namespace, see -:ref:`legacy` for the complete list. - .. _random-quick-start: Quick Start ----------- -Call `default_rng` to get a new instance of a `Generator`, then call its -methods to obtain samples from different distributions. By default, -`Generator` uses bits provided by `PCG64` which has better statistical -properties than the legacy `MT19937` used in `RandomState`. - -.. code-block:: python - - # Do this (new version) - from numpy.random import default_rng - rng = default_rng() - vals = rng.standard_normal(10) - more_vals = rng.standard_normal(10) - - # instead of this (legacy version) - from numpy import random - vals = random.standard_normal(10) - more_vals = random.standard_normal(10) - -`Generator` can be used as a replacement for `RandomState`. Both class -instances hold an internal `BitGenerator` instance to provide the bit -stream, it is accessible as ``gen.bit_generator``. Some long-overdue API -cleanup means that legacy and compatibility methods have been removed from -`Generator` - -=================== ============== ============ -`RandomState` `Generator` Notes -------------------- -------------- ------------ -``random_sample``, ``random`` Compatible with `random.random` -``rand`` -------------------- -------------- ------------ -``randint``, ``integers`` Add an ``endpoint`` kwarg -``random_integers`` -------------------- -------------- ------------ -``tomaxint`` removed Use ``integers(0, np.iinfo(np.int_).max,`` - ``endpoint=False)`` -------------------- -------------- ------------ -``seed`` removed Use `SeedSequence.spawn` -=================== ============== ============ - -See :ref:`new-or-different` for more information. - -Something like the following code can be used to support both ``RandomState`` -and ``Generator``, with the understanding that the interfaces are slightly -different - -.. code-block:: python - - try: - rng_integers = rng.integers - except AttributeError: - rng_integers = rng.randint - a = rng_integers(1000) - -Seeds can be passed to any of the BitGenerators. The provided value is mixed -via `SeedSequence` to spread a possible sequence of seeds across a wider -range of initialization states for the BitGenerator. Here `PCG64` is used and -is wrapped with a `Generator`. - -.. code-block:: python - - from numpy.random import Generator, PCG64 - rng = Generator(PCG64(12345)) - rng.standard_normal() - -Here we use `default_rng` to create an instance of `Generator` to generate a -random float: - ->>> import numpy as np ->>> rng = np.random.default_rng(12345) ->>> print(rng) -Generator(PCG64) ->>> rfloat = rng.random() ->>> rfloat -0.22733602246716966 ->>> type(rfloat) -<class 'float'> - -Here we use `default_rng` to create an instance of `Generator` to generate 3 -random integers between 0 (inclusive) and 10 (exclusive): - ->>> import numpy as np ->>> rng = np.random.default_rng(12345) ->>> rints = rng.integers(low=0, high=10, size=3) ->>> rints -array([6, 2, 7]) ->>> type(rints[0]) -<class 'numpy.int64'> - -Introduction ------------- -The new infrastructure takes a different approach to producing random numbers -from the `RandomState` object. Random number generation is separated into -two components, a bit generator and a random generator. - -The `BitGenerator` has a limited set of responsibilities. It manages state -and provides functions to produce random doubles and random unsigned 32- and -64-bit values. - -The `random generator <Generator>` takes the -bit generator-provided stream and transforms them into more useful -distributions, e.g., simulated normal random values. This structure allows -alternative bit generators to be used with little code duplication. - -The `Generator` is the user-facing object that is nearly identical to the -legacy `RandomState`. It accepts a bit generator instance as an argument. -The default is currently `PCG64` but this may change in future versions. -As a convenience NumPy provides the `default_rng` function to hide these -details: - ->>> from numpy.random import default_rng ->>> rng = default_rng(12345) ->>> print(rng) -Generator(PCG64) ->>> print(rng.random()) -0.22733602246716966 - -One can also instantiate `Generator` directly with a `BitGenerator` instance. - -To use the default `PCG64` bit generator, one can instantiate it directly and -pass it to `Generator`: - ->>> from numpy.random import Generator, PCG64 ->>> rng = Generator(PCG64(12345)) ->>> print(rng) -Generator(PCG64) - -Similarly to use the older `MT19937` bit generator (not recommended), one can -instantiate it directly and pass it to `Generator`: - ->>> from numpy.random import Generator, MT19937 ->>> rng = Generator(MT19937(12345)) ->>> print(rng) -Generator(MT19937) - -What's New or Different -~~~~~~~~~~~~~~~~~~~~~~~ +The :mod:`numpy.random` module implements pseudo-random number generators +(PRNGs or RNGs, for short) with the ability to draw samples from a variety of +probability distributions. In general, users will create a `Generator` instance +with `default_rng` and call the various methods on it to obtain samples from +different distributions. + +:: + + >>> import numpy as np + >>> rng = np.random.default_rng() + # Generate one random float uniformly distributed over the range [0, 1) + >>> rng.random() #doctest: +SKIP + 0.06369197489564249 # may vary + # Generate an array of 10 numbers according to a unit Gaussian distribution. + >>> rng.standard_normal(10) #doctest: +SKIP + array([-0.31018314, -1.8922078 , -0.3628523 , -0.63526532, 0.43181166, # may vary + 0.51640373, 1.25693945, 0.07779185, 0.84090247, -2.13406828]) + # Generate an array of 5 integers uniformly over the range [0, 10). + >>> rng.integers(low=0, high=10, size=5) #doctest: +SKIP + array([8, 7, 6, 2, 0]) # may vary + +Our RNGs are deterministic sequences and can be reproduced by specifying a seed integer to +derive its initial state. By default, with no seed provided, `default_rng` will create +seed the RNG from nondeterministic data from the operating system and therefore +generate different numbers each time. The pseudo-random sequences will be +independent for all practical purposes, at least those purposes for which our +pseudo-randomness was good for in the first place. + +:: + + >>> rng1 = np.random.default_rng() + >>> rng1.random() #doctest: +SKIP + 0.6596288841243357 # may vary + >>> rng2 = np.random.default_rng() + >>> rng2.random() #doctest: +SKIP + 0.11885628817151628 # may vary + .. warning:: - The Box-Muller method used to produce NumPy's normals is no longer available - in `Generator`. It is not possible to reproduce the exact random - values using Generator for the normal distribution or any other - distribution that relies on the normal such as the `RandomState.gamma` or - `RandomState.standard_t`. If you require bitwise backward compatible - streams, use `RandomState`. - -* The Generator's normal, exponential and gamma functions use 256-step Ziggurat - methods which are 2-10 times faster than NumPy's Box-Muller or inverse CDF - implementations. -* Optional ``dtype`` argument that accepts ``np.float32`` or ``np.float64`` - to produce either single or double precision uniform random variables for - select distributions -* 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 <random_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`. - The ``endpoint`` keyword can be used to specify open or closed intervals. - This replaces both ``randint`` and the deprecated ``random_integers``. -* `Generator.random` is now the canonical way to generate floating-point - random numbers, which replaces `RandomState.random_sample`, - `RandomState.sample`, and `RandomState.ranf`. This is consistent with - Python's `random.random`. -* All BitGenerators in numpy use `SeedSequence` to convert seeds into - initialized states. -* The addition of an ``axis`` keyword argument to methods such as - `Generator.choice`, `Generator.permutation`, and `Generator.shuffle` - improves support for sampling from and shuffling multi-dimensional arrays. - -See :ref:`new-or-different` for a complete list of improvements and -differences from the traditional ``Randomstate``. + The pseudo-random number generators implemented in this module are designed + for statistical modeling and simulation. They are not suitable for security + or cryptographic purposes. See the :py:mod:`secrets` module from the + standard library for such use cases. + +Seeds should be large positive integers. `default_rng` can take positive +integers of any size. We recommend using very large, unique numbers to ensure +that your seed is different from anyone else's. This is good practice to ensure +that your results are statistically independent from theirs unless you are +intentionally *trying* to reproduce their result. A convenient way to get +such a seed number is to use :py:func:`secrets.randbits` to get an +arbitrary 128-bit integer. + +:: + + >>> import secrets + >>> import numpy as np + >>> secrets.randbits(128) #doctest: +SKIP + 122807528840384100672342137672332424406 # may vary + >>> rng1 = np.random.default_rng(122807528840384100672342137672332424406) + >>> rng1.random() + 0.5363922081269535 + >>> rng2 = np.random.default_rng(122807528840384100672342137672332424406) + >>> rng2.random() + 0.5363922081269535 + +See the documentation on `default_rng` and `SeedSequence` for more advanced +options for controlling the seed in specialized scenarios. + +`Generator` and its associated infrastructure was introduced in NumPy version +1.17.0. There is still a lot of code that uses the older `RandomState` and the +functions in `numpy.random`. While there are no plans to remove them at this +time, we do recommend transitioning to `Generator` as you can. The algorithms +are faster, more flexible, and will receive more improvements in the future. +For the most part, `Generator` can be used as a replacement for `RandomState`. +See :ref:`legacy` for information on the legacy infrastructure, +:ref:`new-or-different` for information on transitioning, and :ref:`NEP 19 +<NEP19>` for some of the reasoning for the transition. + +Design +------ + +Users primarily interact with `Generator` instances. Each `Generator` instance +owns a `BitGenerator` instance that implements the core RNG algorithm. The +`BitGenerator` has a limited set of responsibilities. It manages state and +provides functions to produce random doubles and random unsigned 32- and 64-bit +values. + +The `Generator` takes the bit generator-provided stream and transforms them +into more useful distributions, e.g., simulated normal random values. This +structure allows alternative bit generators to be used with little code +duplication. + +NumPy implements several different `BitGenerator` classes implementing +different RNG algorithms. `default_rng` currently uses `~PCG64` as the +default `BitGenerator`. It has better statistical properties and performance +than the `~MT19937` algorithm used in the legacy `RandomState`. See +:ref:`random-bit-generators` for more details on the supported BitGenerators. + +`default_rng` and BitGenerators delegate the conversion of seeds into RNG +states to `SeedSequence` internally. `SeedSequence` implements a sophisticated +algorithm that intermediates between the user's input and the internal +implementation details of each `BitGenerator` algorithm, each of which can +require different amounts of bits for its state. Importantly, it lets you use +arbitrary-sized integers and arbitrary sequences of such integers to mix +together into the RNG state. This is a useful primitive for constructing +a :ref:`flexible pattern for parallel RNG streams <seedsequence-spawn>`. + +For backward compatibility, we still maintain the legacy `RandomState` class. +It continues to use the `~MT19937` algorithm by default, and old seeds continue +to reproduce the same results. The convenience :ref:`functions-in-numpy-random` +are still aliases to the methods on a single global `RandomState` instance. See +:ref:`legacy` for the complete details. See :ref:`new-or-different` for +a detailed comparison between `Generator` and `RandomState`. Parallel Generation ~~~~~~~~~~~~~~~~~~~ @@ -235,6 +149,7 @@ Concepts Legacy Generator (RandomState) <legacy> BitGenerators, SeedSequences <bit_generators/index> Upgrading PCG64 with PCG64DXSM <upgrading-pcg64> + compatibility Features -------- diff --git a/doc/source/reference/random/legacy.rst b/doc/source/reference/random/legacy.rst index b1fce49a1..00921c477 100644 --- a/doc/source/reference/random/legacy.rst +++ b/doc/source/reference/random/legacy.rst @@ -52,7 +52,7 @@ using the state of the `RandomState`: :exclude-members: __init__ Seeding and State ------------------ +================= .. autosummary:: :toctree: generated/ @@ -62,7 +62,7 @@ Seeding and State ~RandomState.seed Simple random data ------------------- +================== .. autosummary:: :toctree: generated/ @@ -75,7 +75,7 @@ Simple random data ~RandomState.bytes Permutations ------------- +============ .. autosummary:: :toctree: generated/ @@ -83,7 +83,7 @@ Permutations ~RandomState.permutation Distributions -------------- +============== .. autosummary:: :toctree: generated/ @@ -123,8 +123,10 @@ Distributions ~RandomState.weibull ~RandomState.zipf +.. _functions-in-numpy-random: + Functions in `numpy.random` ---------------------------- +=========================== Many of the RandomState methods above are exported as functions in `numpy.random` This usage is discouraged, as it is implemented via a global `RandomState` instance which is not advised on two counts: @@ -133,8 +135,7 @@ Many of the RandomState methods above are exported as functions in - It uses a `RandomState` rather than the more modern `Generator`. -For backward compatible legacy reasons, we cannot change this. See -:ref:`random-quick-start`. +For backward compatible legacy reasons, we will not change this. .. autosummary:: :toctree: generated/ diff --git a/doc/source/reference/random/new-or-different.rst b/doc/source/reference/random/new-or-different.rst index 8f4a70540..9b5bf38e5 100644 --- a/doc/source/reference/random/new-or-different.rst +++ b/doc/source/reference/random/new-or-different.rst @@ -5,17 +5,9 @@ What's New or Different ----------------------- -.. warning:: - - The Box-Muller method used to produce NumPy's normals is no longer available - in `Generator`. It is not possible to reproduce the exact random - values using ``Generator`` for the normal distribution or any other - distribution that relies on the normal such as the `Generator.gamma` or - `Generator.standard_t`. If you require bitwise backward compatible - streams, use `RandomState`, i.e., `RandomState.gamma` or - `RandomState.standard_t`. - -Quick comparison of legacy :ref:`mtrand <legacy>` to the new `Generator` +NumPy 1.17.0 introduced `Generator` as an improved replacement for +the :ref:`legacy <legacy>` `RandomState`. Here is a quick comparison of the two +implementations. ================== ==================== ============= Feature Older Equivalent Notes @@ -44,21 +36,17 @@ Feature Older Equivalent Notes ``high`` interval endpoint ================== ==================== ============= -And in more detail: - -* Simulate from the complex normal distribution - (`~.Generator.complex_normal`) * The normal, exponential and gamma generators use 256-step Ziggurat methods which are 2-10 times faster than NumPy's default implementation in `~.Generator.standard_normal`, `~.Generator.standard_exponential` or - `~.Generator.standard_gamma`. - + `~.Generator.standard_gamma`. Because of the change in algorithms, it is not + possible to reproduce the exact random values using ``Generator`` for these + distributions or any distribution method that relies on them. .. ipython:: python - from numpy.random import Generator, PCG64 import numpy.random - rng = Generator(PCG64()) + rng = np.random.default_rng() %timeit -n 1 rng.standard_normal(100000) %timeit -n 1 numpy.random.standard_normal(100000) @@ -74,18 +62,25 @@ And in more detail: * `~.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`. - This replaces both ``randint`` and the deprecated ``random_integers``. -* The Box-Muller method used to produce NumPy's normals is no longer available. + random numbers from a discrete uniform distribution. This replaces both + ``randint`` and the deprecated ``random_integers``. +* The ``rand`` and ``randn`` methods are only available through the legacy + `~.RandomState`. +* `Generator.random` is now the canonical way to generate floating-point + random numbers, which replaces `RandomState.random_sample`, + `sample`, and `ranf`, all of which were aliases. This is consistent with + Python's `random.random`. * 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. +* All bit generators use `SeedSequence` to :ref:`convert seed integers to + initialized states <seeding_and_entropy>`. * Optional ``dtype`` argument that accepts ``np.float32`` or ``np.float64`` to produce either single or double precision uniform random variables for - select distributions + select distributions. `~.Generator.integers` accepts a ``dtype`` argument + with any signed or unsigned integer dtype. * Uniforms (`~.Generator.random` and `~.Generator.integers`) * Normals (`~.Generator.standard_normal`) @@ -94,9 +89,10 @@ And in more detail: .. ipython:: python - rng = Generator(PCG64(0)) - rng.random(3, dtype='d') - rng.random(3, dtype='f') + rng = np.random.default_rng() + rng.random(3, dtype=np.float64) + rng.random(3, dtype=np.float32) + rng.integers(0, 256, size=3, dtype=np.uint8) * Optional ``out`` argument that allows existing arrays to be filled for select distributions @@ -111,6 +107,7 @@ And in more detail: .. ipython:: python + rng = np.random.default_rng() existing = np.zeros(4) rng.random(out=existing[:2]) print(existing) @@ -121,9 +118,12 @@ And in more detail: .. ipython:: python - rng = Generator(PCG64(123456789)) + rng = np.random.default_rng() a = np.arange(12).reshape((3, 4)) a rng.choice(a, axis=1, size=5) rng.shuffle(a, axis=1) # Shuffle in-place a + +* Added a method to sample from the complex normal distribution + (`~.Generator.complex_normal`) diff --git a/doc/source/reference/random/parallel.rst b/doc/source/reference/random/parallel.rst index b625d34b7..b4934a0ca 100644 --- a/doc/source/reference/random/parallel.rst +++ b/doc/source/reference/random/parallel.rst @@ -12,6 +12,11 @@ or distributed). `~SeedSequence` spawning ------------------------ +NumPy allows you to spawn new (with very high probability) independent +`~BitGenerator` and `~Generator` instances via their ``spawn()`` method. +This spawning is implemented by the `~SeedSequence` used for initializing +the bit generators random stream. + `~SeedSequence` `implements an algorithm`_ to process a user-provided seed, typically as an integer of some size, and to convert it into an initial state for a `~BitGenerator`. It uses hashing techniques to ensure that low-quality seeds @@ -53,15 +58,25 @@ wrap this together into an API that is easy to use and difficult to misuse. .. end_block -Child `~SeedSequence` objects can also spawn to make grandchildren, and so on. -Each `~SeedSequence` has its position in the tree of spawned `~SeedSequence` -objects mixed in with the user-provided seed to generate independent (with very -high probability) streams. +For convenience the direct use of `~SeedSequence` is not necessary. +The above ``streams`` can be spawned directly from a parent generator +via `~Generator.spawn`: + +.. code-block:: python + + parent_rng = default_rng(12345) + streams = parent_rng.spawn(10) + +.. end_block + +Child objects can also spawn to make grandchildren, and so on. +Each child has a `~SeedSequence` with its position in the tree of spawned +child objects mixed in with the user-provided seed to generate independent +(with very high probability) streams. .. code-block:: python - grandchildren = child_seeds[0].spawn(4) - grand_streams = [default_rng(s) for s in grandchildren] + grandchildren = streams[0].spawn(4) .. end_block |