diff --git a/benches/distributions/exponential.rs b/benches/distributions/exponential.rs index f9b6dcb6bbf..20ecd245769 100644 --- a/benches/distributions/exponential.rs +++ b/benches/distributions/exponential.rs @@ -2,7 +2,7 @@ use std::mem::size_of; use test::Bencher; use rand; use rand::dist::exponential::Exp; -use rand::dist::Sample; +use rand::dist::Distribution; #[bench] fn rand_exp(b: &mut Bencher) { diff --git a/benches/distributions/gamma.rs b/benches/distributions/gamma.rs index 19b63795115..6b122a21ddf 100644 --- a/benches/distributions/gamma.rs +++ b/benches/distributions/gamma.rs @@ -1,7 +1,7 @@ use std::mem::size_of; use test::Bencher; use rand; -use rand::dist::Sample; +use rand::dist::Distribution; use rand::dist::gamma::Gamma; #[bench] diff --git a/benches/distributions/normal.rs b/benches/distributions/normal.rs index 7c53c8f85ac..e602124ce8c 100644 --- a/benches/distributions/normal.rs +++ b/benches/distributions/normal.rs @@ -1,7 +1,7 @@ use std::mem::size_of; use test::Bencher; use rand; -use rand::dist::Sample; +use rand::dist::Distribution; use rand::dist::normal::Normal; #[bench] diff --git a/src/dist/exponential.rs b/src/dist/exponential.rs index 06eac82313e..ea3320fc797 100644 --- a/src/dist/exponential.rs +++ b/src/dist/exponential.rs @@ -11,7 +11,7 @@ //! The exponential distribution. use {Rng}; -use dist::{ziggurat, ziggurat_tables, Sample, uniform01}; +use dist::{ziggurat, ziggurat_tables, Distribution, uniform01}; /// Generates Exp(1) random numbers. /// @@ -60,7 +60,7 @@ pub fn exp1(rng: &mut R) -> f64 { /// # Example /// /// ```rust -/// use rand::dist::{Exp, Sample}; +/// use rand::dist::{Exp, Distribution}; /// /// let exp = Exp::new(2.0); /// let v = exp.sample(&mut rand::thread_rng()); @@ -82,7 +82,7 @@ impl Exp { } } -impl Sample for Exp { +impl Distribution for Exp { fn sample(&self, rng: &mut R) -> f64 { exp1(rng) * self.lambda_inverse } @@ -90,7 +90,7 @@ impl Sample for Exp { #[cfg(test)] mod test { - use dist::{Sample}; + use dist::{Distribution}; use super::Exp; #[test] diff --git a/src/dist/gamma.rs b/src/dist/gamma.rs index a98591a71d5..1d76be8ae1a 100644 --- a/src/dist/gamma.rs +++ b/src/dist/gamma.rs @@ -17,7 +17,7 @@ use self::ChiSquaredRepr::*; use {Rng}; use dist::normal::standard_normal; -use dist::{Sample, Exp, open01}; +use dist::{Distribution, Exp, open01}; /// The Gamma distribution `Gamma(shape, scale)` distribution. /// @@ -38,7 +38,7 @@ use dist::{Sample, Exp, open01}; /// # Example /// /// ```rust -/// use rand::dist::{Sample, Gamma}; +/// use rand::dist::{Distribution, Gamma}; /// /// let gamma = Gamma::new(2.0, 5.0); /// let v = gamma.sample(&mut rand::thread_rng()); @@ -134,7 +134,7 @@ impl GammaLargeShape { } -impl Sample for Gamma { +impl Distribution for Gamma { fn sample(&self, rng: &mut R) -> f64 { match self.repr { Small(ref g) => g.sample(rng), @@ -143,14 +143,14 @@ impl Sample for Gamma { } } } -impl Sample for GammaSmallShape { +impl Distribution for GammaSmallShape { fn sample(&self, rng: &mut R) -> f64 { let u: f64 = open01(rng); self.large_shape.sample(rng) * u.powf(self.inv_shape) } } -impl Sample for GammaLargeShape { +impl Distribution for GammaLargeShape { fn sample(&self, rng: &mut R) -> f64 { loop { let x = standard_normal(rng); @@ -182,7 +182,7 @@ impl Sample for GammaLargeShape { /// # Example /// /// ```rust -/// use rand::dist::{ChiSquared, Sample}; +/// use rand::dist::{ChiSquared, Distribution}; /// /// let chi = ChiSquared::new(11.0); /// let v = chi.sample(&mut rand::thread_rng()); @@ -215,7 +215,7 @@ impl ChiSquared { ChiSquared { repr: repr } } } -impl Sample for ChiSquared { +impl Distribution for ChiSquared { fn sample(&self, rng: &mut R) -> f64 { match self.repr { DoFExactlyOne => { @@ -237,7 +237,7 @@ impl Sample for ChiSquared { /// # Example /// /// ```rust -/// use rand::dist::{FisherF, Sample}; +/// use rand::dist::{FisherF, Distribution}; /// /// let f = FisherF::new(2.0, 32.0); /// let v = f.sample(&mut rand::thread_rng()); @@ -266,7 +266,7 @@ impl FisherF { } } } -impl Sample for FisherF { +impl Distribution for FisherF { fn sample(&self, rng: &mut R) -> f64 { self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio } @@ -278,7 +278,7 @@ impl Sample for FisherF { /// # Example /// /// ```rust -/// use rand::dist::{StudentT, Sample}; +/// use rand::dist::{StudentT, Distribution}; /// /// let t = StudentT::new(11.0); /// let v = t.sample(&mut rand::thread_rng()); @@ -301,7 +301,7 @@ impl StudentT { } } } -impl Sample for StudentT { +impl Distribution for StudentT { fn sample(&self, rng: &mut R) -> f64 { let norm = standard_normal(rng); norm * (self.dof / self.chi.sample(rng)).sqrt() @@ -310,7 +310,7 @@ impl Sample for StudentT { #[cfg(test)] mod test { - use dist::{Sample}; + use dist::{Distribution}; use super::{ChiSquared, StudentT, FisherF}; #[test] diff --git a/src/dist/mod.rs b/src/dist/mod.rs index beed17e1fe0..f3a36838528 100644 --- a/src/dist/mod.rs +++ b/src/dist/mod.rs @@ -12,7 +12,7 @@ //! //! A distribution may have internal state describing the distribution of //! generated values; for example `Range` needs to know its upper and lower -//! bounds. Distributions use the `Sample` trait to yield values: call +//! bounds. Distributions use the `Distribution` trait to yield values: call //! `dist.sample(&mut rng)` to get a random variable. //! //! TODO: is it worth exposing both submodules and re-exporting their members? @@ -33,7 +33,7 @@ pub mod exponential; pub mod weighted; /// Types (distributions) that can be used to create a random instance of `T`. -pub trait Sample { +pub trait Distribution { /// Generate a random value of `T`, using `rng` as the /// source of randomness. fn sample(&self, rng: &mut R) -> T; diff --git a/src/dist/normal.rs b/src/dist/normal.rs index 2e21ad47c79..386edca869c 100644 --- a/src/dist/normal.rs +++ b/src/dist/normal.rs @@ -11,7 +11,7 @@ //! The normal and derived distributions. use {Rng}; -use dist::{ziggurat, ziggurat_tables, Sample, open01}; +use dist::{ziggurat, ziggurat_tables, Distribution, open01}; /// Generates N(0, 1) random numbers /// (a.k.a. a standard normal, or Gaussian). @@ -76,7 +76,7 @@ pub fn standard_normal(rng: &mut R) -> f64 { /// # Example /// /// ```rust -/// use rand::dist::{Normal, Sample}; +/// use rand::dist::{Normal, Distribution}; /// /// // mean 2, standard deviation 3 /// let normal = Normal::new(2.0, 3.0); @@ -105,7 +105,7 @@ impl Normal { } } } -impl Sample for Normal { +impl Distribution for Normal { fn sample(&self, rng: &mut R) -> f64 { self.mean + self.std_dev * standard_normal(rng) } @@ -120,7 +120,7 @@ impl Sample for Normal { /// # Example /// /// ```rust -/// use rand::dist::{LogNormal, Sample}; +/// use rand::dist::{LogNormal, Distribution}; /// /// // mean 2, standard deviation 3 /// let log_normal = LogNormal::new(2.0, 3.0); @@ -145,7 +145,7 @@ impl LogNormal { LogNormal { norm: Normal::new(mean, std_dev) } } } -impl Sample for LogNormal { +impl Distribution for LogNormal { fn sample(&self, rng: &mut R) -> f64 { self.norm.sample(rng).exp() } @@ -153,7 +153,7 @@ impl Sample for LogNormal { #[cfg(test)] mod tests { - use dist::{Sample}; + use dist::{Distribution}; use super::{Normal, LogNormal}; #[test] diff --git a/src/dist/range.rs b/src/dist/range.rs index e80f5f317b2..cf00f7adeab 100644 --- a/src/dist/range.rs +++ b/src/dist/range.rs @@ -15,7 +15,7 @@ use std::num::Wrapping as w; use Rng; -use dist::{Sample, uniform01}; +use dist::{Distribution, uniform01}; /// Sample values uniformly between two bounds. /// @@ -34,7 +34,7 @@ use dist::{Sample, uniform01}; /// # Example /// /// ```rust -/// use rand::dist::{Sample, Range}; +/// use rand::dist::{Distribution, Range}; /// /// fn main() { /// let between = Range::new(10, 10000); @@ -62,7 +62,7 @@ impl Range { } } -impl Sample for Range { +impl Distribution for Range { fn sample(&self, rng: &mut R) -> T { SampleRange::sample_range(self, rng) } @@ -162,7 +162,7 @@ float_impl! { f64 } #[cfg(test)] mod tests { - use dist::{Sample}; + use dist::{Distribution}; use super::Range as Range; #[should_panic] diff --git a/src/dist/uniform.rs b/src/dist/uniform.rs index 80b88466b62..51d0c01f90f 100644 --- a/src/dist/uniform.rs +++ b/src/dist/uniform.rs @@ -11,11 +11,12 @@ //! Generating uniformly distributed numbers use std::char; +use std::fmt; use std::mem; use std::marker::PhantomData; use Rng; -use dist::Sample; +use dist::Distribution; // ----- convenience functions ----- @@ -71,13 +72,13 @@ pub fn codepoint(rng: &mut R) -> char { } -// ----- Sample implementations ----- +// ----- Distribution implementations ----- // TODO: do we want these? If so, implement for other ranges. /// Sample values uniformly over the whole range supported by the type. /// /// No internal state. -#[derive(Clone, Copy, Debug, Default)] +#[derive(Default)] pub struct Uniform { _marker: PhantomData, } @@ -92,7 +93,23 @@ impl Uniform { } } -impl Sample for Uniform { +impl Copy for Uniform {} + +// derive only auto-impls for types T: Clone, but we don't have that restriction +impl Clone for Uniform { + fn clone(&self) -> Self { + Uniform::new() + } +} + +// derive only auto-impls for types T: Debug, but we don't have that restriction +impl fmt::Debug for Uniform { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "Uniform {{}}") + } +} + +impl Distribution for Uniform { fn sample(&self, rng: &mut R) -> T { T::sample_uniform(rng) } @@ -267,7 +284,7 @@ float_impls! { SCALE_F32, f32, 24, next_f32 } #[cfg(test)] mod tests { use {Rng, thread_rng}; - use dist::{uniform, Sample}; + use dist::{uniform, Distribution}; use dist::uniform::{SampleUniform, Uniform}; use dist::{uniform01, open01, closed01}; diff --git a/src/dist/weighted.rs b/src/dist/weighted.rs index 9d9c43b9c20..f4c05eece98 100644 --- a/src/dist/weighted.rs +++ b/src/dist/weighted.rs @@ -14,7 +14,7 @@ //! adapted, or removed entirely. use Rng; -use dist::{Range, Sample}; +use dist::{Range, Distribution}; /// A value with a particular weight for use with `WeightedChoice`. #[derive(Copy, Clone, Debug)] @@ -30,41 +30,36 @@ pub struct Weighted { /// Each item has an associated weight that influences how likely it /// is to be chosen: higher weight is more likely. /// -/// The `Clone` restriction is a limitation of the `Sample` trait. -/// Note that `&T` is (cheaply) `Clone` for -/// all `T`, as is `u32`, so one can store references or indices into -/// another vector. -/// /// # Example /// /// ```rust -/// use rand::dist::Sample; +/// use rand::dist::Distribution; /// use rand::dist::weighted::{Weighted, WeightedChoice}; /// -/// let mut items = vec!(Weighted { weight: 2, item: 'a' }, +/// let items = vec!(Weighted { weight: 2, item: 'a' }, /// Weighted { weight: 4, item: 'b' }, /// Weighted { weight: 1, item: 'c' }); -/// let wc = WeightedChoice::new(&mut items); +/// let wc = WeightedChoice::new(items); /// let mut rng = rand::thread_rng(); /// for _ in 0..16 { /// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. /// println!("{}", wc.sample(&mut rng)); /// } /// ``` -#[derive(Debug)] -pub struct WeightedChoice<'a, T:'a> { - items: &'a mut [Weighted], +#[derive(Clone, Debug)] +pub struct WeightedChoice { + items: Vec>, weight_range: Range } -impl<'a, T: Clone> WeightedChoice<'a, T> { +impl WeightedChoice { /// Create a new `WeightedChoice`. /// /// Panics if: /// - `v` is empty /// - the total weight is 0 /// - the total weight is larger than a `u32` can contain. - pub fn new(items: &'a mut [Weighted]) -> WeightedChoice<'a, T> { + pub fn new(mut items: Vec>) -> WeightedChoice { // strictly speaking, this is subsumed by the total weight == 0 case assert!(!items.is_empty(), "WeightedChoice::new called with no items"); @@ -73,7 +68,7 @@ impl<'a, T: Clone> WeightedChoice<'a, T> { // we convert the list from individual weights to cumulative // weights so we can binary search. This *could* drop elements // with weight == 0 as an optimisation. - for item in items.iter_mut() { + for ref mut item in items.iter_mut() { running_total = match running_total.checked_add(item.weight) { Some(n) => n, None => panic!("WeightedChoice::new called with a total weight \ @@ -93,7 +88,7 @@ impl<'a, T: Clone> WeightedChoice<'a, T> { } } -impl<'a, T: Clone> Sample for WeightedChoice<'a, T> { +impl Distribution for WeightedChoice { fn sample(&self, rng: &mut R) -> T { // we want to find the first element that has cumulative // weight > sample_weight, which we do by binary since the @@ -139,7 +134,7 @@ impl<'a, T: Clone> Sample for WeightedChoice<'a, T> { #[cfg(test)] mod tests { use Rng; - use dist::Sample; + use dist::Distribution; use super::{WeightedChoice, Weighted}; #[derive(PartialEq, Debug)] @@ -166,8 +161,8 @@ mod tests { macro_rules! t { ($items:expr, $expected:expr) => {{ - let mut items = $items; - let wc = WeightedChoice::new(&mut items); + let items = $items; + let wc = WeightedChoice::new(items); let expected = $expected; let mut rng = CountingRng { i: 0 }; @@ -238,17 +233,17 @@ mod tests { #[test] #[should_panic] fn test_weighted_choice_no_items() { - WeightedChoice::::new(&mut []); + WeightedChoice::::new(vec![]); } #[test] #[should_panic] fn test_weighted_choice_zero_weight() { - WeightedChoice::new(&mut [Weighted { weight: 0, item: 0}, + WeightedChoice::new(vec![Weighted { weight: 0, item: 0}, Weighted { weight: 0, item: 1}]); } #[test] #[should_panic] fn test_weighted_choice_weight_overflows() { let x = ::std::u32::MAX / 2; // x + x + 2 is the overflow - WeightedChoice::new(&mut [Weighted { weight: x, item: 0 }, + WeightedChoice::new(vec![Weighted { weight: x, item: 0 }, Weighted { weight: 1, item: 1 }, Weighted { weight: x, item: 2 }, Weighted { weight: 1, item: 3 }]); diff --git a/src/lib.rs b/src/lib.rs index 65b2f7a6672..ba4227628f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,7 +112,7 @@ //! and multiply this fraction by 4. //! //! ``` -//! use rand::dist::{Sample, Range}; +//! use rand::dist::{Distribution, Range}; //! //! fn main() { //! let between = Range::new(-1f64, 1.); @@ -155,7 +155,7 @@ //! //! ``` //! use rand::Rng; -//! use rand::dist::{Sample, Range, uniform}; +//! use rand::dist::{Distribution, Range, uniform}; //! //! struct SimulationResult { //! win: bool, @@ -256,7 +256,7 @@ use std::rc::Rc; pub use read::ReadRng; pub use os::OsRng; -use dist::{Range, Sample}; +use dist::{Range, Distribution}; use dist::range::SampleRange; use prng::IsaacWordRng;