use crate::Random;
pub trait Distribution<T> {
fn sample(&self, rng: &mut Random) -> T;
fn samples<'a>(&'a self, rng: &'a mut Random) -> Iter<'a, Self, T>
where
Self: Sized,
{
Iter {
dist: self,
rng,
_t: core::marker::PhantomData,
}
}
}
#[derive(Debug)]
pub struct Iter<'a, D: Distribution<T> + ?Sized, T> {
dist: &'a D,
rng: &'a mut Random,
_t: core::marker::PhantomData<T>,
}
impl<D: Distribution<T>, T> Iterator for Iter<'_, D, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
Some(self.dist.sample(self.rng))
}
}
#[derive(Clone, Copy, Debug)]
pub struct Normal {
pub mu: f64,
pub sigma: f64,
}
impl Distribution<f64> for Normal {
fn sample(&self, rng: &mut Random) -> f64 {
rng.normal(self.mu, self.sigma)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Exponential {
pub rate: f64,
}
impl Distribution<f64> for Exponential {
fn sample(&self, rng: &mut Random) -> f64 {
rng.exponential(self.rate)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Uniform {
pub low: f64,
pub high: f64,
}
impl Distribution<f64> for Uniform {
fn sample(&self, rng: &mut Random) -> f64 {
rng.uniform(self.low, self.high)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Poisson {
pub mean: f64,
}
impl Distribution<u64> for Poisson {
fn sample(&self, rng: &mut Random) -> u64 {
rng.poisson(self.mean)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(all(not(feature = "alloc"), feature = "std"))]
use std::vec::Vec;
#[test]
fn normal_distribution_samples() {
let mut rng = Random::from_u64_seed(1);
let n = Normal {
mu: 0.0,
sigma: 1.0,
};
for _ in 0..256 {
assert!(n.sample(&mut rng).is_finite());
}
}
#[test]
fn exponential_distribution_samples() {
let mut rng = Random::from_u64_seed(1);
let e = Exponential { rate: 2.0 };
for _ in 0..256 {
assert!(e.sample(&mut rng) >= 0.0);
}
}
#[test]
fn uniform_distribution_in_range() {
let mut rng = Random::from_u64_seed(1);
let u = Uniform {
low: -5.0,
high: 5.0,
};
for _ in 0..256 {
let s = u.sample(&mut rng);
assert!((-5.0..5.0).contains(&s));
}
}
#[test]
fn poisson_distribution_samples() {
let mut rng = Random::from_u64_seed(1);
let p = Poisson { mean: 3.0 };
for _ in 0..256 {
let _ = p.sample(&mut rng);
}
}
#[test]
fn custom_distribution_compiles_and_runs() {
struct Coin {
bias: f64,
}
impl Distribution<bool> for Coin {
fn sample(&self, rng: &mut Random) -> bool {
rng.double() < self.bias
}
}
let mut rng = Random::from_u64_seed(7);
let fair: Vec<bool> =
Coin { bias: 0.5 }.samples(&mut rng).take(64).collect();
assert_eq!(fair.len(), 64);
}
}