7
7
// except according to those terms.
8
8
9
9
//! Low-level API for sampling indices
10
- use core:: { cmp:: Ordering , hash:: Hash , ops:: AddAssign } ;
11
-
12
- #[ cfg( feature = "alloc" ) ]
13
- use core:: slice;
14
-
15
10
#[ cfg( feature = "alloc" ) ]
16
11
use alloc:: vec:: { self , Vec } ;
12
+ use core:: slice;
13
+ use core:: { hash:: Hash , ops:: AddAssign } ;
17
14
// BTreeMap is not as fast in tests, but better than nothing.
18
- #[ cfg( all( feature = "alloc" , not( feature = "std" ) ) ) ]
19
- use alloc:: collections:: BTreeSet ;
20
- #[ cfg( feature = "std" ) ]
21
- use std:: collections:: HashSet ;
22
-
23
15
#[ cfg( feature = "std" ) ]
24
16
use super :: WeightError ;
25
-
17
+ use crate :: distributions :: uniform :: SampleUniform ;
26
18
#[ cfg( feature = "alloc" ) ]
27
- use crate :: {
28
- distributions:: { uniform:: SampleUniform , Distribution , Uniform } ,
29
- Rng ,
30
- } ;
31
-
19
+ use crate :: distributions:: { Distribution , Uniform } ;
20
+ use crate :: Rng ;
21
+ #[ cfg( all( feature = "alloc" , not( feature = "std" ) ) ) ]
22
+ use alloc:: collections:: BTreeSet ;
32
23
#[ cfg( feature = "serde1" ) ]
33
24
use serde:: { Deserialize , Serialize } ;
25
+ #[ cfg( feature = "std" ) ]
26
+ use std:: collections:: HashSet ;
34
27
35
28
/// A vector of indices.
36
29
///
37
30
/// Multiple internal representations are possible.
38
31
#[ derive( Clone , Debug ) ]
32
+ #[ cfg( feature = "alloc" ) ]
39
33
#[ cfg_attr( feature = "serde1" , derive( Serialize , Deserialize ) ) ]
40
34
pub enum IndexVec {
41
35
#[ doc( hidden) ]
@@ -44,6 +38,7 @@ pub enum IndexVec {
44
38
USize ( Vec < usize > ) ,
45
39
}
46
40
41
+ #[ cfg( feature = "alloc" ) ]
47
42
impl IndexVec {
48
43
/// Returns the number of indices
49
44
#[ inline]
@@ -94,6 +89,7 @@ impl IndexVec {
94
89
}
95
90
}
96
91
92
+ #[ cfg( feature = "alloc" ) ]
97
93
impl IntoIterator for IndexVec {
98
94
type IntoIter = IndexVecIntoIter ;
99
95
type Item = usize ;
@@ -108,6 +104,7 @@ impl IntoIterator for IndexVec {
108
104
}
109
105
}
110
106
107
+ #[ cfg( feature = "alloc" ) ]
111
108
impl PartialEq for IndexVec {
112
109
fn eq ( & self , other : & IndexVec ) -> bool {
113
110
use self :: IndexVec :: * ;
@@ -124,13 +121,15 @@ impl PartialEq for IndexVec {
124
121
}
125
122
}
126
123
124
+ #[ cfg( feature = "alloc" ) ]
127
125
impl From < Vec < u32 > > for IndexVec {
128
126
#[ inline]
129
127
fn from ( v : Vec < u32 > ) -> Self {
130
128
IndexVec :: U32 ( v)
131
129
}
132
130
}
133
131
132
+ #[ cfg( feature = "alloc" ) ]
134
133
impl From < Vec < usize > > for IndexVec {
135
134
#[ inline]
136
135
fn from ( v : Vec < usize > ) -> Self {
@@ -171,6 +170,7 @@ impl<'a> Iterator for IndexVecIter<'a> {
171
170
impl < ' a > ExactSizeIterator for IndexVecIter < ' a > { }
172
171
173
172
/// Return type of `IndexVec::into_iter`.
173
+ #[ cfg( feature = "alloc" ) ]
174
174
#[ derive( Clone , Debug ) ]
175
175
pub enum IndexVecIntoIter {
176
176
#[ doc( hidden) ]
@@ -179,6 +179,7 @@ pub enum IndexVecIntoIter {
179
179
USize ( vec:: IntoIter < usize > ) ,
180
180
}
181
181
182
+ #[ cfg( feature = "alloc" ) ]
182
183
impl Iterator for IndexVecIntoIter {
183
184
type Item = usize ;
184
185
@@ -201,6 +202,7 @@ impl Iterator for IndexVecIntoIter {
201
202
}
202
203
}
203
204
205
+ #[ cfg( feature = "alloc" ) ]
204
206
impl ExactSizeIterator for IndexVecIntoIter { }
205
207
206
208
/// Randomly sample exactly `amount` distinct indices from `0..length`, and
@@ -225,6 +227,7 @@ impl ExactSizeIterator for IndexVecIntoIter {}
225
227
/// to adapt the internal `sample_floyd` implementation.
226
228
///
227
229
/// Panics if `amount > length`.
230
+ #[ cfg( feature = "alloc" ) ]
228
231
#[ track_caller]
229
232
pub fn sample < R > ( rng : & mut R , length : usize , amount : usize ) -> IndexVec
230
233
where
@@ -267,6 +270,33 @@ where
267
270
}
268
271
}
269
272
273
+ /// Randomly sample exactly `N` distinct indices from `0..len`, and
274
+ /// return them in random order (fully shuffled).
275
+ ///
276
+ /// This is implemented via Floyd's algorithm. Time complexity is `O(N^2)`
277
+ /// and memory complexity is `O(N)`.
278
+ ///
279
+ /// Returns `None` if (and only if) `N > len`.
280
+ pub fn sample_array < R , const N : usize > ( rng : & mut R , len : usize ) -> Option < [ usize ; N ] >
281
+ where
282
+ R : Rng + ?Sized ,
283
+ {
284
+ if N > len {
285
+ return None ;
286
+ }
287
+
288
+ // Floyd's algorithm
289
+ let mut indices = [ 0 ; N ] ;
290
+ for ( i, j) in ( len - N ..len) . enumerate ( ) {
291
+ let t = rng. gen_range ( 0 ..=j) ;
292
+ if let Some ( pos) = indices[ 0 ..i] . iter ( ) . position ( |& x| x == t) {
293
+ indices[ pos] = j;
294
+ }
295
+ indices[ i] = t;
296
+ }
297
+ Some ( indices)
298
+ }
299
+
270
300
/// Randomly sample exactly `amount` distinct indices from `0..length`, and
271
301
/// return them in an arbitrary order (there is no guarantee of shuffling or
272
302
/// ordering). The weights are to be provided by the input function `weights`,
@@ -329,6 +359,8 @@ where
329
359
N : UInt ,
330
360
IndexVec : From < Vec < N > > ,
331
361
{
362
+ use std:: cmp:: Ordering ;
363
+
332
364
if amount == N :: zero ( ) {
333
365
return Ok ( IndexVec :: U32 ( Vec :: new ( ) ) ) ;
334
366
}
@@ -399,6 +431,7 @@ where
399
431
/// The output values are fully shuffled. (Overhead is under 50%.)
400
432
///
401
433
/// This implementation uses `O(amount)` memory and `O(amount^2)` time.
434
+ #[ cfg( feature = "alloc" ) ]
402
435
fn sample_floyd < R > ( rng : & mut R , length : u32 , amount : u32 ) -> IndexVec
403
436
where
404
437
R : Rng + ?Sized ,
@@ -430,6 +463,7 @@ where
430
463
/// performance in all cases).
431
464
///
432
465
/// Set-up is `O(length)` time and memory and shuffling is `O(amount)` time.
466
+ #[ cfg( feature = "alloc" ) ]
433
467
fn sample_inplace < R > ( rng : & mut R , length : u32 , amount : u32 ) -> IndexVec
434
468
where
435
469
R : Rng + ?Sized ,
@@ -495,6 +529,7 @@ impl UInt for usize {
495
529
///
496
530
/// This function is generic over X primarily so that results are value-stable
497
531
/// over 32-bit and 64-bit platforms.
532
+ #[ cfg( feature = "alloc" ) ]
498
533
fn sample_rejection < X : UInt , R > ( rng : & mut R , length : X , amount : X ) -> IndexVec
499
534
where
500
535
R : Rng + ?Sized ,
@@ -519,9 +554,11 @@ where
519
554
IndexVec :: from ( indices)
520
555
}
521
556
557
+ #[ cfg( feature = "alloc" ) ]
522
558
#[ cfg( test) ]
523
559
mod test {
524
560
use super :: * ;
561
+ use alloc:: vec;
525
562
526
563
#[ test]
527
564
#[ cfg( feature = "serde1" ) ]
@@ -542,9 +579,6 @@ mod test {
542
579
}
543
580
}
544
581
545
- #[ cfg( feature = "alloc" ) ]
546
- use alloc:: vec;
547
-
548
582
#[ test]
549
583
fn test_sample_boundaries ( ) {
550
584
let mut r = crate :: test:: rng ( 404 ) ;
0 commit comments