use crate::{
algorithm::EvaluatedPopulation,
genetic::{Fitness, Genotype, Parents},
operator::{GeneticOperator, MultiObjective, SelectionOp, SingleObjective},
random::{random_index, random_probability, Rng},
};
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct TournamentSelector {
selection_ratio: f64,
num_individuals_per_parents: usize,
tournament_size: usize,
probability: f64,
remove_selected_individuals: bool,
}
impl TournamentSelector {
pub fn new(
selection_ratio: f64,
num_individuals_per_parents: usize,
tournament_size: usize,
probability: f64,
remove_selected_individuals: bool,
) -> Self {
TournamentSelector {
selection_ratio,
num_individuals_per_parents,
tournament_size,
probability,
remove_selected_individuals,
}
}
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;
}
pub fn tournament_size(&self) -> usize {
self.tournament_size
}
pub fn set_tournament_size(&mut self, value: usize) {
self.tournament_size = value;
}
pub fn probability(&self) -> f64 {
self.probability
}
pub fn set_probability(&mut self, value: f64) {
self.probability = value;
}
pub fn is_remove_selected_individuals(&self) -> bool {
self.remove_selected_individuals
}
pub fn set_remove_selected_individuals(&mut self, value: bool) {
self.remove_selected_individuals = value;
}
}
impl SingleObjective for TournamentSelector {}
impl MultiObjective for TournamentSelector {}
impl GeneticOperator for TournamentSelector {
fn name() -> String {
"Tournament-Selection".to_string()
}
}
impl<G, F> SelectionOp<G, F> for TournamentSelector
where
G: Genotype,
F: Fitness,
{
fn select_from<R>(&self, evaluated: &EvaluatedPopulation<G, F>, rng: &mut R) -> Vec<Parents<G>>
where
R: Rng + Sized,
{
let individuals = evaluated.individuals();
let fitness_values = evaluated.fitness_values();
let mut mating_pool: Vec<usize> = (0..fitness_values.len()).collect();
let num_parents_to_select =
(individuals.len() as f64 * self.selection_ratio + 0.5).floor() as usize;
let target_num_candidates = num_parents_to_select * self.num_individuals_per_parents;
let mut picked_candidates = Vec::with_capacity(target_num_candidates);
let mut count_candidates = 0;
while count_candidates < target_num_candidates && !mating_pool.is_empty() {
let mut tournament = Vec::with_capacity(self.tournament_size);
let mut count_participants = 0;
while count_participants < self.tournament_size {
let random = random_index(rng, mating_pool.len());
let participant = mating_pool[random];
tournament.push(participant);
count_participants += 1;
}
if tournament.is_empty() {
break;
}
tournament.sort_by(|x, y| fitness_values[*y].cmp(&fitness_values[*x]));
let mut prob = self.probability;
let mut prob_redux = 1.;
while prob > 0. {
if random_probability(rng) <= prob {
let picked = tournament.remove(0);
if self.remove_selected_individuals {
if let Some(position) = mating_pool.iter().position(|x| *x == picked) {
mating_pool.remove(position);
}
}
picked_candidates.push(picked);
count_candidates += 1;
}
prob_redux *= 1. - prob;
prob *= prob_redux;
}
}
let mut selected: Vec<Parents<G>> = Vec::with_capacity(num_parents_to_select);
while !picked_candidates.is_empty() {
let mut tuple = Vec::with_capacity(self.num_individuals_per_parents);
for _ in 0..self.num_individuals_per_parents {
let index_i = picked_candidates.remove(0);
tuple.push(individuals[index_i].clone());
}
selected.push(tuple);
}
selected
}
}