use crate::{
algorithm::EvaluatedPopulation,
genetic::{Fitness, FitnessFunction, Genotype, Offspring},
operator::{GeneticOperator, MultiObjective, ReinsertionOp, SingleObjective},
random::Rng,
};
use std::marker::PhantomData;
#[derive(Clone, Debug, PartialEq)]
pub struct ElitistReinserter<G, F, E>
where
G: Genotype,
F: Fitness,
E: FitnessFunction<G, F>,
{
fitness_evaluator: Box<E>,
offspring_has_precedence: bool,
replace_ratio: f64,
_g: PhantomData<G>,
_f: PhantomData<F>,
}
impl<G, F, E> ElitistReinserter<G, F, E>
where
G: Genotype,
F: Fitness,
E: FitnessFunction<G, F>,
{
pub fn new(fitness_evaluator: E, offspring_has_precedence: bool, replace_ratio: f64) -> Self {
ElitistReinserter {
fitness_evaluator: Box::new(fitness_evaluator),
offspring_has_precedence,
replace_ratio,
_g: PhantomData,
_f: PhantomData,
}
}
pub fn is_offspring_has_precedence(&self) -> bool {
self.offspring_has_precedence
}
pub fn set_offspring_has_precedence(&mut self, value: bool) {
self.offspring_has_precedence = value;
}
pub fn replace_ratio(&self) -> f64 {
self.replace_ratio
}
pub fn set_replace_ratio(&mut self, value: f64) {
self.replace_ratio = value;
}
}
impl<G, F, E> GeneticOperator for ElitistReinserter<G, F, E>
where
G: Genotype,
F: Fitness,
E: FitnessFunction<G, F>,
{
fn name() -> String {
"Uniform-Reinserter".to_string()
}
}
impl<G, F, E> SingleObjective for ElitistReinserter<G, F, E>
where
G: Genotype,
F: Fitness,
E: FitnessFunction<G, F>,
{
}
impl<G, F, E> MultiObjective for ElitistReinserter<G, F, E>
where
G: Genotype,
F: Fitness,
E: FitnessFunction<G, F>,
{
}
impl<G, F, E> ReinsertionOp<G, F> for ElitistReinserter<G, F, E>
where
G: Genotype,
F: Fitness,
E: FitnessFunction<G, F>,
{
fn combine<R>(
&self,
offspring: &mut Offspring<G>,
evaluated: &EvaluatedPopulation<G, F>,
_: &mut R,
) -> Vec<G>
where
R: Rng + Sized,
{
let old_individuals = evaluated.individuals();
let old_fitness_values = evaluated.fitness_values();
let mut old_population_indices: Vec<usize> = (0..old_fitness_values.len()).collect();
old_population_indices.sort_by(|x, y| old_fitness_values[*y].cmp(&old_fitness_values[*x]));
let population_size = old_individuals.len();
let mut new_population: Vec<G> = Vec::with_capacity(population_size);
let num_offspring = (population_size as f64 * self.replace_ratio + 0.5).floor() as usize;
if self.offspring_has_precedence {
if num_offspring < offspring.len() {
let mut offspring_fitness: Vec<(G, F)> = Vec::with_capacity(offspring.len());
while let Some(child) = offspring.pop() {
let fitness = self.fitness_evaluator.fitness_of(&child);
offspring_fitness.push((child, fitness));
}
offspring_fitness.sort_by(|x, y| x.1.cmp(&y.1));
for _ in 0..num_offspring {
new_population.push(offspring_fitness.pop().unwrap().0);
}
} else {
offspring.truncate(num_offspring);
new_population.append(offspring);
}
let num_old_population = population_size - new_population.len();
for index_old in old_population_indices.iter().take(num_old_population) {
new_population.push(old_individuals[*index_old].clone());
}
} else {
let mut offspring_fitness: Vec<(G, F)> = Vec::with_capacity(offspring.len());
while let Some(child) = offspring.pop() {
let fitness = self.fitness_evaluator.fitness_of(&child);
offspring_fitness.push((child, fitness));
}
offspring_fitness.sort_by(|x, y| x.1.cmp(&y.1));
for _ in 0..population_size {
let index_old = old_population_indices[0];
if !offspring_fitness.is_empty()
&& offspring_fitness[offspring_fitness.len() - 1].1
> old_fitness_values[index_old]
{
let (offspring, _) = offspring_fitness.pop().unwrap();
new_population.push(offspring);
} else {
new_population.push(old_individuals[index_old].clone());
old_population_indices.remove(0);
}
}
}
new_population
}
}