use std::marker::PhantomData; use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, Scalar, U1}; use rand::{Rng, RngCore}; use crate::{binary_string::BinaryString, pairing::ParentPairing, replacement::{EvaluatedPopulation, Population}}; pub trait Crossover { type Chromosome; type Out; fn crossover( &self, parents: &EvaluatedPopulation, pairs: impl Iterator, rng: &mut dyn RngCore ) -> Population; } pub struct BinaryOnePointCrossover { _phantom1: PhantomData, _phantom2: PhantomData } impl BinaryOnePointCrossover where DefaultAllocator: Allocator { pub fn new() -> Self { Self { _phantom1: PhantomData, _phantom2: PhantomData, } } fn find_cross_point(&self, chromosome: &BinaryString, rng: &mut dyn RngCore) -> usize { let (min, max) = (0, chromosome.vec.len()); rng.random_range(min..max) } } // TODO: make common functions for ovector that will be used from both BinaryOnePointCrossover and OVectorOnePointCrossover // for not repeating the code. impl Crossover for BinaryOnePointCrossover where D: Dim, DefaultAllocator: Allocator { type Chromosome = BinaryString; type Out = TOutput; fn crossover( &self, population: &EvaluatedPopulation, pairs: impl Iterator, rng: &mut dyn RngCore ) -> Population { let chromosome = &population.population[0].chromosome.vec; let len = population.population[0].chromosome.vec.len(); let indices = OVector::::from_iterator_generic(chromosome.shape_generic().0, U1, 0..len); let mut offsprings = Vec::new(); for pair in pairs { let ( parent1, parent2 ) = (&population.population[pair.0], &population.population[pair.1]); let ( chromosome1, chromosome2 ) = (&parent1.chromosome, &parent2.chromosome); let cross_point = self.find_cross_point(&population.population[0].chromosome, rng); offsprings.push(BinaryString::from_ovector( chromosome1.vec.zip_zip_map( &chromosome2.vec, &indices, |first, second, i| if i <= cross_point { first } else { second } ))); } Population::from_vec(offsprings) } } pub struct OVectorOnePointCrossover { _phantom1: PhantomData, _phantom2: PhantomData, _phantom3: PhantomData } impl OVectorOnePointCrossover where T: Scalar, DefaultAllocator: Allocator { pub fn new() -> Self { Self { _phantom1: PhantomData, _phantom2: PhantomData, _phantom3: PhantomData, } } fn find_cross_point(&self, chromosome: &OVector, rng: &mut dyn RngCore) -> usize { let (min, max) = (0, chromosome.len()); rng.random_range(min..max) } } impl Crossover for OVectorOnePointCrossover where T: Scalar, D: Dim, DefaultAllocator: Allocator { type Chromosome = OVector; type Out = TOutput; fn crossover( &self, population: &EvaluatedPopulation, pairs: impl Iterator, rng: &mut dyn RngCore ) -> Population { let chromosome = &population.population[0].chromosome; let len = population.population[0].chromosome.len(); let indices = OVector::::from_iterator_generic(chromosome.shape_generic().0, U1, 0..len); let mut offsprings = Vec::new(); for pair in pairs { let ( parent1, parent2 ) = (&population.population[pair.0], &population.population[pair.1]); let ( chromosome1, chromosome2 ) = (&parent1.chromosome, &parent2.chromosome); let cross_point = self.find_cross_point(&population.population[0].chromosome, rng); offsprings.push( chromosome1.zip_zip_map( &chromosome2, &indices, |first, second, i| if i <= cross_point { first } else { second } )); } Population::from_vec(offsprings) } }