use crate::{
core::{context::Context, offspring::Offspring, population::Population, state::State},
operators::GeneticOperator,
};
pub trait GetSize<G, F> {
fn get_size(&self, state: &State<G, F>) -> usize;
}
impl<G, F, T> GetSize<G, F> for T
where
T: Fn(&State<G, F>) -> usize,
{
fn get_size(&self, state: &State<G, F>) -> usize {
(self)(state)
}
}
#[derive(Debug, Clone, Copy)]
pub struct FixedSize(usize);
impl FixedSize {
pub(crate) fn new(size: usize) -> Self {
Self(size)
}
}
impl<G, F> GetSize<G, F> for FixedSize {
fn get_size(&self, _: &State<G, F>) -> usize {
self.0
}
}
#[derive(Debug, Clone, Copy)]
pub struct PopSize(());
impl PopSize {
pub(crate) fn new() -> Self {
Self(())
}
}
impl<G, F> GetSize<G, F> for PopSize {
fn get_size(&self, state: &State<G, F>) -> usize {
state.population().len()
}
}
#[derive(Debug, Clone)]
pub struct Fill<O, S> {
operator: O,
size: S,
}
impl<O, S> Fill<O, S> {
pub fn new(operator: O, size: S) -> Self {
Self { operator, size }
}
}
impl<O> Fill<O, PopSize> {
pub fn from_population_size(operator: O) -> Self {
Self {
operator,
size: PopSize::new(),
}
}
}
impl<O> Fill<O, FixedSize> {
pub fn from_fixed_size(operator: O, size: usize) -> Self {
Self {
operator,
size: FixedSize::new(size),
}
}
}
impl<G, F, Fe, R, C, O, S> GeneticOperator<G, F, Fe, R, C> for Fill<O, S>
where
O: GeneticOperator<G, F, Fe, R, C>,
S: GetSize<G, F>, {
fn apply(&self, state: &State<G, F>, ctx: &mut Context<Fe, R, C>) -> Offspring<G, F> {
let target_size = self.size.get_size(state);
let mut population = Population::with_capacity(target_size);
while population.len() < target_size {
let offspring = self.operator.apply(state, ctx);
match offspring {
Offspring::Single(ind) => population.add(ind),
Offspring::Multiple(mut p) => {
let space_left = target_size - population.len();
if p.len() > space_left {
p.cull(space_left);
}
population.extend(p);
}
}
}
Offspring::Multiple(population)
}
}