Skip to content

Commit

Permalink
Replace the IndependentSample trait with Distribution.
Browse files Browse the repository at this point in the history
Also removed the `Sample` trait.

`IndependentSample` is really a probability distribution of values, and hence renamed to `Distribution`, but with an associated `Output` type instead of being generic over a type.  The `Sample` trait is a state-mutating version of `IndependentSample` and is really a random process.  A random process can be infinite (e.g. a random walk) or finite (e.g. drawing from a bag without replacement).  So really, a random process is best represented by an `Iterator`.  Additionally all previous implementations of `Sample` simply called through to `IndependentSample.ind_sample`, so `Sample` has simply been removed.

The related trait `SampleRange` has been renamed to `RangeDistribution`.
  • Loading branch information
GrahamDennis committed Mar 23, 2015
1 parent 0b8c3eb commit 6e30259
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 176 deletions.
24 changes: 11 additions & 13 deletions src/distributions/exponential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use std::num::Float;

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 @@ -60,10 +60,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(Copy)]
Expand All @@ -81,28 +81,26 @@ 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 for Exp {
type Output = f64;

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();
for _ in 0..1000 {
assert!(exp.sample(&mut rng) >= 0.0);
assert!(exp.ind_sample(&mut rng) >= 0.0);
}
}
#[test]
Expand All @@ -124,12 +122,12 @@ mod bench {
use self::test::Bencher;
use std::mem::size_of;
use super::Exp;
use distributions::Sample;
use distributions::Distribution;

#[bench]
fn rand_exp(b: &mut Bencher) {
let mut rng = ::test::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
108 changes: 48 additions & 60 deletions src/distributions/gamma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::num::Float;

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 @@ -40,10 +40,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 @@ -128,34 +128,30 @@ 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 Distribution for Gamma {
type Output = f64;

impl IndependentSample<f64> for Gamma {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
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 for GammaSmallShape {
type Output = f64;

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 for GammaLargeShape {
type Output = f64;

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 @@ -186,10 +182,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)
/// ```
pub struct ChiSquared {
Expand Down Expand Up @@ -217,18 +213,17 @@ 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 for ChiSquared {
type Output = f64;

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 @@ -242,10 +237,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)
/// ```
pub struct FisherF {
Expand All @@ -270,12 +265,11 @@ 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 for FisherF {
type Output = f64;

fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio
}
}

Expand All @@ -285,10 +279,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)
/// ```
pub struct StudentT {
Expand All @@ -307,46 +301,42 @@ 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 for StudentT {
type Output = f64;

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();
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_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();
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_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();
for _ in 0..1000 {
chi.sample(&mut rng);
chi.ind_sample(&mut rng);
}
}
#[test]
Expand All @@ -357,21 +347,19 @@ 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();
for _ in 0..1000 {
f.sample(&mut rng);
f.ind_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();
for _ in 0..1000 {
t.sample(&mut rng);
t.ind_sample(&mut rng);
}
}
}
Expand All @@ -381,7 +369,7 @@ mod bench {
extern crate test;
use self::test::Bencher;
use std::mem::size_of;
use distributions::IndependentSample;
use distributions::Distribution;
use super::Gamma;


Expand All @@ -392,7 +380,7 @@ mod bench {

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 @@ -405,7 +393,7 @@ mod bench {

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
Loading

0 comments on commit 6e30259

Please sign in to comment.