oxigen/
stop_criteria.rs

1//! This module contains the trait definition of StopCriterion and the provided stop criteria.
2
3/// This trait can be implemented to provide a stop criterion of the genetic algorithm
4/// using the generation, the progress of the last executions, the number of solutions
5/// found and the fitness of all individuals of the population.
6pub trait StopCriterion: Send + Sync {
7    /// Returns if the genetic algorithm has finished according to the generation,
8    /// the progress of the last generations, the number of solutions found and the
9    /// fitness of the population.
10    fn stop(
11        &self,
12        generation: u64,
13        progress: f64,
14        n_solutions: usize,
15        population_fitness: &[f64],
16    ) -> bool;
17}
18
19/// Provided stop criteria.
20pub enum StopCriteria {
21    /// Stop when a solution has been found.
22    SolutionFound,
23    /// Stop when this number of solutions have been found.
24    SolutionsFound(usize),
25    /// Stop when the specified solutions have been found or a specific generation,
26    /// what happens before
27    SolutionsFoundOrGeneration(usize, u64),
28    /// Stop in a specific generation.
29    Generation(u64),
30    /// Stop when the mean progress in the last generations is lower than a specific threshold.
31    Progress(f64),
32    /// Stop when the generation is bigger than the first value and the mean progress in the last
33    /// generations is lower than the specific threshold specified as the second value.
34    GenerationAndProgress(u64, f64),
35    /// Stop when the max fitness is bigger or equal than a specific threshold.
36    MaxFitness(f64),
37    /// Stop when the min fitness is bigger or equal than a specific threshold.
38    MinFitness(f64),
39    /// Stop when the average fitness is bigger or equal than a specific threshold.
40    AvgFitness(f64),
41}
42
43impl StopCriterion for StopCriteria {
44    fn stop(
45        &self,
46        generation: u64,
47        progress: f64,
48        n_solutions: usize,
49        population_fitness: &[f64],
50    ) -> bool {
51        match self {
52            StopCriteria::SolutionFound => n_solutions > 0,
53            StopCriteria::SolutionsFound(i) => n_solutions >= *i,
54            StopCriteria::SolutionsFoundOrGeneration(i, g) => n_solutions >= *i || generation >= *g,
55            StopCriteria::Generation(g) => generation >= *g,
56            StopCriteria::Progress(p) => progress <= *p,
57            StopCriteria::GenerationAndProgress(g, p) => generation >= *g && progress <= *p,
58            StopCriteria::MaxFitness(f) => {
59                *population_fitness
60                    .iter()
61                    .max_by(|x, y| x.partial_cmp(&y).unwrap())
62                    .unwrap()
63                    >= *f
64            }
65            StopCriteria::MinFitness(f) => {
66                *population_fitness
67                    .iter()
68                    .min_by(|x, y| x.partial_cmp(&y).unwrap())
69                    .unwrap()
70                    >= *f
71            }
72            StopCriteria::AvgFitness(f) => {
73                population_fitness.iter().sum::<f64>() / population_fitness.len() as f64 >= *f
74            }
75        }
76    }
77}