statrs/distribution/
dirac.rs

1use crate::distribution::{Continuous, ContinuousCDF};
2use crate::statistics::*;
3use crate::{Result, StatsError};
4use rand::Rng;
5
6/// Implements the [Dirac Delta](https://en.wikipedia.org/wiki/Dirac_delta_function#As_a_distribution)
7/// distribution
8///
9/// # Examples
10///
11/// ```
12/// use statrs::distribution::{Dirac, Continuous};
13/// use statrs::statistics::Distribution;
14///
15/// let n = Dirac::new(3.0).unwrap();
16/// assert_eq!(n.mean().unwrap(), 3.0);
17/// ```
18#[derive(Debug, Copy, Clone, PartialEq)]
19pub struct Dirac(f64);
20
21impl Dirac {
22    ///  Constructs a new dirac distribution function at value `v`.
23    ///
24    /// # Errors
25    ///
26    /// Returns an error if `v` is not-a-number.
27    ///
28    /// # Examples
29    ///
30    /// ```
31    /// use statrs::distribution::Dirac;
32    ///
33    /// let mut result = Dirac::new(0.0);
34    /// assert!(result.is_ok());
35    ///
36    /// result = Dirac::new(f64::NAN);
37    /// assert!(result.is_err());
38    /// ```
39    pub fn new(v: f64) -> Result<Self> {
40        if v.is_nan() {
41            Err(StatsError::BadParams)
42        } else {
43            Ok(Dirac(v))
44        }
45    }
46}
47
48impl ::rand::distributions::Distribution<f64> for Dirac {
49    fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> f64 {
50        self.0
51    }
52}
53
54impl ContinuousCDF<f64, f64> for Dirac {
55    /// Calculates the cumulative distribution function for the
56    /// dirac distribution at `x`
57    ///
58    /// Where the value is 1 if x > `v`, 0 otherwise.
59    ///
60    fn cdf(&self, x: f64) -> f64 {
61        if x < self.0 {
62            0.0
63        } else {
64            1.0
65        }
66    }
67
68    /// Calculates the survival function for the
69    /// dirac distribution at `x`
70    ///
71    /// Where the value is 0 if x > `v`, 1 otherwise.
72    ///
73    fn sf(&self, x: f64) -> f64 {
74        if x < self.0 {
75            1.0
76        } else {
77            0.0
78        }
79    }
80}
81
82impl Min<f64> for Dirac {
83    /// Returns the minimum value in the domain of the
84    /// dirac distribution representable by a double precision float
85    ///
86    /// # Formula
87    ///
88    /// ```ignore
89    /// v
90    /// ```
91    fn min(&self) -> f64 {
92        self.0
93    }
94}
95
96impl Max<f64> for Dirac {
97    /// Returns the maximum value in the domain of the
98    /// dirac distribution representable by a double precision float
99    ///
100    /// # Formula
101    ///
102    /// ```ignore
103    /// v
104    /// ```
105    fn max(&self) -> f64 {
106        self.0
107    }
108}
109
110impl Distribution<f64> for Dirac {
111    /// Returns the mean of the dirac distribution
112    ///
113    /// # Remarks
114    ///
115    /// Since the only value that can be produced by this distribution is `v` with probability
116    /// 1, it is just `v`.
117    fn mean(&self) -> Option<f64> {
118        Some(self.0)
119    }
120    /// Returns the variance of the dirac distribution
121    ///
122    /// # Formula
123    ///
124    /// ```ignore
125    /// 0
126    /// ```
127    ///
128    /// Since only one value can be produced there is no variance.
129    fn variance(&self) -> Option<f64> {
130        Some(0.0)
131    }
132    /// Returns the entropy of the dirac distribution
133    ///
134    /// # Formula
135    ///
136    /// ```ignore
137    /// 0
138    /// ```
139    ///
140    /// Since this distribution has full certainty, it encodes no information
141    fn entropy(&self) -> Option<f64> {
142        Some(0.0)
143    }
144    /// Returns the skewness of the dirac distribution
145    ///
146    /// # Formula
147    ///
148    /// ```ignore
149    /// 0
150    /// ```
151    fn skewness(&self) -> Option<f64> {
152        Some(0.0)
153    }
154}
155
156impl Median<f64> for Dirac {
157    /// Returns the median of the dirac distribution
158    ///
159    /// # Formula
160    ///
161    /// ```ignore
162    /// v
163    /// ```
164    ///
165    /// where `v` is the point of the dirac distribution
166    fn median(&self) -> f64 {
167        self.0
168    }
169}
170
171impl Mode<Option<f64>> for Dirac {
172    /// Returns the mode of the dirac distribution
173    ///
174    /// # Formula
175    ///
176    /// ```ignore
177    /// v
178    /// ```
179    ///
180    /// where `v` is the point of the dirac distribution
181    fn mode(&self) -> Option<f64> {
182        Some(self.0)
183    }
184}
185
186#[rustfmt::skip]
187#[cfg(all(test, feature = "nightly"))]
188mod tests {
189    use crate::statistics::*;
190    use crate::distribution::{ContinuousCDF, Continuous, Dirac};
191    use crate::consts::ACC;
192
193    fn try_create(v: f64) -> Dirac {
194        let d = Dirac::new(v);
195        assert!(d.is_ok());
196        d.unwrap()
197    }
198
199    fn create_case(v: f64) {
200        let d = try_create(v);
201        assert_eq!(v, d.mean().unwrap());
202    }
203
204    fn bad_create_case(v: f64) {
205        let d = Dirac::new(v);
206        assert!(d.is_err());
207    }
208
209    fn test_case<F>(v: f64, expected: f64, eval: F)
210        where F: Fn(Dirac) -> f64
211    {
212        let x = eval(try_create(v));
213        assert_eq!(expected, x);
214    }
215
216    #[test]
217    fn test_create() {
218        create_case(10.0);
219        create_case(-5.0);
220        create_case(10.0);
221        create_case(100.0);
222        create_case(f64::INFINITY);
223    }
224
225    #[test]
226    fn test_bad_create() {
227        bad_create_case(f64::NAN);
228    }
229
230    #[test]
231    fn test_variance() {
232        let variance = |x: Dirac| x.variance().unwrap();
233        test_case(0.0, 0.0, variance);
234        test_case(-5.0, 0.0, variance);
235        test_case(f64::INFINITY, 0.0, variance);
236    }
237
238    #[test]
239    fn test_entropy() {
240        let entropy = |x: Dirac| x.entropy().unwrap();
241        test_case(0.0, 0.0, entropy);
242        test_case(f64::INFINITY, 0.0, entropy);
243    }
244
245    #[test]
246    fn test_skewness() {
247        let skewness = |x: Dirac| x.skewness().unwrap();
248        test_case(0.0, 0.0, skewness);
249        test_case(4.0, 0.0, skewness);
250        test_case(0.3, 0.0, skewness);
251        test_case(f64::INFINITY, 0.0, skewness);
252    }
253
254    #[test]
255    fn test_mode() {
256        let mode = |x: Dirac| x.mode().unwrap();
257        test_case(0.0, 0.0, mode);
258        test_case(3.0, 3.0, mode);
259        test_case(f64::INFINITY, f64::INFINITY, mode);
260    }
261
262    #[test]
263    fn test_median() {
264        let median = |x: Dirac| x.median();
265        test_case(0.0, 0.0, median);
266        test_case(3.0, 3.0, median);
267        test_case(f64::INFINITY, f64::INFINITY, median);
268    }
269
270    #[test]
271    fn test_min_max() {
272        let min = |x: Dirac| x.min();
273        let max = |x: Dirac| x.max();
274        test_case(0.0, 0.0, min);
275        test_case(3.0, 3.0, min);
276        test_case(f64::INFINITY, f64::INFINITY, min);
277
278        test_case(0.0, 0.0, max);
279        test_case(3.0, 3.0, max);
280        test_case(f64::NEG_INFINITY, f64::NEG_INFINITY, max);
281    }
282
283    #[test]
284    fn test_cdf() {
285        let cdf = |arg: f64| move |x: Dirac| x.cdf(arg);
286        test_case(0.0, 1.0, cdf(0.0));
287        test_case(3.0, 1.0, cdf(3.0));
288        test_case(f64::INFINITY, 0.0, cdf(1.0));
289        test_case(f64::INFINITY, 1.0, cdf(f64::INFINITY));
290    }
291
292    #[test]
293    fn test_sf() {
294        let sf = |arg: f64| move |x: Dirac| x.sf(arg);
295        test_case(0.0, 0.0, sf(0.0));
296        test_case(3.0, 0.0, sf(3.0));
297        test_case(f64::INFINITY, 1.0, sf(1.0));
298        test_case(f64::INFINITY, 0.0, sf(f64::INFINITY));
299    }
300}