Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select "SimpleRand" over generic "Rand" for backwards compatibility #71

Merged
merged 5 commits into from
Dec 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 19 additions & 25 deletions src/distributions/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
//! Generic value creation

use Rng;
use distributions::{Distribution, Rand};
use distributions::uniform::{Uniform, Uniform01, codepoint};
use distributions::Distribution;
use distributions::uniform::{Uniform, Uniform01, Codepoint};

/// A generic random value distribution. Generates values using what appears to
/// be "the best" distribution for each type, but ultimately the choice is arbitrary.
Expand All @@ -21,67 +21,61 @@ use distributions::uniform::{Uniform, Uniform01, codepoint};
///
/// * [`Uniform`] for integer types
/// * [`Uniform01`] for floating point types
///
/// Makes use of the following methods:
///
/// * [`codepoint`] for `char`
/// * [`Codepoint`] for `char`
///
/// TODO: link
#[derive(Debug)]
pub struct Default;

// ----- implementations -----

impl<T: Rand<Uniform>> Distribution<T> for Default {
impl<T> Distribution<T> for Default where Uniform: Distribution<T>{
fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> T {
T::rand(rng, Uniform)
Uniform.sample(rng)
}
}

// FIXME: https://github.com/rust-lang/rust/issues/23341
// impl<T: Rand<Uniform01>> Distribution<T> for Default {
// impl<T> Distribution<T> for Default where Uniform01: Distribution<T>{
// fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> T {
// T::rand(rng, Uniform01)
// Uniform01.sample(rng)
// }
// }
// workaround above issue:
impl Distribution<f32> for Default {
fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> f32 {
f32::rand(rng, Uniform01)
Uniform01.sample(rng)
}
}
impl Distribution<f64> for Default {
fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> f64 {
f64::rand(rng, Uniform01)
Uniform01.sample(rng)
}
}

impl Distribution<char> for Default {
fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> char {
codepoint(rng)
Codepoint.sample(rng)
}
}


#[cfg(test)]
mod tests {
use {Rng, thread_rng};
use distributions::{Rand, Default};
use {Rng, Sample, thread_rng};
use distributions::{Default};

#[test]
fn test_types() {
let rng: &mut Rng = &mut thread_rng();
fn do_test<T: Rand<Default>>(rng: &mut Rng) -> T {
T::rand(rng, Default)
}

do_test::<u32>(rng);
do_test::<i8>(rng);
do_test::<f32>(rng);
do_test::<f64>(rng);
rng.sample::<u32, _>(Default);
rng.sample::<i8, _>(Default);
rng.sample::<f32, _>(Default);
rng.sample::<f64, _>(Default);
#[cfg(feature = "i128_support")]
do_test::<u128>(rng);
do_test::<char>(rng);
do_test::<bool>(rng);
rng.sample::<u128, _>(Default);
rng.sample::<char, _>(Default);
rng.sample::<bool, _>(Default);
}
}
4 changes: 2 additions & 2 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};
use distributions::{ziggurat, ziggurat_tables, Distribution, Uniform01, Rand};
use distributions::{ziggurat, ziggurat_tables, Distribution, Uniform01};

/// Generates Exp(1) random numbers.
///
Expand Down Expand Up @@ -43,7 +43,7 @@ pub fn exp1<R: Rng+?Sized>(rng: &mut R) -> f64 {
}
#[inline]
fn zero_case<R:Rng+?Sized>(rng: &mut R, _u: f64) -> f64 {
let x = f64::rand(rng, Uniform01);
let x: f64 = Uniform01.sample(rng);
ziggurat_tables::ZIG_EXP_R - x.ln()
}

Expand Down
6 changes: 3 additions & 3 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};
use distributions::normal::standard_normal;
use distributions::{Distribution, Exp, Rand, Open01};
use distributions::{Distribution, Exp, Open01};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
Expand Down Expand Up @@ -145,7 +145,7 @@ impl Distribution<f64> for Gamma {
}
impl Distribution<f64> for GammaSmallShape {
fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> f64 {
let u = f64::rand(rng, Open01);
let u: f64 = Open01.sample(rng);

self.large_shape.sample(rng) * u.powf(self.inv_shape)
}
Expand All @@ -160,7 +160,7 @@ impl Distribution<f64> for GammaLargeShape {
}

let v = v_cbrt * v_cbrt * v_cbrt;
let u = f64::rand(rng, Open01);
let u: f64 = Open01.sample(rng);

let x_sqr = x * x;
if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
Expand Down
56 changes: 13 additions & 43 deletions src/distributions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
use Rng;

pub use self::default::Default;
pub use self::uniform::{uniform, codepoint, ascii_word_char};
pub use self::uniform::{Uniform, Uniform01, Open01, Closed01, AsciiWordChar};
pub use self::uniform::{Uniform, Uniform01, Open01, Closed01, Codepoint, AsciiWordChar};
pub use self::range::Range;

#[cfg(feature="std")]
Expand Down Expand Up @@ -77,55 +76,26 @@ impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D {
}
}

/// Generic trait for sampling random values from some distribution
/// Trait for sampling values from the `Default` distribution.
///
/// TODO: quite possibly remove both this and `SimpleRand` since `Sample` is
/// more convenient and distributions like `Default` handle all the real work.
/// This is mostly a shim around `Default` for backwards compatibility; the
/// implementation is simply `Default.sample(rng)`.
///
/// # Example
/// ```rust
/// use rand::distributions::{Rand, Default, Range};
/// use rand::{Rand, thread_rng};
///
/// let mut rng = rand::thread_rng();
/// println!("Random byte: {}", u8::rand(&mut rng, Default));
/// println!("Random range: {}", i32::rand(&mut rng, Range::new(-99, 100)));
/// ```
pub trait Rand<D> {
/// Generate a random value of the given type, according to the specified
/// distribution.
///
/// The distributions `Default` (or `Uniform` and `Uniform01`) and `Range`
/// should cover most simpler usages; `Normal`, `LogNormal`, `Exp`, `Gamma`
/// and a few others are also available.
fn rand<R: Rng+?Sized>(rng: &mut R, distr: D) -> Self;
}

