#![warn(missing_docs)]
#![forbid(unsafe_code)]
#[cfg(test)]
#[path = "../tests/helpers/mod.rs"]
#[macro_use]
pub mod helpers;
pub mod algorithms;
pub mod evolution;
pub mod example;
pub mod hyper;
pub mod population;
pub mod prelude;
pub mod termination;
pub mod utils;
use crate::algorithms::math::RemedianUsize;
use crate::evolution::{Telemetry, TelemetryMetrics, TelemetryMode};
use crate::population::*;
use crate::prelude::*;
use crate::utils::Timer;
use std::hash::Hash;
use std::sync::Arc;
pub trait HeuristicSolution: Send + Sync {
fn fitness(&self) -> impl Iterator<Item = Float>;
fn deep_copy(&self) -> Self;
}
pub type DynHeuristicPopulation<O, S> = dyn HeuristicPopulation<Objective = O, Individual = S> + Send + Sync;
pub type HeuristicResult<O, S> = Result<(Box<DynHeuristicPopulation<O, S>>, Option<TelemetryMetrics>), GenericError>;
pub trait HeuristicContext: Send + Sync {
type Objective: HeuristicObjective<Solution = Self::Solution>;
type Solution: HeuristicSolution;
fn objective(&self) -> &Self::Objective;
fn selected<'a>(&'a self) -> Box<dyn Iterator<Item = &Self::Solution> + 'a>;
fn ranked<'a>(&'a self) -> Box<dyn Iterator<Item = &Self::Solution> + 'a>;
fn statistics(&self) -> &HeuristicStatistics;
fn selection_phase(&self) -> SelectionPhase;
fn environment(&self) -> &Environment;
fn on_initial(&mut self, solution: Self::Solution, item_time: Timer);
fn on_generation(&mut self, offspring: Vec<Self::Solution>, termination_estimate: Float, generation_time: Timer);
fn on_result(self) -> HeuristicResult<Self::Objective, Self::Solution>;
}
#[derive(Clone)]
pub struct HeuristicStatistics {
pub generation: usize,
pub time: Timer,
pub speed: HeuristicSpeed,
pub improvement_all_ratio: Float,
pub improvement_1000_ratio: Float,
pub termination_estimate: Float,
}
impl Default for HeuristicStatistics {
fn default() -> Self {
Self {
generation: 0,
time: Timer::start(),
speed: HeuristicSpeed::Unknown,
improvement_all_ratio: 0.,
improvement_1000_ratio: 0.,
termination_estimate: 0.,
}
}
}
pub struct TelemetryHeuristicContext<O, S>
where
O: HeuristicObjective<Solution = S>,
S: HeuristicSolution,
{
objective: Arc<O>,
population: Box<DynHeuristicPopulation<O, S>>,
telemetry: Telemetry<O, S>,
environment: Arc<Environment>,
}
impl<O, S> TelemetryHeuristicContext<O, S>
where
O: HeuristicObjective<Solution = S>,
S: HeuristicSolution,
{
pub fn new(
objective: Arc<O>,
population: Box<DynHeuristicPopulation<O, S>>,
telemetry_mode: TelemetryMode,
environment: Arc<Environment>,
) -> Self {
let telemetry = Telemetry::new(telemetry_mode);
Self { objective, population, telemetry, environment }
}
pub fn add_solution(&mut self, solution: S) {
self.population.add(solution);
}
}
impl<O, S> HeuristicContext for TelemetryHeuristicContext<O, S>
where
O: HeuristicObjective<Solution = S>,
S: HeuristicSolution,
{
type Objective = O;
type Solution = S;
fn objective(&self) -> &Self::Objective {
&self.objective
}
fn selected<'a>(&'a self) -> Box<dyn Iterator<Item = &Self::Solution> + 'a> {
self.population.select()
}
fn ranked<'a>(&'a self) -> Box<dyn Iterator<Item = &Self::Solution> + 'a> {
self.population.ranked()
}
fn statistics(&self) -> &HeuristicStatistics {
self.telemetry.get_statistics()
}
fn selection_phase(&self) -> SelectionPhase {
self.population.selection_phase()
}
fn environment(&self) -> &Environment {
self.environment.as_ref()
}
fn on_initial(&mut self, solution: Self::Solution, item_time: Timer) {
self.telemetry.on_initial(&solution, item_time);
self.population.add(solution);
}
fn on_generation(&mut self, offspring: Vec<Self::Solution>, termination_estimate: Float, generation_time: Timer) {
let is_improved = self.population.add_all(offspring);
self.telemetry.on_generation(self.population.as_ref(), termination_estimate, generation_time, is_improved);
self.population.on_generation(self.telemetry.get_statistics());
}
fn on_result(self) -> Result<(Box<DynHeuristicPopulation<O, S>>, Option<TelemetryMetrics>), GenericError> {
let mut telemetry = self.telemetry;
telemetry.on_result(self.population.as_ref());
Ok((self.population, telemetry.take_metrics()))
}
}
#[derive(Clone, Debug)]
pub enum HeuristicSpeed {
Unknown,
Slow {
ratio: Float,
average: Float,
median: Option<usize>,
},
Moderate {
average: Float,
median: Option<usize>,
},
}
impl HeuristicSpeed {
pub fn get_median(&self) -> Option<usize> {
match self {
HeuristicSpeed::Unknown => None,
HeuristicSpeed::Slow { median, .. } => *median,
HeuristicSpeed::Moderate { median, .. } => *median,
}
}
}
pub trait Stateful {
type Key: Hash + Eq;
fn set_state<T: 'static + Send + Sync>(&mut self, key: Self::Key, state: T);
fn get_state<T: 'static + Send + Sync>(&self, key: &Self::Key) -> Option<&T>;
fn state_mut<T: 'static + Send + Sync, F: Fn() -> T>(&mut self, key: Self::Key, inserter: F) -> &mut T;
}
pub fn get_default_selection_size(environment: &Environment) -> usize {
environment.parallelism.available_cpus().min(8)
}
pub fn get_default_population<O, S>(
objective: Arc<O>,
environment: Arc<Environment>,
selection_size: usize,
) -> Box<dyn HeuristicPopulation<Objective = O, Individual = S>>
where
O: HeuristicObjective<Solution = S> + Shuffled + 'static,
S: HeuristicSolution + RosomaxaWeighted + 'static,
{
if selection_size == 1 {
Box::new(Greedy::new(objective, 1, None))
} else {
let config = RosomaxaConfig::new_with_defaults(selection_size);
let population =
Rosomaxa::new(objective, environment, config).expect("cannot create rosomaxa with default configuration");
Box::new(population)
}
}