~ruther/ctu-fee-eoa

944bef5f91e6a509a496111259b61d79d7df3e31 — Rutherther a month ago 44fb8c9
feat(tsp): add nearest neighbor initializer
2 files changed, 148 insertions(+), 5 deletions(-)

M codes/tsp_hw01/src/initializers.rs
M codes/tsp_hw01/src/tsp.rs
M codes/tsp_hw01/src/initializers.rs => codes/tsp_hw01/src/initializers.rs +144 -3
@@ 1,8 1,8 @@
use std::marker::PhantomData;
use std::{cmp::Ordering, marker::PhantomData};
use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, U1};
use rand::{prelude::SliceRandom, RngCore};
use rand::{prelude::SliceRandom, Rng, RngCore};
use eoa_lib::initializer::Initializer;
use crate::tsp::NodePermutation;
use crate::tsp::{NodePermutation, TSPInstance};

pub struct TSPRandomInitializer<D>
where


@@ 36,3 36,144 @@ where
        NodePermutation { permutation: indices }
    }
}

pub struct NearestNeighborInitializer<'a, D: Dim>
where
    DefaultAllocator: nalgebra::allocator::Allocator<D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>
{
    instance: &'a TSPInstance<D>,
    neighbors_order: Vec<Vec<usize>>,
    _phantom: PhantomData<D>,
}

impl<'a, D: Dim> NearestNeighborInitializer<'a, D>
where
    DefaultAllocator: nalgebra::allocator::Allocator<D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>
{
    pub fn new(instance: &'a TSPInstance<D>) -> Self {
        let mut neighbors_order = vec![
            (0..instance.cities.len()).collect::<Vec<_>>();
            instance.cities.len()
        ];

        for node in 0..instance.cities.len() {
            let neighbor_order = &mut neighbors_order[node];
            neighbor_order.sort_by(
                |&neighbor1, &neighbor2| instance.distances(node, neighbor1)
                    .partial_cmp(&instance.distances(node, neighbor2))
                    .unwrap_or(Ordering::Less)
            );
        }

        Self {
            neighbors_order,
            instance,
            _phantom: PhantomData
        }
    }

    fn initialize_from(
        &self,
        size: D,
        index: usize,
        p_choose_second: f64,
        rng: &mut dyn RngCore
    ) -> NodePermutation<D> {
        let mut used_neighbors = vec![false; size.value()];
        let mut individual =
            OVector::zeros_generic(size, U1);

        let mut current_node = index;
        individual[0] = current_node;
        used_neighbors[current_node] = true;

        for i in 1..size.value() {
            let neighbor_order = &self.neighbors_order[current_node];

            let mut next_node = None;
            for &neighbor in neighbor_order {
                if !used_neighbors[neighbor] {
                    next_node = Some(neighbor);

                    // Do not choose third, ...
                    if next_node.is_some() {
                        break;
                    }

                    // Possibility to choose second nearest neighbor
                    if !rng.random_bool(p_choose_second) {
                        break;
                    }
                }
            }

            current_node = next_node.unwrap();
            used_neighbors[current_node] = true;
            individual[i] = current_node;
        }

        NodePermutation { permutation: individual }
    }
}

impl<'a, D: Dim> Initializer<D, NodePermutation<D>> for NearestNeighborInitializer<'a, D>
where
    DefaultAllocator: nalgebra::allocator::Allocator<D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>
{
    fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> NodePermutation<D> {
        let starting_node = rng.random_range(0..size.value());
        self.initialize_from(size, starting_node, rng.random_range(0.0..=0.7), rng)
    }

    fn initialize(
        &self,
        size: D,
        mut count: usize,
        rng: &mut dyn RngCore
    ) -> Vec<NodePermutation<D>> {
        let mut population = Vec::with_capacity(count);

        // 1. Initialize from all starting nodes with nearest (p_choose_second == 0)
        for i in 0..size.value() {
            population.push(self.initialize_from(
                size,
                i,
                0.0,
                rng
            ));

            count -= 1;

            if count == 0 {
                return population;
            }
        }

        // 2. Initialize from all starting nodes with second nearest (p_choose_second == 1)
        for i in 0..size.value() {
            population.push(self.initialize_from(
                size,
                i,
                1.0,
                rng
            ));

            count -= 1;

            if count == 0 {
                return population;
            }
        }

        // 3. Initialize randomly with random p_choose_second (call initialize_single)
        for i in 0..count {
            population.push(self.initialize_single(size, rng))
        }


        population
    }
}

M codes/tsp_hw01/src/tsp.rs => codes/tsp_hw01/src/tsp.rs +4 -2
@@ 27,8 27,8 @@ where
    D: Dim,
    DefaultAllocator: Allocator<D, D>
{
    cities: Vec<TSPCity>,
    distances: OMatrix<f64, D, D>
    pub cities: Vec<TSPCity>,
    pub distances: OMatrix<f64, D, D>
}

impl TSPInstance<Dyn>


@@ 199,6 199,8 @@ where
    type Err = Infallible;

    fn fit(self: &Self, inp: &Self::In) -> Result<Self::Out, Self::Err> {
        assert_eq!(inp.permutation.len(), self.cities.len());
        assert!(TSPInstance::verify_solution(inp));
        Ok(self.solution_cost(inp))
    }
}