statrs/distribution/
dirac.rs1use crate::distribution::ContinuousCDF;
2use crate::statistics::*;
3
4#[derive(Debug, Copy, Clone, PartialEq)]
17pub struct Dirac(f64);
18
19#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
21#[non_exhaustive]
22pub enum DiracError {
23 ValueInvalid,
25}
26
27impl std::fmt::Display for DiracError {
28 #[cfg_attr(coverage_nightly, coverage(off))]
29 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
30 match self {
31 DiracError::ValueInvalid => write!(f, "Value v is NaN"),
32 }
33 }
34}
35
36impl std::error::Error for DiracError {}
37
38impl Dirac {
39 pub fn new(v: f64) -> Result<Self, DiracError> {
57 if v.is_nan() {
58 Err(DiracError::ValueInvalid)
59 } else {
60 Ok(Dirac(v))
61 }
62 }
63}
64
65impl std::fmt::Display for Dirac {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "δ_{}", self.0)
68 }
69}
70
71#[cfg(feature = "rand")]
72#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
73impl ::rand::distributions::Distribution<f64> for Dirac {
74 fn sample<R: ::rand::Rng + ?Sized>(&self, _: &mut R) -> f64 {
75 self.0
76 }
77}
78
79impl ContinuousCDF<f64, f64> for Dirac {
80 fn cdf(&self, x: f64) -> f64 {
85 if x < self.0 {
86 0.0
87 } else {
88 1.0
89 }
90 }
91
92 fn sf(&self, x: f64) -> f64 {
97 if x < self.0 {
98 1.0
99 } else {
100 0.0
101 }
102 }
103}
104
105impl Min<f64> for Dirac {
106 fn min(&self) -> f64 {
115 self.0
116 }
117}
118
119impl Max<f64> for Dirac {
120 fn max(&self) -> f64 {
129 self.0
130 }
131}
132
133impl Distribution<f64> for Dirac {
134 fn mean(&self) -> Option<f64> {
141 Some(self.0)
142 }
143
144 fn variance(&self) -> Option<f64> {
154 Some(0.0)
155 }
156
157 fn entropy(&self) -> Option<f64> {
167 Some(0.0)
168 }
169
170 fn skewness(&self) -> Option<f64> {
178 Some(0.0)
179 }
180}
181
182impl Median<f64> for Dirac {
183 fn median(&self) -> f64 {
193 self.0
194 }
195}
196
197impl Mode<Option<f64>> for Dirac {
198 fn mode(&self) -> Option<f64> {
208 Some(self.0)
209 }
210}
211
212#[rustfmt::skip]
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use crate::testing_boiler;
217
218 testing_boiler!(v: f64; Dirac; DiracError);
219
220 #[test]
221 fn test_create() {
222 create_ok(10.0);
223 create_ok(-5.0);
224 create_ok(10.0);
225 create_ok(100.0);
226 create_ok(f64::INFINITY);
227 }
228
229 #[test]
230 fn test_bad_create() {
231 create_err(f64::NAN);
232 }
233
234 #[test]
235 fn test_variance() {
236 let variance = |x: Dirac| x.variance().unwrap();
237 test_exact(0.0, 0.0, variance);
238 test_exact(-5.0, 0.0, variance);
239 test_exact(f64::INFINITY, 0.0, variance);
240 }
241
242 #[test]
243 fn test_entropy() {
244 let entropy = |x: Dirac| x.entropy().unwrap();
245 test_exact(0.0, 0.0, entropy);
246 test_exact(f64::INFINITY, 0.0, entropy);
247 }
248
249 #[test]
250 fn test_skewness() {
251 let skewness = |x: Dirac| x.skewness().unwrap();
252 test_exact(0.0, 0.0, skewness);
253 test_exact(4.0, 0.0, skewness);
254 test_exact(0.3, 0.0, skewness);
255 test_exact(f64::INFINITY, 0.0, skewness);
256 }
257
258 #[test]
259 fn test_mode() {
260 let mode = |x: Dirac| x.mode().unwrap();
261 test_exact(0.0, 0.0, mode);
262 test_exact(3.0, 3.0, mode);
263 test_exact(f64::INFINITY, f64::INFINITY, mode);
264 }
265
266 #[test]
267 fn test_median() {
268 let median = |x: Dirac| x.median();
269 test_exact(0.0, 0.0, median);
270 test_exact(3.0, 3.0, median);
271 test_exact(f64::INFINITY, f64::INFINITY, median);
272 }
273
274 #[test]
275 fn test_min_max() {
276 let min = |x: Dirac| x.min();
277 let max = |x: Dirac| x.max();
278 test_exact(0.0, 0.0, min);
279 test_exact(3.0, 3.0, min);
280 test_exact(f64::INFINITY, f64::INFINITY, min);
281
282 test_exact(0.0, 0.0, max);
283 test_exact(3.0, 3.0, max);
284 test_exact(f64::NEG_INFINITY, f64::NEG_INFINITY, max);
285 }
286
287 #[test]
288 fn test_cdf() {
289 let cdf = |arg: f64| move |x: Dirac| x.cdf(arg);
290 test_exact(0.0, 1.0, cdf(0.0));
291 test_exact(3.0, 1.0, cdf(3.0));
292 test_exact(f64::INFINITY, 0.0, cdf(1.0));
293 test_exact(f64::INFINITY, 1.0, cdf(f64::INFINITY));
294 }
295
296 #[test]
297 fn test_sf() {
298 let sf = |arg: f64| move |x: Dirac| x.sf(arg);
299 test_exact(0.0, 0.0, sf(0.0));
300 test_exact(3.0, 0.0, sf(3.0));
301 test_exact(f64::INFINITY, 1.0, sf(1.0));
302 test_exact(f64::INFINITY, 0.0, sf(f64::INFINITY));
303 }
304}