1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::utils::{rank_rev, reindex, sort_vector_rev};
use std::ops::Mul;
pub struct BenjaminiYekutieli {
num_elements: f64,
current_max: f64,
cumulative: f64,
}
impl BenjaminiYekutieli {
#[must_use]
pub fn new(num_elements: f64) -> Self {
let cumulative = (1..=num_elements as usize).fold(0.0, |acc, x| acc + (1.0 / x as f64));
Self {
num_elements,
current_max: 1.0,
cumulative,
}
}
pub fn adjust(&mut self, pvalue: f64, rank: usize) -> f64 {
let qvalue = pvalue
.mul(self.cumulative * (self.num_elements / rank as f64))
.min(self.current_max)
.min(1.0);
self.current_max = qvalue;
qvalue
}
#[must_use]
pub fn adjust_slice(slice: &[f64]) -> Vec<f64> {
if slice.is_empty() {
return Vec::new();
}
let mut method = Self::new(slice.len() as f64);
let original_index = rank_rev(slice);
let max = original_index.len() - 1;
let sorted_qvalues = sort_vector_rev(slice)
.iter()
.enumerate()
.map(|(idx, p)| (max - idx + 1, p))
.map(|(r, p)| method.adjust(*p, r))
.collect::<Vec<f64>>();
reindex(&sorted_qvalues, &original_index)
}
}
#[cfg(test)]
mod testing {
use super::BenjaminiYekutieli;
#[test]
fn example() {
let pvalues = vec![0.1, 0.2, 0.3, 0.4, 0.1];
let adj_pvalues = BenjaminiYekutieli::adjust_slice(&pvalues);
assert_eq!(
adj_pvalues,
vec![
0.5708333333333333,
0.7611111111111111,
0.8562500,
0.91333333333333333,
0.5708333333333333
]
);
}
#[test]
fn example_null() {
let pvalues = vec![];
let adj_pvalues = BenjaminiYekutieli::adjust_slice(&pvalues);
assert_eq!(adj_pvalues, vec![]);
}
#[test]
fn example_adjust() {
let mut b = BenjaminiYekutieli::new(100.0);
assert_eq!(b.adjust(0.001, 1), 0.5187377517639621);
assert_eq!(b.adjust(0.001, 2), 0.25936887588198104);
assert_eq!(b.adjust(0.001, 3), 0.1729125839213207);
}
}