Skip to main content

gam_problem/
dispersion.rs

1//! Dispersion/scale contract used by covariance and reference-distribution code.
2
3use serde::{Deserialize, Serialize};
4
5/// Dispersion contract used by inferential covariance and reference distributions.
6///
7/// `Known(phi)` is used for fixed-scale exponential-family fits such as
8/// Poisson and Binomial (`phi = 1`). `Estimated(phi)` is used when the
9/// residual/likelihood scale is estimated from the data, e.g. Gaussian
10/// (`phi = sigma^2`) and Gamma (`phi = 1 / shape`). Stored covariance
11/// matrices are scaled by this `phi`.
12#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
13pub enum Dispersion {
14    Known(f64),
15    Estimated(f64),
16}
17
18impl Dispersion {
19    #[inline]
20    pub const fn phi(self) -> f64 {
21        match self {
22            Self::Known(phi) | Self::Estimated(phi) => phi,
23        }
24    }
25
26    #[inline]
27    pub const fn is_estimated(self) -> bool {
28        matches!(self, Self::Estimated(_))
29    }
30}
31
32impl Default for Dispersion {
33    fn default() -> Self {
34        Self::Known(1.0)
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn phi_known_returns_inner_value() {
44        assert_eq!(Dispersion::Known(2.5).phi(), 2.5);
45    }
46
47    #[test]
48    fn phi_estimated_returns_inner_value() {
49        assert_eq!(Dispersion::Estimated(0.5).phi(), 0.5);
50    }
51
52    #[test]
53    fn is_estimated_false_for_known() {
54        assert!(!Dispersion::Known(1.0).is_estimated());
55    }
56
57    #[test]
58    fn is_estimated_true_for_estimated() {
59        assert!(Dispersion::Estimated(0.1).is_estimated());
60    }
61
62    #[test]
63    fn default_is_known_one() {
64        let d = Dispersion::default();
65        assert_eq!(d.phi(), 1.0);
66        assert!(!d.is_estimated());
67    }
68
69    #[test]
70    fn known_and_estimated_same_phi_are_not_equal() {
71        assert_ne!(Dispersion::Known(1.0), Dispersion::Estimated(1.0));
72    }
73}