1use crate::distribution::{Continuous, ContinuousCDF};
2use crate::statistics::*;
3use crate::{Result, StatsError};
4use rand::distributions::Uniform as RandUniform;
5use rand::Rng;
6use std::f64;
7
8#[derive(Debug, Copy, Clone, PartialEq)]
23pub struct Uniform {
24 min: f64,
25 max: f64,
26}
27
28impl Uniform {
29 pub fn new(min: f64, max: f64) -> Result<Uniform> {
49 if min > max || min.is_nan() || max.is_nan() {
50 Err(StatsError::BadParams)
51 } else {
52 Ok(Uniform { min, max })
53 }
54 }
55}
56
57impl ::rand::distributions::Distribution<f64> for Uniform {
58 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
59 let d = RandUniform::new_inclusive(self.min, self.max);
60 rng.sample(d)
61 }
62}
63
64impl ContinuousCDF<f64, f64> for Uniform {
65 fn cdf(&self, x: f64) -> f64 {
75 if x <= self.min {
76 0.0
77 } else if x >= self.max {
78 1.0
79 } else {
80 (x - self.min) / (self.max - self.min)
81 }
82 }
83
84 fn sf(&self, x: f64) -> f64 {
93 if x <= self.min {
94 1.0
95 } else if x >= self.max {
96 0.0
97 } else if x.is_infinite() && self.max.is_infinite() {
98 0.0
99 } else if self.max.is_infinite() {
100 1.0
101 } else {
102 (self.max - x) / (self.max - self.min)
103 }
104 }
105}
106
107impl Min<f64> for Uniform {
108 fn min(&self) -> f64 {
109 self.min
110 }
111}
112
113impl Max<f64> for Uniform {
114 fn max(&self) -> f64 {
115 self.max
116 }
117}
118
119impl Distribution<f64> for Uniform {
120 fn mean(&self) -> Option<f64> {
128 Some((self.min + self.max) / 2.0)
129 }
130 fn variance(&self) -> Option<f64> {
138 Some((self.max - self.min) * (self.max - self.min) / 12.0)
139 }
140 fn entropy(&self) -> Option<f64> {
148 Some((self.max - self.min).ln())
149 }
150 fn skewness(&self) -> Option<f64> {
158 Some(0.0)
159 }
160}
161
162impl Median<f64> for Uniform {
163 fn median(&self) -> f64 {
171 (self.min + self.max) / 2.0
172 }
173}
174
175impl Mode<Option<f64>> for Uniform {
176 fn mode(&self) -> Option<f64> {
189 Some((self.min + self.max) / 2.0)
190 }
191}
192
193impl Continuous<f64, f64> for Uniform {
194 fn pdf(&self, x: f64) -> f64 {
207 if x < self.min || x > self.max {
208 0.0
209 } else {
210 1.0 / (self.max - self.min)
211 }
212 }
213
214 fn ln_pdf(&self, x: f64) -> f64 {
228 if x < self.min || x > self.max {
229 f64::NEG_INFINITY
230 } else {
231 -(self.max - self.min).ln()
232 }
233 }
234}
235
236#[rustfmt::skip]
237#[cfg(all(test, feature = "nightly"))]
238mod tests {
239 use crate::statistics::*;
240 use crate::distribution::{ContinuousCDF, Continuous, Uniform};
241 use crate::distribution::internal::*;
242 use crate::consts::ACC;
243
244 fn try_create(min: f64, max: f64) -> Uniform {
245 let n = Uniform::new(min, max);
246 assert!(n.is_ok());
247 n.unwrap()
248 }
249
250 fn create_case(min: f64, max: f64) {
251 let n = try_create(min, max);
252 assert_eq!(n.min(), min);
253 assert_eq!(n.max(), max);
254 }
255
256 fn bad_create_case(min: f64, max: f64) {
257 let n = Uniform::new(min, max);
258 assert!(n.is_err());
259 }
260
261 fn get_value<F>(min: f64, max: f64, eval: F) -> f64
262 where F: Fn(Uniform) -> f64
263 {
264 let n = try_create(min, max);
265 eval(n)
266 }
267
268 fn test_case<F>(min: f64, max: f64, expected: f64, eval: F)
269 where F: Fn(Uniform) -> f64
270 {
271
272 let x = get_value(min, max, eval);
273 assert_eq!(expected, x);
274 }
275
276 fn test_almost<F>(min: f64, max: f64, expected: f64, acc: f64, eval: F)
277 where F: Fn(Uniform) -> f64
278 {
279
280 let x = get_value(min, max, eval);
281 assert_almost_eq!(expected, x, acc);
282 }
283
284 #[test]
285 fn test_create() {
286 create_case(0.0, 0.0);
287 create_case(0.0, 0.1);
288 create_case(0.0, 1.0);
289 create_case(10.0, 10.0);
290 create_case(-5.0, 11.0);
291 create_case(-5.0, 100.0);
292 }
293
294 #[test]
295 fn test_bad_create() {
296 bad_create_case(f64::NAN, 1.0);
297 bad_create_case(1.0, f64::NAN);
298 bad_create_case(f64::NAN, f64::NAN);
299 bad_create_case(1.0, 0.0);
300 }
301
302 #[test]
303 fn test_variance() {
304 let variance = |x: Uniform| x.variance().unwrap();
305 test_case(-0.0, 2.0, 1.0 / 3.0, variance);
306 test_case(0.0, 2.0, 1.0 / 3.0, variance);
307 test_almost(0.1, 4.0, 1.2675, 1e-15, variance);
308 test_case(10.0, 11.0, 1.0 / 12.0, variance);
309 test_case(0.0, f64::INFINITY, f64::INFINITY, variance);
310 }
311
312 #[test]
313 fn test_entropy() {
314 let entropy = |x: Uniform| x.entropy().unwrap();
315 test_case(-0.0, 2.0, 0.6931471805599453094172, entropy);
316 test_case(0.0, 2.0, 0.6931471805599453094172, entropy);
317 test_almost(0.1, 4.0, 1.360976553135600743431, 1e-15, entropy);
318 test_case(1.0, 10.0, 2.19722457733621938279, entropy);
319 test_case(10.0, 11.0, 0.0, entropy);
320 test_case(0.0, f64::INFINITY, f64::INFINITY, entropy);
321 }
322
323 #[test]
324 fn test_skewness() {
325 let skewness = |x: Uniform| x.skewness().unwrap();
326 test_case(-0.0, 2.0, 0.0, skewness);
327 test_case(0.0, 2.0, 0.0, skewness);
328 test_case(0.1, 4.0, 0.0, skewness);
329 test_case(1.0, 10.0, 0.0, skewness);
330 test_case(10.0, 11.0, 0.0, skewness);
331 test_case(0.0, f64::INFINITY, 0.0, skewness);
332 }
333
334 #[test]
335 fn test_mode() {
336 let mode = |x: Uniform| x.mode().unwrap();
337 test_case(-0.0, 2.0, 1.0, mode);
338 test_case(0.0, 2.0, 1.0, mode);
339 test_case(0.1, 4.0, 2.05, mode);
340 test_case(1.0, 10.0, 5.5, mode);
341 test_case(10.0, 11.0, 10.5, mode);
342 test_case(0.0, f64::INFINITY, f64::INFINITY, mode);
343 }
344
345 #[test]
346 fn test_median() {
347 let median = |x: Uniform| x.median();
348 test_case(-0.0, 2.0, 1.0, median);
349 test_case(0.0, 2.0, 1.0, median);
350 test_case(0.1, 4.0, 2.05, median);
351 test_case(1.0, 10.0, 5.5, median);
352 test_case(10.0, 11.0, 10.5, median);
353 test_case(0.0, f64::INFINITY, f64::INFINITY, median);
354 }
355
356 #[test]
357 fn test_pdf() {
358 let pdf = |arg: f64| move |x: Uniform| x.pdf(arg);
359 test_case(0.0, 0.0, 0.0, pdf(-5.0));
360 test_case(0.0, 0.0, f64::INFINITY, pdf(0.0));
361 test_case(0.0, 0.0, 0.0, pdf(5.0));
362 test_case(0.0, 0.1, 0.0, pdf(-5.0));
363 test_case(0.0, 0.1, 10.0, pdf(0.05));
364 test_case(0.0, 0.1, 0.0, pdf(5.0));
365 test_case(0.0, 1.0, 0.0, pdf(-5.0));
366 test_case(0.0, 1.0, 1.0, pdf(0.5));
367 test_case(0.0, 0.1, 0.0, pdf(5.0));
368 test_case(0.0, 10.0, 0.0, pdf(-5.0));
369 test_case(0.0, 10.0, 0.1, pdf(1.0));
370 test_case(0.0, 10.0, 0.1, pdf(5.0));
371 test_case(0.0, 10.0, 0.0, pdf(11.0));
372 test_case(-5.0, 100.0, 0.0, pdf(-10.0));
373 test_case(-5.0, 100.0, 0.009523809523809523809524, pdf(-5.0));
374 test_case(-5.0, 100.0, 0.009523809523809523809524, pdf(0.0));
375 test_case(-5.0, 100.0, 0.0, pdf(101.0));
376 test_case(0.0, f64::INFINITY, 0.0, pdf(-5.0));
377 test_case(0.0, f64::INFINITY, 0.0, pdf(10.0));
378 test_case(0.0, f64::INFINITY, 0.0, pdf(f64::INFINITY));
379 }
380
381 #[test]
382 fn test_ln_pdf() {
383 let ln_pdf = |arg: f64| move |x: Uniform| x.ln_pdf(arg);
384 test_case(0.0, 0.0, f64::NEG_INFINITY, ln_pdf(-5.0));
385 test_case(0.0, 0.0, f64::INFINITY, ln_pdf(0.0));
386 test_case(0.0, 0.0, f64::NEG_INFINITY, ln_pdf(5.0));
387 test_case(0.0, 0.1, f64::NEG_INFINITY, ln_pdf(-5.0));
388 test_almost(0.0, 0.1, 2.302585092994045684018, 1e-15, ln_pdf(0.05));
389 test_case(0.0, 0.1, f64::NEG_INFINITY, ln_pdf(5.0));
390 test_case(0.0, 1.0, f64::NEG_INFINITY, ln_pdf(-5.0));
391 test_case(0.0, 1.0, 0.0, ln_pdf(0.5));
392 test_case(0.0, 0.1, f64::NEG_INFINITY, ln_pdf(5.0));
393 test_case(0.0, 10.0, f64::NEG_INFINITY, ln_pdf(-5.0));
394 test_case(0.0, 10.0, -2.302585092994045684018, ln_pdf(1.0));
395 test_case(0.0, 10.0, -2.302585092994045684018, ln_pdf(5.0));
396 test_case(0.0, 10.0, f64::NEG_INFINITY, ln_pdf(11.0));
397 test_case(-5.0, 100.0, f64::NEG_INFINITY, ln_pdf(-10.0));
398 test_case(-5.0, 100.0, -4.653960350157523371101, ln_pdf(-5.0));
399 test_case(-5.0, 100.0, -4.653960350157523371101, ln_pdf(0.0));
400 test_case(-5.0, 100.0, f64::NEG_INFINITY, ln_pdf(101.0));
401 test_case(0.0, f64::INFINITY, f64::NEG_INFINITY, ln_pdf(-5.0));
402 test_case(0.0, f64::INFINITY, f64::NEG_INFINITY, ln_pdf(10.0));
403 test_case(0.0, f64::INFINITY, f64::NEG_INFINITY, ln_pdf(f64::INFINITY));
404 }
405
406 #[test]
407 fn test_cdf() {
408 let cdf = |arg: f64| move |x: Uniform| x.cdf(arg);
409 test_case(0.0, 0.0, 0.0, cdf(0.0));
410 test_case(0.0, 0.1, 0.5, cdf(0.05));
411 test_case(0.0, 1.0, 0.5, cdf(0.5));
412 test_case(0.0, 10.0, 0.1, cdf(1.0));
413 test_case(0.0, 10.0, 0.5, cdf(5.0));
414 test_case(-5.0, 100.0, 0.0, cdf(-5.0));
415 test_case(-5.0, 100.0, 0.04761904761904761904762, cdf(0.0));
416 test_case(0.0, f64::INFINITY, 0.0, cdf(10.0));
417 test_case(0.0, f64::INFINITY, 1.0, cdf(f64::INFINITY));
418 }
419
420 #[test]
421 fn test_cdf_lower_bound() {
422 let cdf = |arg: f64| move |x: Uniform| x.cdf(arg);
423 test_case(0.0, 3.0, 0.0, cdf(-1.0));
424 }
425
426 #[test]
427 fn test_cdf_upper_bound() {
428 let cdf = |arg: f64| move |x: Uniform| x.cdf(arg);
429 test_case(0.0, 3.0, 1.0, cdf(5.0));
430 }
431
432
433 #[test]
434 fn test_sf() {
435 let sf = |arg: f64| move |x: Uniform| x.sf(arg);
436 test_case(0.0, 0.0, 1.0, sf(0.0));
437 test_case(0.0, 0.1, 0.5, sf(0.05));
438 test_case(0.0, 1.0, 0.5, sf(0.5));
439 test_case(0.0, 10.0, 0.9, sf(1.0));
440 test_case(0.0, 10.0, 0.5, sf(5.0));
441 test_case(-5.0, 100.0, 1.0, sf(-5.0));
442 test_case(-5.0, 100.0, 0.9523809523809523, sf(0.0));
443 test_case(0.0, f64::INFINITY, 1.0, sf(10.0));
444 test_case(0.0, f64::INFINITY, 0.0, sf(f64::INFINITY));
445 }
446
447 #[test]
448 fn test_sf_lower_bound() {
449 let sf = |arg: f64| move |x: Uniform| x.sf(arg);
450 test_case(0.0, 3.0, 1.0, sf(-1.0));
451 }
452
453 #[test]
454 fn test_sf_upper_bound() {
455 let sf = |arg: f64| move |x: Uniform| x.sf(arg);
456 test_case(0.0, 3.0, 0.0, sf(5.0));
457 }
458
459 #[test]
460 fn test_continuous() {
461 test::check_continuous_distribution(&try_create(0.0, 10.0), 0.0, 10.0);
462 test::check_continuous_distribution(&try_create(-2.0, 15.0), -2.0, 15.0);
463 }
464
465 #[test]
466 fn test_samples_in_range() {
467 use rand::rngs::StdRng;
468 use rand::SeedableRng;
469 use rand::distributions::Distribution;
470
471 let seed = [
472 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
473 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
474 ];
475 let mut r: StdRng = SeedableRng::from_seed(seed);
476
477 let min = -0.5;
478 let max = 0.5;
479 let num_trials = 10_000;
480 let n = try_create(min, max);
481
482 assert!((0..num_trials)
483 .map(|_| n.sample::<StdRng>(&mut r))
484 .all(|v| (min <= v) && (v < max))
485 );
486 }
487}