use rand::Rng;
use crate::error::OperatorResult;
use crate::genome::bounds::MultiBounds;
use crate::genome::traits::EvolutionaryGenome;
pub trait SelectionOperator<G: EvolutionaryGenome>: Send + Sync {
fn select<R: Rng>(
&self,
population: &[(G, f64)], rng: &mut R,
) -> usize;
fn select_many<R: Rng>(
&self,
population: &[(G, f64)],
count: usize,
rng: &mut R,
) -> Vec<usize> {
(0..count).map(|_| self.select(population, rng)).collect()
}
}
pub trait CrossoverOperator<G: EvolutionaryGenome>: Send + Sync {
fn crossover<R: Rng>(&self, parent1: &G, parent2: &G, rng: &mut R) -> OperatorResult<(G, G)>;
fn crossover_probability(&self) -> f64 {
1.0
}
}
pub trait MutationOperator<G: EvolutionaryGenome>: Send + Sync {
fn mutate<R: Rng>(&self, genome: &mut G, rng: &mut R);
fn mutation_probability(&self) -> Option<f64> {
Some(1.0)
}
}
pub trait BoundedMutationOperator<G: EvolutionaryGenome>: MutationOperator<G> {
fn mutate_bounded<R: Rng>(&self, genome: &mut G, bounds: &MultiBounds, rng: &mut R);
}
pub trait BoundedCrossoverOperator<G: EvolutionaryGenome>: CrossoverOperator<G> {
fn crossover_bounded<R: Rng>(
&self,
parent1: &G,
parent2: &G,
bounds: &MultiBounds,
rng: &mut R,
) -> OperatorResult<(G, G)>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::OperatorResult;
use crate::genome::real_vector::RealVector;
use crate::genome::traits::{EvolutionaryGenome, RealValuedGenome};
struct MockSelection;
impl SelectionOperator<RealVector> for MockSelection {
fn select<R: Rng>(&self, population: &[(RealVector, f64)], rng: &mut R) -> usize {
rng.gen_range(0..population.len())
}
}
struct MockCrossover;
impl CrossoverOperator<RealVector> for MockCrossover {
fn crossover<R: Rng>(
&self,
parent1: &RealVector,
parent2: &RealVector,
_rng: &mut R,
) -> OperatorResult<(RealVector, RealVector)> {
OperatorResult::Success((parent2.clone(), parent1.clone()))
}
}
struct MockMutation;
impl MutationOperator<RealVector> for MockMutation {
fn mutate<R: Rng>(&self, genome: &mut RealVector, rng: &mut R) {
if let Some(genes) = genome.as_mut_slice() {
for gene in genes.iter_mut() {
*gene += rng.gen_range(-0.1..0.1);
}
}
}
}
#[test]
fn test_mock_selection() {
let mut rng = rand::thread_rng();
let population: Vec<(RealVector, f64)> = (0..10)
.map(|i| (RealVector::new(vec![i as f64]), i as f64))
.collect();
let selection = MockSelection;
let idx = selection.select(&population, &mut rng);
assert!(idx < population.len());
}
#[test]
fn test_mock_selection_many() {
let mut rng = rand::thread_rng();
let population: Vec<(RealVector, f64)> = (0..10)
.map(|i| (RealVector::new(vec![i as f64]), i as f64))
.collect();
let selection = MockSelection;
let indices = selection.select_many(&population, 5, &mut rng);
assert_eq!(indices.len(), 5);
for idx in indices {
assert!(idx < population.len());
}
}
#[test]
fn test_mock_crossover() {
let mut rng = rand::thread_rng();
let parent1 = RealVector::new(vec![1.0, 2.0, 3.0]);
let parent2 = RealVector::new(vec![4.0, 5.0, 6.0]);
let crossover = MockCrossover;
let result = crossover.crossover(&parent1, &parent2, &mut rng);
assert!(result.is_ok());
let (child1, child2) = result.genome().unwrap();
assert_eq!(child1.genes(), parent2.genes());
assert_eq!(child2.genes(), parent1.genes());
}
#[test]
fn test_mock_mutation() {
let mut rng = rand::thread_rng();
let original = RealVector::new(vec![1.0, 2.0, 3.0]);
let mut genome = original.clone();
let mutation = MockMutation;
mutation.mutate(&mut genome, &mut rng);
assert_ne!(genome, original);
}
}