Skip to main content

numra_stats/distributions/
exponential.rs

1//! Exponential distribution.
2//!
3//! Author: Moussa Leblouba
4//! Date: 9 February 2026
5//! Modified: 2 May 2026
6
7use numra_core::Scalar;
8use rand::RngCore;
9
10use super::normal::random_uniform_01;
11use super::ContinuousDistribution;
12
13/// Exponential distribution with rate parameter lambda.
14#[derive(Clone, Debug)]
15pub struct Exponential<S: Scalar> {
16    pub lambda: S,
17}
18
19impl<S: Scalar> Exponential<S> {
20    pub fn new(lambda: S) -> Self {
21        Self { lambda }
22    }
23}
24
25impl<S: Scalar> ContinuousDistribution<S> for Exponential<S> {
26    fn pdf(&self, x: S) -> S {
27        if x < S::ZERO {
28            S::ZERO
29        } else {
30            self.lambda * (S::ZERO - self.lambda * x).exp()
31        }
32    }
33
34    fn cdf(&self, x: S) -> S {
35        if x < S::ZERO {
36            S::ZERO
37        } else {
38            S::ONE - (S::ZERO - self.lambda * x).exp()
39        }
40    }
41
42    fn quantile(&self, p: S) -> S {
43        // Inverse CDF: -ln(1-p) / lambda
44        (S::ZERO - (S::ONE - p).ln()) / self.lambda
45    }
46
47    fn mean(&self) -> S {
48        S::ONE / self.lambda
49    }
50
51    fn variance(&self) -> S {
52        S::ONE / (self.lambda * self.lambda)
53    }
54
55    fn sample(&self, rng: &mut dyn RngCore) -> S {
56        let u = random_uniform_01::<S>(rng);
57        self.quantile(u)
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_exponential_pdf() {
67        let e = Exponential::new(2.0_f64);
68        assert!((e.pdf(0.0) - 2.0).abs() < 1e-12);
69        assert!((e.pdf(1.0) - 2.0 * (-2.0_f64).exp()).abs() < 1e-12);
70    }
71
72    #[test]
73    fn test_exponential_cdf() {
74        let e = Exponential::new(1.0_f64);
75        assert!(e.cdf(0.0).abs() < 1e-14);
76        assert!((e.cdf(1.0) - (1.0 - (-1.0_f64).exp())).abs() < 1e-12);
77    }
78
79    #[test]
80    fn test_exponential_quantile_roundtrip() {
81        let e = Exponential::new(3.0_f64);
82        for &p in &[0.1, 0.5, 0.9, 0.99] {
83            let x = e.quantile(p);
84            let p2 = e.cdf(x);
85            assert!((p - p2).abs() < 1e-12, "p={}, p2={}", p, p2);
86        }
87    }
88
89    #[test]
90    fn test_exponential_mean_variance() {
91        let e = Exponential::new(0.5_f64);
92        assert!((e.mean() - 2.0).abs() < 1e-14);
93        assert!((e.variance() - 4.0).abs() < 1e-14);
94    }
95}