streams

Stream and seed management is core to any good experimental design for a simulation study. Simulation experiments should be fully reproducible for scientific reasons. Yet, we also want different replications to use different values for the stochastic variables. Seed management and the ability to set and change seeds is needed to accomplish this. To use techniques for variance reduction such as Common Random Numbers, multiple so-called streams of random values need to be defined in the simulation model. The StreamInterface and MersenneTwister implementation in this module make it possible to have multiple random number streams, to reset the streams independent of each other, and to save and retrieve the state of a random number generator.

This module contains one implementation of a Random Number Generator (RNG), the Mersenne Twister that is considered the standard for modern stochastic model implementations. The MersenneTwister class in the streams module wraps the Random class from Python that already contains a decent implementation of the Mersenne Twister. Other RNGs can be easily added by extending the StreamInterface Abstract Base Class, and implementing the abstract methods.

In addition to providing RNGs, the streams module also contains helper classes for stream and seed management. Again, when modelers want to use a different algorithm than the ones provided here, it is sufficient to extend the StreamUpdater Abstract Base Class and implement the update_seed method. After this, the seed management class can be seamlessly used in the model and experiment modules.

class pydsol.core.streams.StreamInterface[source]

Bases: ABC

The StreamInterface defines the random streams to be used within the pydsol project. The interface of the random package has changed quite a lot over time, so this interface provides a stable wrapper.

abstract next_bool() bool[source]

Return the next pseudo-random, uniformly distributed boolean value.

Returns:

a pseudo-random boolean with 50/50 chance for true or false

Return type:

bool

abstract next_float() float[source]

Return a pseudo-random number from the stream over the interval [0,1) using this stream, after advancing its state by one step.

Returns:

a pseudo-random number between 0 and 1

Return type:

float

abstract next_int(lo: int, hi: int) int[source]

Return pseudo-random number from the stream between the integers lo (inclusive) and hi (inclusive).

Parameters:
  • lo (int) – the minimal value (inclusive)

  • hi (int) – the maximum value (nnclusive)

Returns:

a value between lo and hi (both inclusive)

Return type:

int

abstract seed() int[source]

Return the seed of the generator.

Returns:

the seed

Return type:

int

abstract original_seed() int[source]

Return the original seed of the generator with which it has been first initialized.

Returns:

the original seed of the generator when it was first initialized

Return type:

int

abstract set_seed(seed: int)[source]

Set the seed of the generator.

Parameters:

seed (int) – the new seed

abstract reset()[source]

Reset the stream to use the original seed with which it was initialized.

abstract save_state() object[source]

Save the state of the RNG into a byte array, e.g. to roll it back to this state.

Returns:

the state as an object specific to the RNG.

Return type:

object

abstract restore_state(state: object)[source]

Restore the state from an earlier saved state object.

Parameters:

state (object) – state Object; the earlier saved state to which the RNG rolls back.

class pydsol.core.streams.MersenneTwister(seed: int | None = None)[source]

Bases: StreamInterface

The MersenneTwister class is the default random stream in pydsol. The class wraps the builtin Random class of Python, to enforce the fixed and stable StreamInterface for the random number class.

Attributes:
  • _original_seed (int) – The seed value that the random stream has been initialized with originally.

  • _random (Random) – The wrapped Python implementation of the Mersenne Twister.

__init__(seed: int | None = None)[source]

Create a new random stream to be used in a simulation. The model can define and use as many different and independent random streams as needed.

Note

Note that when no initial seed is given, the class uses the current time in milliseconds as the seed – an unknown number, but still reproducible when the stream uses calls reset(), or saves and retrieves its state.

Parameters:

seed (int (optional)) –

next_bool() bool[source]

Return the next pseudo-random, uniformly distributed boolean value.

Returns:

a pseudo-random boolean with 50/50 chance for true or false

Return type:

bool

next_float() float[source]

Return a pseudo-random number from the stream over the interval [0,1) using this stream, after advancing its state by one step.

Returns:

