pub fn assign_crowding_distance(objectives: &[&[f64]], crowding: &mut [f64]) {
let n = objectives.len();
if n == 0 {
return;
}
for c in crowding.iter_mut() {
*c = 0.0;
}
if n <= 2 {
for c in crowding.iter_mut() {
*c = f64::INFINITY;
}
return;
}
let num_objectives = objectives[0].len();
for m in 0..num_objectives {
let obj_col: Vec<f64> = objectives.iter().map(|o| o[m]).collect();
let mut sorted_indices: Vec<usize> = (0..n).collect();
sorted_indices.sort_by(|&a, &b| {
obj_col[a]
.partial_cmp(&obj_col[b])
.unwrap_or(std::cmp::Ordering::Equal)
});
crowding[sorted_indices[0]] = f64::INFINITY;
crowding[sorted_indices[n - 1]] = f64::INFINITY;
let obj_min = obj_col[sorted_indices[0]];
let obj_max = obj_col[sorted_indices[n - 1]];
let range = obj_max - obj_min;
if range < f64::EPSILON {
continue;
}
for k in 1..(n - 1) {
let prev = sorted_indices[k - 1];
let next = sorted_indices[k + 1];
let idx = sorted_indices[k];
if crowding[idx].is_finite() {
crowding[idx] += (obj_col[next] - obj_col[prev]) / range;
}
}
}
}