use crate::{
genetic::{Fitness, Genotype},
random::Prng,
};
use chrono::{DateTime, Local};
use std::{error::Error, fmt::Debug, rc::Rc};
pub trait Algorithm {
type Output: Clone + Debug + PartialEq;
type Error: Error + Clone + Debug + PartialEq;
fn next(&mut self, iteration: u64, rng: &mut Prng) -> Result<Self::Output, Self::Error>;
fn reset(&mut self) -> Result<bool, Self::Error>;
}
pub trait OptimizationResult<G, F>
where
G: Genotype,
F: Fitness,
{
fn best_solution(&self) -> &BestSolution<G, F>;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Evaluated<G, F>
where
G: Genotype,
F: Fitness,
{
pub genome: G,
pub fitness: F,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BestSolution<G, F>
where
G: Genotype,
F: Fitness,
{
pub found_at: DateTime<Local>,
pub generation: u64,
pub solution: Evaluated<G, F>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EvaluatedPopulation<G, F>
where
G: Genotype,
F: Fitness,
{
individuals: Rc<Vec<G>>,
fitness_values: Vec<F>,
highest_fitness: F,
lowest_fitness: F,
average_fitness: F,
}
impl<G, F> EvaluatedPopulation<G, F>
where
G: Genotype,
F: Fitness,
{
pub fn new(
individuals: Rc<Vec<G>>,
fitness_values: Vec<F>,
highest_fitness: F,
lowest_fitness: F,
average_fitness: F,
) -> Self {
EvaluatedPopulation {
individuals,
fitness_values,
highest_fitness,
lowest_fitness,
average_fitness,
}
}
pub fn individuals(&self) -> Rc<Vec<G>> {
self.individuals.clone()
}
pub fn fitness_values(&self) -> &[F] {
&self.fitness_values
}
pub fn highest_fitness(&self) -> &F {
&self.highest_fitness
}
pub fn lowest_fitness(&self) -> &F {
&self.lowest_fitness
}
pub fn average_fitness(&self) -> &F {
&self.average_fitness
}
pub fn individual(&self, index: usize) -> Option<&G> {
self.individuals.get(index)
}
pub fn fitness_of_individual(&self, individual: &G) -> Option<&F> {
self.index_of_individual(individual)
.map(|index| &self.fitness_values[index])
}
pub fn individual_with_fitness(&self, fitness: &F) -> Option<&G> {
self.index_of_fitness(fitness)
.map(|index| &self.individuals[index])
}
pub fn evaluated_individual_with_fitness(&self, fitness: &F) -> Option<Evaluated<G, F>> {
self.index_of_fitness(&fitness).map(|index| Evaluated {
genome: self.individuals[index].clone(),
fitness: self.fitness_values[index].clone(),
})
}
fn index_of_individual(&self, individual: &G) -> Option<usize> {
self.individuals.iter().position(|v| *v == *individual)
}
fn index_of_fitness(&self, fitness: &F) -> Option<usize> {
self.fitness_values.iter().position(|v| *v == *fitness)
}
}