use std::mem::swap;
use std::time::{Duration, Instant};
use crate::cfg::{Cfg, Crossover, Mutation, Niching, Selection, Species, Survival};
use crate::eval::Evaluator;
use crate::examples::ackley::ackley_runner;
use crate::examples::griewank::griewank_runner;
use crate::examples::knapsack::knapsack_runner;
use crate::examples::rastrigin::rastrigin_runner;
use crate::examples::target_string::target_string_runner;
use crate::hyper::eval::{HyperAlg, StatFn, State};
use crate::run::result::Stats;
use crate::run::runner::{CreateRunnerFn, Runner};
pub struct HyperBuilder {
stat_fns: Vec<Box<dyn StatFn>>,
pop_size: usize,
num_crossover: usize,
num_mutation: usize,
sample_dur: Duration,
}
impl HyperBuilder {
#[must_use]
pub fn new(pop_size: usize, sample_dur: Duration) -> Self {
Self { stat_fns: Vec::new(), pop_size, num_crossover: 0, num_mutation: 0, sample_dur }
}
pub fn add<F: CreateRunnerFn<E>, E: Evaluator>(&mut self, max_fitness: f64, f: F) {
self.num_crossover = self.num_crossover.max(E::NUM_CROSSOVER);
self.num_mutation = self.num_mutation.max(E::NUM_MUTATION);
let sample_dur = self.sample_dur;
self.stat_fns.push(Box::new(move |cfg| {
let mut runner = f(cfg);
let st = Instant::now();
let mut r1 = None;
let mut r2 = None;
while (Instant::now() - st) < sample_dur {
swap(&mut r1, &mut r2);
r2 = Some(runner.run_iter().unwrap());
}
if let Some(mut r) = r1 {
let mut stats = Stats::from_run(&mut r);
stats.best_fitness /= max_fitness;
stats.mean_fitness /= max_fitness;
Some(stats)
} else {
None
}
}));
}
#[must_use]
pub fn build(self) -> Runner<HyperAlg> {
let cfg = Cfg::new(100)
.with_mutation(Mutation::Adaptive)
.with_crossover(Crossover::Adaptive)
.with_survival(Survival::TopProportion(0.25))
.with_selection(Selection::Sus)
.with_species(Species::None)
.with_niching(Niching::None)
.with_par_dist(false)
.with_par_fitness(true);
let pop_size = self.pop_size;
let num_crossover = self.num_crossover;
let num_mutation = self.num_mutation;
let genomefn = move || State::rand(pop_size, num_crossover, num_mutation);
Runner::new(HyperAlg::new(self.stat_fns), cfg, genomefn)
}
}
#[must_use]
pub fn hyper_runner(pop_size: usize, sample_dur: Duration) -> Runner<HyperAlg> {
let mut builder = HyperBuilder::new(pop_size, sample_dur);
builder.add(1.0, &|cfg| rastrigin_runner(2, cfg));
builder.add(1.0, &|cfg| griewank_runner(2, cfg));
builder.add(1.0, &|cfg| ackley_runner(2, cfg));
builder.add(1000.0, &knapsack_runner);
builder.add(12.0, &target_string_runner);
builder.build()
}