Skip to content

Commit 3b890dc

Browse files
authored
Merge pull request #575 from vks/triangular
Implement triangular distribution
2 parents fa269c3 + 7f1bf4e commit 3b890dc

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/distributions/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@
9898
//! - [`ChiSquared`] distribution
9999
//! - [`StudentT`] distribution
100100
//! - [`FisherF`] distribution
101+
//! - Triangular distribution:
102+
//! - [`Triangular`] distribution
101103
//! - Multivariate probability distributions
102104
//! - [`Dirichlet`] distribution
103105
//! - [`UnitSphereSurface`] distribution
@@ -168,6 +170,7 @@
168170
//! [`Standard`]: struct.Standard.html
169171
//! [`StandardNormal`]: struct.StandardNormal.html
170172
//! [`StudentT`]: struct.StudentT.html
173+
//! [`Triangular`]: struct.Triangular.html
171174
//! [`Uniform`]: struct.Uniform.html
172175
//! [`Uniform::new`]: struct.Uniform.html#method.new
173176
//! [`Uniform::new_inclusive`]: struct.Uniform.html#method.new_inclusive
@@ -192,6 +195,7 @@ pub use self::bernoulli::Bernoulli;
192195
#[cfg(feature="std")] pub use self::binomial::Binomial;
193196
#[cfg(feature="std")] pub use self::cauchy::Cauchy;
194197
#[cfg(feature="std")] pub use self::dirichlet::Dirichlet;
198+
#[cfg(feature="std")] pub use self::triangular::Triangular;
195199

196200
pub mod uniform;
197201
mod bernoulli;
@@ -206,6 +210,7 @@ mod bernoulli;
206210
#[cfg(feature="std")] mod binomial;
207211
#[cfg(feature="std")] mod cauchy;
208212
#[cfg(feature="std")] mod dirichlet;
213+
#[cfg(feature="std")] mod triangular;
209214

210215
mod float;
211216
mod integer;

src/distributions/triangular.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// https://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//! The triangular distribution.
11+
12+
use Rng;
13+
use distributions::{Distribution, Standard};
14+
15+
/// The triangular distribution.
16+
///
17+
/// # Example
18+
///
19+
/// ```rust
20+
/// use rand::distributions::{Triangular, Distribution};
21+
///
22+
/// let d = Triangular::new(0., 5., 2.5);
23+
/// let v = d.sample(&mut rand::thread_rng());
24+
/// println!("{} is from a triangular distribution", v);
25+
/// ```
26+
#[derive(Clone, Copy, Debug)]
27+
pub struct Triangular {
28+
min: f64,
29+
max: f64,
30+
mode: f64,
31+
}
32+
33+
impl Triangular {
34+
/// Construct a new `Triangular` with minimum `min`, maximum `max` and mode
35+
/// `mode`.
36+
///
37+
/// # Panics
38+
///
39+
/// If `max < mode`, `mode < max` or `max == min`.
40+
///
41+
#[inline]
42+
pub fn new(min: f64, max: f64, mode: f64) -> Triangular {
43+
assert!(max >= mode);
44+
assert!(mode >= min);
45+
assert!(max != min);
46+
Triangular { min, max, mode }
47+
}
48+
}
49+
50+
impl Distribution<f64> for Triangular {
51+
#[inline]
52+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
53+
let f: f64 = rng.sample(Standard);
54+
let diff_mode_min = self.mode - self.min;
55+
let diff_max_min = self.max - self.min;
56+
if f * diff_max_min < diff_mode_min {
57+
self.min + (f * diff_max_min * diff_mode_min).sqrt()
58+
} else {
59+
self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt()
60+
}
61+
}
62+
}
63+
64+
#[cfg(test)]
65+
mod test {
66+
use distributions::Distribution;
67+
use super::Triangular;
68+
69+
#[test]
70+
fn test_new() {
71+
for &(min, max, mode) in &[
72+
(-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3),
73+
(0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17),
74+
] {
75+
println!("{} {} {}", min, max, mode);
76+
let _ = Triangular::new(min, max, mode);
77+
}
78+
}
79+
80+
#[test]
81+
fn test_sample() {
82+
let norm = Triangular::new(0., 1., 0.5);
83+
let mut rng = ::test::rng(1);
84+
for _ in 0..1000 {
85+
norm.sample(&mut rng);
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)