use crate::{
genetic::{D12, Fronts, FrontsExt, PopulationMOO},
non_dominated_sorting::build_fronts,
operators::survival::SurvivalOperator,
random::RandomGenerator,
};
pub(crate) mod agemoea;
pub(crate) mod helpers;
pub(crate) mod ibea;
pub(crate) mod nsga2;
pub(crate) mod nsga3;
pub(crate) mod reference_points;
pub(crate) mod revea;
pub(crate) mod rnsga2;
pub(crate) mod spea2;
pub use agemoea::AgeMoeaSurvival;
pub use ibea::IbeaHyperVolumeSurvivalOperator;
pub use nsga2::Nsga2RankCrowdingSurvival;
pub use nsga3::Nsga3ReferencePointsSurvival;
pub use reference_points::{DanAndDenisReferencePoints, StructuredReferencePoints};
pub use revea::ReveaReferencePointsSurvival;
pub use rnsga2::Rnsga2ReferencePointsSurvival;
pub use spea2::Spea2KnnSurvival;
#[derive(Debug, Clone)]
pub enum SurvivalScoringComparison {
Maximize,
Minimize,
}
pub trait FrontsAndRankingBasedSurvival: SurvivalOperator<FDim = ndarray::Ix2> {
fn scoring_comparison(&self) -> SurvivalScoringComparison {
SurvivalScoringComparison::Maximize
}
fn set_front_survival_score<ConstrDim>(
&self,
fronts: &mut Fronts<ConstrDim>,
rng: &mut impl RandomGenerator,
) where
ConstrDim: D12;
fn operate<ConstrDim>(
&mut self,
population: PopulationMOO<ConstrDim>,
num_survive: usize,
rng: &mut impl RandomGenerator,
) -> PopulationMOO<ConstrDim>
where
ConstrDim: D12,
{
let mut fronts = build_fronts(population, num_survive);
self.set_front_survival_score(&mut fronts, rng);
let drained = fronts.drain(..);
let mut survivors_parts: Vec<PopulationMOO<ConstrDim>> = Vec::new();
let mut n_survivors = 0;
for front in drained {
let front_len = front.len();
if n_survivors + front_len <= num_survive {
survivors_parts.push(front);
n_survivors += front_len;
} else {
let remaining = num_survive - n_survivors;
if remaining > 0 {
let scores = front
.survival_score
.clone()
.expect("No survival score set for splitting front");
let mut indices: Vec<usize> = (0..front_len).collect();
indices.sort_by(|&i, &j| match self.scoring_comparison() {
SurvivalScoringComparison::Maximize => scores[j]
.partial_cmp(&scores[i])
.unwrap_or(std::cmp::Ordering::Equal),
SurvivalScoringComparison::Minimize => scores[i]
.partial_cmp(&scores[j])
.unwrap_or(std::cmp::Ordering::Equal),
});
let selected_indices: Vec<usize> =
indices.into_iter().take(remaining).collect();
let partial = front.selected(&selected_indices);
survivors_parts.push(partial);
}
break;
}
}
survivors_parts.to_population()
}
}
impl<T: FrontsAndRankingBasedSurvival> SurvivalOperator for T {
type FDim = ndarray::Ix2;
fn operate<ConstrDim>(
&mut self,
population: PopulationMOO<ConstrDim>,
num_survive: usize,
rng: &mut impl RandomGenerator,
) -> PopulationMOO<ConstrDim>
where
ConstrDim: D12,
{
<T as FrontsAndRankingBasedSurvival>::operate(self, population, num_survive, rng)
}
}