Skip to content

Commit

Permalink
Replace Sample and IndependentSample with Distribution
Browse files Browse the repository at this point in the history
This is heavily inspired by #27 by @GrahamDennis but simpler trait and
maintains backwards compatibility with deprecations.
  • Loading branch information
dhardy committed Feb 8, 2018
1 parent c1c29f7 commit 09f46e2
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 150 deletions.
4 changes: 2 additions & 2 deletions benches/distributions/exponential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use std::mem::size_of;
use test::Bencher;
use rand;
use rand::distributions::exponential::Exp;
use rand::distributions::Sample;
use rand::distributions::Distribution;

#[bench]
fn rand_exp(b: &mut Bencher) {
let mut rng = rand::weak_rng();
let mut exp = Exp::new(2.71828 * 3.14159);
let exp = Exp::new(2.71828 * 3.14159);

b.iter(|| {
for _ in 0..::RAND_BENCH_N {
Expand Down
6 changes: 3 additions & 3 deletions benches/distributions/gamma.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::mem::size_of;
use test::Bencher;
use rand;
use rand::distributions::IndependentSample;
use rand::distributions::Distribution;
use rand::distributions::gamma::Gamma;

#[bench]
Expand All @@ -11,7 +11,7 @@ fn bench_gamma_large_shape(b: &mut Bencher) {

b.iter(|| {
for _ in 0..::RAND_BENCH_N {
gamma.ind_sample(&mut rng);
gamma.sample(&mut rng);
}
});
b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
Expand All @@ -24,7 +24,7 @@ fn bench_gamma_small_shape(b: &mut Bencher) {

b.iter(|| {
for _ in 0..::RAND_BENCH_N {
gamma.ind_sample(&mut rng);
gamma.sample(&mut rng);
}
});
b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
Expand Down
4 changes: 2 additions & 2 deletions benches/distributions/normal.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::mem::size_of;
use test::Bencher;
use rand;
use rand::distributions::Sample;
use rand::distributions::Distribution;
use rand::distributions::normal::Normal;

#[bench]
fn rand_normal(b: &mut Bencher) {
let mut rng = rand::weak_rng();
let mut normal = Normal::new(-2.71828, 3.14159);
let normal = Normal::new(-2.71828, 3.14159);

b.iter(|| {
for _ in 0..::RAND_BENCH_N {
Expand Down
19 changes: 8 additions & 11 deletions src/distributions/exponential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! The exponential distribution.

use {Rng, Rand};
use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
use distributions::{ziggurat, ziggurat_tables, Distribution};

/// A wrapper around an `f64` to generate Exp(1) random numbers.
///
Expand Down Expand Up @@ -65,10 +65,10 @@ impl Rand for Exp1 {
/// # Example
///
/// ```rust
/// use rand::distributions::{Exp, IndependentSample};
/// use rand::distributions::{Exp, Distribution};
///
/// let exp = Exp::new(2.0);
/// let v = exp.ind_sample(&mut rand::thread_rng());
/// let v = exp.sample(&mut rand::thread_rng());
/// println!("{} is from a Exp(2) distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
Expand All @@ -87,28 +87,25 @@ impl Exp {
}
}

impl Sample<f64> for Exp {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Exp {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
impl Distribution<f64> for Exp {
fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
let Exp1(n) = rng.gen::<Exp1>();
n * self.lambda_inverse
}
}

#[cfg(test)]
mod test {
use distributions::{Sample, IndependentSample};
use distributions::Distribution;
use super::Exp;

#[test]
fn test_exp() {
let mut exp = Exp::new(10.0);
let exp = Exp::new(10.0);
let mut rng = ::test::rng(221);
for _ in 0..1000 {
assert!(exp.sample(&mut rng) >= 0.0);
assert!(exp.ind_sample(&mut rng) >= 0.0);
assert!(exp.sample(&mut rng) >= 0.0);
}
}
#[test]
Expand Down
97 changes: 39 additions & 58 deletions src/distributions/gamma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use self::ChiSquaredRepr::*;

use {Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};
use super::{Distribution, Exp};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
Expand All @@ -38,10 +38,10 @@ use super::{IndependentSample, Sample, Exp};
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Gamma};
/// use rand::distributions::{Distribution, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::thread_rng());
/// let v = gamma.sample(&mut rand::thread_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
Expand Down Expand Up @@ -133,34 +133,24 @@ impl GammaLargeShape {
}
}

impl Sample<f64> for Gamma {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}

impl IndependentSample<f64> for Gamma {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
impl Distribution<f64> for Gamma {
fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
match self.repr {
Small(ref g) => g.ind_sample(rng),
One(ref g) => g.ind_sample(rng),
Large(ref g) => g.ind_sample(rng),
Small(ref g) => g.sample(rng),
One(ref g) => g.sample(rng),
Large(ref g) => g.sample(rng),
}
}
}
impl IndependentSample<f64> for GammaSmallShape {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
impl Distribution<f64> for GammaSmallShape {
fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
let Open01(u) = rng.gen::<Open01<f64>>();

self.large_shape.ind_sample(rng) * u.powf(self.inv_shape)
self.large_shape.sample(rng) * u.powf(self.inv_shape)
}
}
impl IndependentSample<f64> for GammaLargeShape {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
impl Distribution<f64> for GammaLargeShape {
fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
loop {
let StandardNormal(x) = rng.gen::<StandardNormal>();
let v_cbrt = 1.0 + self.c * x;
Expand Down Expand Up @@ -191,10 +181,10 @@ impl IndependentSample<f64> for GammaLargeShape {
/// # Example
///
/// ```rust
/// use rand::distributions::{ChiSquared, IndependentSample};
/// use rand::distributions::{ChiSquared, Distribution};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::thread_rng());
/// let v = chi.sample(&mut rand::thread_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -224,18 +214,15 @@ impl ChiSquared {
ChiSquared { repr: repr }
}
}
impl Sample<f64> for ChiSquared {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
impl Distribution<f64> for ChiSquared {
fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
match self.repr {
DoFExactlyOne => {
// k == 1 => N(0,1)^2
let StandardNormal(norm) = rng.gen::<StandardNormal>();
norm * norm
}
DoFAnythingElse(ref g) => g.ind_sample(rng)
DoFAnythingElse(ref g) => g.sample(rng)
}
}
}
Expand All @@ -249,10 +236,10 @@ impl IndependentSample<f64> for ChiSquared {
/// # Example
///
/// ```rust
/// use rand::distributions::{FisherF, IndependentSample};
/// use rand::distributions::{FisherF, Distribution};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::thread_rng());
/// let v = f.sample(&mut rand::thread_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
Expand All @@ -278,12 +265,9 @@ impl FisherF {
}
}
}
impl Sample<f64> for FisherF {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
impl Distribution<f64> for FisherF {
fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio
}
}

Expand All @@ -293,10 +277,10 @@ impl IndependentSample<f64> for FisherF {
/// # Example
///
/// ```rust
/// use rand::distributions::{StudentT, IndependentSample};
/// use rand::distributions::{StudentT, Distribution};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::thread_rng());
/// let v = t.sample(&mut rand::thread_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
Expand All @@ -316,46 +300,43 @@ impl StudentT {
}
}
}
impl Sample<f64> for StudentT {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
impl Distribution<f64> for StudentT {
fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
let StandardNormal(norm) = rng.gen::<StandardNormal>();
norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
norm * (self.dof / self.chi.sample(rng)).sqrt()
}
}

#[cfg(test)]
mod test {
use distributions::{Sample, IndependentSample};
use distributions::Distribution;
use super::{ChiSquared, StudentT, FisherF};

#[test]
fn test_chi_squared_one() {
let mut chi = ChiSquared::new(1.0);
let chi = ChiSquared::new(1.0);
let mut rng = ::test::rng(201);
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_sample(&mut rng);
chi.sample(&mut rng);
}
}
#[test]
fn test_chi_squared_small() {
let mut chi = ChiSquared::new(0.5);
let chi = ChiSquared::new(0.5);
let mut rng = ::test::rng(202);
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_sample(&mut rng);
chi.sample(&mut rng);
}
}
#[test]
fn test_chi_squared_large() {
let mut chi = ChiSquared::new(30.0);
let chi = ChiSquared::new(30.0);
let mut rng = ::test::rng(203);
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_sample(&mut rng);
chi.sample(&mut rng);
}
}
#[test]
Expand All @@ -366,21 +347,21 @@ mod test {

#[test]
fn test_f() {
let mut f = FisherF::new(2.0, 32.0);
let f = FisherF::new(2.0, 32.0);
let mut rng = ::test::rng(204);
for _ in 0..1000 {
f.sample(&mut rng);
f.ind_sample(&mut rng);
f.sample(&mut rng);
}
}

#[test]
fn test_t() {
let mut t = StudentT::new(11.0);
let t = StudentT::new(11.0);
let mut rng = ::test::rng(205);
for _ in 0..1000 {
t.sample(&mut rng);
t.ind_sample(&mut rng);
t.sample(&mut rng);
}
}
}
Loading

0 comments on commit 09f46e2

Please sign in to comment.