pub fn order_increasing(x: &[f64]) -> Vec<usize> {
let mut idx: Vec<usize> = (0..x.len()).collect();
idx.sort_by(|&a, &b| x[a].total_cmp(&x[b]).then(a.cmp(&b)));
idx
}
pub fn order_decreasing(x: &[f64]) -> Vec<usize> {
let mut idx: Vec<usize> = (0..x.len()).collect();
idx.sort_by(|&a, &b| x[b].total_cmp(&x[a]).then(a.cmp(&b)));
idx
}
pub fn rank_last(x: &[f64]) -> Vec<usize> {
let mut idx: Vec<usize> = (0..x.len()).collect();
idx.sort_by(|&a, &b| x[a].total_cmp(&x[b]).then(b.cmp(&a)));
let mut ranks = vec![0usize; x.len()];
for (r, &i) in idx.iter().enumerate() {
ranks[i] = r + 1;
}
ranks
}
pub fn rank_average(x: &[f64]) -> Vec<f64> {
let n = x.len();
let order = order_increasing(x);
let mut ranks = vec![0.0f64; n];
let mut i = 0;
while i < n {
let mut j = i;
while j + 1 < n && x[order[j + 1]] == x[order[i]] {
j += 1;
}
let avg = ((i + 1) + (j + 1)) as f64 / 2.0;
for &pos in &order[i..=j] {
ranks[pos] = avg;
}
i = j + 1;
}
ranks
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn order_is_stable_ascending() {
let o = order_increasing(&[3.0, 1.0, 2.0, 1.0]);
assert_eq!(o, [1, 3, 2, 0]);
}
#[test]
fn rank_average_ties() {
let r = rank_average(&[3.0, 1.0, 2.0, 1.0]);
assert_eq!(r, [4.0, 1.5, 3.0, 1.5]);
}
#[test]
fn rank_no_ties() {
let r = rank_average(&[10.0, 30.0, 20.0]);
assert_eq!(r, [1.0, 3.0, 2.0]);
}
#[test]
fn rank_last_ties() {
let r = rank_last(&[0.2, 0.9, 0.5, 0.9, 0.1]);
assert_eq!(r, [2, 5, 3, 4, 1]);
let r = rank_last(&[7.0, 7.0, 7.0]);
assert_eq!(r, [3, 2, 1]);
let r = rank_last(&[10.0, 30.0, 20.0]);
assert_eq!(r, [1, 3, 2]);
}
#[test]
fn order_decreasing_stable_ties() {
let o = order_decreasing(&[5.0, 3.0, 5.0, 3.0]);
assert_eq!(o, [0, 2, 1, 3]);
let o = order_decreasing(&[2.0, 2.0, 2.0, 1.0, 3.0]);
assert_eq!(o, [4, 0, 1, 2, 3]);
}
}