use crate::configuration::ProblemSolving;
use crate::traits::ChromosomeT;
use log::{debug, trace};
use rayon::prelude::*;
use std::fmt;
use std::ops::{Index, IndexMut};
pub struct Population<U>
where
U: ChromosomeT,
{
pub chromosomes: Vec<U>,
pub best_chromosome: U,
pub(crate) best_chromosome_is_set: bool,
pub generation_numbers: Vec<usize>,
pub f_avg: f64,
pub f_max: f64,
}
impl<U> Population<U>
where
U: ChromosomeT,
{
pub fn new_empty() -> Population<U> {
Population {
chromosomes: vec![],
generation_numbers: vec![],
f_avg: 0.0,
f_max: 0.0,
best_chromosome: U::new(),
best_chromosome_is_set: false,
}
}
pub fn new(chromosomes: Vec<U>) -> Population<U> {
Population {
chromosomes,
generation_numbers: vec![],
f_avg: 0.0,
f_max: 0.0,
best_chromosome: U::new(),
best_chromosome_is_set: false,
}
}
pub fn recalculate_aga(&mut self) {
self.f_max = f64::NEG_INFINITY;
self.f_avg = 0.0;
for chromosome in self.chromosomes.as_slice() {
self.f_max = if chromosome.fitness() > self.f_max {
chromosome.fitness()
} else {
self.f_max
};
self.f_avg += chromosome.fitness();
}
self.f_avg /= self.chromosomes.len() as f64;
}
pub fn add_chromosomes(&mut self, chromosomes: &mut Vec<U>) {
self.chromosomes.append(chromosomes);
}
pub fn size(&self) -> usize {
self.chromosomes.len()
}
pub fn fitness_calculation(
&mut self,
_number_of_threads: usize,
problem_solving: ProblemSolving,
) {
debug!(target="population_events", method="fitness_calculation"; "Started the population fitness calculation");
self.chromosomes.par_iter_mut().for_each(|chromosome| {
if chromosome.fitness().is_nan() {
chromosome.calculate_fitness();
}
});
if let Some(best_idx) = find_best_index(&self.chromosomes, problem_solving) {
if !self.best_chromosome_is_set {
self.best_chromosome = self.chromosomes[best_idx].clone();
self.best_chromosome_is_set = true;
} else {
let candidate_fitness = self.chromosomes[best_idx].fitness();
let current_fitness = self.best_chromosome.fitness();
let candidate_is_better = match problem_solving {
ProblemSolving::Maximization | ProblemSolving::FixedFitness => {
candidate_fitness > current_fitness
}
ProblemSolving::Minimization => candidate_fitness < current_fitness,
};
if candidate_is_better {
self.best_chromosome = self.chromosomes[best_idx].clone();
}
}
}
debug!(target="ga_events", method="population_fitness_calculation"; "Population fitness calculation finished");
}
pub fn decide_best_chromosome(&mut self, new_chromosome: &U, problem_solving: ProblemSolving) {
debug!(target="population_events", method="decide_best_chromosome"; "Started the best chromosome method");
if !self.best_chromosome_is_set {
self.best_chromosome = new_chromosome.clone();
self.best_chromosome_is_set = true;
} else {
trace!(target="population_events", method="decide_best_chromosome"; "Best chromosome fitness: {} - New chromosome fitness: {}",
self.best_chromosome.fitness(), new_chromosome.fitness());
let is_self_better = match problem_solving {
ProblemSolving::Maximization => {
self.best_chromosome.fitness() >= new_chromosome.fitness()
}
ProblemSolving::Minimization => {
self.best_chromosome.fitness() < new_chromosome.fitness()
}
_ => self.best_chromosome.fitness() >= new_chromosome.fitness(),
};
if !is_self_better {
self.best_chromosome = new_chromosome.clone();
};
}
debug!(target="chromosome_events", method="get_best_chromosome"; "Best chromosome method finished");
}
}
fn find_best_index<U: ChromosomeT>(
chromosomes: &[U],
problem_solving: ProblemSolving,
) -> Option<usize> {
if chromosomes.is_empty() {
return None;
}
let mut best_idx = 0;
let mut best_fit = chromosomes[0].fitness();
for (i, c) in chromosomes.iter().enumerate().skip(1) {
let fit = c.fitness();
let is_better = match problem_solving {
ProblemSolving::Maximization | ProblemSolving::FixedFitness => fit > best_fit,
ProblemSolving::Minimization => fit < best_fit,
};
if is_better {
best_idx = i;
best_fit = fit;
}
}
Some(best_idx)
}
impl<U: ChromosomeT + Clone> Clone for Population<U> {
fn clone(&self) -> Self {
Population {
chromosomes: self.chromosomes.clone(),
best_chromosome: self.best_chromosome.clone(),
best_chromosome_is_set: self.best_chromosome_is_set,
generation_numbers: self.generation_numbers.clone(),
f_avg: self.f_avg,
f_max: self.f_max,
}
}
}
impl<U: ChromosomeT + fmt::Debug> fmt::Debug for Population<U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Population")
.field("size", &self.chromosomes.len())
.field("f_avg", &self.f_avg)
.field("f_max", &self.f_max)
.field("best_chromosome_is_set", &self.best_chromosome_is_set)
.finish()
}
}
impl<U: ChromosomeT> Default for Population<U> {
fn default() -> Self {
Population::new_empty()
}
}
impl<U: ChromosomeT> IntoIterator for Population<U> {
type Item = U;
type IntoIter = std::vec::IntoIter<U>;
fn into_iter(self) -> Self::IntoIter {
self.chromosomes.into_iter()
}
}
impl<'a, U: ChromosomeT> IntoIterator for &'a Population<U> {
type Item = &'a U;
type IntoIter = std::slice::Iter<'a, U>;
fn into_iter(self) -> Self::IntoIter {
self.chromosomes.iter()
}
}
impl<'a, U: ChromosomeT> IntoIterator for &'a mut Population<U> {
type Item = &'a mut U;
type IntoIter = std::slice::IterMut<'a, U>;
fn into_iter(self) -> Self::IntoIter {
self.chromosomes.iter_mut()
}
}
impl<U: ChromosomeT> FromIterator<U> for Population<U> {
fn from_iter<I: IntoIterator<Item = U>>(iter: I) -> Self {
let chromosomes: Vec<U> = iter.into_iter().collect();
Population::new(chromosomes)
}
}
impl<U: ChromosomeT> Index<usize> for Population<U> {
type Output = U;
fn index(&self, index: usize) -> &Self::Output {
&self.chromosomes[index]
}
}
impl<U: ChromosomeT> IndexMut<usize> for Population<U> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.chromosomes[index]
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::*;
use serde::de::{self, MapAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::marker::PhantomData;
impl<U> Serialize for Population<U>
where
U: ChromosomeT + Serialize,
{
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut state = serializer.serialize_struct("Population", 6)?;
state.serialize_field("chromosomes", &self.chromosomes)?;
state.serialize_field("best_chromosome", &self.best_chromosome)?;
state.serialize_field("best_chromosome_is_set", &self.best_chromosome_is_set)?;
state.serialize_field("generation_numbers", &self.generation_numbers)?;
state.serialize_field("f_avg", &self.f_avg)?;
state.serialize_field("f_max", &self.f_max)?;
state.end()
}
}
impl<'de, U> Deserialize<'de> for Population<U>
where
U: ChromosomeT + Deserialize<'de>,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(serde::Deserialize)]
#[serde(field_identifier, rename_all = "snake_case")]
enum Field {
Chromosomes,
BestChromosome,
BestChromosomeIsSet,
GenerationNumbers,
FAvg,
FMax,
}
struct PopulationVisitor<U>(PhantomData<U>);
impl<'de, U> Visitor<'de> for PopulationVisitor<U>
where
U: ChromosomeT + Deserialize<'de>,
{
type Value = Population<U>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("struct Population")
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let mut chromosomes: Option<Vec<U>> = None;
let mut best_chromosome: Option<U> = None;
let mut best_chromosome_is_set: Option<bool> = None;
let mut generation_numbers: Option<Vec<usize>> = None;
let mut f_avg: Option<f64> = None;
let mut f_max: Option<f64> = None;
while let Some(key) = map.next_key()? {
match key {
Field::Chromosomes => {
chromosomes = Some(map.next_value()?);
}
Field::BestChromosome => {
best_chromosome = Some(map.next_value()?);
}
Field::BestChromosomeIsSet => {
best_chromosome_is_set = Some(map.next_value()?);
}
Field::GenerationNumbers => {
generation_numbers = Some(map.next_value()?);
}
Field::FAvg => {
f_avg = Some(map.next_value()?);
}
Field::FMax => {
f_max = Some(map.next_value()?);
}
}
}
Ok(Population {
chromosomes: chromosomes
.ok_or_else(|| de::Error::missing_field("chromosomes"))?,
best_chromosome: best_chromosome
.ok_or_else(|| de::Error::missing_field("best_chromosome"))?,
best_chromosome_is_set: best_chromosome_is_set
.ok_or_else(|| de::Error::missing_field("best_chromosome_is_set"))?,
generation_numbers: generation_numbers
.ok_or_else(|| de::Error::missing_field("generation_numbers"))?,
f_avg: f_avg.ok_or_else(|| de::Error::missing_field("f_avg"))?,
f_max: f_max.ok_or_else(|| de::Error::missing_field("f_max"))?,
})
}
}
const FIELDS: &[&str] = &[
"chromosomes",
"best_chromosome",
"best_chromosome_is_set",
"generation_numbers",
"f_avg",
"f_max",
];
deserializer.deserialize_struct("Population", FIELDS, PopulationVisitor(PhantomData))
}
}
}