a pseudo-random number between 0 and 1

Return type:

float

next_int(lo: int, hi: int) int[source]

Return pseudo-random number from the stream between the integers lo (inclusive) and hi (inclusive).

Parameters:
  • lo (int) – the minimal value (inclusive)

  • hi (int) – the maximum value (inclusive)

Returns:

a value between lo and hi (both inclusive)

Return type:

int

seed() int[source]

Return the seed of the generator.

Returns:

the seed

Return type:

int

original_seed() int[source]

Return the original seed of the generator with which it has been first initialized.

Returns:

the original seed of the generator when it was first initialized

Return type:

int

set_seed(seed: int)[source]

Set the seed of the generator.

Parameters:

seed (int) – the new seed

reset()[source]

Reset the stream to use the seed value. Note: when the seed has been changed, this method returns the seed to the changed value, not to the original seed defined in the __init__ method.

save_state() object[source]

Save the state of the RNG into an object, e.g. to roll it back to this state. Note that the type of object can differ between RNGs.

Returns:

the state as an object specific to the RNG.

Return type:

object

restore_state(state: object)[source]

Restore the state from an earlier saved state object. Note that the type of object can differ between RNGs.

Parameters:

state (object) – state object; the earlier saved state to which the RNG rolls back.

class pydsol.core.streams.StreamInformation(default_stream: StreamInterface | None = None)[source]

Bases: object

StreamInformation contains information about Random Streams that exists before the model has been constructed. The model can use the (named) streams from this class. The Experiment can automatically take care of updating the seeds of the Random Number Generators that are used in the model for each new replication or experiment.

Attributes:

_streams (dict[str, StreamInterface]) – dictionary of streams that are maintained for the model. Each stream is identified by a unique id in the dict.

__init__(default_stream: StreamInterface | None = None)[source]

Construct a StreamInformation object that can be used to pass information about streams to to a model.

Parameters:

default_stream (StreamInterface) – The default stream that can be retrieved with the name “default” When default_stream is not provided, it will be created and initialized with a fixed seed.

Raises:

TypeError – when default_stream is not implementing StreamInterface

add_stream(stream_id: str, stream: StreamInterface)[source]

Add a new stream, based on a stream id, possibly overwriting a previous existing stream with the same stream_id. No warning will be given if previous information is overwritten.

Parameters:
  • stream_id (str) – The name (id) of the stream to be added

  • stream (StreamInterface) – The stream to be added with the given stream_id

Raises:
  • TypeError – when stream_id is not a string

  • TypeError – when stream is not implementing StreamInterface

get_streams() Dict[str, StreamInterface][source]

Return the dict with streams of this model, where stream ids are mapped to the streams.

Returns:

The dict with streams of this model

Return type:

dict[str, StreamInterface]

get_stream(stream_id: str) StreamInterface[source]

Return a specific stream, based on a stream id, or None when no stream with that id is present.

Parameters:

stream_id (str) – The name (id) to look up the stream for

Returns:

The stream belonging to the stream_id, or None if not present

Return type:

StreamInterface

Raises:

TypeError – when stream_id is not a string

class pydsol.core.streams.StreamSeedInformation(default_stream: StreamInterface | None = None)[source]

Bases: StreamInformation

StreamSeedInformation stores information about the streams, but also about the way the seeds have to be updated for each replication. The StreamSeedUpdater class uses this StreamSeedInformation class to make the seed updates. The seeds are predetermined and stored for each replication number in a list.

Attributes:

_stream_seeds (dict[str, list[int]]) – Dictionary of lists of seed values per replication that are maintained for the model. Each list of seeds is identified by a unique id in the dict that has to match a key in the _streams attribute in the parent StreamInformation class.

__init__(default_stream: StreamInterface | None = None)[source]

Construct a StreamSeedInformation object that can be used to pass information about streams to to a model, and information about the seed values for each replication to the Experiment.

Parameters:

default_stream (StreamInterface) – The default stream that can be retrieved with the name “default” When default_stream is not provided, it will be created and initialized with a fixed seed.

