Bit generators — NumPy v2.3.dev0 Manual (original) (raw)

The random values produced by Generatororiginate in a BitGenerator. The BitGenerators do not directly provide random numbers and only contains methods used for seeding, getting or setting the state, jumping or advancing the state, and for accessing low-level wrappers for consumption by code that can efficiently access the functions provided, e.g., numba.

Supported BitGenerators#

The included BitGenerators are:

Seeding and entropy#

A BitGenerator provides a stream of random values. In order to generate reproducible streams, BitGenerators support setting their initial state via a seed. All of the provided BitGenerators will take an arbitrary-sized non-negative integer, or a list of such integers, as a seed. BitGenerators need to take those inputs and process them into a high-quality internal state for the BitGenerator. All of the BitGenerators in numpy delegate that task toSeedSequence, which uses hashing techniques to ensure that even low-quality seeds generate high-quality initial states.

from numpy.random import PCG64

bg = PCG64(12345678903141592653589793)

SeedSequence is designed to be convenient for implementing best practices. We recommend that a stochastic program defaults to using entropy from the OS so that each run is different. The program should print out or log that entropy. In order to reproduce a past value, the program should allow the user to provide that value through some mechanism, a command-line argument is common, so that the user can then re-enter that entropy to reproduce the result.SeedSequence can take care of everything except for communicating with the user, which is up to you.

from numpy.random import PCG64, SeedSequence

Get the user's seed somehow, maybe through argparse.

If the user did not provide a seed, it should return None.

seed = get_user_seed() ss = SeedSequence(seed) print(f'seed = {ss.entropy}') bg = PCG64(ss)

We default to using a 128-bit integer using entropy gathered from the OS. This is a good amount of entropy to initialize all of the generators that we have in numpy. We do not recommend using small seeds below 32 bits for general use. Using just a small set of seeds to instantiate larger state spaces means that there are some initial states that are impossible to reach. This creates some biases if everyone uses such values.

There will not be anything wrong with the results, per se; even a seed of 0 is perfectly fine thanks to the processing that SeedSequence does. If you just need some fixed value for unit tests or debugging, feel free to use whatever seed you like. But if you want to make inferences from the results or publish them, drawing from a larger set of seeds is good practice.

If you need to generate a good seed “offline”, then SeedSequence().entropyor using secrets.randbits(128) from the standard library are both convenient ways.

If you need to run several stochastic simulations in parallel, best practice is to construct a random generator instance for each simulation. To make sure that the random streams have distinct initial states, you can use the spawn method of SeedSequence. For instance, here we construct a list of 12 instances:

from numpy.random import PCG64, SeedSequence

High quality initial entropy

entropy = 0x87351080e25cb0fad77a44a3be03b491 base_seq = SeedSequence(entropy) child_seqs = base_seq.spawn(12) # a list of 12 SeedSequences generators = [PCG64(seq) for seq in child_seqs]

If you already have an initial random generator instance, you can shorten the above by using the spawn method:

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 integerworker_id

from numpy.random import PCG64, SeedSequence

High quality initial entropy

entropy = 0x87351080e25cb0fad77a44a3be03b491 sequences = [SeedSequence((entropy, worker_id)) for worker_id in range(12)] generators = [PCG64(seq) for seq in sequences]

Note that the sequences produced by the latter method will be distinct from those constructed via spawn.