impl<T, D: Distribution<T>> Rand<D> for T {
fn rand<R: Rng+?Sized>(rng: &mut R, distr: D) -> Self {
distr.sample(rng)
}
}

/// Simpler version of `Rand`, without support for alternative distributions.
///
/// TODO: decide which version of `Rand` to keep. If this one, rename struct to
/// `Rand` and function to `rand`.
///
/// # Example
/// ```rust
/// use rand::distributions::SimpleRand;
///
/// let mut rng = rand::thread_rng();
/// println!("Random byte: {}", u8::simple_rand(&mut rng));
/// let mut rng = thread_rng();
/// println!("Random byte: {}", u8::rand(&mut rng));
/// ```
pub trait SimpleRand {
pub trait Rand : Sized {
/// Generate a random value of the given type, using the `Default`
/// distribution.
fn simple_rand<R: Rng+?Sized>(rng: &mut R) -> Self;
fn rand<R: Rng+?Sized>(rng: &mut R) -> Self;
}

impl<T> SimpleRand for T where Default: Distribution<T> {
fn simple_rand<R: Rng+?Sized>(rng: &mut R) -> Self {
impl<T> Rand for T where Default: Distribution<T> {
fn rand<R: Rng+?Sized>(rng: &mut R) -> Self {
Default.sample(rng)
}
}
Expand Down Expand Up @@ -165,7 +135,7 @@ fn ziggurat<R: Rng+?Sized, P, Z>(
// precision of using 64 bits for f64 does not buy us much.
// Because for some RNG's the least significant bits can be of lower
// statistical quality, we use bits 3..10 for i.
let bits: u64 = uniform(rng);
let bits: u64 = rng.sample(Uniform);

// u is either U(-1, 1) or U(0, 1) depending on if this is a
// symmetric distribution or not.
Expand All @@ -190,7 +160,7 @@ fn ziggurat<R: Rng+?Sized, P, Z>(
return zero_case(rng, u);
}
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * f64::rand(rng, Uniform01) < pdf(x) {
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.sample::<f64, _>(Uniform01) < pdf(x) {
return x;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/distributions/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! The normal and derived distributions.

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

/// Generates N(0, 1) random numbers
/// (a.k.a. a standard normal, or Gaussian).
Expand Down Expand Up @@ -50,8 +50,8 @@ pub fn standard_normal<R:Rng+?Sized>(rng: &mut R) -> f64 {
let mut y = 0.0f64;

while -2.0 * y < x * x {
let x_ = f64::rand(rng, Open01);
let y_ = f64::rand(rng, Open01);
let x_: f64 = Open01.sample(rng);
let y_: f64 = Open01.sample(rng);

x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
y = y_.ln();
Expand Down
17 changes: 8 additions & 9 deletions src/distributions/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

//! A distribution generating numbers within a given range.

use Rand;
use Rng;
use distributions::{Distribution, Uniform};
use utils::FloatConversions;
Expand Down Expand Up @@ -262,7 +261,7 @@ macro_rules! range_int_impl {
// casting is a no-op.
let zone = self.zone as $signed as $i_large as $u_large;
loop {
let v: $u_large = Rand::rand(rng, Uniform);
let v: $u_large = Uniform.sample(rng);
if $use_mult {
let (hi, lo) = v.wmul(range);
if lo <= zone {
Expand All @@ -276,7 +275,7 @@ macro_rules! range_int_impl {
}
} else {
// Sample from the entire integer range.
Rand::rand(rng, Uniform)
Uniform.sample(rng)
}
}

Expand All @@ -297,7 +296,7 @@ macro_rules! range_int_impl {
};

loop {
let v: $u_large = Rand::rand(rng, Uniform);
let v: $u_large = Uniform.sample(rng);
if $use_mult {
let (hi, lo) = v.wmul(range);
if lo <= zone {
Expand Down Expand Up @@ -553,8 +552,8 @@ range_float_impl! { f64, Rng::next_u64 }

#[cfg(test)]
mod tests {
use {Rng, thread_rng};
use distributions::{Rand, Distribution};
use {Rng, Sample, thread_rng};
use distributions::{Distribution};
use distributions::range::{Range, RangeImpl, RangeFloat, SampleRange};

#[test]
Expand Down Expand Up @@ -612,7 +611,7 @@ mod tests {
for &(low, high) in v.iter() {
let my_range = Range::new(low, high);
for _ in 0..1000 {
let v: $ty = Rand::rand(&mut rng, my_range);
let v: $ty = rng.sample(my_range);
assert!(low <= v && v < high);
}
}
Expand All @@ -638,7 +637,7 @@ mod tests {
for &(low, high) in v.iter() {
let my_range = Range::new(low, high);
for _ in 0..1000 {
let v: $ty = Rand::rand(&mut rng, my_range);
let v: $ty = rng.sample(my_range);
assert!(low <= v && v < high);
}
}
Expand Down Expand Up @@ -681,7 +680,7 @@ mod tests {
let range = Range::new(low, high);
let mut rng = ::test::rng();
for _ in 0..100 {
let x = MyF32::rand(&mut rng, range);
let x: MyF32 = rng.sample(range);
assert!(low <= x && x < high);
}
}
Expand Down
Loading