Raises:

TypeError – when default_stream is not implementing StreamInterface

add_seed_values(stream_id: str, seeds: List[int])[source]

Add a new seed list for a stream, based on a stream id, possibly overwriting a previous existing seed list with the same stream_id. No warning will be given is previous information is overwritten.

Parameters:
  • stream_id (str) – The id of the stream that has to already exist in the class.

  • seeds (list[int]) – The list of seed values per replication number, 0-based.

Raises:
  • TypeError – when stream_id is not a string

  • TypeError – when seeds is not a list or seeds contains non-integers

  • ValueError – when the stream information with the given stream_id does not exist

get_seeds() Dict[str, List[int]][source]

Return the dict with seed lists of this model, where stream ids are mapped to the seed lists.

Returns:

The dict with seed lists of this model

Return type:

dict[str, list[int]]

get_seed_values(stream_id: str) List[int][source]

Return a specific set of seed values, based on a stream id, or None when no seed values with that id are present.

Returns:

The list of seed values belonging to the stream_id, or None if not present

Return type:

list[int]

Raises:

TypeError – when stream_id is not a string

add_stream(stream_id: str, stream: StreamInterface)

Add a new stream, based on a stream id, possibly overwriting a previous existing stream with the same stream_id. No warning will be given if previous information is overwritten.

Parameters:
  • stream_id (str) – The name (id) of the stream to be added

  • stream (StreamInterface) – The stream to be added with the given stream_id

Raises:
  • TypeError – when stream_id is not a string

  • TypeError – when stream is not implementing StreamInterface

get_stream(stream_id: str) StreamInterface

Return a specific stream, based on a stream id, or None when no stream with that id is present.

Parameters:

stream_id (str) – The name (id) to look up the stream for

Returns:

The stream belonging to the stream_id, or None if not present

Return type:

StreamInterface

Raises:

TypeError – when stream_id is not a string

get_streams() Dict[str, StreamInterface]

Return the dict with streams of this model, where stream ids are mapped to the streams.

Returns:

The dict with streams of this model

Return type:

dict[str, StreamInterface]

class pydsol.core.streams.StreamUpdater[source]

Bases: ABC

The StreamUpdater abstract class defines the methods that determine how to update the seed values for a replication.

update_seeds(streams: Dict[str, StreamInterface], replication_nr: int)[source]

Update all seeds for the given replication number. The method should be fully reproducible, and can be based on the previous seed values, possibly the String representation, and the replication number.

Parameters:
  • streams (dict[str, StreamInterface]) – A dict mapping stream ids onto streams. This dict can come from the StreamInformation or StreamSeedInformation class, but that is not enforced. Any dict with this info will do. Note that the structure of the dict is not checked.

  • replication_nr (int) – The replication number for which to set the seed values.

Raises:

TypeError – when replication_nr is not an int

abstract update_seed(key: str, stream: StreamInterface, replication_nr: int)[source]

Update one seed for the given streamId and replication number. The method should be fully reproducible, and can be based on the previous seed value of the stream, possibly the String representation, and the replication number.

class pydsol.core.streams.StreamSeedUpdater(stream_seeds: Dict[str, List[int]])[source]

Bases: StreamUpdater

StreamSeedUpdater updates the seed for the streams in the replications based on a stored map of replication numbers to seed numbers.

Attributes:
  • _stream_seeds (dict[str, list[int]]) – The dict that maps the stream id on the seed lists for this model where the seed list is indexed on the replication number.

  • _fallback_stream_updater (StreamUpdater) – The updater that will be used to generate seed numbers for replications of streams that are not contained in the _stream_seeds dict.

__init__(stream_seeds: Dict[str, List[int]])[source]

Construct a new StreamSeedUpdater object an initialize it with the seed map.

Parameters:

stream_seeds (dict[str, list[int]]:) – The dict that maps the stream id on the seed lists for this model where the seed list is indexed on the replication number.

