pub mod creation;
pub mod cross;
pub mod mutation;
pub mod pairing;
pub mod pre_birth;
pub mod selection;
use std::cmp::Ordering;
use std::f64;
use std::ops;
use std::slice;
use crate::tools::logging::Logger;
use crate::tools::stopchecker::StopChecker;
use crate::{Agent, AgentsState, AlgorithmState, Goal, IterativeOptimizer, Optimizer, Solution};
#[derive(Debug)]
pub struct Individual<T> {
chromosomes: T,
fitness: f64,
alive: bool,
}
impl<T: Clone> Clone for Individual<T> {
fn clone(&self) -> Individual<T> {
Individual {
chromosomes: self.chromosomes.clone(),
fitness: self.fitness,
alive: self.alive,
}
}
}
impl<T> Agent<T> for Individual<T> {
fn get_goal(&self) -> f64 {
self.fitness
}
fn get_parameter(&self) -> &T {
&self.chromosomes
}
}
impl<T> Individual<T> {
pub fn get_chromosomes(&self) -> &T {
&self.chromosomes
}
pub fn get_fitness(&self) -> f64 {
self.fitness
}
pub fn is_alive(&self) -> bool {
self.alive
}
pub fn kill(&mut self) {
self.alive = false;
}
}
pub struct Population<'a, T> {
goal: Box<dyn Goal<T> + 'a>,
individuals: Vec<Individual<T>>,
best_individual: Option<Individual<T>>,
worst_individual: Option<Individual<T>>,
iteration: usize,
}
impl<'a, T: Clone> Population<'a, T> {
fn update_best_worst_individuals(&mut self) {
let best = self
.individuals
.iter()
.min_by(|ind_1, ind_2| self.individuals_min_cmp(ind_1, ind_2));
if let Some(ref individual) = best {
self.best_individual = Some((*individual).clone());
}
let worst = self
.individuals
.iter()
.max_by(|ind_1, ind_2| self.individuals_max_cmp(ind_1, ind_2));
if let Some(ref individual) = worst {
self.worst_individual = Some((*individual).clone());
}
}
}
impl<'a, T: Clone> AgentsState<T> for Population<'a, T> {
type Agent = Individual<T>;
fn get_agents(&self) -> Vec<&Self::Agent> {
let mut agents: Vec<&Self::Agent> = Vec::with_capacity(self.len());
for individual in self.individuals.iter() {
agents.push(individual);
}
agents
}
}
impl<'a, T> Population<'a, T> {
fn new(goal: Box<dyn Goal<T> + 'a>) -> Self {
Population {
goal,
individuals: vec![],
best_individual: None,
worst_individual: None,
iteration: 0,
}
}
fn reset(&mut self) {
self.individuals.clear();
self.best_individual = None;
self.worst_individual = None;
self.iteration = 0;
}
fn push(&mut self, chromosomes: T) {
let fitness = self.goal.get(&chromosomes);
let new_individual = Individual {
chromosomes,
fitness,
alive: true,
};
self.individuals.push(new_individual);
}
fn append(&mut self, chromosomes_list: Vec<T>) {
for chromosome in chromosomes_list {
self.push(chromosome);
}
}
pub fn iter(&self) -> slice::Iter<Individual<T>> {
self.individuals.iter()
}
pub fn iter_mut(&mut self) -> slice::IterMut<Individual<T>> {
self.individuals.iter_mut()
}
pub fn get_iteration(&self) -> usize {
self.iteration
}
pub fn len_alive(&self) -> usize {
self.individuals
.iter()
.filter(|individual| individual.is_alive())
.count()
}
pub fn get_best(&self) -> &Option<Individual<T>> {
&self.best_individual
}
pub fn get_worst(&self) -> &Option<Individual<T>> {
&self.worst_individual
}
pub fn len(&self) -> usize {
self.individuals.len()
}
fn individuals_min_cmp(
&self,
individual_1: &Individual<T>,
individual_2: &Individual<T>,
) -> Ordering {
let goal_1 = individual_1.get_goal();
let goal_2 = individual_2.get_goal();
if goal_1.is_nan() && goal_2.is_nan() {
Ordering::Greater
} else if goal_1.is_nan() {
Ordering::Greater
} else if goal_2.is_nan() {
Ordering::Less
} else {
goal_1.partial_cmp(&goal_2).unwrap()
}
}
fn individuals_max_cmp(
&self,
individual_1: &Individual<T>,
individual_2: &Individual<T>,
) -> Ordering {
let goal_1 = individual_1.get_goal();
let goal_2 = individual_2.get_goal();
if goal_1.is_nan() && goal_2.is_nan() {
Ordering::Less
} else if goal_1.is_nan() {
Ordering::Less
} else if goal_2.is_nan() {
Ordering::Greater
} else {
goal_1.partial_cmp(&goal_2).unwrap()
}
}
fn next_iteration(&mut self) {
self.iteration += 1;
}
fn remove_dead(&mut self) {
self.individuals.retain(|individual| individual.is_alive());
}
}
impl<'a, T> ops::Index<usize> for Population<'a, T> {
type Output = Individual<T>;
fn index(&self, index: usize) -> &Individual<T> {
&self.individuals[index]
}
}
impl<'a, T> ops::IndexMut<usize> for Population<'a, T> {
fn index_mut<'b>(&'b mut self, index: usize) -> &'b mut Individual<T> {
&mut self.individuals[index]
}
}
impl<'a, T: Clone> AlgorithmState<T> for Population<'a, T> {
fn get_best_solution(&self) -> Option<(T, f64)> {
match &self.best_individual {
None => None,
Some(individual) => Some((individual.chromosomes.clone(), individual.fitness)),
}
}
fn get_iteration(&self) -> usize {
self.iteration
}
}
pub trait Creator<T> {
fn create(&mut self) -> Vec<T>;
}
pub trait Cross<T> {
fn cross(&mut self, parents: &[&T]) -> Vec<T>;
}
pub trait Mutation<T> {
fn mutation(&mut self, chromosomes: &T) -> T;
}
pub trait PreBirth<T> {
fn pre_birth(&mut self, population: &Population<T>, new_chromosomes: &mut Vec<T>);
}
pub trait Selection<T> {
fn kill(&mut self, population: &mut Population<T>);
}
pub trait Pairing<T> {
fn get_pairs(&mut self, population: &Population<T>) -> Vec<Vec<usize>>;
}
pub struct GeneticOptimizer<'a, T> {
stop_checker: Box<dyn StopChecker<T> + 'a>,
creator: Box<dyn Creator<T> + 'a>,
pairing: Box<dyn Pairing<T> + 'a>,
cross: Box<dyn Cross<T> + 'a>,
mutation: Box<dyn Mutation<T> + 'a>,
selections: Vec<Box<dyn Selection<T> + 'a>>,
pre_births: Vec<Box<dyn PreBirth<T> + 'a>>,
loggers: Vec<Box<dyn Logger<T> + 'a>>,
population: Population<'a, T>,
}
impl<'a, T: Clone> GeneticOptimizer<'a, T> {
pub fn new(
goal: Box<dyn Goal<T> + 'a>,
stop_checker: Box<dyn StopChecker<T> + 'a>,
creator: Box<dyn Creator<T> + 'a>,
pairing: Box<dyn Pairing<T> + 'a>,
cross: Box<dyn Cross<T> + 'a>,
mutation: Box<dyn Mutation<T> + 'a>,
selections: Vec<Box<dyn Selection<T> + 'a>>,
pre_births: Vec<Box<dyn PreBirth<T> + 'a>>,
) -> GeneticOptimizer<'a, T> {
GeneticOptimizer {
creator,
stop_checker,
pairing,
cross,
mutation,
selections,
pre_births,
loggers: vec![],
population: Population::new(goal),
}
}
pub fn set_loggers(&mut self, loggers: Vec<Box<dyn Logger<T> + 'a>>) {
self.loggers = loggers;
}
pub fn set_pairing(&mut self, pairing: Box<dyn Pairing<T>>) {
self.pairing = pairing;
}
pub fn set_cross(&mut self, cross: Box<dyn Cross<T>>) {
self.cross = cross;
}
pub fn set_mutation(&mut self, mutation: Box<dyn Mutation<T>>) {
self.mutation = mutation;
}
pub fn set_selection(&mut self, selections: Vec<Box<dyn Selection<T>>>) {
self.selections = selections;
}
pub fn set_pre_birth(&mut self, pre_births: Vec<Box<dyn PreBirth<T>>>) {
self.pre_births = pre_births;
}
pub fn set_stop_checker(&mut self, stop_checker: Box<dyn StopChecker<T>>) {
self.stop_checker = stop_checker;
}
fn run_pairing(&mut self) -> Vec<T> {
let pairs: Vec<Vec<usize>> = self.pairing.get_pairs(&self.population);
let mut new_chromosomes: Vec<T> = Vec::with_capacity(pairs.len());
for pair in pairs {
let mut cross_chromosomes = Vec::with_capacity(pair.len());
for i in pair {
cross_chromosomes.push(self.population[i].get_chromosomes());
}
let mut child_chromosomes = self.cross.cross(&cross_chromosomes);
new_chromosomes.append(&mut child_chromosomes);
}
new_chromosomes
}
}
impl<'a, T: Clone> IterativeOptimizer<T> for GeneticOptimizer<'a, T> {
fn next_iterations(&mut self) -> Option<Solution<T>> {
for logger in &mut self.loggers {
logger.resume(&self.population);
}
while !self.stop_checker.can_stop(&self.population) {
let mut children_chromo_list = self.run_pairing();
let mut children_mutants: Vec<T> = children_chromo_list
.iter_mut()
.map(|chromo| self.mutation.mutation(chromo))
.collect();
for pre_birth in &mut self.pre_births {
pre_birth.pre_birth(&self.population, &mut children_mutants);
}
self.population.append(children_mutants);
for selection in &mut self.selections {
selection.kill(&mut self.population);
}
self.population.remove_dead();
self.population.update_best_worst_individuals();
self.population.next_iteration();
for logger in &mut self.loggers {
logger.next_iteration(&self.population);
}
}
for logger in &mut self.loggers {
logger.finish(&self.population);
}
match &self.population.best_individual {
None => None,
Some(individual) => Some((individual.chromosomes.clone(), individual.fitness)),
}
}
}
impl<'a, T: Clone> Optimizer<T> for GeneticOptimizer<'a, T> {
fn find_min(&mut self) -> Option<(T, f64)> {
self.population.reset();
let start_chromo_list = self.creator.create();
self.population.append(start_chromo_list);
for logger in &mut self.loggers {
logger.start(&self.population);
}
self.next_iterations()
}
}