From 2af10fa047dae02907aeb93bd16fbdc4c4318b12 Mon Sep 17 00:00:00 2001 From: zroug <37004975+zroug@users.noreply.github.com> Date: Sat, 23 Feb 2019 13:25:30 +0100 Subject: [PATCH] Added documentation for AliasMethodWeightedIndex --- src/distributions/weighted.rs | 70 +++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/src/distributions/weighted.rs b/src/distributions/weighted.rs index 520c1fd1a97..0a09c698f9c 100644 --- a/src/distributions/weighted.rs +++ b/src/distributions/weighted.rs @@ -132,7 +132,54 @@ impl Distribution for WeightedIndex where } } -#[allow(missing_docs)] // todo: add docs +/// A distribution using weighted sampling to pick a discretely selected item. +/// +/// Sampling an [`AliasMethodWeightedIndex`] distribution returns the index +/// of a randomly selected element from the vector used to create the +/// [`AliasMethodWeightedIndex`]. The chance of a given element being picked +/// is proportional to the value of the element. The weights can have any type +/// `W` for which an implementation of [`AliasMethodWeight`] exists. +/// +/// # Performance +/// +/// Given that `n` is the number of items in the vector used to create an +/// [`AliasMethodWeightedIndex`], [`AliasMethodWeightedIndex`] will take +/// up `O(n)` amount of memory. More specifically it takes up some constant +/// amount of memory plus the vector used to create it and a [`Vec`] with +/// capacity `n`. +/// +/// Time complexity for the creation of an [`AliasMethodWeightedIndex`] is +/// `O(n)`. Sampling is `O(1)`, it makes a call to [`Uniform::sample`] +/// and a call to [`Uniform::sample`]. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::AliasMethodWeightedIndex; +/// use rand::prelude::*; +/// +/// let choices = vec!['a', 'b', 'c']; +/// let weights = vec![2, 1, 1]; +/// let dist = AliasMethodWeightedIndex::new(weights).unwrap(); +/// let mut rng = thread_rng(); +/// for _ in 0..100 { +/// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c' +/// println!("{}", choices[dist.sample(&mut rng)]); +/// } +/// +/// let items = [('a', 0), ('b', 3), ('c', 7)]; +/// let dist2 = AliasMethodWeightedIndex::new(items.iter().map(|item| item.1).collect()).unwrap(); +/// for _ in 0..100 { +/// // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c' +/// println!("{}", items[dist2.sample(&mut rng)].0); +/// } +/// ``` +/// +/// [`AliasMethodWeightedIndex`]: AliasMethodWeightedIndex +/// [`AliasMethodWeight`]: AliasMethodWeight +/// [`Vec`]: Vec +/// [`Uniform::sample`]: Distribution::sample +/// [`Uniform::sample`]: Distribution::sample pub struct AliasMethodWeightedIndex { aliases: Vec, no_alias_odds: Vec, @@ -141,7 +188,13 @@ pub struct AliasMethodWeightedIndex { } impl AliasMethodWeightedIndex { - #[allow(missing_docs)] // todo: add docs + /// Creates an new [`AliasMethodWeightedIndex`]. + /// + /// Returns an error if: + /// - The vector is empty. + /// - For any weight `w`: `w < 0` or `w > max` where `max = W::MAX / + /// weights.len()`. + /// - The sum of weights is zero. pub fn new(weights: Vec) -> Result { let n = weights.len(); if n == 0 { @@ -338,6 +391,10 @@ fn pairwise_sum(values: &[T]) -> T { } } +/// Trait that must be implemented for weights, that are used with +/// [`AliasMethodWeightedIndex`]. Currently no guarantees on the correctness of +/// [`AliasMethodWeightedIndex`] are given for custom implementations of this +/// trait. pub trait AliasMethodWeight: Sized + Copy @@ -353,9 +410,13 @@ pub trait AliasMethodWeight: + DivAssign + Sum { + /// Maximum number representable by `Self`. const MAX: Self; + + /// Element of `Self` equivalent to 0. const ZERO: Self; + /// Converts an [`usize`] to a `Self`, rounding if necessary. fn try_from_usize_lossy(n: usize) -> Option; } @@ -629,11 +690,14 @@ impl fmt::Display for WeightedError { } } -#[allow(missing_docs)] // todo: add docs +/// Error type returned from [`AliasMethodWeightedIndex::new`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AliasMethodWeightedIndexError { + /// The weight vector is empty. NoItem, + /// A weight is either less than zero or greater than the supported maximum. InvalidWeight, + /// All weights in the provided vector are zero. AllWeightsZero, }