Sanctioned, purely-functional seeded PRNG (Mitigation 3a, spec ยง8).
Randomness in a model MUST come from a generator carried inside
model_state so that (a) two LPs never share a PRNG, coupling their
determinism to scheduling, and (b) rollback restores the PRNG position along
with the rest of the state snapshot โ for free, via structural sharing.
This wraps Erlang's :rand in its explicit-state form (*_s), so there is no
hidden per-process seed and nothing to reset on rollback. Never call :rand
directly in a model โ always thread a %TimeWarp.Rand{} through the state.
Summary
Functions
Exponentially-distributed value with the given mean, rounded to a positive
integer (virtual-time durations). Draws crane cycle times, travel, etc.
Seed a fresh generator deterministically from an integer.
Uniform float in [0.0, 1.0), plus the advanced generator.
Uniform integer in the inclusive range lo..hi, plus the advanced generator.
Types
@type t() :: %TimeWarp.Rand{state: :rand.state()}
Functions
@spec exponential(t(), number()) :: {pos_integer(), t()}
Exponentially-distributed value with the given mean, rounded to a positive
integer (virtual-time durations). Draws crane cycle times, travel, etc.
Seed a fresh generator deterministically from an integer.
Uniform float in [0.0, 1.0), plus the advanced generator.
Uniform integer in the inclusive range lo..hi, plus the advanced generator.