From d8b0d424174f1da974b40490e152c0d7e12d74fd Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 30 Jul 2018 15:17:54 +0200 Subject: [PATCH 1/2] Implement triangular distribution --- src/distributions/mod.rs | 5 ++ src/distributions/triangular.rs | 88 +++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/distributions/triangular.rs diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 082d22278f4..9afc2bc2e87 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -98,6 +98,8 @@ //! - [`ChiSquared`] distribution //! - [`StudentT`] distribution //! - [`FisherF`] distribution +//! - Triangular distribution: +//! - [`Triangular`] distribution //! - Multivariate probability distributions //! - [`Dirichlet`] distribution //! - [`UnitSphereSurface`] distribution @@ -168,6 +170,7 @@ //! [`Standard`]: struct.Standard.html //! [`StandardNormal`]: struct.StandardNormal.html //! [`StudentT`]: struct.StudentT.html +//! [`Triangular`]: struct.Triangular.html //! [`Uniform`]: struct.Uniform.html //! [`Uniform::new`]: struct.Uniform.html#method.new //! [`Uniform::new_inclusive`]: struct.Uniform.html#method.new_inclusive @@ -192,6 +195,7 @@ pub use self::bernoulli::Bernoulli; #[cfg(feature="std")] pub use self::binomial::Binomial; #[cfg(feature="std")] pub use self::cauchy::Cauchy; #[cfg(feature="std")] pub use self::dirichlet::Dirichlet; +#[cfg(feature="std")] pub use self::triangular::Triangular; pub mod uniform; mod bernoulli; @@ -206,6 +210,7 @@ mod bernoulli; #[cfg(feature="std")] mod binomial; #[cfg(feature="std")] mod cauchy; #[cfg(feature="std")] mod dirichlet; +#[cfg(feature="std")] mod triangular; mod float; mod integer; diff --git a/src/distributions/triangular.rs b/src/distributions/triangular.rs new file mode 100644 index 00000000000..5b4c467b68d --- /dev/null +++ b/src/distributions/triangular.rs @@ -0,0 +1,88 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! The triangular distribution. + +use Rng; +use distributions::{Distribution, Standard}; + +/// The triangular distribution. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Triangular, Distribution}; +/// +/// let d = Triangular::new(0., 5., 2.5); +/// let v = d.sample(&mut rand::thread_rng()); +/// println!("{} is from a triangular distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Triangular { + min: f64, + max: f64, + mode: f64, +} + +impl Triangular { + /// Construct a new `Triangular` with minimum `min`, maximum `max` and mode + /// `mode`. + /// + /// # Panics + /// + /// If `max < mode`, `mode < max` or `max == min`. + /// + #[inline] + pub fn new(min: f64, max: f64, mode: f64) -> Triangular { + assert!(max >= mode); + assert!(mode >= min); + assert!(max != min); + Triangular { min, max, mode } + } +} + +impl Distribution for Triangular { + #[inline] + fn sample(&self, rng: &mut R) -> f64 { + let f: f64 = rng.sample(Standard); + let diff_mode_min = self.mode - self.min; + let diff_max_min = self.max - self.min; + if f < diff_mode_min / diff_max_min { + self.min + (f * diff_max_min * diff_mode_min).sqrt() + } else { + self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt() + } + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Triangular; + + #[test] + fn test_new() { + for &(min, max, mode) in &[ + (-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3), + (0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17), + ] { + println!("{} {} {}", min, max, mode); + let _ = Triangular::new(min, max, mode); + } + } + + #[test] + fn test_sample() { + let norm = Triangular::new(0., 1., 0.5); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + norm.sample(&mut rng); + } + } +} From 7f1bf4efc3196c8bffbeee1bc9b9f5bdd4e58582 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 30 Jul 2018 15:22:53 +0200 Subject: [PATCH 2/2] Triangular: Avoid division --- src/distributions/triangular.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/distributions/triangular.rs b/src/distributions/triangular.rs index 5b4c467b68d..27c5c59d0e9 100644 --- a/src/distributions/triangular.rs +++ b/src/distributions/triangular.rs @@ -53,7 +53,7 @@ impl Distribution for Triangular { let f: f64 = rng.sample(Standard); let diff_mode_min = self.mode - self.min; let diff_max_min = self.max - self.min; - if f < diff_mode_min / diff_max_min { + if f * diff_max_min < diff_mode_min { self.min + (f * diff_max_min * diff_mode_min).sqrt() } else { self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt()