From 26456170e0bb9f706af4570dddb4a11743576738 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Mon, 27 Oct 2025 20:50:54 +0100 Subject: [PATCH] refactor: do perturbation in place instead of cloning --- codes/eoa_lib/src/binary_string.rs | 3 +- codes/eoa_lib/src/evolution.rs | 2 +- codes/eoa_lib/src/local_search/mod.rs | 3 +- codes/eoa_lib/src/perturbation/mod.rs | 69 +++++++++++++-------------- 4 files changed, 37 insertions(+), 40 deletions(-) diff --git a/codes/eoa_lib/src/binary_string.rs b/codes/eoa_lib/src/binary_string.rs index 649e5821fc83c487c6b87b2bb790b17b21edd53a..c345bb0eacd70a116c1b8d31af712b58e4df5f0c 100644 --- a/codes/eoa_lib/src/binary_string.rs +++ b/codes/eoa_lib/src/binary_string.rs @@ -71,10 +71,9 @@ where &self.vec } - pub fn perturb(mut self, rng: &mut dyn RngCore, p: f64) -> Self + pub fn perturb(&mut self, rng: &mut dyn RngCore, p: f64) { self.vec.apply(|c| *c = if rng.random::() <= p { 1 - *c } else { *c }); - self } fn to_real_internal<'a, T: DoubleEndedIterator>(vec: T, len: usize, min: f64, max: f64) -> f64 diff --git a/codes/eoa_lib/src/evolution.rs b/codes/eoa_lib/src/evolution.rs index 7c79a48bafca246eba91c88a3540014a84e6a1e2..ab28f13de1efa63a4c0becefbf5ad01d698b15be 100644 --- a/codes/eoa_lib/src/evolution.rs +++ b/codes/eoa_lib/src/evolution.rs @@ -70,7 +70,7 @@ pub fn evolution_algorithm( // Mutation for offspring in offsprings.iter_mut() { - *offspring = perturbation.perturb(offspring); + perturbation.perturb(offspring); } let evaluated_offsprings = offsprings.evaluate(fitness)?; diff --git a/codes/eoa_lib/src/local_search/mod.rs b/codes/eoa_lib/src/local_search/mod.rs index a38edf51c1e075dd602e0eb05b790f7256480dd0..49905b6fbf24c5281f54e0ca3e147c613f422919 100644 --- a/codes/eoa_lib/src/local_search/mod.rs +++ b/codes/eoa_lib/src/local_search/mod.rs @@ -151,7 +151,8 @@ where let mut cycle: usize = 0; while !terminating_condition.should_terminate(&best_candidate, &stats, cycle) { - let perturbed = perturbation_operator.perturb(&best_candidate.pos); + let mut perturbed = best_candidate.pos.clone(); + perturbation_operator.perturb(&mut perturbed); let perturbed_fit = fit.fit(&perturbed)?; // Minimize diff --git a/codes/eoa_lib/src/perturbation/mod.rs b/codes/eoa_lib/src/perturbation/mod.rs index 9af7eaa46141fb36c835625b9493772c454d6432..f3a8d608eeecf35af59dbf1d8fe06fbe168189f4 100644 --- a/codes/eoa_lib/src/perturbation/mod.rs +++ b/codes/eoa_lib/src/perturbation/mod.rs @@ -9,7 +9,7 @@ use crate::binary_string::BinaryString; pub trait PerturbationOperator { type Chromosome; - fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome; + fn perturb(&mut self, chromosome: &mut Self::Chromosome); } pub struct BinaryStringBitPerturbation { @@ -35,8 +35,8 @@ where { type Chromosome = BinaryString; - fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome { - chromosome.clone().perturb(&mut self.rng, self.p) + fn perturb(&mut self, chromosome: &mut Self::Chromosome) { + chromosome.perturb(&mut self.rng, self.p); } } @@ -89,8 +89,8 @@ impl RandomDistributionPerturbation> { impl, const LEN: usize> PerturbationOperator for RandomDistributionPerturbation { type Chromosome = SVector; - fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome { - chromosome + Self::Chromosome::zeros().map(|_| self.distribution.sample(&mut self.rng)) + fn perturb(&mut self, chromosome: &mut Self::Chromosome) { + *chromosome += Self::Chromosome::zeros().map(|_| self.distribution.sample(&mut self.rng)); } } @@ -111,9 +111,7 @@ impl PatternPerturbation { impl PerturbationOperator for PatternPerturbation { type Chromosome = SVector::; - fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome { - let mut chromosome = chromosome.clone(); - + fn perturb(&mut self, chromosome: &mut Self::Chromosome) { // 1. Choose dimension let idx = self.rng.random_range(0..LEN); // 2. Direction @@ -125,8 +123,6 @@ impl PerturbationOperator for PatternPerturbation { // Apply chromosome[idx] += d; - - chromosome } } @@ -182,16 +178,21 @@ impl>> chromosome } - fn retry_perturb(self: &mut Self, chromosome: &SVector, retries: Option) -> SVector { - let perturbed = self.perturbation.perturb(chromosome); + fn retry_perturb(&mut self, chromosome: &mut SVector, retries: Option) { + let mut perturbed = chromosome.clone(); + self.perturbation.perturb(&mut perturbed); if self.within_bounds(&perturbed) { - return perturbed; + *chromosome = perturbed; + return; } match retries { - Some(0) | None => self.bound(perturbed), - Some(retries) => self.retry_perturb(chromosome, Some(retries - 1)) + Some(0) | None => *chromosome = self.bound(perturbed), + Some(retries) => { + *chromosome = perturbed; + self.retry_perturb(chromosome, Some(retries - 1)); + } } } } @@ -202,7 +203,7 @@ where { type Chromosome = SVector; - fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome { + fn perturb(&mut self, chromosome: &mut Self::Chromosome) { match self.strategy { BoundedPerturbationStrategy::Trim => self.retry_perturb(chromosome, None), BoundedPerturbationStrategy::Retry(retries) => self.retry_perturb(chromosome, Some(retries)) @@ -211,13 +212,13 @@ where } /// Perform given perturbation only with given probability -pub struct MutationPerturbation { +pub struct MutationPerturbation { perturbation: Box>, rng: Box, probability: f64 } -impl MutationPerturbation { +impl MutationPerturbation { pub fn new(perturbation: Box>, probability: f64) -> Self { Self { perturbation, @@ -227,23 +228,21 @@ impl MutationPerturbation { } } -impl PerturbationOperator for MutationPerturbation { +impl PerturbationOperator for MutationPerturbation { type Chromosome = T; - fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome { + fn perturb(&mut self, chromosome: &mut Self::Chromosome) { if self.rng.random_bool(self.probability) { - self.perturbation.perturb(chromosome) - } else { - chromosome.clone() + self.perturbation.perturb(chromosome); } } } -pub struct CombinedPerturbation { +pub struct CombinedPerturbation { perturbations: Vec>>, } -impl CombinedPerturbation { +impl CombinedPerturbation { pub fn new(perturbations: Vec>>) -> Self { Self { perturbations, @@ -251,16 +250,13 @@ impl CombinedPerturbation { } } -impl PerturbationOperator for CombinedPerturbation { +impl PerturbationOperator for CombinedPerturbation { type Chromosome = T; - fn perturb(self: &mut Self, chromosome: &Self::Chromosome) -> Self::Chromosome { - let mut current_chromosome = chromosome.clone(); + fn perturb(&mut self, chromosome: &mut Self::Chromosome) { for perturbation in self.perturbations.iter_mut() { - current_chromosome = perturbation.perturb(¤t_chromosome); + perturbation.perturb(chromosome); } - - current_chromosome } } @@ -272,9 +268,10 @@ pub mod tests { fn test_perturb() { let mut rng = rand::rng(); + let mut binary_string1 = BinaryString::new_dyn(vec![1, 1, 0, 0]); + binary_string1.perturb(&mut rng, 1.0); assert_eq!( - *BinaryString::new_dyn(vec![1, 1, 0, 0]) - .perturb(&mut rng, 1.0) + *binary_string1 .vec() .iter() .map(|&x| x) @@ -282,10 +279,10 @@ pub mod tests { vec![0, 0, 1, 1] ); - + let mut binary_string2 = BinaryString::new_dyn(vec![1, 1, 0, 0]); + binary_string2.perturb(&mut rng, 0.0); assert_eq!( - *BinaryString::new_dyn(vec![1, 1, 0, 0]) - .perturb(&mut rng, 0.0) + *binary_string2 .vec() .iter() .map(|&x| x)