diff --git a/src/ga/operators/selection.rs b/src/ga/operators/selection.rs index 6743d6f..15da43c 100644 --- a/src/ga/operators/selection.rs +++ b/src/ga/operators/selection.rs @@ -14,6 +14,7 @@ use crate::ga::{individual::IndividualTrait, Metrics}; /// /// * [RouletteWheel] /// * [Random] +/// * [UniqueRandom] /// * [Rank] /// * [RankR] /// * [Tournament] diff --git a/src/ga/operators/selection/impls.rs b/src/ga/operators/selection/impls.rs index b1950c1..495fe40 100644 --- a/src/ga/operators/selection/impls.rs +++ b/src/ga/operators/selection/impls.rs @@ -1,7 +1,12 @@ use std::{iter::Sum, ops::Index}; use num_traits::{identities::Zero, NumAssignOps}; -use rand::{distributions::Standard, prelude::Distribution, rngs::ThreadRng, Rng}; +use rand::{ + distributions::{Standard, Uniform}, + prelude::Distribution, + rngs::ThreadRng, + Rng, +}; use crate::ga::{individual::IndividualTrait, value_provider::ValueProvider, Metrics}; @@ -101,8 +106,8 @@ where /// /// Individuals are selected with uniform probability. /// -/// **Note**: The same individual *can not* be selected mutiple times. -pub struct Random, R: Rng = ThreadRng> { +/// **Note**: The same individual *can* be selected mutiple times. +pub struct Random, R: Rng + Clone = ThreadRng> { selection_size: SizeValue, rng: R, } @@ -119,7 +124,7 @@ impl> Random { } } -impl, R: Rng> Random { +impl, R: Rng + Clone> Random { /// Returns new instance of [Random] selection operator with custom RNG /// /// ## Arguments @@ -131,21 +136,85 @@ impl, R: Rng> Random { } } -impl, R: Rng> SelectionOperator - for Random +impl, R: Rng + Clone> + SelectionOperator for Random +{ + /// Returns a vector of references to individuals selected to mating pool. + /// + /// Individuals are selected with uniform probability. + /// + /// ### Arguments + /// + /// * `metrics` - [crate::ga::Metrics] information on current stage of the algorithm (iteration, elapsed time, etc.) + /// * `population` - individuals to choose mating pool from + fn apply<'a>(&mut self, metrics: &Metrics, population: &'a [IndividualT]) -> Vec<&'a IndividualT> { + let count = self.selection_size.get(metrics); + let distr_ind = Uniform::new(0, population.len()); + let selection_iter = self + .rng + .clone() + .sample_iter(distr_ind) + .take(count) + .map(|i| &population[i]); + Vec::<&'a IndividualT>::from_iter(selection_iter) + + // We must use index API, as we want to return vector of references, not vector of actual items + // let indices = rand::seq::index::sample(&mut self.rng, population.len(), count); + // let mut selected: Vec<&IndividualT> = Vec::with_capacity(count); + // + // for i in indices { + // selected.push(&population[i]); + // } + // selected + } +} + +/// ### UniqueRandom selection operator +/// +/// This struct implements [SelectionOperator] trait and can be used with GA. +/// +/// Individuals are selected with uniform probability. +/// +/// **Note**: The same individual *can not* be selected mutiple times. +pub struct UniqueRandom, R: Rng = ThreadRng> { + selection_size: SizeValue, + rng: R, +} + +impl> UniqueRandom { + pub fn new(selection_size: SizeValue) -> Self { + Self::with_rng(selection_size, rand::thread_rng()) + } +} + +impl, R: Rng> UniqueRandom { + pub fn with_rng(selection_size: SizeValue, rng: R) -> Self { + Self { selection_size, rng } + } +} + +impl, R: Rng + Clone> + SelectionOperator for UniqueRandom { /// Returns a vector of references to individuals selected to mating pool. /// /// Individuals are selected with uniform probability. /// /// **Note**: The same individual *can not* be selected multiple times. + /// **Note**: Selection size must not be greater than population size, in such case + /// this operator panics. /// /// ### Arguments /// /// * `metrics` - [crate::ga::Metrics] information on current stage of the algorithm (iteration, elapsed time, etc.) /// * `population` - individuals to choose mating pool from + /// + /// ### Panics + /// + /// When selection size is greater than population size. fn apply<'a>(&mut self, metrics: &Metrics, population: &'a [IndividualT]) -> Vec<&'a IndividualT> { let count = self.selection_size.get(metrics); + // We must use index API, as we want to return vector of references, not vector of actual items let indices = rand::seq::index::sample(&mut self.rng, population.len(), count); let mut selected: Vec<&IndividualT> = Vec::with_capacity(count);