Raises:
  • TypeError – when stream_seeds is not a dict

  • TypeError – when a key in stream_seeds is not a string

  • TypeError – when a value stream_seeds is not a list

  • TypeError – when a list with seeds is not containing only integers

update_seed(stream_id: str, stream: StreamInterface, replication_nr: int)[source]

Update one seed for the given stream_id and replication number. The method should be fully reproducible, and can be based on the previous seed value of the stream, possibly the String representation, and the replication number. The update guarantees random number reproducibility across runs and platforms for the given replication and random stream. When the stream_id is not defined, the fallback updater will be used.

Parameters:
  • stream_id (str) – The id of the stream

  • stream (StreamInterface) – The stream that needs to be updated

  • replication_nr (int) – The replication to update the seed for

Raises:
  • TypeError – when stream_id is not a string

  • TypeError – when stream does not implement StreamInterface

  • TypeError – when replication_nr is not an int

  • ValueError – when replication_nr < 0 or > stored seed value list length

set_fallback_stream_updater(stream_updater: StreamUpdater)[source]

Set the fallback stream updater that can generate seed numbers for replications of streams that are not contained in the _stream_seeds dict.

Parameters:

stream_updater (StreamUpdater) – The fallback stream updater that can generate seed numbers for replications of streams that are not contained in the _stream_seeds dict.

Raises:

TypeError – when stream_updater does not implement StreamUpdater

get_fallback_stream_updater() StreamUpdater[source]
Return the fallback stream updater that can generate seed numbers for

replications of streams that are not contained in the _stream_seeds dict.

Returns:

replications of streams that are not contained in the _stream_seeds dict.

Return type:

The fallback stream updater that can generate seed numbers for

get_stream_seeds() Dict[str, List[int]][source]

Return the dict that maps the stream names on the seed lists for this model where the seed list is indexed on the replication number.

Returns:

  • The dict that maps the stream names on the seed lists for this

  • model where the seed list is indexed on the replication number.

update_seeds(streams: Dict[str, StreamInterface], replication_nr: int)

Update all seeds for the given replication number. The method should be fully reproducible, and can be based on the previous seed values, possibly the String representation, and the replication number.

Parameters:
  • streams (dict[str, StreamInterface]) – A dict mapping stream ids onto streams. This dict can come from the StreamInformation or StreamSeedInformation class, but that is not enforced. Any dict with this info will do. Note that the structure of the dict is not checked.

  • replication_nr (int) – The replication number for which to set the seed values.

Raises:

TypeError – when replication_nr is not an int

class pydsol.core.streams.SimpleStreamUpdater[source]

Bases: StreamUpdater

SimpleStreamUpdater updates the seed value for a replication based on the hashCode of the name of the stream and the replication number.

update_seed(stream_id: str, stream: StreamInterface, replication_nr: int)[source]

Update one seed for the given stream_id and replication number. The method should be fully reproducible, and uses the the hashCode of the id of the stream and the replication number to generate a seed value. The update guarantees random number reproducibility across runs and platforms for the given replication and random stream.

Parameters:
  • stream_id (str) – The id of the stream

  • stream (StreamInterface) – The stream that needs to be updated

  • replication_nr (int) – The replication to update the seed for

Raises:
  • TypeError – when stream_id is not a string

  • TypeError – when stream does not implement StreamInterface

  • TypeError – when replication_nr is not an int

  • ValueError – when replication_nr < 0

update_seeds(streams: Dict[str, StreamInterface], replication_nr: int)

Update all seeds for the given replication number. The method should be fully reproducible, and can be based on the previous seed values, possibly the String representation, and the replication number.

Parameters:
  • streams (dict[str, StreamInterface]) – A dict mapping stream ids onto streams. This dict can come from the StreamInformation or StreamSeedInformation class, but that is not enforced. Any dict with this info will do. Note that the structure of the dict is not checked.

  • replication_nr (int) – The replication number for which to set the seed values.

Raises:

TypeError – when replication_nr is not an int