use crate::traits::ChromosomeT;
use rand::Rng;
pub fn rank_selection<U: ChromosomeT>(
chromosomes: &[U],
couples: usize,
num_parents: usize,
) -> Vec<Vec<usize>> {
let num_parents = num_parents.max(2);
crate::log_debug!(target="selection_events", method="rank_selection"; "Starting rank-based selection");
let n = chromosomes.len();
if n < 2 {
return Vec::new();
}
let mut indexed: Vec<(usize, f64)> = chromosomes
.iter()
.enumerate()
.map(|(i, c)| (i, c.fitness()))
.collect();
indexed.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
let rank_sum = (n * (n + 1)) / 2;
let mut cumulative = Vec::with_capacity(n);
let mut cum = 0.0;
for (rank_minus_1, &(original_idx, _)) in indexed.iter().enumerate() {
let rank = (rank_minus_1 + 1) as f64;
cum += rank / rank_sum as f64;
cumulative.push((original_idx, cum));
crate::log_trace!(target="selection_events", method="rank_selection"; "Index {} rank {} cum_prob {}", original_idx, rank_minus_1 + 1, cum);
}
let mut rng = crate::rng::make_rng();
let total_parents = couples * num_parents;
let mut selected = Vec::with_capacity(total_parents);
for _ in 0..total_parents {
let r: f64 = rng.random_range(0.0..1.0);
let idx = cumulative.partition_point(|&(_, cp)| cp < r).min(n - 1);
selected.push(cumulative[idx].0);
}
let mut mating = Vec::new();
for chunk in selected.chunks(num_parents) {
if chunk.len() == num_parents {
let group = chunk.to_vec();
crate::log_trace!(target="selection_events", method="rank_selection"; "Mating group: {:?}", group);
mating.push(group);
}
}
crate::log_debug!(target="selection_events", method="rank_selection"; "Rank-based selection finished with {} groups", mating.len());
mating
}