numra_stats/distributions/
exponential.rs1use numra_core::Scalar;
8use rand::RngCore;
9
10use super::normal::random_uniform_01;
11use super::ContinuousDistribution;
12
13#[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 (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}