use rand::seq::SliceRandom;
use rand::thread_rng;
pub fn permutation_test<X: Into<f64> + Copy, Y: Into<f64> + Copy>(
alist: &[X],
blist: &[X],
hypothesis: &dyn Fn(&[X], &[X]) -> f64,
p_value: Y,
n_permutations: usize,
) -> bool {
let mut rng = thread_rng();
let mut total = vec![];
total.extend_from_slice(alist);
total.extend_from_slice(blist);
let len_a = alist.len();
let t_stats = hypothesis(alist, blist);
let mut better_num = 0;
for _ in 0..n_permutations {
total.shuffle(&mut rng);
let new_a = &total[0..len_a];
let new_b = &total[len_a..];
let new_t_stats = hypothesis(new_a, new_b);
if new_t_stats > t_stats {
better_num += 1;
}
}
let probability = better_num as f64 / (n_permutations + 1) as f64;
probability <= p_value.into()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::stats::estimator::mean;
#[test]
fn test_permutation_test() {
let a = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let b = vec![11.0, 12.0, 13.0, 14.0, 15.0, 11.0, 12.0, 13.0, 14.0, 15.0];
let hypothesis = |a: &[f64], b: &[f64]| mean(a) - mean(b);
let p_value = 0.05;
let n_permutations = 1000;
assert_eq!(permutation_test(&a, &b, &hypothesis, p_value, n_permutations), false);
let a = vec![1.01, 1.02, 1.03, 1.04, 1.05];
let b = vec![0.99, 1.0, 1.01, 1.0, 1.01];
let hypothesis = |a: &[f64], b: &[f64]| mean(a) - mean(b);
let p_value = 0.05;
let n_permutations = 1000;
assert_eq!(permutation_test(&a, &b, &hypothesis, p_value, n_permutations), true);
let a = vec![1, 2, 3, 4, 5];
let b = vec![11, 12, 13, 14, 15, 11, 12, 13, 14, 15];
let hypothesis = |a: &[i32], b: &[i32]| mean(a) - mean(b);
let p_value = 0.05;
let n_permutations = 1000;
assert_eq!(permutation_test(&a, &b, &hypothesis, p_value, n_permutations), false);
}
}