mod builder;
pub use self::builder::{
Builder as ConfigBuilder, TryFromBuilderError as TryFromConfigBuilderError,
};
use genetic_algorithm::chromosome::Chromosome;
use genetic_algorithm::compete::CompeteWrapper;
use genetic_algorithm::crossover::CrossoverWrapper;
use genetic_algorithm::extension::ExtensionWrapper;
use genetic_algorithm::fitness::{Fitness, FitnessValue};
use genetic_algorithm::genotype::{Genotype, MultiDiscreteGenotype};
use genetic_algorithm::mutate::MutateWrapper;
use genetic_algorithm::strategy::evolve::EvolveBuilder;
#[derive(Clone, Debug)]
pub struct Config<G: Genotype, F: Fitness<Genotype = G>> {
pub evolve_builder:
EvolveBuilder<G, MutateWrapper, F, CrossoverWrapper, CompeteWrapper, ExtensionWrapper>,
pub evolve_fitness_to_micro_second_factor: FitnessValue,
pub rounds: usize,
pub target_population_sizes: Vec<usize>,
pub max_stale_generations_options: Vec<Option<usize>>,
pub max_chromosome_age_options: Vec<Option<usize>>,
pub target_fitness_score_options: Vec<Option<FitnessValue>>,
pub mutates: Vec<MutateWrapper>,
pub crossovers: Vec<CrossoverWrapper>,
pub competes: Vec<CompeteWrapper>,
pub extensions: Vec<ExtensionWrapper>,
}
impl<G: Genotype, F: Fitness<Genotype = G>> Config<G, F> {
pub fn builder() -> ConfigBuilder<G, F> {
ConfigBuilder::new()
}
pub fn evolve_builder_for_chromosome(
&self,
chromosome: &Chromosome<MultiDiscreteGenotype>,
) -> EvolveBuilder<G, MutateWrapper, F, CrossoverWrapper, CompeteWrapper, ExtensionWrapper>
{
let genes = &chromosome.genes;
self.evolve_builder
.clone()
.with_target_population_size(self.target_population_sizes[genes[0]])
.with_mutate(self.mutates[genes[1]].clone())
.with_crossover(self.crossovers[genes[2]].clone())
.with_compete(self.competes[genes[3]].clone())
.with_extension(self.extensions[genes[4]].clone())
.with_max_stale_generations_option(self.max_stale_generations_options[genes[5]])
.with_max_chromosome_age_option(self.max_chromosome_age_options[genes[6]])
.with_target_fitness_score_option(self.target_fitness_score_options[genes[7]])
}
pub fn build_genotype(&self) -> MultiDiscreteGenotype {
MultiDiscreteGenotype::builder()
.with_allele_lists(vec![
(0..self.target_population_sizes.len()).collect(),
(0..self.mutates.len()).collect(),
(0..self.crossovers.len()).collect(),
(0..self.competes.len()).collect(),
(0..self.extensions.len()).collect(),
(0..self.max_stale_generations_options.len()).collect(),
(0..self.max_chromosome_age_options.len()).collect(),
(0..self.target_fitness_score_options.len()).collect(),
])
.build()
.unwrap()
}
}
impl<G: Genotype, F: Fitness<Genotype = G>> TryFrom<ConfigBuilder<G, F>> for Config<G, F> {
type Error = TryFromConfigBuilderError;
fn try_from(builder: ConfigBuilder<G, F>) -> Result<Self, Self::Error> {
if builder.evolve_builder.is_none() {
Err(TryFromConfigBuilderError(
"MetaConfig requires an EvolveBuilder",
))
} else if builder
.evolve_builder
.as_ref()
.map(|e| e.genotype.is_none())
.unwrap()
{
Err(TryFromConfigBuilderError(
"MetaConfig's EvolveBuilder requires a Genotype",
))
} else if builder
.evolve_builder
.as_ref()
.map(|e| e.fitness.is_none())
.unwrap()
{
Err(TryFromConfigBuilderError(
"MetaConfig's EvolveBuilder requires a Fitness",
))
} else if builder.target_population_sizes.is_empty() {
Err(TryFromConfigBuilderError(
"MetaConfig requires at least one target_population_size",
))
} else if builder
.max_stale_generations_options
.iter()
.all(|o| o.is_none())
&& builder
.target_fitness_score_options
.iter()
.all(|o| o.is_none())
{
Err(TryFromConfigBuilderError(
"MetaConfig requires at least one max_stale_generations_option or target_fitness_score_option that is not None",
))
} else if builder.mutates.is_empty() {
Err(TryFromConfigBuilderError(
"MetaConfig requires at least one Mutate strategy",
))
} else if builder.extensions.is_empty() {
Err(TryFromConfigBuilderError(
"MetaConfig requires at least one Extension strategy",
))
} else if builder.crossovers.is_empty() {
Err(TryFromConfigBuilderError(
"MetaConfig requires at least one Crossover strategy",
))
} else if builder.competes.is_empty() {
Err(TryFromConfigBuilderError(
"MetaConfig requires at least one Compete strategy",
))
} else {
Ok(Self {
evolve_builder: builder.evolve_builder.unwrap(),
evolve_fitness_to_micro_second_factor: builder
.evolve_fitness_to_micro_second_factor,
rounds: builder.rounds,
target_population_sizes: builder.target_population_sizes,
max_stale_generations_options: builder.max_stale_generations_options,
max_chromosome_age_options: builder.max_chromosome_age_options,
target_fitness_score_options: builder.target_fitness_score_options,
mutates: builder.mutates,
crossovers: builder.crossovers,
competes: builder.competes,
extensions: builder.extensions,
})
}
}
}