Skip to content

osrlib.core.rng

Named deterministic RNG streams backed by pure-Python PCG64.

This module is the determinism contract made concrete: draw sequences are part of the public compatibility guarantee, so every algorithmic choice here is frozen by golden vectors in the test suite. Do not change any of it without bumping expectations consciously — an "equivalent" reimplementation that shifts a single draw breaks replays and golden files.

The generator is PCG64 — specifically the pcg_setseq_128_xsl_rr_64 variant (128-bit LCG state, XSL-RR output to 64 bits), the same generator behind numpy's PCG64 (not PCG64DXSM, which is a different algorithm). Each next_uint64() advances the LCG first, then applies XSL-RR to the new state; this is the pcg-c 128-bit convention numpy follows, and the opposite of the widely tutorialized pcg32 pattern.

Streams are forked from a master seed by stable string keys: seed material is SHA-256(master_seed_bytes + b":" + stream_key_utf8) with the master seed encoded as 16 bytes big-endian, so stream identity depends only on the master seed and the key string. Adding draws to one subsystem's stream never shifts results in another.

Randomness in the library must always come from an explicitly passed RngStream — never the stdlib random module, and never a module-level default.

RngStream

RngStream(initstate: int, initseq: int)

A single PCG64 stream.

Construct via RngStreams.get in normal play; direct construction from an (initstate, initseq) pair runs the canonical PCG64 init and exists for tests and à la carte use.

Initialize the stream with the canonical PCG64 init procedure.

The init is state = 0; inc = (initseq << 1) | 1; step; state += initstate; step, all mod 2**128. It discards the top bit of initseq — expected behavior, not a bug to fix.

Parameters:

Name Type Description Default
initstate int

The 128-bit init state, in [0, 2**128).

required
initseq int

The 128-bit stream-selection constant, in [0, 2**128).

required

Raises:

Type Description
ValueError

If either argument is out of range.

from_seed_material classmethod

from_seed_material(master_seed: int, key: str) -> RngStream

Derive and initialize the named stream for a master seed.

Parameters:

Name Type Description Default
master_seed int

The session's master seed, in [0, 2**128).

required
key str

The stream's name.

required

Returns:

Type Description
RngStream

A freshly initialized stream; the same arguments always produce a stream

RngStream

that yields the identical draw sequence.

restore classmethod

restore(snapshot: RngStreamState) -> RngStream

Restore a stream from an exported snapshot.

Parameters:

Name Type Description Default
snapshot RngStreamState

A state previously returned by export_state.

required

Returns:

Type Description
RngStream

A stream that continues the draw sequence exactly where the exporting

RngStream

stream left off.

export_state

export_state() -> RngStreamState

Export the stream's exact position for serialization.

Returns:

Type Description
RngStreamState

A frozen snapshot of the raw PCG64 state and increment.

next_uint64

next_uint64() -> int

Draw the next raw 64-bit output.

Advances the LCG first, then applies XSL-RR to the new state (the pcg-c 128-bit convention).

Returns:

Type Description
int

A uniformly distributed integer in [0, 2**64).

randbelow

randbelow(n: int) -> int

Draw a uniformly distributed integer in [0, n).

The algorithm is frozen as top-bits rejection sampling: with k = (n - 1).bit_length(), each candidate is next_uint64() >> (64 - k), rejected and redrawn while candidate >= n. No masking of low bits. Rejection means the raw-draw count per bounded draw is variable: power-of-two bounds never reject; others (3, 6, 10, 12, 20, 100) can. randbelow(1) has k = 0, always yields 0, and still consumes one draw.

Parameters:

Name Type Description Default
n int

The exclusive upper bound. Must be positive.

required

Returns:

Type Description
int

A uniformly distributed integer in [0, n).

Raises:

Type Description
ValueError

If n <= 0.

RngStreamState

Bases: BaseModel

A serializable snapshot of an in-progress stream.

Captures the raw PCG64 internals — the 128-bit LCG state and the stream increment — so saves can restore mid-sequence streams exactly via RngStream.restore.

state class-attribute instance-attribute

state: int = Field(ge=0, lt=_SEED_BOUND)

inc class-attribute instance-attribute

inc: int = Field(ge=0, lt=_SEED_BOUND)

RngStreams

RngStreams(master_seed: int)

The named-stream container forked from a session's master seed.

Streams are created lazily on first access and cached: the same key always returns the same stream object, and stream identity depends only on the master seed and the key string.

Examples:

from osrlib.core.rng import RngStreams

streams = RngStreams(master_seed=42)
combat = streams.get("combat")
d20 = combat.randbelow(20) + 1
assert 1 <= d20 <= 20

Create the container for a master seed.

Parameters:

Name Type Description Default
master_seed int

The session's master seed, in [0, 2**128).

required

Raises:

Type Description
ValueError

If master_seed is out of range.

master_seed property

master_seed: int

The master seed this container forks streams from.

get

get(key: str) -> RngStream

Return the named stream, creating it on first use.

Parameters:

Name Type Description Default
key str

The stream's name, e.g. "combat" or "treasure".

required

Returns:

Type Description
RngStream

The stream for key; repeated calls return the same object.

export_states

export_states() -> dict[str, RngStreamState]

Export every touched stream's exact position, keyed by stream name.

Untouched streams need no snapshot — they re-derive from the master seed on first use. Keys are sorted so serialization is deterministic.

Returns:

Type Description
dict[str, RngStreamState]

The stream snapshots for saves.

restore_states

restore_states(states: dict[str, RngStreamState]) -> None

Restore previously exported stream positions.

Parameters:

Name Type Description Default
states dict[str, RngStreamState]

Snapshots from export_states.

required

derive_init_pair

derive_init_pair(master_seed: int, key: str) -> tuple[int, int]

Derive a PCG64 (initstate, initseq) pair for a named stream.

Seed material is SHA-256(master_seed_bytes + b":" + stream_key_utf8) with the master seed encoded as fixed-width 16-byte big-endian. The 32-byte digest splits into the init pair, both halves read big-endian: bytes 0-15 are initstate, bytes 16-31 are initseq.

Parameters:

Name Type Description Default
master_seed int

The session's master seed, in [0, 2**128).

required
key str

The stream's name, e.g. "combat" or "treasure".

required

Returns:

Type Description
tuple[int, int]

The (initstate, initseq) pair for the canonical PCG64 init.

Raises:

Type Description
ValueError

If master_seed is out of range.