1extern crate num_traits;
5extern crate rand;
6
7use std::fmt;
8use std::iter::{FromIterator, Sum};
9use std::vec::Vec;
10
11use num_traits::{Float, NumCast, One, Zero};
12
13use rand::Rng;
14use rand::distributions::range::{Range, SampleRange};
15use rand::distributions::IndependentSample;
16
17
18#[derive(Debug)]
19enum AliasEntry<F> {
20 Aliased {
21 threshold: F,
22 value: usize,
23 alias: usize,
24 },
25 Unaliased(usize),
26}
27use AliasEntry::*;
28
29
30pub struct AliasTable<T, F> {
33 table: Vec<AliasEntry<F>>,
34 objs: Vec<T>,
35 range: Range<usize>,
36 float: Range<F>,
37}
38
39#[derive(Clone)]
41pub struct AliasTableIterator<'a, T: 'a, F: 'a, R>
42 where R: Rng + Sized
43{
44 rng: R,
45 table: &'a AliasTable<T, F>
46}
47
48
49impl<T, F> fmt::Debug for AliasTable<T, F>
50 where F: fmt::Debug
51{
52 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
53 write!(fmt, "AliasTable {{ table: {:?} }}", self.table)
54 }
55}
56
57
58impl<T, F> AliasTable<T, F>
59 where F: PartialOrd + SampleRange
60{
61 pub fn pick<'a, R: Rng>(&'a self, rng: &mut R) -> &'a T {
63 let idx = self.range.ind_sample(rng);
64 let entry = &self.table[idx];
65 match *entry {
66 Aliased { ref threshold, value, alias } => {
67 if &self.float.ind_sample(rng) < threshold {
68 &self.objs[value]
69 } else {
70 &self.objs[alias]
71 }
72 }
73 Unaliased(idx) => &self.objs[idx],
74 }
75 }
76
77 pub fn iter<R: Rng>(&self, rng: R) -> AliasTableIterator<T, F, R> {
80 AliasTableIterator {
81 rng: rng,
82 table: self
83 }
84 }
85}
86
87impl<'a, T, F: 'a> FromIterator<(T, F)> for AliasTable<T, F>
88 where F: Float + NumCast + One + SampleRange + Sum<F> + Zero
89{
90 fn from_iter<I: IntoIterator<Item = (T, F)>>(iter: I) -> Self {
93 let (objs, ps): (Vec<_>, Vec<_>) = iter.into_iter().unzip();
94 let psum: F = ps.iter().cloned().sum();
95
96 let pn = F::from(ps.len())
97 .expect("Error casting usize to generic parameter F of AliasTable<T, F>");
98 let pcoeff = pn / psum;
99
100 let (mut small, mut large): (Vec<_>, Vec<_>) =
101 ps.into_iter().map(|p| pcoeff * p).enumerate().partition(|&(_, p)| p < F::one());
102 let mut table = Vec::new();
103
104
105 while !(small.is_empty() || large.is_empty()) {
106 let (l, p_l) = small.pop().unwrap();
107 let (g, p_g) = large.pop().unwrap();
108
109 table.push(Aliased {
110 threshold: p_l,
111 value: l,
112 alias: g,
113 });
114
115 let p_g = (p_g + p_l) - F::one();
116
117 if p_g < F::one() {
118 &mut small
119 } else {
120 &mut large
121 }
122 .push((g, p_g));
123 }
124
125 table.extend(large.iter().map(|&(g, _)| Unaliased(g)));
126
127 table.extend(small.iter().map(|&(l, _)| Unaliased(l)));
128
129 AliasTable {
130 range: Range::new(0, table.len()),
131 float: Range::new(F::zero(), F::one()),
132 table: table,
133 objs: objs,
134 }
135 }
136}
137
138impl<'a, T: 'a, F, R> Iterator for AliasTableIterator<'a, T, F, R>
139 where F: PartialOrd + SampleRange,
140 R: Rng
141{
142 type Item = &'a T;
143
144 fn next(&mut self) -> Option<Self::Item> {
145 Some(self.table.pick(&mut self.rng))
146 }
147
148 fn size_hint(&self) -> (usize, Option<usize>) {
149 (std::usize::MAX, None)
150 }
151}
152
153impl<'a, T, F> IntoIterator for &'a AliasTable<T, F>
154 where F: Sized + PartialOrd + SampleRange
155{
156 type Item = &'a T;
157 type IntoIter = AliasTableIterator<'a, T, F, rand::ThreadRng>;
158
159 fn into_iter(self) -> Self::IntoIter {
162 self.iter(rand::thread_rng())
163 }
164}