use rand::Rng;
#[inline]
fn sample_exp(rate: f64, rng: &mut impl Rng) -> f64 {
let u: f64 = rng.random();
-((1.0 - u).ln()) / rate
}
pub fn poisson_inter_arrivals(rate: f64, n: usize, rng: &mut impl Rng) -> Vec<f64> {
assert!(rate > 0.0, "rate must be positive");
(0..n).map(|_| sample_exp(rate, rng)).collect()
}
pub fn poisson_arrival_times(rate: f64, n: usize, rng: &mut impl Rng) -> Vec<f64> {
assert!(rate > 0.0, "rate must be positive");
let mut t = 0.0_f64;
(0..n)
.map(|_| {
t += sample_exp(rate, rng);
t
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use rand::SeedableRng;
#[test]
fn inter_arrival_mean_approximates_inverse_rate() {
let mut rng = rand::rngs::StdRng::seed_from_u64(42);
let rate = 20.0;
let xs = poisson_inter_arrivals(rate, 5000, &mut rng);
let mean = xs.iter().sum::<f64>() / xs.len() as f64;
let expected = 1.0 / rate;
let rel_err = (mean - expected).abs() / expected;
assert!(
rel_err < 0.05,
"rel err {rel_err} too large (mean={mean}, expected={expected})"
);
}
#[test]
fn inter_arrival_variance_approximates_inverse_rate_squared() {
let mut rng = rand::rngs::StdRng::seed_from_u64(7);
let rate = 10.0;
let xs = poisson_inter_arrivals(rate, 5000, &mut rng);
let mean = xs.iter().sum::<f64>() / xs.len() as f64;
let var = xs.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / xs.len() as f64;
let stddev = var.sqrt();
let expected_sd = 1.0 / rate;
let rel_err = (stddev - expected_sd).abs() / expected_sd;
assert!(rel_err < 0.05, "stddev rel err {rel_err} too large");
}
#[test]
fn arrival_times_monotonic() {
let mut rng = rand::rngs::StdRng::seed_from_u64(123);
let ts = poisson_arrival_times(5.0, 100, &mut rng);
for w in ts.windows(2) {
assert!(w[1] > w[0]);
}
}
#[test]
#[should_panic(expected = "rate must be positive")]
fn rejects_zero_rate() {
let mut rng = rand::rng();
let _ = poisson_inter_arrivals(0.0, 10, &mut rng);
}
#[test]
fn deterministic_with_seed() {
let mut a = rand::rngs::StdRng::seed_from_u64(99);
let mut b = rand::rngs::StdRng::seed_from_u64(99);
let xa = poisson_inter_arrivals(5.0, 20, &mut a);
let xb = poisson_inter_arrivals(5.0, 20, &mut b);
assert_eq!(xa, xb);
}
}