use crate::{
algorithm::Algorithm,
ga::GeneticAlgorithm,
genetic::{Fitness, FitnessFunction, Genotype},
operator::{CrossoverOp, MutationOp, ReinsertionOp, SelectionOp},
simulation::State,
termination::{StopFlag, Termination},
};
use chrono::{Duration, Local};
use std::marker::PhantomData;
#[derive(Clone, Debug, PartialEq)]
pub struct FitnessLimit<G, F>
where
G: Genotype,
F: Fitness,
{
_g: PhantomData<G>,
fitness_target: F,
}
impl<G, F> FitnessLimit<G, F>
where
G: Genotype,
F: Fitness,
{
pub fn new(fitness_target: F) -> Self {
FitnessLimit {
_g: PhantomData,
fitness_target,
}
}
pub fn fitness_target(&self) -> &F {
&self.fitness_target
}
}
impl<G, F, E, S, C, M, R> Termination<GeneticAlgorithm<G, F, E, S, C, M, R>> for FitnessLimit<G, F>
where
G: Genotype,
F: Fitness + Send + Sync,
E: FitnessFunction<G, F>,
E: FitnessFunction<G, F> + Sync,
S: SelectionOp<G, F>,
C: CrossoverOp<G> + Sync,
M: MutationOp<G> + Sync,
R: ReinsertionOp<G, F>,
{
fn evaluate(&mut self, state: &State<GeneticAlgorithm<G, F, E, S, C, M, R>>) -> StopFlag {
let highest_fitness = &state.result.best_solution.solution.fitness;
if *highest_fitness >= self.fitness_target {
StopFlag::StopNow(format!(
"Simulation stopped after a solution with a fitness of {:?} \
has been found.",
highest_fitness
))
} else {
StopFlag::Continue
}
}
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct GenerationLimit {
max_generations: u64,
}
impl GenerationLimit {
pub fn new(max_generations: u64) -> Self {
GenerationLimit { max_generations }
}
pub fn max_generations(&self) -> u64 {
self.max_generations
}
}
impl<A> Termination<A> for GenerationLimit
where
A: Algorithm,
{
fn evaluate(&mut self, state: &State<A>) -> StopFlag {
if state.iteration >= self.max_generations {
StopFlag::StopNow(format!(
"Simulation stopped after the limit of {} generations have \
been processed.",
&state.iteration
))
} else {
StopFlag::Continue
}
}
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct TimeLimit {
max_time: Duration,
}
impl TimeLimit {
pub fn new(max_time: Duration) -> Self {
TimeLimit { max_time }
}
pub fn max_time(&self) -> &Duration {
&self.max_time
}
}
impl<A> Termination<A> for TimeLimit
where
A: Algorithm,
{
fn evaluate(&mut self, state: &State<A>) -> StopFlag {
let duration = Local::now().signed_duration_since(state.started_at);
if duration >= self.max_time {
StopFlag::StopNow(format!(
"Simulation stopped after running for {} which exceeds the \
maximal runtime of {}.",
&duration, &self.max_time
))
} else {
StopFlag::Continue
}
}
}