genetic_algorithm_tsp/route.rs
1use crate::distance_mat::DistanceMat;
2use crate::subsequence::Subsequence;
3use crate::utils::{change_order, get_random_elem_from_range, ordered_crossover, remove_elem};
4use genetic_algorithm_traits::Individual;
5use rand::seq::SliceRandom;
6use std::cmp::max;
7use std::fmt;
8
9/// The `Route` is an invidiual in the traveling salemens problem that is a valid route.
10#[derive(Debug, PartialEq, Clone, Eq, Hash)]
11pub struct Route {
12 /// The order in which the nodes should be visited.
13 pub indexes: Vec<usize>,
14}
15/// Make Route formattable.
16impl fmt::Display for Route {
17 /// As a string representation of the Route, just display the inidividual
18 /// nodes that are visited.
19 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
20 write!(formatter, "Route({:?})", self.indexes)
21 }
22}
23impl Route {
24 /// Create a new route based on a vector of indexes.
25 ///
26 /// # Arguments
27 ///
28 /// * `indexes` - The order in which the nodes are visited in the Traveling Salesman Problem.
29 ///
30 /// # Examples
31 ///
32 /// ```
33 /// use genetic_algorithm_tsp::route::Route;
34 ///
35 /// let my_individual = Route::from(Route::new(vec![0,1,2]));
36 /// ```
37 pub fn new(indexes: Vec<usize>) -> Self {
38 Self { indexes }
39 }
40 /// Get the number of nodes for this route.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use genetic_algorithm_tsp::route::Route;
46 ///
47 /// let three_node_route = Route::from(Route::new(vec![0,1,2]));
48 /// println!("This route has {} nodes", three_node_route.get_n_nodes());
49 /// ```
50 pub fn get_n_nodes(&self) -> usize {
51 self.indexes.len()
52 }
53}
54impl<'a> Individual<'a> for Route {
55 // The Distance matrix is needed by the individuals to compute their fitness on.
56 type IndividualCost = DistanceMat;
57 /// Randomly changes the order of two nodes in the route
58 ///
59 /// # Arguments
60 ///
61 /// * `prob` - The probability with which the indexes will be changed
62 ///
63 /// # Examples
64 ///
65 /// ```
66 /// use genetic_algorithm_tsp::route::Route;
67 /// use genetic_algorithm_traits::Individual;
68 ///
69 /// let my_individual = Route::from(Route::new(vec![0,1,2]));
70 /// let my_mutated_indiviual = my_individual.mutate(1.0);
71 /// ```
72 fn mutate(self, prob: f32) -> Self {
73 Route {
74 indexes: if get_random_elem_from_range(0.0..1.0) > prob {
75 // With probabilty (1-prop) don't do any mutation.
76 self.indexes
77 } else {
78 // else mutation is applied.
79 // To do so first sample an element to put another element in front of.
80 let put_before_idx: usize = get_random_elem_from_range(0..(self.indexes.len() - 1));
81 change_order(
82 &self.indexes,
83 put_before_idx,
84 // Sample the element that should be put before `put_before_idx`. Should not be
85 // the `put_before_idx` itself.
86 *remove_elem(
87 remove_elem(
88 (0..(self.indexes.len() - 1)).collect::<Vec<usize>>(),
89 put_before_idx,
90 ),
91 max(put_before_idx, 1) - 1,
92 )
93 .choose(&mut rand::thread_rng())
94 .unwrap_or(&((put_before_idx + 1) % self.indexes.len())),
95 )
96 },
97 }
98 }
99 /// Crossover this invidual with another individual to create a new individual. Currently
100 /// uses the `ordered_crossover` algorithm.
101 ///
102 /// # Arguments
103 ///
104 /// * `other` - The other individual you would like to crossover with this individual.
105 ///
106 /// # Examples
107 ///
108 /// ```
109 /// use genetic_algorithm_tsp::route::Route;
110 /// use genetic_algorithm_traits::Individual;
111 ///
112 /// let my_individual = Route::from(Route::new(vec![0,1,2]));
113 /// let my_individual = my_individual.crossover(
114 /// &Route::from(Route::new(vec![1,0,2]))
115 /// );
116 /// ```
117 fn crossover(&self, other: &Route) -> Self {
118 ordered_crossover(
119 self,
120 other,
121 Subsequence::random_subsequence(self.indexes.len()),
122 )
123 }
124 /// Compute how much distance the individual implies with its order of nodes
125 /// and the distance matrix.
126 ///
127 /// # Arguments
128 ///
129 /// * `distance_matrix` - Distance Matrix that determines the length of the proposed
130 /// route
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// use genetic_algorithm_tsp::route::Route;
136 /// use genetic_algorithm_tsp::distance_mat::DistanceMat;
137 /// use genetic_algorithm_traits::Individual;
138 ///
139 /// let my_individual = Route::from(Route::new(vec![0,1,2]));
140 /// println!("Fitness of your individual: {}", my_individual.fitness(
141 /// &DistanceMat::new(vec![vec![0.0,1.0,2.0], vec![1.0,0.0,3.0], vec![2.0,3.0,0.0]]))
142 /// )
143 /// ```
144 ///
145 fn fitness(&self, distance_mat: &DistanceMat) -> f64 {
146 -distance_mat.get_distance(&self.indexes[..])
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 mod test_route {
154 use super::*;
155 use crate::test_utils::valid_permutation;
156 #[test]
157 fn test_format() {
158 let route_to_print = Route::new(vec![1, 2, 3, 4]);
159 assert_eq!(format!("{}", route_to_print), "Route([1, 2, 3, 4])");
160 }
161
162 #[test]
163 fn test_constructor() {
164 let route = Route::new(vec![1, 2, 3, 4]);
165 assert_eq!(route.indexes, vec![1, 2, 3, 4])
166 }
167 #[test]
168 fn test_n_nodes() {
169 let three_node_route = Route::from(Route::new(vec![0, 1, 2]));
170 assert_eq!(three_node_route.get_n_nodes(), 3);
171 }
172 #[test]
173 fn test_mutuate_no_prob() {
174 assert_eq!(
175 Route::new(vec![1, 2, 3, 4]).mutate(0.0).indexes,
176 vec![1, 2, 3, 4]
177 )
178 }
179 // Run the following test five times.
180 #[test]
181 #[test]
182 #[test]
183 #[test]
184 #[test]
185 fn test_mutuate_100_prob() {
186 assert_ne!(
187 Route::new(vec![1, 2, 3, 4]).mutate(1.0).indexes,
188 vec![1, 2, 3, 4]
189 )
190 }
191 #[test]
192 fn test_mutuate_100_prob_3_elems() {
193 assert_ne!(Route::new(vec![1, 2, 3]).mutate(1.0).indexes, vec![1, 2, 3])
194 }
195 #[test]
196 fn test_mutate_simple_run() {
197 let test_route = Route::new(vec![1, 2, 0]);
198 valid_permutation(&test_route.indexes, &test_route.clone().mutate(0.5).indexes);
199 }
200 }
201 mod test_crossover {
202 use super::*;
203 use crate::test_utils::valid_permutation;
204
205 #[test]
206 fn random_test_10() {
207 let n_tests = 1000;
208 let route_a = Route {
209 indexes: vec![0, 12, 7, 3, 9, 8, 11, 5, 13, 1, 4, 6, 10, 15, 2, 14],
210 };
211 let route_b = Route {
212 indexes: vec![7, 10, 15, 12, 2, 9, 5, 3, 1, 6, 4, 13, 14, 11, 8, 0],
213 };
214 let mut n_no_crossover = 0;
215 for _ in 1..n_tests {
216 let result = route_a.crossover(&route_b);
217 if result.indexes == route_a.indexes || result.indexes == route_b.indexes {
218 n_no_crossover += 1;
219 }
220 valid_permutation(&result.indexes, &route_a.indexes);
221 valid_permutation(&result.indexes, &route_a.indexes);
222 }
223 assert!(n_no_crossover <= n_tests / 5);
224 }
225 }
226 mod test_fitness {
227 use super::*;
228 use crate::test_utils::test_dist_mat;
229 #[test]
230 fn simple_functionality_test() {
231 let distance_mat = test_dist_mat();
232 let route = Route::new(vec![1, 2, 0]);
233 assert_eq!(route.fitness(&distance_mat), -6.0);
234 }
235 }
236}