///|
/// Pack an integer `seed` into a 32-byte buffer using a 32-bit
/// little-endian encoding of `seed` (as a signed 32-bit integer;
/// `-1` becomes `0xFF FF FF FF`). The four bytes are tiled 8 times
/// to fill the 32-byte key that `chacha8` requires. Distinct
/// integer seeds give distinct byte strings, and the layout is
/// independent of the host endianness.
///
/// Encoding (per byte index 0..3):
/// byte[0] = seed & 0xff
/// byte[1] = (seed >> 8) & 0xff
/// byte[2] = (seed >> 16) & 0xff
/// byte[3] = (seed >> 24) & 0xff
///
/// `seed` is a signed 64-bit `Int`; the upper 32 bits are ignored
/// so the 32-bit LE view is well-defined for any seed. For
/// negative seeds, arithmetic right-shift + mask is sign-clean
/// (e.g. `seed = -1` gives `[0xff, 0xff, 0xff, 0xff]`).
///
/// This is the canonical seed-to-bytes helper for the dml
/// package's RNG-backed tests and for `cmd/main`'s demo entry
/// point. It supersedes the earlier 7-bit-tiling helper that
/// existed in `irm_test.mbt` and `cmd/main/main.mbt` and produced
/// non-portable encodings.
pub fn seed_to_bytes(seed : Int) -> Array[Byte] {
let b0 : Byte = (seed & 0xff).to_byte()
let b1 : Byte = ((seed >> 8) & 0xff).to_byte()
let b2 : Byte = ((seed >> 16) & 0xff).to_byte()
let b3 : Byte = ((seed >> 24) & 0xff).to_byte()
let bytes : Array[Byte] = []
for k = 0; k < 32; k = k + 1 {
// `k` ranges over `0..32`, so `k % 4 ∈ {0, 1, 2, 3}`. We use
// the wildcard for `3` because MoonBit's match-exhaustiveness
// check accepts either `3 => b3` or `_ => b3`; the wildcard
// is the path-of-least-resistance under `Int % Int` returning
// signed values for `k < 0` (which never happens here, but
// the compiler can't prove that).
let b = match k % 4 {
0 => b0
1 => b1
2 => b2
_ => b3
}
bytes.push(b)
}
bytes
}
///|
/// Convenience constructor: `chacha8_rng(seed)` is shorthand for
/// `Rand::chacha8(seed=Bytes::from_array(seed_to_bytes(seed)))`.
/// Use this anywhere the package's tests / demos need a
/// deterministic RNG keyed by an integer seed.
pub fn chacha8_rng(seed : Int) -> @random.Rand {
@random.Rand::chacha8(seed=Bytes::from_array(seed_to_bytes(seed)))
}
///|
/// Box-Muller pair (mu=0, sigma=1). Returns two independent
/// standard normals per call. Shared helper used by the DGP
/// modules (`dgp_plr_CCDDHNR`, `dgp_irm`, ...) to avoid
/// duplicating the helper across files.
pub fn box_muller_pair(rng : @random.Rand) -> (Double, Double) {
let u1 = rng.double()
let u2 = rng.double()
let safe = if u1 < 1.0e-12 { 1.0e-12 } else { u1 }
let r = (-2.0 * @math.ln(safe)).sqrt()
let theta = 2.0 * 3.141592653589793 * u2
(r * @math.cos(theta), r * @math.sin(theta))
}