use crate::{
algorithm::EvaluatedPopulation,
genetic::{AsScalar, Fitness, Genotype, Parents},
operator::{GeneticOperator, SelectionOp, SingleObjective},
random::{random_probability, Rng, WeightedDistribution},
};
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct RouletteWheelSelector {
selection_ratio: f64,
num_individuals_per_parents: usize,
}
impl RouletteWheelSelector {
pub fn new(selection_ratio: f64, num_individuals_per_parents: usize) -> Self {
RouletteWheelSelector {
selection_ratio,
num_individuals_per_parents,
}
}
pub fn selection_ratio(&self) -> f64 {
self.selection_ratio
}
pub fn set_selection_ratio(&mut self, value: f64) {
self.selection_ratio = value;
}
pub fn num_individuals_per_parents(&self) -> usize {
self.num_individuals_per_parents
}
pub fn set_num_individuals_per_parents(&mut self, value: usize) {
self.num_individuals_per_parents = value;
}
}
impl SingleObjective for RouletteWheelSelector {}
impl GeneticOperator for RouletteWheelSelector {
fn name() -> String {
"Roulette-Wheel-Selection".to_string()
}
}
impl<G, F> SelectionOp<G, F> for RouletteWheelSelector
where
G: Genotype,
F: Fitness + AsScalar,
{
fn select_from<R>(&self, evaluated: &EvaluatedPopulation<G, F>, rng: &mut R) -> Vec<Parents<G>>
where
R: Rng + Sized,
{
let individuals = evaluated.individuals();
let num_parents_to_select =
(individuals.len() as f64 * self.selection_ratio + 0.5).floor() as usize;
let mut parents = Vec::with_capacity(num_parents_to_select);
let weighted_distribution =
WeightedDistribution::from_scalar_values(evaluated.fitness_values());
for _ in 0..num_parents_to_select {
let mut tuple = Vec::with_capacity(self.num_individuals_per_parents);
for _ in 0..self.num_individuals_per_parents {
let random = random_probability(rng) * weighted_distribution.sum();
let selected = weighted_distribution.select(random);
tuple.push(individuals[selected].clone());
}
parents.push(tuple);
}
parents
}
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct UniversalSamplingSelector {
selection_ratio: f64,
num_individuals_per_parents: usize,
}
impl UniversalSamplingSelector {
pub fn new(selection_ratio: f64, num_individuals_per_parents: usize) -> Self {
UniversalSamplingSelector {
selection_ratio,
num_individuals_per_parents,
}
}
pub fn selection_ratio(&self) -> f64 {
self.selection_ratio
}
pub fn set_selection_ratio(&mut self, value: f64) {
self.selection_ratio = value;
}
pub fn num_individuals_per_parents(&self) -> usize {
self.num_individuals_per_parents
}
pub fn set_num_individuals_per_parents(&mut self, value: usize) {
self.num_individuals_per_parents = value;
}
}
impl SingleObjective for UniversalSamplingSelector {}
impl GeneticOperator for UniversalSamplingSelector {
fn name() -> String {
"Stochastic-Universal-Sampling-Selection".to_string()
}
}
impl<G, F> SelectionOp<G, F> for UniversalSamplingSelector
where
G: Genotype,
F: Fitness + AsScalar,
{
fn select_from<R>(&self, evaluated: &EvaluatedPopulation<G, F>, rng: &mut R) -> Vec<Parents<G>>
where
R: Rng + Sized,
{
let individuals = evaluated.individuals();
let num_parents_to_select =
(individuals.len() as f64 * self.selection_ratio + 0.5).floor() as usize;
let mut parents = Vec::with_capacity(num_parents_to_select);
let weighted_distribution =
WeightedDistribution::from_scalar_values(evaluated.fitness_values());
let distance = weighted_distribution.sum()
/ (num_parents_to_select * self.num_individuals_per_parents) as f64;
let mut pointer = random_probability(rng) * weighted_distribution.sum();
for _ in 0..num_parents_to_select {
let mut tuple = Vec::with_capacity(self.num_individuals_per_parents);
for _ in 0..self.num_individuals_per_parents {
let selected = weighted_distribution.select(pointer);
tuple.push(individuals[selected].clone());
pointer += distance;
}
parents.push(tuple);
}
parents
}
}