From 944bef5f91e6a509a496111259b61d79d7df3e31 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 1 Nov 2025 17:17:49 +0100 Subject: [PATCH] feat(tsp): add nearest neighbor initializer --- codes/tsp_hw01/src/initializers.rs | 147 ++++++++++++++++++++++++++++- codes/tsp_hw01/src/tsp.rs | 6 +- 2 files changed, 148 insertions(+), 5 deletions(-) diff --git a/codes/tsp_hw01/src/initializers.rs b/codes/tsp_hw01/src/initializers.rs index 2875a2013a9312237ff62a3ef6729903a69ef8a3..995af405ba297369e24878550732806e8ce5152d 100644 --- a/codes/tsp_hw01/src/initializers.rs +++ b/codes/tsp_hw01/src/initializers.rs @@ -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 where @@ -36,3 +36,144 @@ where NodePermutation { permutation: indices } } } + +pub struct NearestNeighborInitializer<'a, D: Dim> +where + DefaultAllocator: nalgebra::allocator::Allocator, + DefaultAllocator: nalgebra::allocator::Allocator +{ + instance: &'a TSPInstance, + neighbors_order: Vec>, + _phantom: PhantomData, +} + +impl<'a, D: Dim> NearestNeighborInitializer<'a, D> +where + DefaultAllocator: nalgebra::allocator::Allocator, + DefaultAllocator: nalgebra::allocator::Allocator +{ + pub fn new(instance: &'a TSPInstance) -> Self { + let mut neighbors_order = vec![ + (0..instance.cities.len()).collect::>(); + 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 { + 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> for NearestNeighborInitializer<'a, D> +where + DefaultAllocator: nalgebra::allocator::Allocator, + DefaultAllocator: nalgebra::allocator::Allocator +{ + fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> NodePermutation { + 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> { + 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 + } +} diff --git a/codes/tsp_hw01/src/tsp.rs b/codes/tsp_hw01/src/tsp.rs index a639f900c60774ab3c32615f5b187989f6dffb29..13d9fa4218f0b0ee81cdbcd67f5c80b2f2d1f5e2 100644 --- a/codes/tsp_hw01/src/tsp.rs +++ b/codes/tsp_hw01/src/tsp.rs @@ -27,8 +27,8 @@ where D: Dim, DefaultAllocator: Allocator { - cities: Vec, - distances: OMatrix + pub cities: Vec, + pub distances: OMatrix } impl TSPInstance @@ -199,6 +199,8 @@ where type Err = Infallible; fn fit(self: &Self, inp: &Self::In) -> Result { + assert_eq!(inp.permutation.len(), self.cities.len()); + assert!(TSPInstance::verify_solution(inp)); Ok(self.solution_cost(inp)) } }