kwutil.util_random module

Implements a version of ensure_rng that does not require on numpy (but allows for it). This mirrors :kwarray:`ensure_rng`, which is a numpy-first implementation.

kwutil.util_random._npstate_to_pystate(npstate)[source]

Convert state of a NumPy RandomState object to a state that can be used by Python’s Random. Derived from [SO44313620].

References

Example

>>> # xdoctest: +REQUIRES(module:numpy)
>>> import numpy as np
>>> py_rng = random.Random(0)
>>> np_rng = np.random.RandomState(seed=0)
>>> npstate = np_rng.get_state()
>>> pystate = _npstate_to_pystate(npstate)
>>> py_rng.setstate(pystate)
>>> assert np_rng.rand() == py_rng.random()
kwutil.util_random._pystate_to_npstate(pystate)[source]

Convert state of a Python Random object to state usable by NumPy RandomState. Derived from [SO44313620].

References

Example

>>> # xdoctest: +REQUIRES(module:numpy)
>>> import numpy as np
>>> py_rng = random.Random(0)
>>> np_rng = np.random.RandomState(seed=0)
>>> pystate = py_rng.getstate()
>>> npstate = _pystate_to_npstate(pystate)
>>> np_rng.set_state(npstate)
>>> assert np_rng.rand() == py_rng.random()
kwutil.util_random._coerce_rng_type(rng)[source]

Internal method that transforms input seeds into an integer form.

kwutil.util_random.ensure_rng(rng=None, api='python')[source]

Coerces input into a random number generator.

This function is useful for ensuring that your code uses a controlled internal random state that is independent of other modules.

If the input is None, then a global random state is returned.

If the input is a numeric value, then that is used as a seed to construct a random state.

If the input is a random number generator, then another random number generator with the same state is returned. Depending on the api, this random state is either return as-is, or used to construct an equivalent random state with the requested api.

Parameters:
  • rng (int | float | None | numpy.random.RandomState | random.Random) – if None, then defaults to the global rng. Otherwise this can be an integer or a RandomState class. Defaults to the global random.

  • api (str) – specify the type of random number generator to use. This can either be ‘numpy’ for a numpy.random.RandomState object or ‘python’ for a random.Random object. Defaults to numpy.

Returns:

rng - either a numpy or python random number generator, depending on the setting of api.

Return type:

(numpy.random.RandomState | random.Random)

Example

>>> # xdoctest: +REQUIRES(module:numpy)
>>> from kwutil.util_random import *  # NOQA
>>> from kwutil.util_random import ensure_rng
>>> rng = ensure_rng(None)
>>> ensure_rng(0, 'python').randint(0, 1000)
864
>>> # xdoctest: +REQUIRES(module:numpy)
>>> import numpy as np
>>> ensure_rng(np.random.RandomState(1)).randint(0, 1000)
427

Example

>>> from kwutil.util_random import *  # NOQA
>>> from kwutil.util_random import ensure_rng
>>> num = 4
>>> print('--- Python as PYTHON ---')
>>> py_rng = random.Random(0)
>>> pp_nums = [py_rng.random() for _ in range(num)]
>>> print(pp_nums)
>>> print('--- Numpy as PYTHON ---')
>>> # xdoctest: +REQUIRES(module:numpy)
>>> import numpy as np
>>> np_rng = ensure_rng(random.Random(0), api='numpy')
>>> np_nums = [np_rng.rand() for _ in range(num)]
>>> print(np_nums)
>>> print('--- Numpy as NUMPY---')
>>> np_rng = np.random.RandomState(seed=0)
>>> nn_nums = [np_rng.rand() for _ in range(num)]
>>> print(nn_nums)
>>> print('--- Python as NUMPY---')
>>> py_rng = ensure_rng(np.random.RandomState(seed=0), api='python')
>>> pn_nums = [py_rng.random() for _ in range(num)]
>>> print(pn_nums)
>>> assert np_nums == pp_nums
>>> assert pn_nums == nn_nums

Example

>>> # Test that random modules can be coerced
>>> # xdoctest: +REQUIRES(module:numpy)
>>> from kwutil.util_random import *  # NOQA
>>> import random
>>> import numpy as np
>>> ensure_rng(random, api='python')
>>> ensure_rng(random, api='numpy')
>>> ensure_rng(np.random, api='python')
>>> ensure_rng(np.random, api='numpy')