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

  • Exsss

    Xorshift116** — default, fast, good statistics. Period 2¹¹⁶-1.

  • Exro928ss

    Xoroshiro928** — much longer period (2⁹²⁸-1), jump ahead.

  • Exrop

    Xoroshiro116+. Slightly faster than Exsss but weak low bits.

  • Exsp

    Xorshift116+. Legacy.

  • Exs1024s

    Xorshift1024*. 64-bit precision.

  • Mwc59

    MWC59 — multiply-with-carry, very fast 32-bit floats.

Opaque immutable PRNG state.

Internally an Erlang :rand state tuple. Pass through sampling functions; never mutate.

pub type Seed

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 normal(
  seed: Seed,
  mu: Float,
  sigma: Float,
) -> #(Float, Seed)

Normal N(mu, sigma²).

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_normal(seed: Seed) -> #(Float, Seed)

Standard normal N(0, 1).

pub fn standard_normals(
  seed: Seed,
  n: Int,
) -> #(List(Float), Seed)

Sample n standard normals at once.

pub fn uniform(seed: Seed) -> #(Float, Seed)

Uniform float in [0.0, 1.0).

pub fn uniform_in(
  seed: Seed,
  low: Float,
  high: Float,
) -> #(Float, Seed)

Uniform float in [low, high).

pub fn uniforms(seed: Seed, n: Int) -> #(List(Float), Seed)

Sample n uniforms in [0, 1) at once.

pub fn with_algo(algorithm: Algorithm, seed: Int) -> Seed

Build a seed with an explicit algorithm.

Search Document