Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
//! Thermal noise sources: Gaussian (Langevin) and Poisson spike noise.
use rand::Rng;
use rand_distr::{Distribution, Normal, Poisson};
/// Draw a Gaussian noise sample with standard deviation σ = √(2/β).
///
/// This matches the fluctuation-dissipation theorem for overdamped Langevin:
/// the noise amplitude must be √(2kT) = √(2/β) in dimensionless units.
#[inline]
pub fn langevin_noise(beta: f32, rng: &mut impl Rng) -> f32 {
if beta <= 0.0 || !beta.is_finite() {
return 0.0;
}
let sigma = (2.0 / beta).sqrt();
Normal::new(0.0_f32, sigma)
.unwrap_or_else(|_| Normal::new(0.0_f32, 1e-6).unwrap())
.sample(rng)
}
/// Draw `n` independent Langevin noise samples.
pub fn langevin_noise_vec(beta: f32, n: usize, rng: &mut impl Rng) -> Vec<f32> {
if beta <= 0.0 || !beta.is_finite() {
return vec![0.0; n];
}
let sigma = (2.0 / beta).sqrt();
let dist = Normal::new(0.0_f32, sigma).unwrap_or_else(|_| Normal::new(0.0_f32, 1e-6).unwrap());
(0..n).map(|_| dist.sample(rng)).collect()
}
/// Poisson spike noise: add a random kick of magnitude `kick` with rate λ.
///
/// Returns the kick to add to a single activation (0.0 if no spike this step).
#[inline]
pub fn poisson_spike(rate: f64, kick: f32, rng: &mut impl Rng) -> f32 {
if rate <= 0.0 || !rate.is_finite() {
return 0.0;
}
let dist = Poisson::new(rate).unwrap_or_else(|_| Poisson::new(1e-6).unwrap());
let count = dist.sample(rng) as u64;
if count > 0 {
// Random sign
let sign = if rng.gen::<bool>() { 1.0 } else { -1.0 };
sign * kick * count as f32
} else {
0.0
}
}