use crate::{
core::{context::Context, offspring::Offspring, population::Population, state::State},
operators::GeneticOperator,
};
#[derive(Debug, Clone)]
pub struct Pipeline<O: ?Sized>(O);
impl<O> Pipeline<O> {
pub fn new(operators: O) -> Self {
Self(operators)
}
}
macro_rules! impl_genetic_pipeline {
() => {};
($first:ident) => {
impl<G, F, Fe, R, C, $first> GeneticOperator<G, F, Fe, R, C>
for Pipeline<($first,)>
where
$first: GeneticOperator<G, F, Fe, R, C>,
{
fn apply(
&self,
state: &State<G, F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<G, F> {
self.0.0.apply(state, ctx)
}
}
};
($first:ident, $($rest:ident),+) => {
impl<G, F, Fe, R, C, $first, $($rest),*> GeneticOperator<G, F, Fe, R, C>
for Pipeline<($first, $($rest,)*)>
where
$first: GeneticOperator<G, F, Fe, R, C>,
$($rest: GeneticOperator<G, F, Fe, R, C>),*,
{
fn apply(
&self,
state: &State<G, F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<G, F> {
#[allow(non_snake_case)]
let ($first, $($rest,)*) = &self.0;
let mut current_population = match $first.apply(state, ctx) {
Offspring::Single(ind) => {
let mut p = Population::new();
p.add(ind);
p
}
Offspring::Multiple(p) => p,
};
$(
let next_state = state.with_population(current_population);
current_population = match $rest.transform(next_state, ctx) {
Offspring::Single(ind) => {
let mut p = Population::new();
p.add(ind);
p
}
Offspring::Multiple(p) => p,
};
)*
Offspring::Multiple(current_population)
}
}
impl_genetic_pipeline!($($rest),*);
};
}
impl_genetic_pipeline!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16
);
impl<G, F, Fe, R, C, O> GeneticOperator<G, F, Fe, R, C> for Pipeline<[O]>
where
O: GeneticOperator<G, F, Fe, R, C>,
{
fn apply(&self, state: &State<G, F>, ctx: &mut Context<Fe, R, C>) -> Offspring<G, F> {
let mut offspring = self.0[0].apply(state, ctx);
for operator in &self.0[1..] {
let population = offspring.into_population();
let owned_state = state.with_population(population);
offspring = operator.transform(owned_state, ctx);
}
offspring
}
}
impl<G, F, Fe, R, C, O> GeneticOperator<G, F, Fe, R, C> for Pipeline<Vec<O>>
where
O: GeneticOperator<G, F, Fe, R, C>,
{
fn apply(&self, state: &State<G, F>, ctx: &mut Context<Fe, R, C>) -> Offspring<G, F> {
let mut offspring = self.0[0].apply(state, ctx);
for operator in &self.0[1..] {
let population = offspring.into_population();
let owned_state = state.with_population(population);
offspring = operator.transform(owned_state, ctx);
}
offspring
}
}
impl<G, F, Fe, R, C, O> GeneticOperator<G, F, Fe, R, C> for Pipeline<Box<[O]>>
where
O: GeneticOperator<G, F, Fe, R, C>,
{
fn apply(&self, state: &State<G, F>, ctx: &mut Context<Fe, R, C>) -> Offspring<G, F> {
let mut offspring = self.0[0].apply(state, ctx);
for operator in &self.0[1..] {
let population = offspring.into_population();
let owned_state = state.with_population(population);
offspring = operator.transform(owned_state, ctx);
}
offspring
}
}