~ruther/ctu-fee-eoa

be955686286443cb9a4dd270d844b9875b62a9e9 — Rutherther a month ago e9632af
feat(tsp): add MinimalSpanningTree initializer
1 files changed, 127 insertions(+), 4 deletions(-)

M codes/tsp_hw01/src/initializers.rs
M codes/tsp_hw01/src/initializers.rs => codes/tsp_hw01/src/initializers.rs +127 -4
@@ 1,8 1,8 @@
use std::{cmp::Ordering, marker::PhantomData};
use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, U1};
use rand::{prelude::SliceRandom, Rng, RngCore};
use nalgebra::{allocator::Allocator, Const, DefaultAllocator, Dim, OVector, U1, U2};
use rand::{prelude::SliceRandom, seq::IteratorRandom, Rng, RngCore};
use eoa_lib::initializer::Initializer;
use crate::tsp::{NodePermutation, TSPInstance};
use crate::{graph::{Graph, minimal_spanning_tree_kruskal, GenericGraph}, tsp::{NodePermutation, TSPCity, TSPEdge, TSPInstance}};

pub struct TSPRandomInitializer<D>
where


@@ 169,10 169,133 @@ where
        }

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

        population
    }
}

pub struct MinimumSpanningTreeInitializer<'a, D: Dim>
where
    DefaultAllocator: nalgebra::allocator::Allocator<D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>
{
    instance: &'a TSPInstance<D>,
    minimal_spanning_tree: GenericGraph<TSPCity, TSPEdge>,
    _phantom: PhantomData<D>,
}

impl<'a, D: Dim> MinimumSpanningTreeInitializer<'a, D>
where
    DefaultAllocator: nalgebra::allocator::Allocator<D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, U2>,
{
    pub fn new(instance: &'a TSPInstance<D>) -> Self {
        let tsp_graph = instance.clone().to_graph();
        let minimal_spanning_tree =
            minimal_spanning_tree_kruskal(
                &tsp_graph,
                None,
                |_| true
            );

        assert_eq!(minimal_spanning_tree.components_count(), 1);
        let minimal_spanning_tree = tsp_graph
            .filter_edges(|i, _|
                          minimal_spanning_tree.edges.contains(&i));

        Self {
            instance,
            minimal_spanning_tree,
            _phantom: PhantomData
        }
    }

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

        let mut current_node = node;
        for i in 0..size.value()-1 {
            individual[i] = current_node;
            used_nodes[current_node] = true;

            let usable_neighbors = self.minimal_spanning_tree
                .neighbor_idxs(current_node)
                .unwrap()
                .filter(|&neighbor| !used_nodes[neighbor]);

            let chosen = usable_neighbors.choose(rng);

            current_node = if let Some(next_node) = chosen {
                next_node
            } else {
                // Choose closest node
                (0..size.value())
                    .filter(|&node| !used_nodes[node])
                    .min_by(|&next_node1, &next_node2|
                            self.instance.distances(current_node, next_node1)
                            .partial_cmp(&self.instance.distances(current_node, next_node2))
                            .unwrap_or(Ordering::Less))
                    // There has to be unused node since we haven't yet used size.value() nodes.
                    .unwrap()
            }
        }

        // The last node
        individual[size.value() - 1] = current_node;

        NodePermutation { permutation: individual }
    }
}

impl<'a, D: Dim> Initializer<D, NodePermutation<D>> for MinimumSpanningTreeInitializer<'a, D>
where
    DefaultAllocator: nalgebra::allocator::Allocator<D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, D>,
    DefaultAllocator: nalgebra::allocator::Allocator<D, U2>,
{
    fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> NodePermutation<D> {
        let starting_node = rng.random_range(0..size.value());
        self.initialize_from(starting_node, size, 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 every node
        for i in 0..size.value() {
            population.push(self.initialize_from(
                i,
                size,
                rng
            ));

            count -= 1;

            if count == 0 {
                return population;
            }
        }

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

        population
    }