use crate::common::*;
use crate::individual::*;
use crate::population::*;
use crate::random::*;
use super::*;
#[derive(Debug, Clone)]
pub struct RandomSelection {
n: usize,
allow_repetition: bool,
}
impl RandomSelection {
pub fn new(n: usize) -> Self {
Self {
n,
allow_repetition: true,
}
}
fn select<'a, G, R>(&self, population: &'a Population<G>, rng: &mut R) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
let all_members: Vec<_> = population.members().collect();
if self.allow_repetition {
let mut selected = vec![];
for _ in 0..self.n {
let member = all_members
.choose(rng)
.expect("cannot select from empty slice");
selected.push(member.clone());
}
selected
} else {
all_members.choose_multiple(rng, self.n).cloned().collect()
}
}
}
impl SelectionOperator for RandomSelection {
fn select_from<'a, G, R>(
&self,
population: &'a Population<G>,
rng: &mut R,
) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
self.select(population, rng)
}
}
#[derive(Debug, Clone)]
pub struct ElitistSelection {
n: usize,
}
impl ElitistSelection {
pub fn new(n: usize) -> Self {
Self { n }
}
fn select<'a, G>(&self, population: &'a Population<G>) -> Vec<Member<'a, G>>
where
G: Genome,
{
let mut members: Vec<_> = population.members().collect();
members.sort_by_fitness();
members[..self.n].to_vec()
}
}
impl SelectionOperator for ElitistSelection {
fn select_from<'a, G, R>(
&self,
population: &'a Population<G>,
_rng: &mut R,
) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
self.select(population)
}
}
#[derive(Debug, Clone)]
pub struct RouletteWheelSelection {
n: usize,
}
impl RouletteWheelSelection {
pub fn new(n: usize) -> Self {
Self { n }
}
fn select<'a, G, R>(&self, population: &'a Population<G>, rng: &mut R) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
let mut selected: Vec<_> = vec![];
let choices: Vec<_> = population.members().enumerate().collect();
for _ in 0..self.n {
let (i, m) = choices
.choose_weighted(rng, |(_, m)| m.fitness_value())
.unwrap_or_else(|e| panic!("Weighted selection failed: {:?}", e));
selected.push(m.clone());
}
selected
}
}
impl SelectionOperator for RouletteWheelSelection {
fn select_from<'a, G, R>(
&self,
population: &'a Population<G>,
rng: &mut R,
) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
self.select(population, rng)
}
}
#[derive(Debug, Clone)]
pub struct TournamentSelection {
n: usize,
}
impl TournamentSelection {
pub fn new(n: usize) -> Self {
Self { n }
}
fn select<'a, G, R>(&self, population: &'a Population<G>, rng: &mut R) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
let psize = population.size();
assert!(psize >= self.n, "select too many individuals!");
let tsize = (psize as f64 / self.n as f64).floor() as usize;
let mut members: Vec<_> = population.members().collect();
members.shuffle(rng);
members
.chunks_mut(tsize)
.map(|mut part| {
part.sort_by_fitness();
part[0].clone()
})
.collect()
}
}
impl SelectionOperator for TournamentSelection {
fn select_from<'a, G, R>(
&self,
population: &'a Population<G>,
rng: &mut R,
) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
self.select(population, rng)
}
}
#[derive(Clone, Debug)]
pub struct StochasticUniversalSampling {
n: usize,
}
impl StochasticUniversalSampling {
pub fn new(n: usize) -> Self {
Self { n }
}
}
impl SelectionOperator for StochasticUniversalSampling {
fn select_from<'a, G, R>(
&self,
population: &'a Population<G>,
rng: &mut R,
) -> Vec<Member<'a, G>>
where
G: Genome,
R: Rng + Sized,
{
let mut members: Vec<_> = population.members().collect();
for m in members.iter() {
assert!(
m.fitness_value().is_sign_positive(),
"invalid member fitness: {:}",
m.fitness_value()
);
}
members.sort_by_fitness();
let fsum = members.iter().fold(0.0, |acc, m| acc + m.fitness_value());
let mut chosen = vec![];
let distance = fsum / self.n as f64;
let start = rng.gen_range(0.0..distance);
let points = (0..self.n).map(|i| start + distance * i as f64);
for p in points {
let mut i = 0;
let mut sum_ = members[i].fitness_value();
while sum_ < p {
i += 1;
sum_ += members[i].fitness_value();
}
chosen.push(members[i].clone())
}
chosen
}
}