~ruther/ctu-fee-eoa

1d889574a80d4c9b9e2188a0ded547f359ba9881 — Rutherther a month ago c6e0be8
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.
1 files changed, 97 insertions(+), 5 deletions(-)

M codes/eoa_lib/src/perturbation/mod.rs
M codes/eoa_lib/src/perturbation/mod.rs => codes/eoa_lib/src/perturbation/mod.rs +97 -5
@@ 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<T: PerturbationOperator> 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<TPerturbation: 'static>(&self) -> Option<&TPerturbation> {
        self.borrow_any().downcast_ref()
    }

    fn borrow_mut<TPerturbation: 'static>(&mut self) -> Option<&mut TPerturbation> {
        self.borrow_any_mut().downcast_mut()
    }
}

pub trait ListWrapperPerturbation: PerturbationOperator {
    fn borrow_list_any<'a>(&'a self) -> impl Iterator<Item = &'a dyn Any>;
    fn borrow_list_any_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut dyn Any>;

    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<TChromosome> {
    _phantom: PhantomData<TChromosome>
}

impl<TChromosome: 'static> PerturbationOperator for IdentityPerturbation<TChromosome> {
    type Chromosome = TChromosome;

    fn perturb(&self, _: &mut Self::Chromosome, _: &mut dyn RngCore) {
        // Do nothing.
    }
}

pub struct BinaryStringBitPerturbation<D> {
    p: f64,
    _phantom: PhantomData<D>


@@ 133,7 195,7 @@ impl<const LEN: usize> RandomDistributionPerturbation<LEN, Uniform<f64>> {
    }
}

impl<TDistribution: Distribution<f64>, const LEN: usize> PerturbationOperator for RandomDistributionPerturbation<LEN, TDistribution> {
impl<TDistribution: Distribution<f64> + 'static, const LEN: usize> PerturbationOperator for RandomDistributionPerturbation<LEN, TDistribution> {
    type Chromosome = SVector<f64, LEN>;

    fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {


@@ 256,6 318,16 @@ where
    }
}

impl<const LEN: usize, T: PerturbationOperator<Chromosome = SVector<f64, LEN>> + 'static> WrapperPerturbation for BoundedPerturbation<LEN, T> {
    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<T> {
    perturbation: Box<dyn PerturbationOperator<Chromosome = T>>,


@@ 271,7 343,7 @@ impl<T> MutationPerturbation<T> {
    }
}

impl<T> PerturbationOperator for MutationPerturbation<T> {
impl<T: 'static> PerturbationOperator for MutationPerturbation<T> {
    type Chromosome = T;

    fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {


@@ 281,6 353,16 @@ impl<T> PerturbationOperator for MutationPerturbation<T> {
    }
}

impl<T: 'static> WrapperPerturbation for MutationPerturbation<T> {
    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<T> {
    perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T>>>,
}


@@ 293,7 375,7 @@ impl<T> CombinedPerturbation<T> {
    }
}

impl<T> PerturbationOperator for CombinedPerturbation<T> {
impl<T: 'static> PerturbationOperator for CombinedPerturbation<T> {
    type Chromosome = T;

    fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {


@@ 303,6 385,16 @@ impl<T> PerturbationOperator for CombinedPerturbation<T> {
    }
}

impl<T: 'static> ListWrapperPerturbation for CombinedPerturbation<T> {
    fn borrow_list_any<'a>(&'a self) -> impl Iterator<Item = &'a dyn Any> {
        self.perturbations.iter().map(|p| p.as_any())
    }

    fn borrow_list_any_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut dyn Any> {
        self.perturbations.iter_mut().map(|p| p.as_any_mut())
    }
}

#[cfg(test)]
pub mod tests {
    use crate::binary_string::BinaryString;