~ruther/ctu-fee-eoa

ref: 944bef5f91e6a509a496111259b61d79d7df3e31 ctu-fee-eoa/codes/tsp_hw01/src/initializers.rs -rw-r--r-- 5.0 KiB
944bef5f — Rutherther feat(tsp): add nearest neighbor initializer a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use std::{cmp::Ordering, marker::PhantomData};
use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, U1};
use rand::{prelude::SliceRandom, Rng, RngCore};
use eoa_lib::initializer::Initializer;
use crate::tsp::{NodePermutation, TSPInstance};

pub struct TSPRandomInitializer<D>
where
    D: Dim,
    DefaultAllocator: Allocator<D, D>,
{
    _phantom: PhantomData<D>
}

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

impl<D> Initializer<D, NodePermutation<D>> for TSPRandomInitializer<D>
where
    D: Dim,
    DefaultAllocator: Allocator<D, D>,
    DefaultAllocator: Allocator<D>,
{
    fn initialize_single(&self, size: D, rng: &mut dyn RngCore) -> NodePermutation<D> {
        let len = size.value();
        let mut indices = OVector::<usize, D>::from_iterator_generic(size, U1, 0..len);
        indices.as_mut_slice().shuffle(rng);

        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
    }
}