viva_math/random
Pure functional random number generation.
Built on top of Erlang’s :rand module (OTP 22+). The Seed type is
opaque and immutable: every sampling function returns a new seed,
allowing fully reproducible deterministic streams without process state.
The default algorithm is exsss (Xorshift116** with StarStar scrambler,
period 2¹¹⁶-1, 58-bit output). For longer streams or jump-ahead, use
with_algo(Exro928ss, seed).
Why not the hash-based generator in common?
common.deterministic_noise is fine for reproducible fixtures, but it
is statistically weak. For Monte Carlo, neural net initialization or
Bayesian sampling, prefer this module.
Example
import viva_math/random
let seed0 = random.from_int(42)
let #(x, seed1) = random.uniform(seed0)
let #(y, seed2) = random.normal(seed1, 0.0, 1.0)
// Same seed0 always produces the same x, y sequence.
Types
Available PRNG algorithms exposed by OTP :rand.
pub type Algorithm {
Exsss
Exro928ss
Exrop
Exsp
Exs1024s
Mwc59
}
Constructors
-
ExsssXorshift116** — default, fast, good statistics. Period 2¹¹⁶-1.
-
Exro928ssXoroshiro928** — much longer period (2⁹²⁸-1), jump ahead.
-
ExropXoroshiro116+. Slightly faster than Exsss but weak low bits.
-
ExspXorshift116+. Legacy.
-
Exs1024sXorshift1024*. 64-bit precision.
-
Mwc59MWC59 — multiply-with-carry, very fast 32-bit floats.
Values
pub fn bernoulli(seed: Seed, p: Float) -> #(Bool, Seed)
Bernoulli sample: True with probability p. p is clamped to [0, 1].
pub fn categorical(
seed: Seed,
probs: List(Float),
) -> Result(#(Int, Seed), Nil)
Sample an index from a categorical distribution defined by probs.
Probabilities are renormalised internally. Returns an error if the list is empty or sums to a non-positive value.
pub fn choice(seed: Seed, xs: List(a)) -> Result(#(a, Seed), Nil)
Pick a uniformly random element from a list.
pub fn from_int(seed: Int) -> Seed
Build a seed from an integer using the default algorithm (Exsss).
pub fn integer(seed: Seed, n: Int) -> Result(#(Int, Seed), Nil)
Uniform integer in [1, n]. Returns an error if n < 1.
pub fn jump(seed: Seed) -> Seed
Advance the seed by 2⁶⁴ calls. Useful for non-overlapping parallel streams.
pub fn shuffle(seed: Seed, xs: List(a)) -> #(List(a), Seed)
Return a random permutation of xs via Fisher–Yates (modern Durstenfeld
variant), implemented on top of a dict for O(log n) indexed swaps.
Truly uniform over all n! permutations (no float-key collision bias the sort-based shuffle suffered from).
pub fn standard_normals(
seed: Seed,
n: Int,
) -> #(List(Float), Seed)
Sample n standard normals at once.
pub fn uniform_in(
seed: Seed,
low: Float,
high: Float,
) -> #(Float, Seed)
Uniform float in [low, high).