use num_traits::NumCast;
use rand::rngs::StdRng;
use rand::{RngExt, SeedableRng};
use rand_distr::Distribution;
use rayon::prelude::*;
const CHUNK: usize = 8192;
#[inline]
pub fn mix_seed(base: u64, salt: u64) -> u64 {
let mut z = base ^ salt.wrapping_mul(0x9E37_79B9_7F4A_7C15);
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
#[inline]
pub fn name_seed(base: u64, name: &str) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325; for &b in name.as_bytes() {
h ^= b as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3); }
mix_seed(base, h)
}
pub fn collect_f32_seeded<D>(n: usize, dist: D, seed: u64) -> Vec<f32>
where
D: Distribution<f32> + Clone + Send + Sync,
{
if n == 0 {
return Vec::new();
}
let n_chunks = n.div_ceil(CHUNK);
(0..n_chunks)
.into_par_iter()
.flat_map_iter(move |ci| {
let start = ci * CHUNK;
let end = ((ci + 1) * CHUNK).min(n);
let mut rng = StdRng::seed_from_u64(mix_seed(seed, ci as u64 + 1));
let dist = dist.clone();
(start..end).map(move |_| dist.sample(&mut rng))
})
.collect()
}
pub fn collect_seeded<T, D>(n: usize, dist: D, seed: u64) -> Vec<T>
where
T: NumCast + Send,
D: Distribution<f32> + Clone + Send + Sync,
{
collect_f32_seeded(n, dist, seed)
.into_iter()
.map(|x| T::from(x).expect("sampled f32 not representable in target type"))
.collect()
}
#[inline]
pub fn entropy_seed() -> u64 {
rand::rng().random()
}
pub fn normal_f32_seeded(n: usize, stdev: f32, seed: u64) -> Vec<f32> {
let dist = rand_distr::Normal::new(0.0f32, stdev).expect("finite stdev");
collect_f32_seeded(n, dist, seed)
}
#[cfg(test)]
mod tests {
use super::*;
use rand_distr::StandardNormal;
#[test]
fn same_seed_same_output() {
let a = collect_f32_seeded(100_000, StandardNormal, 42);
let b = collect_f32_seeded(100_000, StandardNormal, 42);
assert_eq!(a, b, "same seed must reproduce byte-identical output");
}
#[test]
fn different_seed_different_output() {
let a = collect_f32_seeded(10_000, StandardNormal, 1);
let b = collect_f32_seeded(10_000, StandardNormal, 2);
assert_ne!(a, b, "distinct seeds must diverge");
}
#[test]
fn independent_of_thread_count() {
let reference = collect_f32_seeded(200_000, StandardNormal, 7);
let single = rayon::ThreadPoolBuilder::new()
.num_threads(1)
.build()
.unwrap()
.install(|| collect_f32_seeded(200_000, StandardNormal, 7));
assert_eq!(reference, single);
}
#[test]
fn mix_seed_avalanche() {
assert_ne!(mix_seed(42, 1), mix_seed(42, 2));
assert_ne!(mix_seed(0, 0), mix_seed(0, 1));
}
}