radiate-engines 1.3.0

Engines for the Radiate genetic algorithm library.
Documentation
use crate::Chromosome;
use crate::Generation;
use crate::GeneticEngineBuilder;
use crate::builder::EngineParams;
use crate::builder::evaluators::EvaluationParams;
use crate::builder::objectives::OptimizeParams;
use crate::builder::population::PopulationParams;
use crate::builder::problem::ProblemParams;
use crate::builder::selectors::SelectionParams;
use crate::builder::species::SpeciesParams;
use crate::genome::phenotype::Phenotype;
use crate::objectives::Objective;
use crate::{EventHandler, Front, Problem, ReplacementStrategy, Select};
use radiate_core::Expr;
use radiate_core::MetricQuery;
use radiate_core::metric_names;
use radiate_core::{Alterer, Diversity, Ecosystem, Evaluator, Executor, Genotype, Rate};
use std::sync::{Arc, Mutex, RwLock};

#[derive(Clone)]
pub(crate) struct EngineConfig<C: Chromosome, T: Clone> {
    ecosystem: Ecosystem<C>,
    problem: Arc<dyn Problem<C, T>>,
    survivor_selector: Arc<dyn Select<C>>,
    offspring_selector: Arc<dyn Select<C>>,
    replacement_strategy: Arc<dyn ReplacementStrategy<C>>,
    alterers: Vec<Alterer<C>>,
    species_threshold: Rate,
    diversity: Option<Arc<dyn Diversity<C>>>,
    evaluator: Arc<dyn Evaluator<C, T>>,
    objective: Objective,
    max_age: usize,
    max_species_age: usize,
    front: Arc<RwLock<Front<Phenotype<C>>>>,
    offspring_fraction: f32,
    executor: EvaluationParams<C, T>,
    handlers: Vec<Arc<Mutex<dyn EventHandler<T>>>>,
    exprs: Option<Arc<Mutex<Vec<MetricQuery>>>>,
    generation: Option<Generation<C, T>>,
}

impl<C: Chromosome, T: Clone> EngineConfig<C, T> {
    pub fn ecosystem(&self) -> &Ecosystem<C> {
        &self.ecosystem
    }

    pub fn survivor_selector(&self) -> Arc<dyn Select<C>> {
        Arc::clone(&self.survivor_selector)
    }

    pub fn offspring_selector(&self) -> Arc<dyn Select<C>> {
        Arc::clone(&self.offspring_selector)
    }

    pub fn replacement_strategy(&self) -> Arc<dyn ReplacementStrategy<C>> {
        Arc::clone(&self.replacement_strategy)
    }

    pub fn alters(&self) -> &[Alterer<C>] {
        &self.alterers
    }

    pub fn objective(&self) -> Objective {
        self.objective.clone()
    }

    pub fn max_age(&self) -> usize {
        self.max_age
    }

    pub fn max_species_age(&self) -> usize {
        self.max_species_age
    }

    pub fn species_threshold(&self) -> Rate {
        self.species_threshold.clone()
    }

    pub fn diversity(&self) -> Option<Arc<dyn Diversity<C>>> {
        self.diversity.clone()
    }

    pub fn front(&self) -> Arc<RwLock<Front<Phenotype<C>>>> {
        Arc::clone(&self.front)
    }

    pub fn evaluator(&self) -> Arc<dyn Evaluator<C, T>> {
        Arc::clone(&self.evaluator)
    }

    pub fn survivor_count(&self) -> usize {
        self.ecosystem.population().len() - self.offspring_count()
    }

    pub fn offspring_count(&self) -> usize {
        (self.ecosystem.population().len() as f32 * self.offspring_fraction) as usize
    }

    pub fn bus_executor(&self) -> Arc<Executor> {
        Arc::clone(&self.executor.bus_executor)
    }

    pub fn species_executor(&self) -> Arc<Executor> {
        Arc::clone(&self.executor.species_executor)
    }

    pub fn handlers(&self) -> Vec<Arc<Mutex<dyn EventHandler<T>>>> {
        self.handlers.clone()
    }

    pub fn problem(&self) -> Arc<dyn Problem<C, T>> {
        Arc::clone(&self.problem)
    }

    pub fn generation(&self) -> Option<Generation<C, T>>
    where
        C: Clone,
        T: Clone,
    {
        self.generation.clone()
    }

    pub fn encoder(&self) -> Arc<dyn Fn() -> Genotype<C> + Send + Sync>
    where
        C: 'static,
        T: 'static,
    {
        let problem = Arc::clone(&self.problem);
        Arc::new(move || problem.encode())
    }

    pub fn exprs(&self) -> Option<Arc<Mutex<Vec<MetricQuery>>>> {
        self.exprs.clone()
    }

    // pub fn limits(&self) -> Option<Vec<Limit>> {
    //     self.limits.clone()
    // }
}

impl<C, T> From<&EngineParams<C, T>> for EngineConfig<C, T>
where
    C: Chromosome + Clone + 'static,
    T: Clone + Send + Sync + 'static,
{
    fn from(params: &EngineParams<C, T>) -> Self {
        let threshold = if let Some(count) = params.species_params.target_species_count {
            let curr_threshold = params.species_params.species_threshold.get_by_index(1);

            let index = Expr::select(metric_names::INDEX);
            let thresh = Expr::select(metric_names::SPECIES_THRESHOLD);
            let err = Expr::select(metric_names::SPECIES_COUNT).error(count as f32) * 0.05;

            Rate::Expr(
                Expr::when(index.lt(2))
                    .then(curr_threshold)
                    .otherwise(err + thresh),
            )
        } else {
            params.species_params.species_threshold.clone()
        };

        Self {
            ecosystem: params.population_params.ecosystem.clone().unwrap(),
            problem: params.problem_params.problem.clone().unwrap(),
            survivor_selector: params.selection_params.survivor_selector.clone(),
            offspring_selector: params.selection_params.offspring_selector.clone(),
            replacement_strategy: params.replacement_strategy.clone(),
            alterers: params.alterers.clone(),
            objective: params.optimization_params.objectives.clone(),
            max_age: params.population_params.max_age,
            max_species_age: params.species_params.max_species_age,
            species_threshold: threshold,
            diversity: params.species_params.diversity.clone(),
            front: Arc::new(RwLock::new(
                params.optimization_params.front.clone().unwrap(),
            )),
            offspring_fraction: params.selection_params.offspring_fraction,
            evaluator: params.evaluation_params.evaluator.clone(),
            executor: params.evaluation_params.clone(),
            handlers: params.handlers.clone(),
            generation: params.generation.clone(),
            exprs: params.exprs.clone(),
        }
    }
}

impl<C, T> From<EngineConfig<C, T>> for GeneticEngineBuilder<C, T>
where
    C: Chromosome + Clone + 'static,
    T: Clone + Send + Sync + 'static,
{
    fn from(config: EngineConfig<C, T>) -> Self {
        GeneticEngineBuilder {
            params: EngineParams {
                population_params: PopulationParams {
                    population_size: config.ecosystem.population().len(),
                    max_age: config.max_age,
                    ecosystem: Some(config.ecosystem),
                },
                species_params: SpeciesParams {
                    diversity: config.diversity,
                    species_threshold: config.species_threshold,
                    max_species_age: config.max_species_age,
                    target_species_count: None,
                },
                evaluation_params: config.executor,
                selection_params: SelectionParams {
                    offspring_fraction: config.offspring_fraction,
                    survivor_selector: config.survivor_selector,
                    offspring_selector: config.offspring_selector,
                },
                optimization_params: OptimizeParams {
                    objectives: config.objective,
                    front_range: config.front.read().unwrap().range().clone(),
                    front: Some(config.front.read().unwrap().clone()),
                },
                problem_params: ProblemParams {
                    codec: None,
                    problem: Some(config.problem),
                    fitness_fn: None,
                    batch_fitness_fn: None,
                    raw_fitness_fn: None,
                    raw_batch_fitness_fn: None,
                },

                replacement_strategy: config.replacement_strategy,
                alterers: config.alterers,
                handlers: config.handlers,
                exprs: config.exprs,
                generation: config.generation,
            },
            errors: Vec::new(),
        }
    }
}