@@ -380,33 +380,18 @@ where
380
380
/// This implementation uses `O(amount)` memory and `O(amount^2)` time.
381
381
fn sample_floyd < R > ( rng : & mut R , length : u32 , amount : u32 ) -> IndexVec
382
382
where R : Rng + ?Sized {
383
- // For small amount we use Floyd's fully-shuffled variant. For larger
384
- // amounts this is slow due to Vec::insert performance, so we shuffle
385
- // afterwards. Benchmarks show little overhead from extra logic.
386
- let floyd_shuffle = amount < 50 ;
387
-
383
+ // Note that the values returned by `rng.gen_range()` can be
384
+ // inferred from the returned vector by working backwards from
385
+ // the last entry. This bijection proves the algorithm fair.
388
386
debug_assert ! ( amount <= length) ;
389
387
let mut indices = Vec :: with_capacity ( amount as usize ) ;
390
388
for j in length - amount..length {
391
389
let t = rng. gen_range ( 0 ..=j) ;
392
- if floyd_shuffle {
393
- if let Some ( pos) = indices. iter ( ) . position ( |& x| x == t) {
394
- indices. insert ( pos, j) ;
395
- continue ;
396
- }
397
- } else if indices. contains ( & t) {
398
- indices. push ( j) ;
399
- continue ;
390
+ if let Some ( pos) = indices. iter ( ) . position ( |& x| x == t) {
391
+ indices[ pos] = j;
400
392
}
401
393
indices. push ( t) ;
402
394
}
403
- if !floyd_shuffle {
404
- // Reimplement SliceRandom::shuffle with smaller indices
405
- for i in ( 1 ..amount) . rev ( ) {
406
- // invariant: elements with index > i have been locked in place.
407
- indices. swap ( i as usize , rng. gen_range ( 0 ..=i) as usize ) ;
408
- }
409
- }
410
395
IndexVec :: from ( indices)
411
396
}
412
397
@@ -628,8 +613,8 @@ mod test {
628
613
) ;
629
614
} ;
630
615
631
- do_test ( 10 , 6 , & [ 8 , 0 , 3 , 5 , 9 , 6 ] ) ; // floyd
632
- do_test ( 25 , 10 , & [ 18 , 15 , 14 , 9 , 0 , 13 , 5 , 24 ] ) ; // floyd
616
+ do_test ( 10 , 6 , & [ 8 , 3 , 5 , 9 , 0 , 6 ] ) ; // floyd
617
+ do_test ( 25 , 10 , & [ 18 , 14 , 9 , 15 , 0 , 13 , 5 , 24 ] ) ; // floyd
633
618
do_test ( 300 , 8 , & [ 30 , 283 , 150 , 1 , 73 , 13 , 285 , 35 ] ) ; // floyd
634
619
do_test ( 300 , 80 , & [ 31 , 289 , 248 , 154 , 5 , 78 , 19 , 286 ] ) ; // inplace
635
620
do_test ( 300 , 180 , & [ 31 , 289 , 248 , 154 , 5 , 78 , 19 , 286 ] ) ; // inplace
0 commit comments