use super::pareto::{constrained_dominates, dominates, dominates_with_directions};
use crate::nsga2::configuration::ObjectiveDirection;
pub fn non_dominated_sort(objectives: &[&[f64]]) -> Vec<Vec<usize>> {
non_dominated_sort_inner(objectives, dominates)
}
pub fn non_dominated_sort_with_directions(
objectives: &[&[f64]],
directions: &[ObjectiveDirection],
) -> Vec<Vec<usize>> {
non_dominated_sort_inner(objectives, |a, b| {
dominates_with_directions(a, b, directions)
})
}
pub fn non_dominated_sort_constrained(
objectives: &[&[f64]],
violations: &[f64],
directions: &[ObjectiveDirection],
) -> Vec<Vec<usize>> {
let n = objectives.len();
if n == 0 {
return vec![];
}
let mut domination_count: Vec<usize> = vec![0; n];
let mut dominated_set: Vec<Vec<usize>> = vec![vec![]; n];
let mut fronts: Vec<Vec<usize>> = vec![];
for i in 0..n {
for j in (i + 1)..n {
let vi = violations.get(i).copied().unwrap_or(0.0);
let vj = violations.get(j).copied().unwrap_or(0.0);
if constrained_dominates(objectives[i], objectives[j], vi, vj, directions) {
dominated_set[i].push(j);
domination_count[j] += 1;
} else if constrained_dominates(objectives[j], objectives[i], vj, vi, directions) {
dominated_set[j].push(i);
domination_count[i] += 1;
}
}
}
let mut current_front: Vec<usize> = (0..n).filter(|&i| domination_count[i] == 0).collect();
while !current_front.is_empty() {
let mut next_front: Vec<usize> = vec![];
for &i in ¤t_front {
for &j in &dominated_set[i] {
domination_count[j] -= 1;
if domination_count[j] == 0 {
next_front.push(j);
}
}
}
fronts.push(current_front);
current_front = next_front;
}
fronts
}
fn non_dominated_sort_inner<F>(objectives: &[&[f64]], dom: F) -> Vec<Vec<usize>>
where
F: Fn(&[f64], &[f64]) -> bool,
{
let n = objectives.len();
if n == 0 {
return vec![];
}
let mut domination_count: Vec<usize> = vec![0; n];
let mut dominated_set: Vec<Vec<usize>> = vec![vec![]; n];
let mut fronts: Vec<Vec<usize>> = vec![];
for i in 0..n {
for j in (i + 1)..n {
if dom(objectives[i], objectives[j]) {
dominated_set[i].push(j);
domination_count[j] += 1;
} else if dom(objectives[j], objectives[i]) {
dominated_set[j].push(i);
domination_count[i] += 1;
}
}
}
let mut current_front: Vec<usize> = (0..n).filter(|&i| domination_count[i] == 0).collect();
while !current_front.is_empty() {
let mut next_front: Vec<usize> = vec![];
for &i in ¤t_front {
for &j in &dominated_set[i] {
domination_count[j] -= 1;
if domination_count[j] == 0 {
next_front.push(j);
}
}
}
fronts.push(current_front);
current_front = next_front;
}
fronts
}
pub fn assign_ranks(ranks: &mut [usize], fronts: &[Vec<usize>]) {
for (rank, front) in fronts.iter().enumerate() {
for &idx in front {
if idx < ranks.len() {
ranks[idx] = rank;
}
}
}
}