Wado

core:prng

Seedable, reproducible pseudo-randomness for simulation, sampling, procedural generation, randomized algorithms and tests.

Three ways to ask, and they do not mix. [Rng] answers "the next value" one word at a time and carries the derived uniform operations. [VectorRng] answers with sixteen words at once, for a consumer that has use for all of them. [Squares64] answers "the value at this counter", so the draw order belongs to the caller and nothing is carried between calls.

A [Seed] is data and every constructor of one is arithmetic, so nothing here declares an effect. Entropy lives one module away: core:secure_random exports seed(), which carries Random.

Nothing here is cryptographic. These generators are built to pass statistical tests at the least work per word, not to resist an adversary who has seen their output. A token, a session identifier, a nonce, a salt or a key comes from core:secure_random.

An algorithm named in a type is fixed: [Xoshiro256pp] emits what xoshiro256++ emits, for a given state, forever. Everything else may change between releases: how a Seed becomes a state, what split derives, and how many draws an operation takes.

Synopsis

let mut rng = Xoshiro256pp::from_seed(Seed::from_u64(42));

let die = rng.random_range(1..=6);
assert 1 <= die <= 6;
assert 0.0 <= rng.random_f64() < 1.0;

let mut deck: List<i32> = [1, 2, 3, 4, 5];
rng.shuffle(&mut deck);
assert deck.len() == 5;

// The same seed replays the same stream, with no capability to declare.
let mut again = Xoshiro256pp::from_seed(Seed::from_u64(42));
assert again.random_range(1..=6) == die;

Traits

pub trait Seedable with ()

A generator that can be built from a [Seed].

fn from_seed(seed: Seed) -> Self

pub trait Rng with ()

A scalar generator: one u64 per draw, plus the uniform operations derived from it. A shape other than uniform is a distribution and does not live here.

fn next_u64(&mut self) -> u64

The next 64 bits of the stream, every bit of them usable.

fn random_range<S: SampleRange>(&mut self, range: S) -> S::Value

A uniform value from low..<high or low..=high, by Lemire's multiply-shift with the rare rejection.

fn random_f64(&mut self) -> f64

A uniform f64 in [0, 1), from the draw's top 53 bits.

fn random_bool(&mut self) -> bool

true or false with equal probability, from one bit of the draw.

fn shuffle<T>(&mut self, items: &mut List<T>)

Permute items in place, uniformly over all permutations (Fisher-Yates).

fn choose<T>(&mut self, items: &List<T>) -> Option<T>

A uniformly chosen element of items, or None when it is empty.

pub trait SampleRange with ()

A range that random_range can draw from: ..< or ..= over any [SampleUniform] type.

fn sample_from<R: Rng>(&self, rng: &mut R) -> Self::Value

pub trait SampleUniform with ()

An integer type a uniform range can be drawn over.

fn sample_inclusive<R: Rng>(rng: &mut R, low: Self, high: Self) -> Self

fn sample_exclusive<R: Rng>(rng: &mut R, low: Self, high: Self) -> Self

pub trait VectorRng with ()

A lane-parallel generator: sixteen u64 per call, as eight u64x2. The width is the library's, not the engine's, so a whole-batch consumer knows it.

fn next_batch(&mut self) -> [u64x2, u64x2, u64x2, u64x2, u64x2, u64x2, u64x2, u64x2]

Structs

pub struct Seed

Two hundred and fifty-six bits of well-distributed state, and the one input every engine here takes. Nothing about it is secret.

Fields are private.

pub fn from_u64(n: u64) -> Seed

Expand one number into a seed, through SplitMix64. Seed::from_u64(0) is as good a seed as any other.

pub fn from_bytes<B: AsByteSlice>(bytes: &B) -> Seed

Absorb any byte source — a ByteList, a ByteSlice, or a String's UTF-8 bytes — into a seed.

pub fn from_str(s: &String) -> Seed

Absorb a string's bytes into a seed, so a world can be named rather than numbered.

pub fn split(&self, index: u64) -> Seed

Derive an independent child seed at index. Worker n derives its own with no coordination; independence is statistical, not proven.

pub struct Xoshiro256pp

xoshiro256++ (Blackman & Vigna): four words, shifts, xors and two rotates. Period 2^256 - 1, and every 4-tuple of consecutive outputs appears once over it.

Fields are private.

pub fn jump(&mut self)

Advance 2^128 steps, in the time 256 steps take. Two streams a jump apart are provably disjoint for 2^128 draws apiece.

pub fn long_jump(&mut self)

The same, 2^192 steps on.

impl Seedable for Xoshiro256pp

fn from_seed(seed: Seed) -> Xoshiro256pp

impl Rng for Xoshiro256pp

fn next_u64(&mut self) -> u64

pub struct Squares64

Squares (Widynski, arXiv:2004.06278): the value at a counter, not the next one. A revisit regenerates it, and no two callers need agree on draw order.

Fields are private.

pub fn at(&self, counter: u64) -> u64

The value at counter. Distinct counters give unrelated values; the same counter always gives the same one.

impl Seedable for Squares64

fn from_seed(seed: Seed) -> Squares64

pub struct XoshiroSimd

xoshiro256++ in eight lanes at once. Each lane starts 2^128 steps past the one before, so the eight streams are disjoint for 2^128 draws apiece.

Fields are private.

impl Seedable for XoshiroSimd

fn from_seed(seed: Seed) -> XoshiroSimd

impl VectorRng for XoshiroSimd

fn next_batch(&mut self) -> [u64x2, u64x2, u64x2, u64x2, u64x2, u64x2, u64x2, u64x2]

pub struct Shishua

SHISHUA: the fastest generator here, and vector-only, since its round is eight vectors wide and nothing smaller exists inside it. It has no jump.

Fields are private.

impl Seedable for Shishua

fn from_seed(seed: Seed) -> Shishua

impl VectorRng for Shishua

fn next_batch(&mut self) -> [u64x2, u64x2, u64x2, u64x2, u64x2, u64x2, u64x2, u64x2]