@@ -25,10 +25,10 @@ use Rng;
25
25
/// Given that `n` is the number of items in the vector used to create an
26
26
/// [`WeightedIndex<W>`], [`WeightedIndex<W>`] will require `O(n)` amount of
27
27
/// memory. More specifically it takes up some constant amount of memory plus
28
- /// the vector used to create it and a [`Vec<usize >`] with capacity `n`.
28
+ /// the vector used to create it and a [`Vec<u32 >`] with capacity `n`.
29
29
///
30
30
/// Time complexity for the creation of a [`WeightedIndex<W>`] is `O(n)`.
31
- /// Sampling is `O(1)`, it makes a call to [`Uniform<usize >::sample`] and a call
31
+ /// Sampling is `O(1)`, it makes a call to [`Uniform<u32 >::sample`] and a call
32
32
/// to [`Uniform<W>::sample`].
33
33
///
34
34
/// # Example
@@ -56,13 +56,13 @@ use Rng;
56
56
///
57
57
/// [`WeightedIndex<W>`]: crate::distributions::weighted::alias_method::WeightedIndex
58
58
/// [`Weight`]: crate::distributions::weighted::alias_method::Weight
59
- /// [`Vec<usize >`]: Vec
60
- /// [`Uniform<usize >::sample`]: Distribution::sample
59
+ /// [`Vec<u32 >`]: Vec
60
+ /// [`Uniform<u32 >::sample`]: Distribution::sample
61
61
/// [`Uniform<W>::sample`]: Distribution::sample
62
62
pub struct WeightedIndex < W : Weight > {
63
- aliases : Vec < usize > ,
63
+ aliases : Vec < u32 > ,
64
64
no_alias_odds : Vec < W > ,
65
- uniform_index : Uniform < usize > ,
65
+ uniform_index : Uniform < u32 > ,
66
66
uniform_within_weight_sum : Uniform < W > ,
67
67
}
68
68
@@ -71,16 +71,20 @@ impl<W: Weight> WeightedIndex<W> {
71
71
///
72
72
/// Returns an error if:
73
73
/// - The vector is empty.
74
+ /// - The vector is longer than `u32::MAX`.
74
75
/// - For any weight `w`: `w < 0` or `w > max` where `max = W::MAX /
75
76
/// weights.len()`.
76
77
/// - The sum of weights is zero.
77
78
pub fn new ( weights : Vec < W > ) -> Result < Self , WeightedError > {
78
79
let n = weights. len ( ) ;
79
80
if n == 0 {
80
81
return Err ( WeightedError :: NoItem ) ;
82
+ } else if n > :: core:: u32:: MAX as usize {
83
+ return Err ( WeightedError :: TooMany ) ;
81
84
}
85
+ let n = n as u32 ;
82
86
83
- let max_weight_size = W :: try_from_usize_lossy ( n)
87
+ let max_weight_size = W :: try_from_u32_lossy ( n)
84
88
. map ( |n| W :: MAX / n)
85
89
. unwrap_or ( W :: ZERO ) ;
86
90
if !weights
@@ -103,7 +107,7 @@ impl<W: Weight> WeightedIndex<W> {
103
107
}
104
108
105
109
// `weight_sum` would have been zero if `try_from_lossy` causes an error here.
106
- let n_converted = W :: try_from_usize_lossy ( n) . unwrap ( ) ;
110
+ let n_converted = W :: try_from_u32_lossy ( n) . unwrap ( ) ;
107
111
108
112
let mut no_alias_odds = weights;
109
113
for odds in no_alias_odds. iter_mut ( ) {
@@ -119,52 +123,52 @@ impl<W: Weight> WeightedIndex<W> {
119
123
/// be ensured that a single index is only ever in one of them at the
120
124
/// same time.
121
125
struct Aliases {
122
- aliases : Vec < usize > ,
123
- smalls_head : usize ,
124
- bigs_head : usize ,
126
+ aliases : Vec < u32 > ,
127
+ smalls_head : u32 ,
128
+ bigs_head : u32 ,
125
129
}
126
130
127
131
impl Aliases {
128
- fn new ( size : usize ) -> Self {
132
+ fn new ( size : u32 ) -> Self {
129
133
Aliases {
130
- aliases : vec ! [ 0 ; size] ,
131
- smalls_head : :: core:: usize :: MAX ,
132
- bigs_head : :: core:: usize :: MAX ,
134
+ aliases : vec ! [ 0 ; size as usize ] ,
135
+ smalls_head : :: core:: u32 :: MAX ,
136
+ bigs_head : :: core:: u32 :: MAX ,
133
137
}
134
138
}
135
139
136
- fn push_small ( & mut self , idx : usize ) {
137
- self . aliases [ idx] = self . smalls_head ;
140
+ fn push_small ( & mut self , idx : u32 ) {
141
+ self . aliases [ idx as usize ] = self . smalls_head ;
138
142
self . smalls_head = idx;
139
143
}
140
144
141
- fn push_big ( & mut self , idx : usize ) {
142
- self . aliases [ idx] = self . bigs_head ;
145
+ fn push_big ( & mut self , idx : u32 ) {
146
+ self . aliases [ idx as usize ] = self . bigs_head ;
143
147
self . bigs_head = idx;
144
148
}
145
149
146
- fn pop_small ( & mut self ) -> usize {
150
+ fn pop_small ( & mut self ) -> u32 {
147
151
let popped = self . smalls_head ;
148
- self . smalls_head = self . aliases [ popped] ;
152
+ self . smalls_head = self . aliases [ popped as usize ] ;
149
153
popped
150
154
}
151
155
152
- fn pop_big ( & mut self ) -> usize {
156
+ fn pop_big ( & mut self ) -> u32 {
153
157
let popped = self . bigs_head ;
154
- self . bigs_head = self . aliases [ popped] ;
158
+ self . bigs_head = self . aliases [ popped as usize ] ;
155
159
popped
156
160
}
157
161
158
162
fn smalls_is_empty ( & self ) -> bool {
159
- self . smalls_head == :: core:: usize :: MAX
163
+ self . smalls_head == :: core:: u32 :: MAX
160
164
}
161
165
162
166
fn bigs_is_empty ( & self ) -> bool {
163
- self . bigs_head == :: core:: usize :: MAX
167
+ self . bigs_head == :: core:: u32 :: MAX
164
168
}
165
169
166
- fn set_alias ( & mut self , idx : usize , alias : usize ) {
167
- self . aliases [ idx] = alias;
170
+ fn set_alias ( & mut self , idx : u32 , alias : u32 ) {
171
+ self . aliases [ idx as usize ] = alias;
168
172
}
169
173
}
170
174
@@ -173,9 +177,9 @@ impl<W: Weight> WeightedIndex<W> {
173
177
// Split indices into those with small weights and those with big weights.
174
178
for ( index, & odds) in no_alias_odds. iter ( ) . enumerate ( ) {
175
179
if odds < weight_sum {
176
- aliases. push_small ( index) ;
180
+ aliases. push_small ( index as u32 ) ;
177
181
} else {
178
- aliases. push_big ( index) ;
182
+ aliases. push_big ( index as u32 ) ;
179
183
}
180
184
}
181
185
@@ -186,9 +190,11 @@ impl<W: Weight> WeightedIndex<W> {
186
190
let b = aliases. pop_big ( ) ;
187
191
188
192
aliases. set_alias ( s, b) ;
189
- no_alias_odds[ b] = no_alias_odds[ b] - weight_sum + no_alias_odds[ s] ;
193
+ no_alias_odds[ b as usize ] = no_alias_odds[ b as usize ]
194
+ - weight_sum
195
+ + no_alias_odds[ s as usize ] ;
190
196
191
- if no_alias_odds[ b] < weight_sum {
197
+ if no_alias_odds[ b as usize ] < weight_sum {
192
198
aliases. push_small ( b) ;
193
199
} else {
194
200
aliases. push_big ( b) ;
@@ -198,10 +204,10 @@ impl<W: Weight> WeightedIndex<W> {
198
204
// The remaining indices should have no alias odds of about 100%. This is due to
199
205
// numeric accuracy. Otherwise they would be exactly 100%.
200
206
while !aliases. smalls_is_empty ( ) {
201
- no_alias_odds[ aliases. pop_small ( ) ] = weight_sum;
207
+ no_alias_odds[ aliases. pop_small ( ) as usize ] = weight_sum;
202
208
}
203
209
while !aliases. bigs_is_empty ( ) {
204
- no_alias_odds[ aliases. pop_big ( ) ] = weight_sum;
210
+ no_alias_odds[ aliases. pop_big ( ) as usize ] = weight_sum;
205
211
}
206
212
207
213
// Prepare distributions for sampling. Creating them beforehand improves
@@ -221,10 +227,10 @@ impl<W: Weight> WeightedIndex<W> {
221
227
impl < W : Weight > Distribution < usize > for WeightedIndex < W > {
222
228
fn sample < R : Rng + ?Sized > ( & self , rng : & mut R ) -> usize {
223
229
let candidate = rng. sample ( self . uniform_index ) ;
224
- if rng. sample ( & self . uniform_within_weight_sum ) < self . no_alias_odds [ candidate] {
225
- candidate
230
+ if rng. sample ( & self . uniform_within_weight_sum ) < self . no_alias_odds [ candidate as usize ] {
231
+ candidate as usize
226
232
} else {
227
- self . aliases [ candidate]
233
+ self . aliases [ candidate as usize ] as usize
228
234
}
229
235
}
230
236
}
@@ -282,10 +288,10 @@ pub trait Weight:
282
288
/// Element of `Self` equivalent to 0.
283
289
const ZERO : Self ;
284
290
285
- /// Produce an instance of `Self` from a `usize ` value, or return `None` if
291
+ /// Produce an instance of `Self` from a `u32 ` value, or return `None` if
286
292
/// out of range. Loss of precision (where `Self` is a floating point type)
287
293
/// is acceptable.
288
- fn try_from_usize_lossy ( n : usize ) -> Option < Self > ;
294
+ fn try_from_u32_lossy ( n : u32 ) -> Option < Self > ;
289
295
290
296
/// Sums all values in slice `values`.
291
297
fn sum ( values : & [ Self ] ) -> Self {
@@ -299,7 +305,7 @@ macro_rules! impl_weight_for_float {
299
305
const MAX : Self = :: core:: $T:: MAX ;
300
306
const ZERO : Self = 0.0 ;
301
307
302
- fn try_from_usize_lossy ( n: usize ) -> Option <Self > {
308
+ fn try_from_u32_lossy ( n: u32 ) -> Option <Self > {
303
309
Some ( n as $T)
304
310
}
305
311
@@ -328,9 +334,9 @@ macro_rules! impl_weight_for_int {
328
334
const MAX : Self = :: core:: $T:: MAX ;
329
335
const ZERO : Self = 0 ;
330
336
331
- fn try_from_usize_lossy ( n: usize ) -> Option <Self > {
337
+ fn try_from_u32_lossy ( n: u32 ) -> Option <Self > {
332
338
let n_converted = n as Self ;
333
- if n_converted >= Self :: ZERO && n_converted as usize == n {
339
+ if n_converted >= Self :: ZERO && n_converted as u32 == n {
334
340
Some ( n_converted)
335
341
} else {
336
342
None
@@ -439,21 +445,21 @@ mod test {
439
445
where
440
446
WeightedIndex < W > : fmt:: Debug ,
441
447
{
442
- const NUM_WEIGHTS : usize = 10 ;
443
- const ZERO_WEIGHT_INDEX : usize = 3 ;
448
+ const NUM_WEIGHTS : u32 = 10 ;
449
+ const ZERO_WEIGHT_INDEX : u32 = 3 ;
444
450
const NUM_SAMPLES : u32 = 15000 ;
445
451
let mut rng = :: test:: rng ( 0x9c9fa0b0580a7031 ) ;
446
452
447
453
let weights = {
448
- let mut weights = Vec :: with_capacity ( NUM_WEIGHTS ) ;
454
+ let mut weights = Vec :: with_capacity ( NUM_WEIGHTS as usize ) ;
449
455
let random_weight_distribution = :: distributions:: Uniform :: new_inclusive (
450
456
W :: ZERO ,
451
- W :: MAX / W :: try_from_usize_lossy ( NUM_WEIGHTS ) . unwrap ( ) ,
457
+ W :: MAX / W :: try_from_u32_lossy ( NUM_WEIGHTS ) . unwrap ( ) ,
452
458
) ;
453
459
for _ in 0 ..NUM_WEIGHTS {
454
460
weights. push ( rng. sample ( & random_weight_distribution) ) ;
455
461
}
456
- weights[ ZERO_WEIGHT_INDEX ] = W :: ZERO ;
462
+ weights[ ZERO_WEIGHT_INDEX as usize ] = W :: ZERO ;
457
463
weights
458
464
} ;
459
465
let weight_sum = weights. iter ( ) . map ( |w| * w) . sum :: < W > ( ) ;
@@ -463,12 +469,12 @@ mod test {
463
469
. collect :: < Vec < f64 > > ( ) ;
464
470
let weight_distribution = WeightedIndex :: new ( weights) . unwrap ( ) ;
465
471
466
- let mut counts = vec ! [ 0_usize ; NUM_WEIGHTS ] ;
472
+ let mut counts = vec ! [ 0 ; NUM_WEIGHTS as usize ] ;
467
473
for _ in 0 ..NUM_SAMPLES {
468
474
counts[ rng. sample ( & weight_distribution) ] += 1 ;
469
475
}
470
476
471
- assert_eq ! ( counts[ ZERO_WEIGHT_INDEX ] , 0 ) ;
477
+ assert_eq ! ( counts[ ZERO_WEIGHT_INDEX as usize ] , 0 ) ;
472
478
for ( count, expected_count) in counts. into_iter ( ) . zip ( expected_counts) {
473
479
let difference = ( count as f64 - expected_count) . abs ( ) ;
474
480
let max_allowed_difference = NUM_SAMPLES as f64 / NUM_WEIGHTS as f64 * 0.1 ;
0 commit comments