~ruther/ctu-fee-eoa

44fb8c9207de16114ae0b0017575ba6b94f3ecb6 — Rutherther a month ago 11befbf
feat(tsp): add cycle, no and partially mapped crossovers
1 files changed, 199 insertions(+), 1 deletions(-)

M codes/tsp_hw01/src/crossovers.rs
M codes/tsp_hw01/src/crossovers.rs => codes/tsp_hw01/src/crossovers.rs +199 -1
@@ 1,11 1,45 @@
use std::marker::PhantomData;
use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, Const, OMatrix, OVector};
use nalgebra::{allocator::Allocator, Const, DefaultAllocator, Dim, OMatrix, OVector, U1};
use rand::{prelude::IteratorRandom, Rng, RngCore};
use eoa_lib::replacement::Population;
use itertools::Itertools;
use eoa_lib::crossover::Crossover;
use crate::tsp::NodePermutation;

pub struct NoCrossover<D> {
    _phantom: PhantomData<D>
}

impl<D> NoCrossover<D> {
    pub fn new() -> Self {
        Self { _phantom: PhantomData }
    }
}

impl<D> Crossover<2> for NoCrossover<D>
where
    D: Dim,
    DefaultAllocator: Allocator<D>,
{
    type Chromosome = NodePermutation<D>;
    type Out = f64;

    fn crossover(
        &self,
        parents: &eoa_lib::replacement::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        pairs: impl Iterator<Item = eoa_lib::pairing::ParentPairing<2>>,
        _: &mut dyn RngCore
    ) -> Population<Self::Chromosome> {
        let mut offsprings = vec![];
        for pair in pairs {
            offsprings.push(parents.population[pair[0]].chromosome.clone());
            offsprings.push(parents.population[pair[1]].chromosome.clone());
        }

        Population::from_vec(offsprings)
    }
}

pub struct EdgeRecombinationCrossover<D> {
    _phantom: PhantomData<D>
}


@@ 138,3 172,167 @@ where
        Population::from_vec(offsprings)
    }
}

pub struct CycleCrossover<D: Dim> {
    _phantom: PhantomData<D>
}

impl<D: Dim> CycleCrossover<D>
where
    D: Dim,
    DefaultAllocator: Allocator<D>,
{
    pub fn new() -> Self {
        Self { _phantom: PhantomData }
    }

    fn perform_crossover(
        &self,
        parent1: &OVector<usize, D>,
        parent2: &OVector<usize, D>,
        city_positions: &mut [usize]
    ) -> NodePermutation<D> {
        let mut offspring = parent2.clone();

        for (i, &city) in parent1.iter().enumerate() {
            city_positions[city] = i;
        }

        let mut i = 0;
        let mut first = true;
        while i != 0 || first {
            first = false;

            let city = parent1[i];

            offspring[i] = city;

            let city = parent2[i];
            i = city_positions[city];
        }

        NodePermutation { permutation: offspring }
    }
}

impl<D: Dim> Crossover<2> for CycleCrossover<D>
where
    D: Dim,
    DefaultAllocator: Allocator<D>,
{
    type Chromosome = NodePermutation<D>;
    type Out = f64;

    fn crossover(
        &self,
        parents: &eoa_lib::replacement::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        pairs: impl Iterator<Item = eoa_lib::pairing::ParentPairing<2>>,
        rng: &mut dyn RngCore
    ) -> Population<Self::Chromosome> {
        let mut offsprings = vec![];

        let permutation = &parents.population[0].chromosome.permutation;
        let mut city_positions =
            OVector::zeros_generic(permutation.shape_generic().0, U1);

        for pair in pairs {
            let parent1 = &parents.population[pair.x].chromosome;
            let parent2 = &parents.population[pair.y].chromosome;

            let (perm1, perm2) = (
                &parent1.permutation,
                &parent2.permutation
            );

            offsprings.push(self.perform_crossover(perm1, perm2, city_positions.as_mut_slice()));
            offsprings.push(self.perform_crossover(perm2, perm1, city_positions.as_mut_slice()));
        }

        Population::from_vec(offsprings)
    }
}

pub struct PartiallyMappedCrossover<D: Dim> {
    _phantom: PhantomData<D>
}

impl<D: Dim> PartiallyMappedCrossover<D>
where
    D: Dim,
    DefaultAllocator: Allocator<D>,
{
    pub fn new() -> Self {
        Self { _phantom: PhantomData }
    }

    fn find_cross_points(&self, chromosome: &NodePermutation<D>, rng: &mut dyn RngCore) -> [usize; 2] {
        let (min, max) = (0, chromosome.permutation.len());
        let first = rng.random_range(min..max);
        let second = rng.random_range(min..max);

        [ first.min(second), first.max(second) ]
    }

    fn perform_crossover(
        &self,
        parent1: &OVector<usize, D>,
        parent2: &OVector<usize, D>,
        crossover_points: &[usize; 2],
        city_positions: &mut [usize]
    ) -> NodePermutation<D> {
        let mut offspring = parent1.clone();

        for (i, &city) in parent1.iter().enumerate() {
            city_positions[city] = i;
        }

        for i in crossover_points[0]..crossover_points[1] {
            let city = parent2[i];

            offspring.swap_rows(
                i,
                city_positions[city]
            );
        }

        NodePermutation { permutation: offspring }
    }
}

impl<D: Dim> Crossover<2> for PartiallyMappedCrossover<D>
where
    D: Dim,
    DefaultAllocator: Allocator<D>,
{
    type Chromosome = NodePermutation<D>;
    type Out = f64;

    fn crossover(
        &self,
        parents: &eoa_lib::replacement::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        pairs: impl Iterator<Item = eoa_lib::pairing::ParentPairing<2>>,
        rng: &mut dyn RngCore
    ) -> Population<Self::Chromosome> {
        let mut offsprings = vec![];

        let permutation = &parents.population[0].chromosome.permutation;
        let mut city_positions =
            OVector::zeros_generic(permutation.shape_generic().0, U1);

        for pair in pairs {
            let parent1 = &parents.population[pair.x].chromosome;
            let parent2 = &parents.population[pair.y].chromosome;

            let (perm1, perm2) = (
                &parent1.permutation,
                &parent2.permutation
            );

            let cross_points = self.find_cross_points(parent1, rng);
            offsprings.push(self.perform_crossover(perm1, perm2, &cross_points, city_positions.as_mut_slice()));
            offsprings.push(self.perform_crossover(perm2, perm1, &cross_points, city_positions.as_mut_slice()));
        }

        Population::from_vec(offsprings)
    }
}