use genotype::Genotype;
use rand::distributions::Uniform;
use rand::prelude::*;
use rayon::prelude::*;
use std::cmp::PartialEq;
use std::sync::mpsc::channel;
use IndWithFitness;
use SurvivalPressureFunctions::*;
pub struct M(usize);
impl M {
pub fn new(m: usize, n_children: usize, population_size: usize) -> M {
if m > n_children && m < population_size {
M { 0: m }
} else {
panic!(
"m shall be greater than the number of children and lower than the population size"
)
}
}
}
pub struct Reproduction {
pub parents: (usize, usize),
pub children: (usize, usize),
}
pub trait SurvivalPressure<T: PartialEq + Send + Sync, G: Genotype<T>>: Send + Sync {
fn kill(
&self,
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
);
}
pub enum SurvivalPressureFunctions {
Worst,
ChildrenReplaceMostSimilar,
ChildrenReplaceParents,
ChildrenReplaceParentsAndTheRestWorst,
ChildrenReplaceParentsAndTheRestRandomly,
ChildrenReplaceParentsAndTheRestRandomMostSimilar,
ChildrenReplaceParentsAndTheRestMostSimilar,
ChildrenReplaceParentsAndTheRestOldest,
ChildrenFightMostSimilar,
ChildrenFightParents,
ChildrenFightParentsAndTheRestWorst,
ChildrenFightParentsAndTheRestRandomly,
ChildrenFightParentsAndTheRestRandomMostSimilar,
ChildrenFightParentsAndTheRestMostSimilar,
ChildrenFightParentsAndTheRestOldest,
Overpopulation(M),
CompetitiveOverpopulation(M),
DeterministicOverpopulation,
}
impl<T: PartialEq + Send + Sync, G: Genotype<T>> SurvivalPressure<T, G>
for SurvivalPressureFunctions
{
fn kill(
&self,
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
) {
match self {
Worst => {
Self::remove_worst(population_size, population);
}
ChildrenReplaceMostSimilar => {
Self::children_replace_most_similar(population, parents_children, population_size);
}
ChildrenReplaceParents => {
Self::children_replace_parents(population, parents_children);
}
ChildrenReplaceParentsAndTheRestWorst => {
Self::children_replace_parents(population, parents_children);
Self::remove_worst(population_size, population);
}
ChildrenReplaceParentsAndTheRestRandomly => {
Self::children_replace_parents(population, parents_children);
Self::remove_randomly(population_size, population);
}
ChildrenReplaceParentsAndTheRestRandomMostSimilar => {
Self::children_replace_parents(population, parents_children);
Self::random_most_similar(population_size, population);
}
ChildrenReplaceParentsAndTheRestMostSimilar => {
Self::children_replace_parents(population, parents_children);
Self::most_similar(population_size, population);
}
ChildrenReplaceParentsAndTheRestOldest => {
Self::children_replace_parents(population, parents_children);
Self::remove_oldest(population_size, population);
}
ChildrenFightMostSimilar => {
Self::children_fight_most_similar(population, parents_children, population_size);
}
ChildrenFightParents => {
Self::children_fight_parents(population, parents_children);
}
ChildrenFightParentsAndTheRestWorst => {
Self::children_fight_parents(population, parents_children);
Self::remove_worst(population_size, population);
}
ChildrenFightParentsAndTheRestRandomly => {
Self::children_fight_parents(population, parents_children);
Self::remove_randomly(population_size, population);
}
ChildrenFightParentsAndTheRestRandomMostSimilar => {
Self::children_fight_parents(population, parents_children);
Self::random_most_similar(population_size, population);
}
ChildrenFightParentsAndTheRestMostSimilar => {
Self::children_fight_parents(population, parents_children);
Self::most_similar(population_size, population);
}
ChildrenFightParentsAndTheRestOldest => {
Self::children_fight_parents(population, parents_children);
Self::remove_oldest(population_size, population);
}
Overpopulation(m) => {
Self::overpopulation(m.0, population_size, population, parents_children);
}
CompetitiveOverpopulation(m) => {
Self::competitive_overpopulation(
m.0,
population_size,
population,
parents_children,
);
}
DeterministicOverpopulation => {
Self::deterministic_overpopulation(population, parents_children);
}
}
}
}
impl SurvivalPressureFunctions {
fn remove_worst<T: PartialEq + Send + Sync, G: Genotype<T>>(
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
) {
sort_population(population);
let mut i = population.len();
while i > population_size {
population.pop();
i -= 1;
}
}
fn remove_randomly<T: PartialEq + Send + Sync, G: Genotype<T>>(
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
) {
let mut rgen = SmallRng::from_entropy();
let mut i = population.len();
while i > population_size {
let chosen = rgen.sample(Uniform::from(0..i));
population.remove(chosen);
i -= 1;
}
}
fn remove_oldest<T: PartialEq + Send + Sync, G: Genotype<T>>(
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
) {
sort_population_by_age(population);
let mut i = population.len();
while i > population_size {
population.pop();
i -= 1;
}
}
fn children_replace_most_similar<T: PartialEq + Send + Sync, G: Genotype<T>>(
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
population_size: usize,
) {
let mut killed = Vec::with_capacity(parents_children.len() * 2);
for repr in parents_children.iter() {
let most_similar_0 = population
.par_iter()
.enumerate()
.filter(|(i, _el)| *i < population_size && !killed.contains(i))
.map(|(i, el)| (i, population[repr.children.0].ind.distance(&el.ind)))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap()
.0;
killed.push(most_similar_0);
let most_similar_1 = population
.par_iter()
.enumerate()
.filter(|(i, _el)| *i < population_size && !killed.contains(i))
.map(|(i, el)| (i, population[repr.children.1].ind.distance(&el.ind)))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap()
.0;
killed.push(most_similar_1);
}
killed.par_sort_unstable();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn children_replace_parents<T: PartialEq + Send + Sync, G: Genotype<T>>(
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
) {
let mut killed = Vec::with_capacity(parents_children.len() * 2);
let (sender, receiver) = channel();
parents_children
.par_iter()
.for_each_with(sender, |s, repr| {
s.send(repr.parents).unwrap();
});
for parents in receiver {
killed.push(parents.0);
killed.push(parents.1);
}
killed.par_sort_unstable();
killed.dedup();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn children_fight_most_similar<T: PartialEq + Send + Sync, G: Genotype<T>>(
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
population_size: usize,
) {
let mut killed = Vec::with_capacity(parents_children.len() * 2);
for repr in parents_children.iter() {
let most_similar_0 = population
.par_iter()
.enumerate()
.filter(|(i, _el)| *i < population_size && !killed.contains(i))
.map(|(i, el)| (i, population[repr.children.0].ind.distance(&el.ind)))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap()
.0;
if population[most_similar_0].fitness.unwrap().fitness
> population[repr.children.0].fitness.unwrap().fitness
{
killed.push(repr.children.0);
} else {
killed.push(most_similar_0);
}
let most_similar_1 = population
.par_iter()
.enumerate()
.filter(|(i, _el)| *i < population_size && !killed.contains(i))
.map(|(i, el)| (i, population[repr.children.1].ind.distance(&el.ind)))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap()
.0;
if population[most_similar_1].fitness.unwrap().fitness
> population[repr.children.1].fitness.unwrap().fitness
{
killed.push(repr.children.1);
} else {
killed.push(most_similar_1);
}
}
killed.par_sort_unstable();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn children_fight_parents<T: PartialEq + Send + Sync, G: Genotype<T>>(
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
) {
let mut killed = Vec::with_capacity(parents_children.len() * 2);
let mut rgen = SmallRng::from_entropy();
for repr in parents_children {
let par0 = &population[repr.parents.0];
let par1 = &population[repr.parents.1];
let child0 = &population[repr.children.0];
let child1 = &population[repr.children.1];
if rgen.gen_bool(0.5) {
if par0.fitness.unwrap().fitness > child0.fitness.unwrap().fitness {
killed.push(repr.children.0);
} else {
killed.push(repr.parents.0);
}
if par1.fitness.unwrap().fitness > child1.fitness.unwrap().fitness {
killed.push(repr.children.1);
} else {
killed.push(repr.parents.1);
}
} else {
if par0.fitness.unwrap().fitness > child1.fitness.unwrap().fitness {
killed.push(repr.children.1);
} else {
killed.push(repr.parents.0);
}
if par1.fitness.unwrap().fitness > child0.fitness.unwrap().fitness {
killed.push(repr.children.0);
} else {
killed.push(repr.parents.1);
}
}
}
killed.par_sort_unstable();
killed.dedup();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn deterministic_overpopulation<T: PartialEq + Send + Sync, G: Genotype<T>>(
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
) {
let mut killed = Vec::with_capacity(parents_children.len() * 2);
for repr in parents_children {
let par0 = &population[repr.parents.0];
let par1 = &population[repr.parents.1];
let child0 = &population[repr.children.0];
let child1 = &population[repr.children.1];
let dist0_0 = par0.ind.distance(&child0.ind);
let dist0_1 = par0.ind.distance(&child1.ind);
let dist1_0 = par1.ind.distance(&child0.ind);
let dist1_1 = par1.ind.distance(&child1.ind);
if dist0_0 + dist1_1 <= dist0_1 + dist1_0 {
if par0.fitness.unwrap().fitness > child0.fitness.unwrap().fitness {
killed.push(repr.children.0);
} else {
killed.push(repr.parents.0);
}
if par1.fitness.unwrap().fitness > child1.fitness.unwrap().fitness {
killed.push(repr.children.1);
} else {
killed.push(repr.parents.1);
}
} else {
if par0.fitness.unwrap().fitness > child1.fitness.unwrap().fitness {
killed.push(repr.children.1);
} else {
killed.push(repr.parents.0);
}
if par1.fitness.unwrap().fitness > child0.fitness.unwrap().fitness {
killed.push(repr.children.0);
} else {
killed.push(repr.parents.1);
}
}
}
killed.par_sort_unstable();
killed.dedup();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn overpopulation<T: PartialEq + Send + Sync, G: Genotype<T>>(
m: usize,
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
) {
if m < parents_children.len() * 2 {
panic!(
"m < children length. m: {}, children_len: {}",
m,
parents_children.len() * 2
)
}
let mut killed = Vec::with_capacity(parents_children.len() * 2);
let mut choosable: Vec<usize> = Vec::with_capacity(m);
let mut rgen = SmallRng::from_entropy();
let mut children: Vec<usize> = Vec::with_capacity(parents_children.len() * 2);
for (child0, child1) in parents_children
.iter()
.map(|pc| (pc.children.0, pc.children.1))
{
children.push(child0);
children.push(child1);
}
for _i in 0..m {
let mut chosen = rgen.sample(Uniform::from(0..population_size));
while choosable.contains(&chosen) {
chosen = rgen.sample(Uniform::from(0..population_size));
}
choosable.push(chosen);
}
for child in children {
let most_similar = choosable
.par_iter()
.enumerate()
.map(|(i, el)| (i, population[child].ind.distance(&population[*el].ind)))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap()
.0;
killed.push(choosable[most_similar]);
choosable.remove(most_similar);
}
killed.par_sort_unstable();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn competitive_overpopulation<T: PartialEq + Send + Sync, G: Genotype<T>>(
m: usize,
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
parents_children: &[Reproduction],
) {
if m < parents_children.len() * 2 {
panic!(
"m < children length. m: {}, children_len: {}",
m,
parents_children.len() * 2
)
}
let mut killed = Vec::with_capacity(parents_children.len() * 2);
let mut choosable: Vec<usize> = Vec::with_capacity(m);
let mut rgen = SmallRng::from_entropy();
let mut children: Vec<usize> = Vec::with_capacity(parents_children.len() * 2);
for (child0, child1) in parents_children
.iter()
.map(|pc| (pc.children.0, pc.children.1))
{
children.push(child0);
children.push(child1);
}
for _i in 0..m {
let mut chosen = rgen.sample(Uniform::from(0..population_size));
while choosable.contains(&chosen) {
chosen = rgen.sample(Uniform::from(0..population_size));
}
choosable.push(chosen);
}
for child in children {
let most_similar = choosable
.par_iter()
.enumerate()
.map(|(i, el)| (i, population[child].ind.distance(&population[*el].ind)))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap()
.0;
if population[choosable[most_similar]].fitness.unwrap().fitness
> population[child].fitness.unwrap().fitness
{
killed.push(child);
} else {
killed.push(choosable[most_similar]);
}
choosable.remove(most_similar);
}
killed.par_sort_unstable();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn random_most_similar<T: PartialEq + Send + Sync, G: Genotype<T>>(
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
) {
let tobekilled = population.len() - population_size;
let mut killed = Vec::with_capacity(tobekilled);
let mut choosable: Vec<usize> = population.iter().enumerate().map(|(i, _p)| i).collect();
let mut rgen = SmallRng::from_entropy();
let mut n_killed = 0;
while n_killed < tobekilled {
let chosen = rgen.sample(Uniform::from(0..choosable.len()));
let most_similar = choosable
.par_iter()
.enumerate()
.filter(|(i, _el)| *i != chosen)
.map(|(i, el)| (i, population[chosen].ind.distance(&population[*el].ind)))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap()
.0;
if population[choosable[chosen]].fitness.unwrap().fitness
> population[choosable[most_similar]].fitness.unwrap().fitness
{
killed.push(choosable[most_similar]);
} else {
killed.push(choosable[chosen]);
}
if chosen > most_similar {
choosable.remove(chosen);
choosable.remove(most_similar);
} else {
choosable.remove(most_similar);
choosable.remove(chosen);
}
n_killed += 1;
}
killed.par_sort_unstable();
for el in killed.iter().rev() {
population.remove(*el);
}
}
fn most_similar<T: PartialEq + Send + Sync, G: Genotype<T>>(
population_size: usize,
population: &mut Vec<IndWithFitness<T, G>>,
) {
let tobekilled = population.len() - population_size;
let mut killed = Vec::with_capacity(tobekilled);
let mut dists: Vec<Vec<(usize, f64)>> = population
.iter()
.enumerate()
.map(|_el| Vec::with_capacity(population.len()))
.collect();
dists.par_iter_mut().enumerate().for_each(|(i, dists)| {
for (j, indwf) in population.iter().enumerate() {
dists.push((j, population[i].ind.distance(&indwf.ind)));
}
});
let mut n_killed = 0;
while n_killed < tobekilled {
let (chosen, (most_similar, _distance)) = dists
.par_iter()
.enumerate()
.filter(|(i, _el)| !killed.contains(i))
.map(|(i, distances)| {
(
i,
distances
.iter()
.filter(|(j, _dist)| i != *j && !killed.contains(j))
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap())
.unwrap(),
)
})
.min_by(|x, y| (x.1).1.partial_cmp(&(y.1).1).unwrap())
.unwrap();
if population[chosen].fitness.unwrap().fitness
> population[*most_similar].fitness.unwrap().fitness
{
killed.push(*most_similar);
} else {
killed.push(chosen);
}
n_killed += 1;
}
killed.par_sort_unstable();
for i in killed.iter().rev() {
population.remove(*i);
}
}
}
fn sort_population<T: PartialEq + Send + Sync, G: Genotype<T>>(
population: &mut [IndWithFitness<T, G>],
) {
population.par_sort_unstable_by(|el1, el2| {
el2.fitness
.unwrap()
.fitness
.partial_cmp(&el1.fitness.unwrap().fitness)
.unwrap()
});
}
fn sort_population_by_age<T: PartialEq + Send + Sync, G: Genotype<T>>(
population: &mut [IndWithFitness<T, G>],
) {
population.par_sort_unstable_by(|el1, el2| {
el2.fitness
.unwrap()
.age
.partial_cmp(&el1.fitness.unwrap().age)
.unwrap()
});
}