pub mod builder;
pub mod evolve;
pub mod hill_climb;
pub mod permutate;
pub mod prelude;
pub mod reporter;
use self::evolve::EvolveVariant;
use self::hill_climb::HillClimbVariant;
use self::permutate::PermutateVariant;
use crate::chromosome::{Chromosome, Genes};
use crate::crossover::CrossoverEvent;
use crate::extension::ExtensionEvent;
use crate::fitness::{FitnessCache, FitnessOrdering, FitnessValue};
use crate::genotype::Genotype;
use crate::mutate::MutateEvent;
use crate::population::Population;
use crate::select::SelectEvent;
use std::collections::HashMap;
use std::fmt::Display;
use std::time::Duration;
pub use self::builder::{
Builder as StrategyBuilder, TryFromBuilderError as TryFromStrategyBuilderError,
};
pub use self::reporter::Duration as StrategyReporterDuration;
pub use self::reporter::Noop as StrategyReporterNoop;
pub use self::reporter::Simple as StrategyReporterSimple;
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum StrategyAction {
SetupAndCleanup,
Extension,
Select,
Crossover,
Mutate,
Fitness,
UpdateBestChromosome,
Other,
}
pub const STRATEGY_ACTIONS: [StrategyAction; 8] = [
StrategyAction::SetupAndCleanup,
StrategyAction::Extension,
StrategyAction::Select,
StrategyAction::Crossover,
StrategyAction::Mutate,
StrategyAction::Fitness,
StrategyAction::UpdateBestChromosome,
StrategyAction::Other,
];
#[derive(Copy, Clone, Debug)]
pub enum StrategyVariant {
Evolve(EvolveVariant),
HillClimb(HillClimbVariant),
Permutate(PermutateVariant),
}
impl Display for StrategyVariant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StrategyVariant::Evolve(EvolveVariant::Standard) => write!(f, "evolve"),
StrategyVariant::HillClimb(HillClimbVariant::Stochastic) => {
write!(f, "hill_climb/stochastic")
}
StrategyVariant::HillClimb(HillClimbVariant::SteepestAscent) => {
write!(f, "hill_climb/steepest_ascent")
}
StrategyVariant::Permutate(PermutateVariant::Standard) => write!(f, "permutate"),
}
}
}
pub trait Strategy<G: Genotype> {
fn call(&mut self);
fn best_generation(&self) -> usize;
fn best_fitness_score(&self) -> Option<FitnessValue>;
fn best_genes(&self) -> Option<Genes<G::Allele>>;
fn best_genes_and_fitness_score(&self) -> Option<(Genes<G::Allele>, FitnessValue)> {
if let Some(fitness_value) = self.best_fitness_score() {
self.best_genes().map(|genes| (genes, fitness_value))
} else {
None
}
}
fn flush_reporter(&mut self, _output: &mut Vec<u8>);
}
pub trait StrategyConfig: Display {
fn variant(&self) -> StrategyVariant;
fn fitness_ordering(&self) -> FitnessOrdering;
fn fitness_cache(&self) -> Option<&FitnessCache> {
None
}
fn par_fitness(&self) -> bool;
fn replace_on_equal_fitness(&self) -> bool;
}
pub trait StrategyState<G: Genotype>: Display {
fn chromosome_as_ref(&self) -> &Option<Chromosome<G::Allele>>;
fn chromosome_as_mut(&mut self) -> &mut Option<Chromosome<G::Allele>>;
fn population_as_ref(&self) -> &Population<G::Allele>;
fn population_as_mut(&mut self) -> &mut Population<G::Allele>;
fn best_fitness_score(&self) -> Option<FitnessValue>;
fn best_generation(&self) -> usize;
fn best_genes(&self) -> Option<Genes<G::Allele>>;
fn current_generation(&self) -> usize;
fn current_iteration(&self) -> usize;
fn stale_generations(&self) -> usize;
fn scale_generation(&self) -> usize;
fn population_cardinality(&self) -> Option<usize>;
fn durations(&self) -> &HashMap<StrategyAction, Duration>;
fn add_duration(&mut self, action: StrategyAction, duration: Duration);
fn total_duration(&self) -> Duration;
fn close_duration(&mut self, total_duration: Duration) {
if let Some(other_duration) = total_duration.checked_sub(self.total_duration()) {
self.add_duration(StrategyAction::Other, other_duration);
}
}
fn fitness_duration_rate(&self) -> f32 {
let fitness_duration = self
.durations()
.get(&StrategyAction::Fitness)
.copied()
.unwrap_or_else(Duration::default);
fitness_duration.as_secs_f32() / self.total_duration().as_secs_f32()
}
fn increment_generation(&mut self);
fn increment_stale_generations(&mut self);
fn reset_stale_generations(&mut self);
fn reset_scale_generation(&mut self);
fn is_better_chromosome(
&self,
contending_chromosome: &Chromosome<G::Allele>,
fitness_ordering: &FitnessOrdering,
replace_on_equal_fitness: bool,
) -> (bool, bool) {
match (
self.best_fitness_score(),
contending_chromosome.fitness_score(),
) {
(None, None) => (false, false),
(Some(_), None) => (false, false),
(None, Some(_)) => (true, true),
(Some(current_fitness_score), Some(contending_fitness_score)) => match fitness_ordering
{
FitnessOrdering::Maximize => {
if contending_fitness_score > current_fitness_score {
(true, true)
} else if replace_on_equal_fitness
&& contending_fitness_score == current_fitness_score
{
(true, false)
} else {
(false, false)
}
}
FitnessOrdering::Minimize => {
if contending_fitness_score < current_fitness_score {
(true, true)
} else if replace_on_equal_fitness
&& contending_fitness_score == current_fitness_score
{
(true, false)
} else {
(false, false)
}
}
},
}
}
}
pub trait StrategyReporter: Clone + Send + Sync {
type Genotype: Genotype;
fn flush(&mut self, _output: &mut Vec<u8>) {}
fn on_enter<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_exit<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_start<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_finish<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_generation_complete<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_selection_complete<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_new_best_chromosome<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_new_best_chromosome_equal_fitness<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_select_event<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_event: SelectEvent,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_extension_event<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_event: ExtensionEvent,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_crossover_event<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_event: CrossoverEvent,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
fn on_mutate_event<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
_event: MutateEvent,
_genotype: &Self::Genotype,
_state: &S,
_config: &C,
) {
}
}