// Copyright 2018 Developers of the Rand project. // Copyright 2013-2017 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Distribution trait and associates use crate::Rng; use core::iter; #[cfg(feature = "alloc")] use alloc::string::String; /// Types (distributions) that can be used to create a random instance of `T`. /// /// It is possible to sample from a distribution through both the /// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and /// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which /// produces an iterator that samples from the distribution. /// /// All implementations are expected to be immutable; this has the significant /// advantage of not needing to consider thread safety, and for most /// distributions efficient state-less sampling algorithms are available. /// /// Implementations are typically expected to be portable with reproducible /// results when used with a PRNG with fixed seed; see the /// [portability chapter](https://rust-random.github.io/book/portability.html) /// of The Rust Rand Book. In some cases this does not apply, e.g. the `usize` /// type requires different sampling on 32-bit and 64-bit machines. /// /// [`sample_iter`]: Distribution::sample_iter pub trait Distribution { /// Generate a random value of `T`, using `rng` as the source of randomness. fn sample(&self, rng: &mut R) -> T; /// Create an iterator that generates random values of `T`, using `rng` as /// the source of randomness. /// /// Note that this function takes `self` by value. This works since /// `Distribution` is impl'd for `&D` where `D: Distribution`, /// however borrowing is not automatic hence `distr.sample_iter(...)` may /// need to be replaced with `(&distr).sample_iter(...)` to borrow or /// `(&*distr).sample_iter(...)` to reborrow an existing reference. /// /// # Example /// /// ``` /// use rand::thread_rng; /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard}; /// /// let mut rng = thread_rng(); /// /// // Vec of 16 x f32: /// let v: Vec = Standard.sample_iter(&mut rng).take(16).collect(); /// /// // String: /// let s: String = Alphanumeric /// .sample_iter(&mut rng) /// .take(7) /// .map(char::from) /// .collect(); /// /// // Dice-rolling: /// let die_range = Uniform::new_inclusive(1, 6); /// let mut roll_die = die_range.sample_iter(&mut rng); /// while roll_die.next().unwrap() != 6 { /// println!("Not a 6; rolling again!"); /// } /// ``` fn sample_iter(self, rng: R) -> DistIter where R: Rng, Self: Sized, { DistIter { distr: self, rng, phantom: ::core::marker::PhantomData, } } /// Create a distribution of values of 'S' by mapping the output of `Self` /// through the closure `F` /// /// # Example /// /// ``` /// use rand::thread_rng; /// use rand::distributions::{Distribution, Uniform}; /// /// let mut rng = thread_rng(); /// /// let die = Uniform::new_inclusive(1, 6); /// let even_number = die.map(|num| num % 2 == 0); /// while !even_number.sample(&mut rng) { /// println!("Still odd; rolling again!"); /// } /// ``` fn map(self, func: F) -> DistMap where F: Fn(T) -> S, Self: Sized, { DistMap { distr: self, func, phantom: ::core::marker::PhantomData, } } } impl<'a, T, D: Distribution> Distribution for &'a D { fn sample(&self, rng: &mut R) -> T { (*self).sample(rng) } } /// An iterator that generates random values of `T` with distribution `D`, /// using `R` as the source of randomness. /// /// This `struct` is created by the [`sample_iter`] method on [`Distribution`]. /// See its documentation for more. /// /// [`sample_iter`]: Distribution::sample_iter #[derive(Debug)] pub struct DistIter { distr: D, rng: R, phantom: ::core::marker::PhantomData, } impl Iterator for DistIter where D: Distribution, R: Rng, { type Item = T; #[inline(always)] fn next(&mut self) -> Option { // Here, self.rng may be a reference, but we must take &mut anyway. // Even if sample could take an R: Rng by value, we would need to do this // since Rng is not copyable and we cannot enforce that this is "reborrowable". Some(self.distr.sample(&mut self.rng)) } fn size_hint(&self) -> (usize, Option) { (usize::max_value(), None) } } impl iter::FusedIterator for DistIter where D: Distribution, R: Rng, { } #[cfg(features = "nightly")] impl iter::TrustedLen for DistIter where D: Distribution, R: Rng, { } /// A distribution of values of type `S` derived from the distribution `D` /// by mapping its output of type `T` through the closure `F`. /// /// This `struct` is created by the [`Distribution::map`] method. /// See its documentation for more. #[derive(Debug)] pub struct DistMap { distr: D, func: F, phantom: ::core::marker::PhantomData S>, } impl Distribution for DistMap where D: Distribution, F: Fn(T) -> S, { fn sample(&self, rng: &mut R) -> S { (self.func)(self.distr.sample(rng)) } } /// `String` sampler /// /// Sampling a `String` of random characters is not quite the same as collecting /// a sequence of chars. This trait contains some helpers. #[cfg(feature = "alloc")] pub trait DistString { /// Append `len` random chars to `string` fn append_string(&self, rng: &mut R, string: &mut String, len: usize); /// Generate a `String` of `len` random chars #[inline] fn sample_string(&self, rng: &mut R, len: usize) -> String { let mut s = String::new(); self.append_string(rng, &mut s, len); s } } #[cfg(test)] mod tests { use crate::distributions::{Distribution, Uniform}; use crate::Rng; #[test] fn test_distributions_iter() { use crate::distributions::Open01; let mut rng = crate::test::rng(210); let distr = Open01; let mut iter = Distribution::::sample_iter(distr, &mut rng); let mut sum: f32 = 0.; for _ in 0..100 { sum += iter.next().unwrap(); } assert!(0. < sum && sum < 100.); } #[test] fn test_distributions_map() { let dist = Uniform::new_inclusive(0, 5).map(|val| val + 15); let mut rng = crate::test::rng(212); let val = dist.sample(&mut rng); assert!((15..=20).contains(&val)); } #[test] fn test_make_an_iter() { fn ten_dice_rolls_other_than_five( rng: &mut R, ) -> impl Iterator + '_ { Uniform::new_inclusive(1, 6) .sample_iter(rng) .filter(|x| *x != 5) .take(10) } let mut rng = crate::test::rng(211); let mut count = 0; for val in ten_dice_rolls_other_than_five(&mut rng) { assert!((1..=6).contains(&val) && val != 5); count += 1; } assert_eq!(count, 10); } #[test] #[cfg(feature = "alloc")] fn test_dist_string() { use core::str; use crate::distributions::{Alphanumeric, DistString, Standard}; let mut rng = crate::test::rng(213); let s1 = Alphanumeric.sample_string(&mut rng, 20); assert_eq!(s1.len(), 20); assert_eq!(str::from_utf8(s1.as_bytes()), Ok(s1.as_str())); let s2 = Standard.sample_string(&mut rng, 20); assert_eq!(s2.chars().count(), 20); assert_eq!(str::from_utf8(s2.as_bytes()), Ok(s2.as_str())); } }