use crate::error::Result;
use crate::multi_objective;
use crate::nas_engine::config::*;
use crate::nas_engine::results::*;
use scirs2_core::numeric::Float;
use std::fmt::Debug;
use super::support::MultiObjectiveOptimizer;
pub(super) struct NSGA2Optimizer<
T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum,
> {
pub(super) inner: crate::multi_objective::NSGA2<T>,
pub(super) config: MultiObjectiveConfig<T>,
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
NSGA2Optimizer<T>
{
pub fn new(config: &MultiObjectiveConfig<T>) -> Result<Self> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
let mut inner = crate::multi_objective::NSGA2::<T>::new(1, 0.9, 0.1);
inner.initialize(config)?;
Ok(Self {
inner,
config: config.clone(),
})
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
MultiObjectiveOptimizer<T> for NSGA2Optimizer<T>
{
fn update_pareto_front(
&mut self,
results: &[SearchResult<T>],
) -> Result<multi_objective::ParetoFront<T>> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
if results.is_empty() {
return Ok(self.inner.get_pareto_front().clone());
}
Ok(self.inner.pareto_front_from_results(results))
}
fn select_candidates(
&self,
candidates: &[SearchResult<T>],
population_size: usize,
) -> Result<Vec<SearchResult<T>>> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
if candidates.is_empty() || population_size == 0 {
return Ok(Vec::new());
}
let mut ranker = crate::multi_objective::NSGA2::<T>::new(candidates.len(), 0.9, 0.1);
ranker.initialize(&self.config)?;
let selected_indices = ranker.select_by_rank_and_crowding(candidates, population_size);
Ok(selected_indices
.into_iter()
.map(|idx| candidates[idx].clone())
.collect())
}
fn calculate_diversity(&self, population: &[SearchResult<T>]) -> f64 {
self.inner.mean_objective_distance(population)
}
}
pub(super) struct WeightedSumOptimizer<
T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum,
> {
pub(super) inner: crate::multi_objective::WeightedSum<T>,
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
WeightedSumOptimizer<T>
{
pub fn new(config: &MultiObjectiveConfig<T>) -> Result<Self> {
Ok(Self {
inner: crate::multi_objective::WeightedSum::new(&config.objectives)?,
})
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
MultiObjectiveOptimizer<T> for WeightedSumOptimizer<T>
{
fn update_pareto_front(
&mut self,
results: &[SearchResult<T>],
) -> Result<multi_objective::ParetoFront<T>> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
self.inner.update_pareto_front(results)
}
fn select_candidates(
&self,
candidates: &[SearchResult<T>],
population_size: usize,
) -> Result<Vec<SearchResult<T>>> {
if candidates.is_empty() || population_size == 0 {
return Ok(Vec::new());
}
let mut scored: Vec<(usize, T)> = candidates
.iter()
.enumerate()
.map(|(idx, result)| (idx, self.inner.scalarized_cost_for_result(result)))
.collect();
scored.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
Ok(scored
.into_iter()
.take(population_size)
.map(|(idx, _)| candidates[idx].clone())
.collect())
}
fn calculate_diversity(&self, population: &[SearchResult<T>]) -> f64 {
self.inner.mean_objective_distance(population)
}
}
pub(super) struct NSGA3Optimizer<
T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum,
> {
pub(super) inner: crate::multi_objective::NSGA3<T>,
pub(super) config: MultiObjectiveConfig<T>,
pub(super) ranking_seed: u64,
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
NSGA3Optimizer<T>
{
pub fn new(config: &MultiObjectiveConfig<T>) -> Result<Self> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
let ranking_seed = scirs2_core::random::random::<u64>();
let mut inner = crate::multi_objective::NSGA3::<T>::with_seed(
crate::multi_objective::nsga3::DEFAULT_REFERENCE_TARGET,
0.9,
0.1,
scirs2_core::random::random::<u64>(),
);
inner.initialize(config)?;
Ok(Self {
inner,
config: config.clone(),
ranking_seed,
})
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
MultiObjectiveOptimizer<T> for NSGA3Optimizer<T>
{
fn update_pareto_front(
&mut self,
results: &[SearchResult<T>],
) -> Result<multi_objective::ParetoFront<T>> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
if results.is_empty() {
return Ok(self.inner.get_pareto_front().clone());
}
self.inner.update_pareto_front(results)
}
fn select_candidates(
&self,
candidates: &[SearchResult<T>],
population_size: usize,
) -> Result<Vec<SearchResult<T>>> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
if candidates.is_empty() || population_size == 0 {
return Ok(Vec::new());
}
let mut ranker = crate::multi_objective::NSGA3::<T>::with_seed(
crate::multi_objective::nsga3::DEFAULT_REFERENCE_TARGET,
0.9,
0.1,
self.ranking_seed,
);
ranker.initialize(&self.config)?;
let selected = ranker.select_by_rank_and_niching(candidates, population_size);
Ok(selected
.into_iter()
.filter_map(|index| candidates.get(index).cloned())
.collect())
}
fn calculate_diversity(&self, population: &[SearchResult<T>]) -> f64 {
self.inner.mean_objective_distance(population)
}
}
pub(super) struct MOEADAdapter<
T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum,
> {
pub(super) inner: crate::multi_objective::MOEADOptimizer<T>,
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
MOEADAdapter<T>
{
pub fn new(config: &MultiObjectiveConfig<T>) -> Result<Self> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
let mut inner = crate::multi_objective::MOEADOptimizer::<T>::new(config.clone())?;
inner.initialize(config)?;
Ok(Self { inner })
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + PartialOrd + std::iter::Sum>
MultiObjectiveOptimizer<T> for MOEADAdapter<T>
{
fn update_pareto_front(
&mut self,
results: &[SearchResult<T>],
) -> Result<multi_objective::ParetoFront<T>> {
use crate::multi_objective::MultiObjectiveOptimizer as InnerMultiObjective;
if results.is_empty() {
return Ok(self.inner.get_pareto_front().clone());
}
self.inner.update_pareto_front(results)
}
fn select_candidates(
&self,
candidates: &[SearchResult<T>],
population_size: usize,
) -> Result<Vec<SearchResult<T>>> {
if candidates.is_empty() || population_size == 0 {
return Ok(Vec::new());
}
Ok(self
.inner
.select_by_decomposition(candidates, population_size)
.into_iter()
.filter_map(|index| candidates.get(index).cloned())
.collect())
}
fn calculate_diversity(&self, population: &[SearchResult<T>]) -> f64 {
self.inner.mean_objective_distance(population)
}
}