use crate::error::StaticError;
use crate::uncertainty::rng::SplitMix64;
use crate::uncertainty::summary::PercentileSummary;
#[derive(Debug, Clone)]
pub struct Realizations {
pub values: Vec<f64>,
}
impl Realizations {
pub fn summary(&self) -> Result<PercentileSummary, StaticError> {
PercentileSummary::from_realizations(&self.values)
}
}
pub fn run<F>(n: usize, seed: u64, mut trial: F) -> Realizations
where
F: FnMut(&mut SplitMix64) -> f64,
{
let mut rng = SplitMix64::new(seed);
let values = (0..n).map(|_| trial(&mut rng)).collect();
Realizations { values }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::uncertainty::distribution::Distribution;
#[test]
fn reproducible_for_same_seed() {
let d = Distribution::lognormal(3.0, 0.4).unwrap();
let a = run(5_000, 99, |r| d.sample(r));
let b = run(5_000, 99, |r| d.sample(r));
assert_eq!(a.values, b.values);
}
#[test]
fn recovers_known_normal_percentiles() {
let d = Distribution::normal(100.0, 10.0).unwrap();
let s = run(200_000, 7, |r| d.sample(r)).summary().unwrap();
assert!((s.p50 - 100.0).abs() < 0.3, "p50={}", s.p50);
assert!((s.p10 - 112.816).abs() < 0.3, "p10={}", s.p10);
assert!((s.p90 - 87.184).abs() < 0.3, "p90={}", s.p90);
assert!((s.mean - 100.0).abs() < 0.2, "mean={}", s.mean);
}
#[test]
fn swanson_mean_near_true_mean_for_symmetric() {
let d = Distribution::normal(50.0, 5.0).unwrap();
let s = run(200_000, 3, |r| d.sample(r)).summary().unwrap();
assert!((s.swanson_mean() - 50.0).abs() < 0.3);
}
}