use std::marker::PhantomData; use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, Const, OMatrix, OVector}; 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 EdgeRecombinationCrossover { _phantom: PhantomData } impl EdgeRecombinationCrossover { pub fn new() -> Self { Self { _phantom: PhantomData } } } impl Crossover<2> for EdgeRecombinationCrossover where D: Dim, DefaultAllocator: Allocator, DefaultAllocator: Allocator, DefaultAllocator: nalgebra::allocator::Allocator> { type Chromosome = NodePermutation; type Out = f64; fn crossover( &self, parents: &eoa_lib::replacement::EvaluatedPopulation, pairs: impl Iterator>, rng: &mut dyn RngCore ) -> eoa_lib::replacement::Population { let mut offsprings = vec![]; let permutation = &parents.population[0].chromosome.permutation; let len = permutation.len(); let mut adjacency_lists = OMatrix::from_element_generic( permutation.shape_generic().0, Const::<4>, None); let mut used_nodes = OVector::from_element_generic( permutation.shape_generic().0, Const::<1>, false ); let mut neighbors_count = OVector::from_element_generic( permutation.shape_generic().0, Const::<1>, 2usize ); for pair in pairs { let parent1 = &parents.population[pair.x].chromosome; let parent2 = &parents.population[pair.y].chromosome; used_nodes.apply(|n| *n = false); // 1. Populate adjacency lists for (&c1, &n, &c2) in parent1.permutation.iter().circular_tuple_windows() { adjacency_lists[(n, 0)] = Some(c1); adjacency_lists[(n, 1)] = Some(c2); neighbors_count[n] = 2; } for (&c1, &n, &c2) in parent2.permutation.iter().circular_tuple_windows() { // Not duplicit? if adjacency_lists[(n, 0)].unwrap() != c1 && adjacency_lists[(n, 1)].unwrap() != c1 { neighbors_count[n] += 1; adjacency_lists[(n, 2)] = Some(c1); } else { // Duplicit adjacency_lists[(n, 2)] = None; } // Not duplicit if adjacency_lists[(n, 0)].unwrap() != c2 && adjacency_lists[(n, 1)].unwrap() != c2 { neighbors_count[n] += 1; adjacency_lists[(n, 3)] = Some(c2); } else { // Duplicit adjacency_lists[(n, 3)] = None; } } let chosen_parent = if rng.random_bool(0.5) { &parent1 } else { &parent2 }; let mut offspring = OVector::from_element_generic(permutation.shape_generic().0, Const::<1>, 0); let mut current_node = chosen_parent.permutation[0]; for i in 0..len-1 { offspring[i] = current_node; used_nodes[current_node] = true; for neighbor in adjacency_lists.row(current_node) { if let Some(neighbor) = neighbor { neighbors_count[*neighbor] -= 1; } } let min_neighbors = adjacency_lists.row(current_node) .iter() .flatten() .filter(|&&neighbor| !used_nodes[neighbor]) .map(|&neighbor| neighbors_count[neighbor]) .min(); let neighbor = if let Some(min_neighbors) = min_neighbors { adjacency_lists.row(current_node) .iter() .flatten() .copied() .filter(|&neighbor| !used_nodes[neighbor] && neighbors_count[neighbor] == min_neighbors) .choose(rng) } else { None }; current_node = if let Some(neighbor) = neighbor { neighbor } else { (0..len).filter(|&node| !used_nodes[node]) .choose(rng) .unwrap() }; } offspring[len - 1] = current_node; offsprings.push(NodePermutation { permutation: offspring }); } Population::from_vec(offsprings) } }