use super::*;
use rayon::prelude::*;
use std::ops::Deref;
pub struct Population<I: Individual> {
individuals: Vec<I>,
generation: usize,
stagnation: usize,
stats: PopulatedStats,
}
impl<I: Individual> Population<I> {
pub fn new(mut initial_population: Vec<I>) -> Self {
let stats = sort_dedup_and_collect_stats(&mut initial_population);
Self {
individuals: initial_population,
generation: 0,
stagnation: 0,
stats,
}
}
#[inline]
pub fn replace(&mut self, new_population: &mut Vec<I>) {
std::mem::swap(&mut self.individuals, new_population);
let previous_best = self.stats.max();
self.stats = sort_dedup_and_collect_stats(&mut self.individuals);
self.generation += 1;
if self.stats.max() > previous_best {
self.stagnation = 0;
} else {
self.stagnation += 1;
}
}
#[inline]
pub fn generation(&self) -> usize {
self.generation
}
#[inline]
pub fn stagnation(&self) -> usize {
self.stagnation
}
#[inline]
pub fn stats(&self) -> &PopulatedStats {
&self.stats
}
#[inline]
pub fn fittest(&self) -> &I {
&self.individuals[self.stats.arg_max()]
}
#[inline]
pub fn take_fittest(mut self) -> I {
self.individuals.swap_remove(self.stats.arg_max())
}
}
impl<I: Individual> Deref for Population<I> {
type Target = [I];
#[inline]
fn deref(&self) -> &Self::Target {
&self.individuals
}
}
impl<I: Individual> TryFrom<Vec<I>> for Population<I> {
type Error = Vec<I>;
fn try_from(individuals: Vec<I>) -> Result<Self, Self::Error> {
if !individuals.is_empty() {
Ok(Self::new(individuals))
} else {
Err(individuals)
}
}
}
impl<I: Individual> From<Population<I>> for Vec<I> {
fn from(population: Population<I>) -> Self {
population.individuals
}
}
#[inline]
fn sort_dedup_and_collect_stats<I: Individual>(individuals: &mut Vec<I>) -> PopulatedStats {
individuals.par_sort_unstable_by(compare_fitness);
individuals.dedup();
individuals
.iter()
.map(|i| i.fitness())
.collect::<Stats>()
.try_into()
.unwrap()
}