use rand::Rng;
use crate::prng::make_prng;
pub fn shuffle<T>(randomness: [u8; 32], mut data: Vec<T>) -> Vec<T> {
let mut rng = make_prng(randomness);
for i in (1..data.len()).rev() {
let j = rng.gen_range(0..=i);
data.swap(i, j);
}
data
}
#[cfg(test)]
mod tests {
use crate::RANDOMNESS1;
use super::*;
#[test]
fn shuffle_works() {
let data: Vec<i32> = vec![];
let shuffled = shuffle(RANDOMNESS1, data);
assert_eq!(shuffled, Vec::<i32>::new());
let data = vec![5];
let shuffled = shuffle(RANDOMNESS1, data);
assert_eq!(shuffled, vec![5]);
let data = vec![1, 2, 3, 4];
let shuffled = shuffle(RANDOMNESS1, data);
assert_eq!(shuffled.len(), 4);
assert_ne!(shuffled, vec![1, 2, 3, 4]);
}
#[test]
fn shuffle_distribution_is_uniform() {
use crate::sub_randomness::sub_randomness;
use std::collections::HashMap;
const TEST_SAMPLE_SIZE: usize = 100_000;
const ACCURACY: f32 = 0.05;
let data = vec!["a", "b", "c", "d", "e", "f", "h", "i", "j", "k"];
let mut result = vec![];
for subrand in sub_randomness(RANDOMNESS1).take(TEST_SAMPLE_SIZE) {
result.push(shuffle(subrand, data.clone()));
}
let estimation_min = (TEST_SAMPLE_SIZE / data.len()) as f32 * (1_f32 - ACCURACY);
let estimation_max = (TEST_SAMPLE_SIZE / data.len()) as f32 * (1_f32 + ACCURACY);
println!(
"estimation min: {} estimation max: {} ",
estimation_min, estimation_max
);
for i in 0..data.len() {
let mut histogram = HashMap::new();
for vec in &result {
let element = vec.get(i).unwrap();
let count = histogram.entry(element).or_insert(0);
*count += 1;
}
for (bin, count) in histogram {
println!("Histogram index: {} - {}: {}", i, bin, count);
assert!(count >= estimation_min as i32 && count <= estimation_max as i32);
}
}
}
}