~ruther/ctu-fee-eoa

914ee761437025cc3ab6fc0fa3bfc37cd0c68225 — Rutherther a month ago fddfde9
feat: split params out of PerturbationOperator to allow for non-'static PerturbationOperator

This means PerturbationOperators can now hold non-'static references.
Right away, utilize this in the Random2OptPerturbation for the TSPInstance.
2 files changed, 56 insertions(+), 36 deletions(-)

M codes/eoa_lib/src/perturbation/mod.rs
M codes/tsp_hw01/src/perturbations.rs
M codes/eoa_lib/src/perturbation/mod.rs => codes/eoa_lib/src/perturbation/mod.rs +50 -30
@@ 6,7 6,7 @@ use rand_distr::{uniform, Normal, NormalError, Uniform};

use crate::binary_string::BinaryString;

pub trait AnyPerturbationOperator: Any {
pub trait AsAny: Any {
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
}


@@ 14,7 14,7 @@ pub trait AnyPerturbationOperator: Any {
pub enum Wrapped<'a, T> {
    Single,
    Wrapped(&'a dyn PerturbationOperator<Chromosome = T>),
    ListWrapped(Vec<&'a dyn PerturbationOperator<Chromosome = T>>),
    ListWrapped(Vec<&'a (dyn PerturbationOperator<Chromosome = T>)>),
}

pub enum WrappedMut<'a, T> {


@@ 23,9 23,18 @@ pub enum WrappedMut<'a, T> {
    ListWrapped(Vec<&'a mut dyn PerturbationOperator<Chromosome = T>>),
}

pub trait PerturbationOperator: AnyPerturbationOperator {
pub struct NoParams;
pub trait PerturbationOperator {
    type Chromosome;

    fn try_get_params(&self) -> Option<&dyn Any> {
        None
    }

    fn try_get_params_mut(&mut self) -> Option<&mut dyn Any> {
        None
    }

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

    fn wrapped(&self) -> Wrapped<'_, Self::Chromosome> {


@@ 37,9 46,7 @@ pub trait PerturbationOperator: AnyPerturbationOperator {
    }
}

impl<T: PerturbationOperator> AnyPerturbationOperator for T
where
    T: Any + 'static
impl<T: Any + 'static> AsAny for T
{
    fn as_any(&self) -> &dyn Any {
        self


@@ 53,7 60,7 @@ pub struct IdentityPerturbation<TChromosome> {
    _phantom: PhantomData<TChromosome>
}

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

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


@@ 212,7 219,7 @@ impl<const LEN: usize> RandomDistributionPerturbation<LEN, Uniform<f64>> {
    }
}

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

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


@@ 336,33 343,36 @@ where
}

/// Perform given perturbation only with given probability
pub struct MutationPerturbation<T> {
    perturbation: Box<dyn PerturbationOperator<Chromosome = T>>,
pub struct MutationPerturbationParams {
    pub probability: f64
}
pub struct MutationPerturbation<'a, T> {
    perturbation: Box<dyn PerturbationOperator<Chromosome = T> + 'a>,
    params: MutationPerturbationParams
}

impl<T: 'static> MutationPerturbation<T> {
    pub fn new(perturbation: Box<dyn PerturbationOperator<Chromosome = T>>, probability: f64) -> Self {
impl<'a, T> MutationPerturbation<'a, T> {
    pub fn new(perturbation: Box<dyn PerturbationOperator<Chromosome = T> + 'a>, probability: f64) -> Self {
        Self {
            perturbation,
            probability
            params: MutationPerturbationParams { probability }
        }
    }

    pub fn apply_to_mutations(
        base_perturbation: &mut dyn PerturbationOperator<Chromosome = T>,
        apply: &mut dyn FnMut(&mut MutationPerturbation<T>)
        apply: &mut dyn FnMut(&mut MutationPerturbationParams)
    ) {
        apply_to_perturbations(base_perturbation, apply);
    }
}

pub fn apply_to_perturbations<T: 'static, U: PerturbationOperator<Chromosome = T>>(
pub fn apply_to_perturbations<T, U: AsAny>(
    base_perturbation: &mut dyn PerturbationOperator<Chromosome = T>,
    apply: &mut dyn FnMut(&mut U)
) {
    if let Some(mutation) = base_perturbation.as_any_mut().downcast_mut::<U>() {
        apply(mutation);
    if let Some(params) = base_perturbation.try_get_params_mut().map(|p| p.downcast_mut::<U>()).flatten() {
        apply(params)
    }

    match base_perturbation.wrapped_mut() {


@@ 378,11 388,11 @@ pub fn apply_to_perturbations<T: 'static, U: PerturbationOperator<Chromosome = T
    };
}

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

    fn perturb(&self, chromosome: &mut Self::Chromosome, rng: &mut dyn RngCore) {
        if rng.random_bool(self.probability) {
        if rng.random_bool(self.params.probability) {
            self.perturbation.perturb(chromosome, rng);
        }
    }


@@ 394,21 404,29 @@ impl<T: 'static> PerturbationOperator for MutationPerturbation<T> {
    fn wrapped_mut(&mut self) -> WrappedMut<'_, Self::Chromosome> {
        WrappedMut::Wrapped(self.perturbation.as_mut())
    }

    fn try_get_params(&self) -> Option<&dyn Any> {
        Some(self.params.as_any())
    }

    fn try_get_params_mut(&mut self) -> Option<&mut dyn Any> {
        Some(self.params.as_any_mut())
    }
}

pub struct CombinedPerturbation<T> {
    perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T>>>,
pub struct CombinedPerturbation<'a, T> {
    perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T> + 'a>>,
}

impl<T> CombinedPerturbation<T> {
    pub fn new(perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T>>>) -> Self {
impl<'a, T> CombinedPerturbation<'a, T> {
    pub fn new(perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T> + 'a>>) -> Self {
        Self {
            perturbations,
        }
    }
}

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

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


@@ 428,23 446,25 @@ impl<T: 'static> PerturbationOperator for CombinedPerturbation<T> {
        WrappedMut::ListWrapped(
            self.perturbations
                .iter_mut()
                .map(|p| p.as_mut()).collect())
                .map::<&mut (dyn PerturbationOperator<Chromosome = Self::Chromosome> + '_), _>
                (|p| p.as_mut()).collect()
        )
    }
}

pub struct OneOfPerturbation<T> {
    perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T>>>
pub struct OneOfPerturbation<'a, T> {
    perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T> + 'a>>
}

impl<T> OneOfPerturbation<T> {
    pub fn new(perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T>>>) -> Self {
impl<'a, T> OneOfPerturbation<'a, T> {
    pub fn new(perturbations: Vec<Box<dyn PerturbationOperator<Chromosome = T> + 'a>>) -> Self {
        Self {
            perturbations
        }
    }
}

impl<T: 'static> PerturbationOperator for OneOfPerturbation<T> {
impl<'a, T> PerturbationOperator for OneOfPerturbation<'a, T> {
    type Chromosome = T;

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

M codes/tsp_hw01/src/perturbations.rs => codes/tsp_hw01/src/perturbations.rs +6 -6
@@ 121,37 121,37 @@ where
    }
}

pub struct Random2OptPerturbation<D>
pub struct Random2OptPerturbation<'a, D>
where
    D: Dim,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>
{
    instance: TSPInstance<D>,
    instance: &'a TSPInstance<D>,
    retries: usize,
    reversal: ReverseSubsequencePerturbation<D>,
    _phantom: PhantomData<D>
}

impl<D> Random2OptPerturbation<D>
impl<'a, D> Random2OptPerturbation<'a, D>
where
    D: Dim,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>
{
    pub fn new(instance: &TSPInstance<D>, retries: usize) -> Self {
    pub fn new(instance: &'a TSPInstance<D>, retries: usize) -> Self {
        let mut reversal = ReverseSubsequencePerturbation::new();
        reversal.min_subsequence_len = 5;
        reversal.max_subsequence_len = 15;

        Self {
            retries,
            instance: instance.clone(),
            instance,
            reversal,
            _phantom: PhantomData
        }
    }
}

impl<D> PerturbationOperator for Random2OptPerturbation<D>
impl<'a, D> PerturbationOperator for Random2OptPerturbation<'a, D>
where
    D: Dim,
    DefaultAllocator: nalgebra::allocator::Allocator<D>,