From 1d889574a80d4c9b9e2188a0ded547f359ba9881 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Tue, 28 Oct 2025 13:54:56 +0100 Subject: [PATCH] feat: add utilities to perturbation to iterate through wrappers easily Make PerturbationOperator implement Any, allowing it to be downcasted. Make WrapperPerturbation for perturbations that wrap other perturbations, such as the mutation perturbation and bounded perturbation. Make ListWrapperPerturbation for pertrubations that wrap multiple pertrubations, such as the combined perturbation. This should allow for easily looking through perturbations, finding all perturbations of a specific type and modifying them. One use case can be for changing the probability of a mutation perturbation during evolution. --- codes/eoa_lib/src/perturbation/mod.rs | 102 ++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/codes/eoa_lib/src/perturbation/mod.rs b/codes/eoa_lib/src/perturbation/mod.rs index 19f53273c7020293c9e6d8f756f48114ee4b756d..730e6564675a968ee8edcd3de951f29f4c3b8b8c 100644 --- a/codes/eoa_lib/src/perturbation/mod.rs +++ b/codes/eoa_lib/src/perturbation/mod.rs @@ -1,4 +1,4 @@ -use std::marker::PhantomData; +use std::{any::Any, borrow::{Borrow, BorrowMut}, marker::PhantomData}; use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, SVector}; use rand::{distr::Distribution, Rng, RngCore}; @@ -6,12 +6,74 @@ use rand_distr::{uniform, Normal, NormalError, Uniform}; use crate::binary_string::BinaryString; -pub trait PerturbationOperator { +pub trait AnyPerturbationOperator: Any { + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; +} + +pub trait PerturbationOperator: AnyPerturbationOperator { type Chromosome; fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore); } +impl AnyPerturbationOperator for T +where + T: Any + 'static +{ + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + +pub trait WrapperPerturbation: PerturbationOperator { + fn borrow_any(&self) -> &dyn Any; + fn borrow_any_mut(&mut self) -> &mut dyn Any; + + fn borrow(&self) -> Option<&TPerturbation> { + self.borrow_any().downcast_ref() + } + + fn borrow_mut(&mut self) -> Option<&mut TPerturbation> { + self.borrow_any_mut().downcast_mut() + } +} + +pub trait ListWrapperPerturbation: PerturbationOperator { + fn borrow_list_any<'a>(&'a self) -> impl Iterator; + fn borrow_list_any_mut<'a>(&'a mut self) -> impl Iterator; + + fn borrow<'a, T: 'static>(&'a self, index: usize) -> Option<&'a T> { + self.borrow_list_any() + .nth(index) + .map(|perturbation| perturbation.downcast_ref()) + .flatten() + } + + fn borrow_mut<'a, T: 'static>(&'a mut self, index: usize) -> Option<&'a mut T> { + self.borrow_list_any_mut() + .nth(index) + .map(|perturbation| perturbation.downcast_mut()) + .flatten() + } +} + +pub struct IdentityPerturbation { + _phantom: PhantomData +} + +impl PerturbationOperator for IdentityPerturbation { + type Chromosome = TChromosome; + + fn perturb(&self, _: &mut Self::Chromosome, _: &mut dyn RngCore) { + // Do nothing. + } +} + pub struct BinaryStringBitPerturbation { p: f64, _phantom: PhantomData @@ -133,7 +195,7 @@ impl RandomDistributionPerturbation> { } } -impl, const LEN: usize> PerturbationOperator for RandomDistributionPerturbation { +impl + 'static, const LEN: usize> PerturbationOperator for RandomDistributionPerturbation { type Chromosome = SVector; fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) { @@ -256,6 +318,16 @@ where } } +impl> + 'static> WrapperPerturbation for BoundedPerturbation { + fn borrow_any(&self) -> &dyn Any { + self.perturbation.as_any() + } + + fn borrow_any_mut(&mut self) -> &mut dyn Any { + self.perturbation.as_any_mut() + } +} + /// Perform given perturbation only with given probability pub struct MutationPerturbation { perturbation: Box>, @@ -271,7 +343,7 @@ impl MutationPerturbation { } } -impl PerturbationOperator for MutationPerturbation { +impl PerturbationOperator for MutationPerturbation { type Chromosome = T; fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) { @@ -281,6 +353,16 @@ impl PerturbationOperator for MutationPerturbation { } } +impl WrapperPerturbation for MutationPerturbation { + fn borrow_any(&self) -> &dyn Any { + self.perturbation.as_any() + } + + fn borrow_any_mut(&mut self) -> &mut dyn Any { + self.perturbation.as_any_mut() + } +} + pub struct CombinedPerturbation { perturbations: Vec>>, } @@ -293,7 +375,7 @@ impl CombinedPerturbation { } } -impl PerturbationOperator for CombinedPerturbation { +impl PerturbationOperator for CombinedPerturbation { type Chromosome = T; fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) { @@ -303,6 +385,16 @@ impl PerturbationOperator for CombinedPerturbation { } } +impl ListWrapperPerturbation for CombinedPerturbation { + fn borrow_list_any<'a>(&'a self) -> impl Iterator { + self.perturbations.iter().map(|p| p.as_any()) + } + + fn borrow_list_any_mut<'a>(&'a mut self) -> impl Iterator { + self.perturbations.iter_mut().map(|p| p.as_any_mut()) + } +} + #[cfg(test)] pub mod tests { use crate::binary_string::BinaryString;