M codes/eoa_lib/src/crossover.rs => codes/eoa_lib/src/crossover.rs +18 -19
@@ 10,16 10,16 @@ pub trait Crossover {
type Out;
fn crossover(
- &mut self,
+ &self,
parents: &EvaluatedPopulation<Self::Chromosome, Self::Out>,
- pairs: impl Iterator<Item = ParentPairing>
+ pairs: impl Iterator<Item = ParentPairing>,
+ rng: &mut dyn RngCore
) -> Population<Self::Chromosome>;
}
pub struct BinaryOnePointCrossover<D: Dim, TOutput> {
_phantom1: PhantomData<D>,
- _phantom2: PhantomData<TOutput>,
- rng: Box<dyn RngCore>
+ _phantom2: PhantomData<TOutput>
}
impl<D: Dim, TOutput> BinaryOnePointCrossover<D, TOutput>
@@ 28,15 28,14 @@ where
{
pub fn new() -> Self {
Self {
- rng: Box::new(rand::rng()),
_phantom1: PhantomData,
_phantom2: PhantomData,
}
}
- fn find_cross_point(&mut self, chromosome: &BinaryString<D>) -> usize {
+ fn find_cross_point(&self, chromosome: &BinaryString<D>, rng: &mut dyn RngCore) -> usize {
let (min, max) = (0, chromosome.vec.len());
- self.rng.random_range(min..max)
+ rng.random_range(min..max)
}
}
@@ 52,9 51,10 @@ where
type Out = TOutput;
fn crossover(
- &mut self,
+ &self,
population: &EvaluatedPopulation<Self::Chromosome, Self::Out>,
- pairs: impl Iterator<Item = ParentPairing>
+ pairs: impl Iterator<Item = ParentPairing>,
+ rng: &mut dyn RngCore
) -> Population<Self::Chromosome> {
let chromosome = &population.population[0].chromosome.vec;
@@ 73,7 73,7 @@ where
chromosome2
) = (&parent1.chromosome, &parent2.chromosome);
- let cross_point = self.find_cross_point(&population.population[0].chromosome);
+ let cross_point = self.find_cross_point(&population.population[0].chromosome, rng);
offsprings.push(BinaryString::from_ovector(
chromosome1.vec.zip_zip_map(
@@ 91,8 91,7 @@ where
pub struct OVectorOnePointCrossover<D: Dim, T: Scalar, TOutput> {
_phantom1: PhantomData<D>,
_phantom2: PhantomData<TOutput>,
- _phantom3: PhantomData<T>,
- rng: Box<dyn RngCore>
+ _phantom3: PhantomData<T>
}
impl<D: Dim, T, TOutput> OVectorOnePointCrossover<D, T, TOutput>
@@ 102,16 101,15 @@ where
{
pub fn new() -> Self {
Self {
- rng: Box::new(rand::rng()),
_phantom1: PhantomData,
_phantom2: PhantomData,
_phantom3: PhantomData,
}
}
- fn find_cross_point(&mut self, chromosome: &OVector<T, D>) -> usize {
+ fn find_cross_point(&self, chromosome: &OVector<T, D>, rng: &mut dyn RngCore) -> usize {
let (min, max) = (0, chromosome.len());
- self.rng.random_range(min..max)
+ rng.random_range(min..max)
}
}
@@ 125,9 123,10 @@ where
type Out = TOutput;
fn crossover(
- &mut self,
+ &self,
population: &EvaluatedPopulation<Self::Chromosome, Self::Out>,
- pairs: impl Iterator<Item = ParentPairing>
+ pairs: impl Iterator<Item = ParentPairing>,
+ rng: &mut dyn RngCore
) -> Population<Self::Chromosome> {
let chromosome = &population.population[0].chromosome;
@@ 146,7 145,7 @@ where
chromosome2
) = (&parent1.chromosome, &parent2.chromosome);
- let cross_point = self.find_cross_point(&population.population[0].chromosome);
+ let cross_point = self.find_cross_point(&population.population[0].chromosome, rng);
offsprings.push(
chromosome1.zip_zip_map(
@@ 158,4 157,4 @@ where
Population::from_vec(offsprings)
}
-}
+}<
\ No newline at end of file
M codes/eoa_lib/src/evolution.rs => codes/eoa_lib/src/evolution.rs +24 -19
@@ 1,4 1,5 @@
use std::error::Error;
+use rand::RngCore;
use crate::{comparison::BetterThanOperator, crossover::Crossover, fitness::FitnessFunction, pairing::Pairing, perturbation::PerturbationOperator, replacement::{EvaluatedChromosome, EvaluatedPopulation, Population, Replacement}, selection::Selection};
@@ 31,14 32,15 @@ pub fn evolution_algorithm<TChromosome: Clone, TResult: Clone>(
initial_population: Population<TChromosome>,
parents_count: usize,
fitness: &impl FitnessFunction<In = TChromosome, Out = TResult>,
- selection: &mut impl Selection<TChromosome, TResult>,
+ selection: &impl Selection<TChromosome, TResult>,
pairing: &mut impl Pairing<Chromosome = TChromosome, Out = TResult>,
- crossover: &mut impl Crossover<Chromosome = TChromosome, Out = TResult>,
- perturbation: &mut impl PerturbationOperator<Chromosome = TChromosome>,
- replacement: &mut impl Replacement<TChromosome, TResult>,
+ crossover: &impl Crossover<Chromosome = TChromosome, Out = TResult>,
+ perturbation: &impl PerturbationOperator<Chromosome = TChromosome>,
+ replacement: &impl Replacement<TChromosome, TResult>,
better_than: &impl BetterThanOperator<TResult>,
// TODO: termination condition
- iterations: usize
+ iterations: usize,
+ rng: &mut dyn RngCore,
) -> Result<EvolutionResult<TChromosome, TResult>, Box<dyn Error>> {
let mut current_population = initial_population.evaluate(fitness)?;
@@ 67,21 69,21 @@ pub fn evolution_algorithm<TChromosome: Clone, TResult: Clone>(
}
// Selection
- let parents = selection.select(parents_count, ¤t_population, better_than);
- let parent_pairings = pairing.pair(¤t_population, parents);
+ let parents = selection.select(parents_count, ¤t_population, better_than, rng).collect::<Vec<_>>();
+ let parent_pairings = pairing.pair(¤t_population, parents.into_iter());
// Crossover
- let mut offsprings = crossover.crossover(¤t_population, parent_pairings);
+ let mut offsprings = crossover.crossover(¤t_population, parent_pairings, rng);
// Mutation
for offspring in offsprings.iter_mut() {
- perturbation.perturb(offspring);
+ perturbation.perturb(offspring, rng);
}
let evaluated_offsprings = offsprings.evaluate(fitness)?;
// Replace
- current_population = replacement.replace(current_population, evaluated_offsprings, better_than);
+ current_population = replacement.replace(current_population, evaluated_offsprings, better_than, rng);
}
let best_candidate = last_best_candidate.evaluated_chromosome.clone();
@@ 99,7 101,7 @@ pub fn evolution_algorithm<TChromosome: Clone, TResult: Clone>(
pub mod tests {
use nalgebra::Const;
- use crate::{binary_string::BinaryString, comparison::MinimizingOperator, crossover::BinaryOnePointCrossover, fitness::one_max::OneMax, initializer::{Initializer, RandomInitializer}, pairing::AdjacentPairing, perturbation::{BinaryStringBitPerturbation, MutationPerturbation}, replacement::{BestReplacement, Population, TournamentReplacement}, selection::{BestSelection, TournamentSelection}};
+ use crate::{binary_string::BinaryString, comparison::MinimizingOperator, crossover::BinaryOnePointCrossover, fitness::one_max::OneMax, initializer::{Initializer, RandomInitializer}, pairing::AdjacentPairing, perturbation::{BinaryStringBitPerturbation, MutationPerturbation}, replacement::{BestReplacement, Population}, selection::TournamentSelection};
use super::evolution_algorithm;
@@ 109,28 111,31 @@ pub mod tests {
let optimum = BinaryString::<Const<D>>::new(vec![0; D]);
let one_max = OneMax::<Const<D>>::new();
- let mut initializer = RandomInitializer::<Const<D>, BinaryString::<Const<D>>>::new_binary();
+ let initializer = RandomInitializer::<Const<D>, BinaryString::<Const<D>>>::new_binary();
let population_size = 512;
- let population = Population::from_iterator(
- initializer.initialize(Const::<D>, population_size)
+ let mut rng_init = rand::rng();
+ let population = Population::from_vec(
+ initializer.initialize(Const::<D>, population_size, &mut rng_init)
);
+ let mut rng = rand::rng();
let result = evolution_algorithm(
population,
population_size / 4,
&one_max,
// TODO: tournament should somehow accept sorting?
// TODO: deterministic and nondeterministic tournament ordering
- &mut TournamentSelection::new(3, 0.8),
+ &TournamentSelection::new(3, 0.8),
&mut AdjacentPairing::new(),
- &mut BinaryOnePointCrossover::new(),
- &mut MutationPerturbation::new(
+ &BinaryOnePointCrossover::new(),
+ &MutationPerturbation::new(
Box::new(BinaryStringBitPerturbation::new(0.05)),
0.1),
- &mut BestReplacement::new(),
+ &BestReplacement::new(),
&MinimizingOperator,
- 1000
+ 1000,
+ &mut rng
).unwrap();
println!("{:?}", result.stats.best_candidates
M codes/eoa_lib/src/initializer/mod.rs => codes/eoa_lib/src/initializer/mod.rs +10 -14
@@ 4,10 4,9 @@ use rand::RngCore;
use crate::{binary_string::BinaryString, bounded::{Bounded, BoundedBinaryString}};
pub trait Initializer<D: Dim, T> {
- fn initialize_single(&mut self, size: D) -> T;
- fn initialize(&mut self, size: D, count: usize) -> impl Iterator<Item = T> {
- let size = size;
- (0..count).map(move |_| self.initialize_single(size))
+ fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> T;
+ fn initialize(&self, size: D, count: usize, rng: &mut dyn RngCore) -> Vec<T> {
+ (0..count).map(|_| self.initialize_single(size, rng)).collect()
}
}
@@ 26,9 25,9 @@ where
D: Dim,
DefaultAllocator: Allocator<D>
{
- fn initialize_single(&mut self, size: D) -> BinaryString<D> {
+ fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> BinaryString<D> {
BinaryString::<D>::from_ovector(
- <Self as Initializer<D, OVector<i8, D>>>::initialize_single(self, size)
+ <Self as Initializer<D, OVector<i8, D>>>::initialize_single(self, size, rng)
)
}
}
@@ 39,20 38,18 @@ where
D: Dim,
DefaultAllocator: Allocator<D>
{
- fn initialize_single(&mut self, size: D) -> OVector<T, D> {
+ fn initialize_single(&self, size: D, _rng: &mut dyn RngCore) -> OVector<T, D> {
OVector::<T, D>::from_element_generic(size, U1, Default::default())
}
}
pub struct RandomInitializer<D: Dim, T> {
- rng: Box<dyn RngCore>,
bounded: Box<dyn Bounded<D, Item = T>>
}
impl<T, D: Dim> RandomInitializer<D, T> {
pub fn new(bounded: Box<dyn Bounded<D, Item = T>>) -> Self {
Self {
- rng: Box::new(rand::rng()),
bounded
}
}
@@ 65,7 62,6 @@ where
{
pub fn new_binary() -> Self {
Self {
- rng: Box::new(rand::rng()),
bounded: Box::new(BoundedBinaryString::unbounded())
}
}
@@ 76,8 72,8 @@ where
D: Dim,
DefaultAllocator: Allocator<D>
{
- fn initialize_single(&mut self, size: D) -> BinaryString<D> {
- self.bounded.next_random(size, &mut self.rng)
+ fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> BinaryString<D> {
+ self.bounded.next_random(size, rng)
}
}
@@ 87,7 83,7 @@ where
D: Dim,
DefaultAllocator: Allocator<D>
{
- fn initialize_single(&mut self, size: D) -> OVector<T, D> {
- self.bounded.next_random(size, &mut self.rng)
+ fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> OVector<T, D> {
+ self.bounded.next_random(size, rng)
}
}
M codes/eoa_lib/src/local_search/mod.rs => codes/eoa_lib/src/local_search/mod.rs +24 -6
@@ 1,5 1,6 @@
use std::error::Error;
use std::fmt::Debug;
+use rand::RngCore;
use crate::binary_string::{BinaryString, BinaryStringConversionError};
use crate::evolutionary_strategy::{EvolutionaryStrategy, IdentityStrategy};
use crate::fitness::FitnessFunction;
@@ 103,7 104,8 @@ pub fn local_search_first_improving<
terminating_condition: &mut TTerminatingCondition,
perturbation_operator: &mut TPerturbationOperator,
better_than_operator: &TBetterThanOperator,
- initial: &TInput
+ initial: &TInput,
+ rng: &mut dyn RngCore
) -> Result<LocalSearchResult<TInput, TResult>, Box<dyn Error>>
where
TResult: Clone,
@@ 119,7 121,8 @@ where
perturbation_operator,
better_than_operator,
&mut IdentityStrategy,
- initial
+ initial,
+ rng
)
}
@@ 130,7 133,8 @@ pub fn local_search_first_improving_evolving<
perturbation_operator: &mut TPerturbationOperator,
better_than_operator: &TBetterThanOperator,
evolutionary_strategy: &mut TEvolutionaryStrategy,
- initial: &TInput
+ initial: &TInput,
+ rng: &mut dyn RngCore
) -> Result<LocalSearchResult<TInput, TResult>, Box<dyn Error>>
where
TResult: Clone,
@@ 152,7 156,7 @@ where
while !terminating_condition.should_terminate(&best_candidate, &stats, cycle) {
let mut perturbed = best_candidate.pos.clone();
- perturbation_operator.perturb(&mut perturbed);
+ perturbation_operator.perturb(&mut perturbed, rng);
let perturbed_fit = fit.fit(&perturbed)?;
// Minimize
@@ 303,6 307,7 @@ pub mod tests {
let sphere = Sphere::new(optimum_real);
let sphere_wrapped = BinaryFitnessWrapper::new(sphere, min.clone(), max.clone());
+ let mut rng = rand::rng();
let result = local_search_first_improving(
&sphere_wrapped,
&mut
@@ 315,6 320,7 @@ pub mod tests {
&mut BinaryStringBitPerturbation::new(0.3),
&MinimizingOperator::new(),
&BinaryString::new(vec![1; 10]),
+ &mut rng,
).unwrap();
println!("{:?}", result);
@@ 337,6 343,7 @@ pub mod tests {
let optimum = SVector::<f64, 2>::repeat(4.0);
let sphere = Sphere::new(optimum);
+ let mut rng = rand::rng();
let result = local_search_first_improving_evolving(
&sphere,
&mut
@@ 350,6 357,7 @@ pub mod tests {
&MinimizingOperator::new(),
&mut IdentityStrategy,
&SVector::<f64, 2>::repeat(-5.0),
+ &mut rng,
).unwrap();
println!("{:?}", result);
@@ 370,6 378,7 @@ pub mod tests {
let one_max = OneMax::<U10>::new();
let optimum = BinaryString::<U10>::new(vec![0; 10]);
+ let mut rng = rand::rng();
let result = local_search_first_improving(
&one_max,
&mut
@@ 382,6 391,7 @@ pub mod tests {
&mut BinaryStringBitPerturbation::new(0.3),
&MinimizingOperator::new(),
&BinaryString::<U10>::new(vec![1; 10]),
+ &mut rng,
).unwrap();
println!("{:?}", result);
@@ 438,6 448,7 @@ pub mod tests {
let max = SVector::<f64, 2>::from_element(15.0);
let rosenbrock_wrapped = BinaryFitnessWrapper::new(rosenbrock, min, max);
+ let mut rng = rand::rng();
let result = local_search_first_improving(
&rosenbrock_wrapped,
&mut
@@ 450,6 461,7 @@ pub mod tests {
&mut BinaryStringBitPerturbation::new(0.1),
&MinimizingOperator::new(),
&BinaryString::new(vec![0; 10]),
+ &mut rng,
).unwrap();
println!("{:?}", result);
@@ 473,11 485,12 @@ pub mod tests {
let max = SVector::<f64, 2>::from_vec(vec![10.0, 10.0]);
let min = -SVector::<f64, 2>::from_vec(vec![10.0, 10.0]);
- let mut initializer =
+ let initializer =
RandomInitializer::<U2, OVector<f64, U2>>::new(Box::new(BoundedOVector::<U2>::new(min, max)));
let linear = Linear::new(7.0, SVector::<f64, 2>::from_vec(vec![0.2, -0.5]));
+ let mut rng = rand::rng();
let result = local_search_first_improving(
&linear,
&mut
@@ 493,7 506,8 @@ pub mod tests {
max,
BoundedPerturbationStrategy::Retry(10)),
&MinimizingOperator::new(),
- &initializer.initialize_single(U2),
+ &initializer.initialize_single(U2, &mut rng),
+ &mut rng,
).unwrap();
println!("{:?}", result);
@@ 519,6 533,7 @@ pub mod tests {
let linear = Linear::new(7.0, SVector::<f64, 2>::from_vec(vec![0.2, -0.5]));
+ let mut rng = rand::rng();
let result = local_search_first_improving(
&linear,
&mut
@@ 535,6 550,7 @@ pub mod tests {
BoundedPerturbationStrategy::Retry(10)),
&MinimizingOperator::new(),
&SVector::<f64, 2>::zeros(),
+ &mut rng,
).unwrap();
println!("{:?}", result);
@@ 560,6 576,7 @@ pub mod tests {
let linear = Linear::new(7.0, SVector::<f64, 2>::from_vec(vec![0.2, -0.5]));
+ let mut rng = rand::rng();
let result = local_search_first_improving_evolving(
&linear,
&mut
@@ 577,6 594,7 @@ pub mod tests {
&MinimizingOperator::new(),
&mut OneToFiveStrategy,
&SVector::<f64, 2>::zeros(),
+ &mut rng,
).unwrap();
println!("{:?}", result);
M codes/eoa_lib/src/perturbation/mod.rs => codes/eoa_lib/src/perturbation/mod.rs +22 -31
@@ 9,11 9,10 @@ use crate::binary_string::BinaryString;
pub trait PerturbationOperator {
type Chromosome;
- fn perturb(&mut self, chromosome: &mut Self::Chromosome);
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore);
}
pub struct BinaryStringBitPerturbation<D> {
- rng: Box<dyn RngCore>,
p: f64,
_phantom: PhantomData<D>
}
@@ 21,7 20,6 @@ pub struct BinaryStringBitPerturbation<D> {
impl<D> BinaryStringBitPerturbation<D> {
pub fn new(p: f64) -> Self {
Self {
- rng: Box::new(rand::rng()),
p,
_phantom: PhantomData
}
@@ 35,14 33,13 @@ where
{
type Chromosome = BinaryString<D>;
- fn perturb(&mut self, chromosome: &mut Self::Chromosome) {
- chromosome.perturb(&mut self.rng, self.p);
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
+ chromosome.perturb(rng, self.p);
}
}
pub struct RandomDistributionPerturbation<const LEN: usize, TDistribution: Distribution<f64>> {
distribution: TDistribution,
- rng: Box<dyn RngCore>,
parameter: f64
}
@@ 50,7 47,6 @@ impl<const LEN: usize> RandomDistributionPerturbation<LEN, Normal<f64>> {
pub fn normal(std_dev: f64) -> Result<Self, NormalError> {
Ok(Self {
distribution: Normal::new(0.0, std_dev)?,
- rng: Box::new(rand::rng()),
parameter: std_dev
})
}
@@ 70,7 66,6 @@ impl<const LEN: usize> RandomDistributionPerturbation<LEN, Uniform<f64>> {
pub fn uniform(range: f64) -> Result<Self, uniform::Error> {
Ok(Self {
distribution: Uniform::new(-range/2.0, range/2.0)?,
- rng: Box::new(rand::rng()),
parameter: range,
})
}
@@ 89,21 84,19 @@ impl<const LEN: usize> RandomDistributionPerturbation<LEN, Uniform<f64>> {
impl<TDistribution: Distribution<f64>, const LEN: usize> PerturbationOperator for RandomDistributionPerturbation<LEN, TDistribution> {
type Chromosome = SVector<f64, LEN>;
- fn perturb(&mut self, chromosome: &mut Self::Chromosome) {
- *chromosome += Self::Chromosome::zeros().map(|_| self.distribution.sample(&mut self.rng));
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
+ *chromosome += Self::Chromosome::zeros().map(|_| self.distribution.sample(rng));
}
}
pub struct PatternPerturbation<const LEN: usize> {
- d: f64,
- rng: Box<dyn RngCore>
+ d: f64
}
impl<const LEN: usize> PatternPerturbation<LEN> {
pub fn new(d: f64) -> Self {
Self {
- d,
- rng: Box::new(rand::rng())
+ d
}
}
}
@@ 111,11 104,11 @@ impl<const LEN: usize> PatternPerturbation<LEN> {
impl<const LEN: usize> PerturbationOperator for PatternPerturbation<LEN> {
type Chromosome = SVector::<f64, LEN>;
- fn perturb(&mut self, chromosome: &mut Self::Chromosome) {
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
// 1. Choose dimension
- let idx = self.rng.random_range(0..LEN);
+ let idx = rng.random_range(0..LEN);
// 2. Direction
- let d = if self.rng.random_bool(0.5) {
+ let d = if rng.random_bool(0.5) {
self.d
} else {
-self.d
@@ 178,9 171,9 @@ impl<const LEN: usize, T: PerturbationOperator<Chromosome = SVector<f64, LEN>>>
chromosome
}
- fn retry_perturb(&mut self, chromosome: &mut SVector<f64, LEN>, retries: Option<usize>) {
+ fn retry_perturb(&self, chromosome: &mut SVector<f64, LEN>, retries: Option<usize>, rng: &mut dyn RngCore) {
let mut perturbed = chromosome.clone();
- self.perturbation.perturb(&mut perturbed);
+ self.perturbation.perturb(&mut perturbed, rng);
if self.within_bounds(&perturbed) {
*chromosome = perturbed;
@@ 191,7 184,7 @@ impl<const LEN: usize, T: PerturbationOperator<Chromosome = SVector<f64, LEN>>>
Some(0) | None => *chromosome = self.bound(perturbed),
Some(retries) => {
*chromosome = perturbed;
- self.retry_perturb(chromosome, Some(retries - 1));
+ self.retry_perturb(chromosome, Some(retries - 1), rng);
}
}
}
@@ 203,10 196,10 @@ where
{
type Chromosome = SVector<f64, LEN>;
- fn perturb(&mut self, chromosome: &mut Self::Chromosome) {
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
match self.strategy {
- BoundedPerturbationStrategy::Trim => self.retry_perturb(chromosome, None),
- BoundedPerturbationStrategy::Retry(retries) => self.retry_perturb(chromosome, Some(retries))
+ BoundedPerturbationStrategy::Trim => self.retry_perturb(chromosome, None, rng),
+ BoundedPerturbationStrategy::Retry(retries) => self.retry_perturb(chromosome, Some(retries), rng)
}
}
}
@@ 214,7 207,6 @@ where
/// Perform given perturbation only with given probability
pub struct MutationPerturbation<T> {
perturbation: Box<dyn PerturbationOperator<Chromosome = T>>,
- rng: Box<dyn RngCore>,
probability: f64
}
@@ 222,7 214,6 @@ impl<T> MutationPerturbation<T> {
pub fn new(perturbation: Box<dyn PerturbationOperator<Chromosome = T>>, probability: f64) -> Self {
Self {
perturbation,
- rng: Box::new(rand::rng()),
probability
}
}
@@ 231,9 222,9 @@ impl<T> MutationPerturbation<T> {
impl<T> PerturbationOperator for MutationPerturbation<T> {
type Chromosome = T;
- fn perturb(&mut self, chromosome: &mut Self::Chromosome) {
- if self.rng.random_bool(self.probability) {
- self.perturbation.perturb(chromosome);
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
+ if rng.random_bool(self.probability) {
+ self.perturbation.perturb(chromosome, rng);
}
}
}
@@ 253,9 244,9 @@ impl<T> CombinedPerturbation<T> {
impl<T> PerturbationOperator for CombinedPerturbation<T> {
type Chromosome = T;
- fn perturb(&mut self, chromosome: &mut Self::Chromosome) {
- for perturbation in self.perturbations.iter_mut() {
- perturbation.perturb(chromosome);
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
+ for perturbation in self.perturbations.iter() {
+ perturbation.perturb(chromosome, rng);
}
}
}
M codes/eoa_lib/src/replacement.rs => codes/eoa_lib/src/replacement.rs +19 -20
@@ 134,10 134,11 @@ impl<TChromosome, TResult: Copy> EvaluatedPopulation<TChromosome, TResult> {
pub trait Replacement<TChromosome, TResult> {
fn replace(
- &mut self,
+ &self,
parents_evaluations: EvaluatedPopulation<TChromosome, TResult>,
offsprings_evaluations: EvaluatedPopulation<TChromosome, TResult>,
- better_than: &dyn BetterThanOperator<TResult>
+ better_than: &dyn BetterThanOperator<TResult>,
+ rng: &mut dyn RngCore
) -> EvaluatedPopulation<TChromosome, TResult>;
}
@@ 150,10 151,11 @@ impl BestReplacement {
impl<TChromosome, TResult: Copy + Debug> Replacement<TChromosome, TResult> for BestReplacement {
fn replace(
- &mut self,
+ &self,
parents_evaluations: EvaluatedPopulation<TChromosome, TResult>,
offsprings_evaluations: EvaluatedPopulation<TChromosome, TResult>,
- better_than: &dyn BetterThanOperator<TResult>
+ better_than: &dyn BetterThanOperator<TResult>,
+ _rng: &mut dyn RngCore
) -> EvaluatedPopulation<TChromosome, TResult> {
let count = parents_evaluations.population.len();
let mut population = parents_evaluations;
@@ 177,10 179,11 @@ impl<TChromosome, TResult: Copy + Debug> Replacement<TChromosome, TResult> for B
pub struct GenerationalReplacement;
impl<TInput, TResult> Replacement<TInput, TResult> for GenerationalReplacement {
fn replace(
- &mut self,
+ &self,
parents: EvaluatedPopulation<TInput, TResult>,
mut offsprings: EvaluatedPopulation<TInput, TResult>,
- _: &dyn BetterThanOperator<TResult>
+ _: &dyn BetterThanOperator<TResult>,
+ _rng: &mut dyn RngCore
) -> EvaluatedPopulation<TInput, TResult> {
let count = parents.population.len();
if count == offsprings.population.len() {
@@ 198,24 201,21 @@ impl<TInput, TResult> Replacement<TInput, TResult> for GenerationalReplacement {
}
}
-pub struct RandomReplacement {
- rng: Box<dyn RngCore>
-}
+pub struct RandomReplacement;
impl RandomReplacement {
pub fn new() -> Self {
- Self {
- rng: Box::new(rand::rng())
- }
+ Self
}
}
impl<TInput, TResult> Replacement<TInput, TResult> for RandomReplacement {
fn replace(
- &mut self,
+ &self,
parents: EvaluatedPopulation<TInput, TResult>,
offsprings: EvaluatedPopulation<TInput, TResult>,
- _: &dyn BetterThanOperator<TResult>
+ _: &dyn BetterThanOperator<TResult>,
+ rng: &mut dyn RngCore
) -> EvaluatedPopulation<TInput, TResult> {
let count = parents.population.len();
@@ 223,7 223,7 @@ impl<TInput, TResult> Replacement<TInput, TResult> for RandomReplacement {
parents.deconstruct()
.into_iter()
.chain(offsprings.deconstruct().into_iter())
- .choose_multiple(&mut self.rng, count))
+ .choose_multiple(rng, count))
}
}
@@ 246,19 246,18 @@ impl TournamentReplacement {
impl<TInput, TResult: Copy + Debug> Replacement<TInput, TResult> for TournamentReplacement {
fn replace(
- &mut self,
+ &self,
parents: EvaluatedPopulation<TInput, TResult>,
offsprings: EvaluatedPopulation<TInput, TResult>,
- better_than: &dyn BetterThanOperator<TResult>
+ better_than: &dyn BetterThanOperator<TResult>,
+ rng: &mut dyn RngCore
) -> EvaluatedPopulation<TInput, TResult> {
let count = parents.population.len();
let mut population = parents;
population.join(offsprings);
- self.evaluation_pool.clear();
-
// TODO: use a pool instead of allocating vector every run of this function
- let selected = self.selection.select(count, &population, better_than)
+ let selected = self.selection.select(count, &population, better_than, rng)
.collect::<Vec<_>>();
let population = population.deconstruct();
M codes/eoa_lib/src/selection.rs => codes/eoa_lib/src/selection.rs +15 -13
@@ 4,10 4,11 @@ use std::fmt::Debug;
use crate::{comparison::BetterThanOperator, replacement::EvaluatedPopulation};
pub trait Selection<TChromosome, TResult> {
- fn select(&mut self,
+ fn select(&self,
count: usize,
evaluations: &EvaluatedPopulation<TChromosome, TResult>,
- better_than: &dyn BetterThanOperator<TResult>
+ better_than: &dyn BetterThanOperator<TResult>,
+ rng: &mut dyn RngCore
) -> impl Iterator<Item = usize>;
}
@@ 19,10 20,11 @@ impl BestSelection {
}
impl<TChromosome, TResult: Copy> Selection<TChromosome, TResult> for BestSelection {
- fn select(&mut self,
+ fn select(&self,
count: usize,
evaluations: &EvaluatedPopulation<TChromosome, TResult>,
- better_than: &dyn BetterThanOperator<TResult>
+ better_than: &dyn BetterThanOperator<TResult>,
+ _rng: &mut dyn RngCore
) -> impl Iterator<Item = usize> {
let mut idxs = (0..evaluations.population.len())
.collect::<Vec<_>>();
@@ 36,7 38,6 @@ impl<TChromosome, TResult: Copy> Selection<TChromosome, TResult> for BestSelecti
}
pub struct TournamentSelection {
- rng: Box<dyn RngCore>,
p: f64,
k: usize
}
@@ 47,24 48,24 @@ impl TournamentSelection {
assert!(k > 0);
Self {
- rng: Box::new(rand::rng()),
p,
k
}
}
fn tournament<TChromosome, TResult: Debug + Copy>(
- &mut self,
+ &self,
idxs: &mut Vec<usize>,
evaluations: &EvaluatedPopulation<TChromosome, TResult>,
- better_than: &dyn BetterThanOperator<TResult>
+ better_than: &dyn BetterThanOperator<TResult>,
+ rng: &mut dyn RngCore
) -> usize {
idxs.sort_unstable_by(|&i, &j| better_than.ordering(
&evaluations.population[i].evaluation,
&evaluations.population[j].evaluation)
);
- let mut p_selector = self.rng.random_range(0.0..=1.0f64);
+ let mut p_selector = rng.random_range(0.0..=1.0f64);
let p = self.p;
let k = self.k;
@@ 90,18 91,19 @@ impl TournamentSelection {
impl<TChromosome, TResult: Copy + Debug> Selection<TChromosome, TResult> for TournamentSelection {
fn select(
- &mut self,
+ &self,
count: usize,
evaluations: &EvaluatedPopulation<TChromosome, TResult>,
- better_than: &dyn BetterThanOperator<TResult>
+ better_than: &dyn BetterThanOperator<TResult>,
+ rng: &mut dyn RngCore
) -> impl Iterator<Item = usize> {
// Let's reuse a single vector for the indices
let mut k_selected_idxs = vec![0; self.k];
(0..count).map(move |_| {
// Choose k. Do not care if already selected previously.
- (0..evaluations.population.len()).choose_multiple_fill(&mut self.rng, &mut k_selected_idxs);
+ (0..evaluations.population.len()).choose_multiple_fill(rng, &mut k_selected_idxs);
// Tournament between the k
- let index = self.tournament(&mut k_selected_idxs, evaluations, better_than);
+ let index = self.tournament(&mut k_selected_idxs, evaluations, better_than, rng);
index
})
}
M codes/tsp_hw01/src/tsp.rs => codes/tsp_hw01/src/tsp.rs +11 -17
@@ 139,8 139,7 @@ where
D: Dim,
DefaultAllocator: Allocator<D, D>,
{
- _phantom: PhantomData<D>,
- rng: Box<dyn RngCore>
+ _phantom: PhantomData<D>
}
impl<D> Initializer<D, NodePermutation<D>> for TSPRandomInitializer<D>
@@ 149,18 148,17 @@ where
DefaultAllocator: Allocator<D, D>,
DefaultAllocator: Allocator<D>,
{
- fn initialize_single(&mut self, size: D) -> NodePermutation<D> {
+ fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> NodePermutation<D> {
let len = size.value();
let mut indices = OVector::<usize, D>::from_iterator_generic(size, U1, 0..len);
- indices.as_mut_slice().shuffle(&mut self.rng);
+ indices.as_mut_slice().shuffle(rng);
NodePermutation { permutation: indices }
}
}
pub struct SwapPerturbation<D> {
- _phantom: PhantomData<D>,
- rng: Box<dyn RngCore>,
+ _phantom: PhantomData<D>
}
impl<D> PerturbationOperator for SwapPerturbation<D>
@@ 171,20 169,16 @@ where
{
type Chromosome = NodePermutation<D>;
- fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome {
- let first = self.rng.random_range(0..=chromosome.permutation.len());
- let second = self.rng.random_range(0..=chromosome.permutation.len());
-
- let mut new = chromosome.clone();
+ fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
+ let first = rng.random_range(0..=chromosome.permutation.len());
+ let second = rng.random_range(0..=chromosome.permutation.len());
(
- new.permutation[first],
- new.permutation[second]
+ chromosome.permutation[first],
+ chromosome.permutation[second]
) = (
- new.permutation[second],
- new.permutation[first]
+ chromosome.permutation[second],
+ chromosome.permutation[first]
);
-
- new
}
}