use crate::traits::ChromosomeT;
use log::{debug, trace};
use rand::Rng;
pub fn rank_selection<U: ChromosomeT>(chromosomes: &[U], couples: usize) -> Vec<(usize, usize)> {
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));
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 * 2;
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
.iter()
.position(|&(_, cp)| cp >= r)
.unwrap_or(n - 1);
selected.push(cumulative[idx].0);
}
let mut mating = Vec::new();
for chunk in selected.chunks(2) {
if chunk.len() == 2 {
mating.push((chunk[0], chunk[1]));
trace!(target="selection_events", method="rank_selection"; "Mating pair: {} - {}", chunk[0], chunk[1]);
}
}
debug!(target="selection_events", method="rank_selection"; "Rank-based selection finished with {} pairs", mating.len());
mating
}