use crate::traits::{GeneT, LinearChromosome};
fn hamming_distance<U: LinearChromosome>(a: &U, b: &U) -> usize {
a.dna()
.iter()
.zip(b.dna().iter())
.filter(|(ga, gb)| ga.id() != gb.id())
.count()
}
pub fn deterministic_crowding<U: LinearChromosome>(chromosomes: &mut Vec<U>) {
crate::log_debug!(target="survivor_events", method="deterministic_crowding"; "Starting deterministic crowding survivor");
let mut offspring_indices: Vec<usize> = Vec::new();
let mut parent_indices: Vec<usize> = Vec::new();
for (i, c) in chromosomes.iter().enumerate() {
if c.age() == 0 {
offspring_indices.push(i);
} else {
parent_indices.push(i);
}
}
crate::log_trace!(target="survivor_events", method="deterministic_crowding";
"Offspring: {} | Parents: {}", offspring_indices.len(), parent_indices.len());
let total = chromosomes.len();
let mut survive = vec![true; total];
let mut available_parents: Vec<usize> = parent_indices.clone();
for &off_idx in &offspring_indices {
if available_parents.is_empty() {
crate::log_trace!(target="survivor_events", method="deterministic_crowding";
"Offspring {} has no available parent; survives unconditionally", off_idx);
continue;
}
let (best_pos, best_parent_idx, _) = available_parents
.iter()
.enumerate()
.map(|(pos, &par_idx)| {
let dist = hamming_distance(&chromosomes[off_idx], &chromosomes[par_idx]);
(pos, par_idx, dist)
})
.min_by_key(|&(_, _, dist)| dist)
.expect("available_parents is non-empty");
let off_fitness = chromosomes[off_idx].fitness();
let par_fitness = chromosomes[best_parent_idx].fitness();
let off_wins = off_fitness
.partial_cmp(&par_fitness)
.map(|ord| ord != std::cmp::Ordering::Less)
.unwrap_or(false);
if off_wins {
survive[best_parent_idx] = false;
crate::log_trace!(target="survivor_events", method="deterministic_crowding";
"Offspring {} (fit={}) beats parent {} (fit={})", off_idx, off_fitness, best_parent_idx, par_fitness);
} else {
survive[off_idx] = false;
crate::log_trace!(target="survivor_events", method="deterministic_crowding";
"Parent {} (fit={}) beats offspring {} (fit={})", best_parent_idx, par_fitness, off_idx, off_fitness);
}
available_parents.swap_remove(best_pos);
}
let mut i = 0;
chromosomes.retain(|_| {
let keep = survive[i];
i += 1;
keep
});
crate::log_debug!(target="survivor_events", method="deterministic_crowding";
"Deterministic crowding finished: {} survivors", chromosomes.len());
}