Source code for laser_core.random

"""Functions for seeding and accessing the laser-core random number generator.

Using the seed() function here and the pseudo-random number generator (PRNG)
returned from the prng() function in simulation code will guarantee that the
same random number stream is generated and used during simulation runs using
the same seed value (assuming no changes to code which add or remove PRNG calls
or change the number of random draws requested). This is important for
reproducibility and debugging purposes.
"""

from datetime import datetime

import numba as nb
import numpy as np

_seed: np.uint32 = None
_prng: np.random.Generator = None


@nb.jit((nb.uint32,), nopython=True, nogil=True, parallel=True)
def _nbseed(seed):  # pragma: no cover
    """
    Set the seed for the Numba parallel random number generator (PRNG).

    This function initializes the seed for the non-parallel Numba PRNG and
    then sets the seed for each thread in a parallel execution environment.

    Parameters:

        seed (uint32): The seed value to initialize the PRNG.
    """

    np.random.seed(seed)  # set the non-parallel Numba PRNG seed
    nthreads = nb.get_num_threads()
    for i in nb.prange(nthreads):
        np.random.seed(seed + i)  # actually calls Numba's per-thread PRNG

    return


[docs] def seed(seed) -> np.random.Generator: """ Initialize the pseudo-random number generator with a given seed. This function sets the global pseudo-random number generator (_prng) to a new instance of numpy's default random generator initialized with the provided seed. It also seeds Numba's per-thread random number generators with the same seed. Parameters: seed (int): The seed value to initialize the random number generators. Returns: numpy.random.Generator: The initialized pseudo-random number generator. """ global _seed global _prng _seed = np.uint32(seed) np.random.seed(_seed) _prng = np.random.default_rng(_seed) _nbseed(np.uint32(_seed)) return _prng
[docs] def get_seed() -> np.uint32: """ Return the seed used to initialize the pseudo-random number generator. Returns: uint32: The seed value used to initialize the random number generators. """ return _seed
[docs] def prng() -> np.random.Generator: """Return the global (to LASER) pseudo-random number generator.""" return _prng if _prng is not None else seed(np.uint32(datetime.now(tz=None).microsecond)) # noqa: DTZ005