1use std::{
2 collections::{HashMap, HashSet},
3 hash::Hash,
4 time::{Duration, SystemTime},
5};
6
7use netaheuristics::{
8 algorithms::{
9 lns::LargeNeighborhoodSearch,
10 sa::{FactorSchedule, SimulatedAnnealing},
11 vns::VariableNeighborhoodSearch,
12 },
13 selectors::{AdaptiveSelector, RandomSelector, SequentialSelector},
14 termination::{Terminator, TimeTerminator},
15 Evaluate, ImprovingHeuristic, Operator, Outcome,
16};
17use rand::{Rng, RngCore, SeedableRng};
18
19fn main() {
20 let n = 100;
22 let width = 100.;
23 let height = 100.;
24 let computation_time_max = Duration::new(2, 0);
25
26 let seed = 0;
28 let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
29 let cities: Vec<City> = (0..n)
30 .map(|id| create_random_city(id, width, height, &mut rng))
31 .collect();
32 let cities = Box::new(cities);
33
34 let now = SystemTime::now();
35 let random_tour = construct_random_tour(&mut cities.clone().into_iter(), &mut rng);
36 let duration_random = now.elapsed().unwrap();
37 let random_outcome = Outcome::new(random_tour, duration_random);
38 let now = SystemTime::now();
39 let greedy_tour = construct_greedy_tour(&mut cities.clone().into_iter(), &mut rng);
40 let duration_greedy = now.elapsed().unwrap();
41 let greedy_outcome = Outcome::new(greedy_tour, duration_greedy);
42
43 let operator1 = TwoOpt::new(cities.as_slice());
45 let operator2 = Insertion::new(cities.as_slice());
46 let vns = VariableNeighborhoodSearch::builder()
47 .selector(
48 SequentialSelector::new()
49 .option(operator1)
50 .option(operator2),
51 )
52 .terminator(TimeTerminator::new(computation_time_max))
53 .build();
54 let vns_outcome = vns.optimize_timed(random_outcome.solution().clone());
55
56 let temperature = 100.;
58 let cooling_factor = 0.05;
59 let minimum_acceptance_probability = 0.05;
60 let schedule = FactorSchedule::new(temperature, cooling_factor);
61 let operator = TwoOpt::new(cities.as_slice());
62 let sa = SimulatedAnnealing::builder()
63 .selector(RandomSelector::new(rng.clone()).option(operator))
64 .operator(TwoOptRandom)
65 .cooling_schedule(schedule)
66 .terminator(
67 Terminator::builder()
68 .computation_time(computation_time_max)
69 .build(),
70 )
71 .minimum_acceptance_probability(minimum_acceptance_probability)
72 .rng(rng.clone())
73 .build();
74 let sa_outcome = sa.optimize_timed(random_outcome.solution().clone());
75
76 let n_destroyed_cities = 2;
78 let destroyer = TSPDestroyer::new(n_destroyed_cities);
79 let repairer = TSPRepairer::new(*cities.clone());
80 let lns = LargeNeighborhoodSearch::builder()
81 .selector_destroyer(SequentialSelector::new().option(destroyer))
82 .selector_repairer(SequentialSelector::new().option(repairer))
83 .terminator(
84 Terminator::builder()
85 .computation_time(computation_time_max)
86 .build(),
87 )
88 .rng(rng.clone())
89 .build();
90 let lns_outcome = lns.optimize_timed(random_outcome.solution().clone());
91
92 let decay = 0.5;
94 let operator1 = TwoOpt::new(cities.as_slice());
95 let operator2 = Insertion::new(cities.as_slice());
96 let adaptive_vns = VariableNeighborhoodSearch::builder()
97 .selector(
98 AdaptiveSelector::default_weights(decay, rng)
99 .operator(operator1)
100 .operator(operator2),
101 )
102 .terminator(TimeTerminator::new(computation_time_max))
103 .build();
104 let adaptive_vns_outcome = adaptive_vns.optimize_timed(random_outcome.solution().clone());
105
106 show_solution(random_outcome, "random");
108 show_solution(greedy_outcome, "greedy");
109 show_solution(vns_outcome, "vns");
110 show_solution(adaptive_vns_outcome, "adaptive vns");
111 show_solution(sa_outcome, "sa");
112 show_solution(lns_outcome, "lns");
113}
114
115#[derive(Clone, Debug)]
116struct City {
117 id: usize,
118 x: f32,
119 y: f32,
120}
121
122#[derive(Clone, Debug)]
123struct Tour {
124 cities: Vec<City>,
125}
126
127#[derive(Clone)]
128struct TwoOpt {
129 tour: Option<Tour>,
130 cities: Box<Vec<City>>,
131 index1: usize,
132 index2: usize,
133}
134
135struct TwoOptRandom;
136
137struct Insertion {
138 tour: Option<Tour>,
139 cities: Box<Vec<City>>,
140 index1: usize,
141 index2: usize,
142}
143
144struct TSPDestroyer {
145 n: usize,
146}
147
148struct TSPRepairer {
149 cities: Vec<City>,
150}
151
152fn show_solution<Solution: Evaluate>(outcome: Outcome<Solution>, method: &str) {
153 println!(
154 "{} tour length: {}, computation time: {}",
155 method,
156 outcome.solution().evaluate(),
157 outcome.duration().as_nanos() as f32 * 1e-9
158 );
159}
160
161impl TSPRepairer {
162 fn new(cities: Vec<City>) -> Self {
163 Self { cities }
164 }
165}
166
167impl TSPDestroyer {
168 pub fn new(n: usize) -> Self {
169 Self { n }
170 }
171}
172
173impl Operator for TSPRepairer {
174 type Solution = Tour;
175 fn shake(&self, mut solution: Self::Solution, _rng: &mut dyn rand::RngCore) -> Self::Solution {
176 let map: HashMap<City, usize> = self
177 .cities
178 .iter()
179 .enumerate()
180 .map(|(index, city)| (city.clone(), index))
181 .collect();
182 let cities: HashSet<City> = self.cities.iter().map(|x| x.to_owned()).collect();
183 let cities_tour: HashSet<City> = solution.cities.clone().into_iter().collect();
184 let cities_missing: HashSet<City> = &cities - &cities_tour;
185 let mut cities_missing: Vec<City> = cities_missing.into_iter().collect();
186 cities_missing.sort_by(|x, y| {
187 let index_x = map[x];
188 let index_y = map[y];
189 index_x.cmp(&index_y)
190 });
191
192 for city in cities_missing {
193 let index_to_place = closest_city_to(&city, &solution.cities);
194 solution.cities.insert(index_to_place, city);
195 }
196
197 solution
198 }
199}
200
201fn closest_city_to<'a>(city: &'a City, city_pool: &'a Vec<City>) -> usize {
202 let mut city_closest_index = 0;
203 let mut distance_minimum = distance(city, &city_pool[0]);
204 for i in 1..city_pool.len() {
205 let distance = distance(city, &city_pool[i]);
206 if distance < distance_minimum {
207 distance_minimum = distance;
208 city_closest_index = i;
209 }
210 }
211 city_closest_index
212}
213
214impl Operator for TSPDestroyer {
215 type Solution = Tour;
216 fn shake(&self, mut solution: Self::Solution, rng: &mut dyn rand::RngCore) -> Self::Solution {
217 for _ in 0..self.n {
218 let r = rng.gen_range(0..solution.cities.len());
219 solution.cities.remove(r);
220 }
221 solution
222 }
223}
224
225impl Operator for TwoOptRandom {
226 type Solution = Tour;
227 fn shake(&self, solution: Tour, rng: &mut dyn rand::RngCore) -> Self::Solution {
228 let n = solution.cities.len();
229 let index1 = rng.gen_range(0..n);
230 let index2 = rng.gen_range(0..n);
231
232 let mut neighbor = solution.clone();
233 neighbor.cities.swap(index1, index2);
234 neighbor
235 }
236}
237
238impl<'a> TwoOpt {
239 fn new(cities: &[City]) -> Self {
240 Self {
241 tour: None,
242 cities: Box::new(cities.to_owned()),
243 index1: 0,
244 index2: 0,
245 }
246 }
247
248 fn advance(&mut self) -> bool {
250 let n = self.cities.len();
251 if self.index2 + 1 < n {
253 self.index2 += 1;
254 }
255 else if self.index1 + 1 == n {
257 return false;
258 }
259 else if self.index1 + 1 < n {
261 self.index2 = 0;
262 self.index1 += 1;
263 } else {
264 panic!("unknown state");
265 }
266
267 if self.index1 == self.index2 {
268 self.advance()
269 } else {
270 true
271 }
272 }
273}
274
275impl<'a> Iterator for TwoOpt {
276 type Item = Tour;
277
278 fn next(&mut self) -> Option<Self::Item> {
279 if !self.advance() {
281 return None;
282 }
283
284 if let Some(tour) = &self.tour {
286 Some(tour.swap(self.index1, self.index2))
287 } else {
288 None
289 }
290 }
291}
292
293impl Operator for TwoOpt {
294 type Solution = Tour;
295 fn construct_neighborhood(&self, solution: Tour) -> Box<dyn Iterator<Item = Tour>> {
296 let mut neighborhood = Self::new(self.cities.as_ref());
297 neighborhood.tour = Some(solution.clone());
298 Box::new(neighborhood)
299 }
300
301 fn shake(&self, solution: Self::Solution, rng: &mut dyn rand::RngCore) -> Self::Solution {
302 let n = solution.cities.len();
303 let index1 = rng.gen_range(0..n);
304 let index2 = rng.gen_range(0..n);
305
306 let mut neighbor = solution.clone();
307 neighbor.cities.swap(index1, index2);
308 neighbor
309 }
310}
311
312impl Insertion {
313 fn new(cities: &[City]) -> Self {
314 Self {
315 tour: None,
316 cities: Box::new(cities.to_owned()),
317 index1: 0,
318 index2: 1,
319 }
320 }
321
322 fn advance(&mut self) -> bool {
324 let number_cities = self.cities.len();
326
327 if self.index1 == number_cities - 1 && self.index2 == number_cities - 1 {
329 return false;
330 }
331 else if self.index1 < number_cities - 1 && self.index2 == number_cities - 1 {
333 self.index1 += 1;
334 self.index2 = 0;
335 }
336 else {
338 self.index2 += 1;
339 }
340
341 if self.index1 == self.index2 {
342 self.advance()
343 } else {
344 true
345 }
346 }
347}
348
349impl Iterator for Insertion {
350 type Item = Tour;
351
352 fn next(&mut self) -> Option<Self::Item> {
353 if !self.advance() {
354 return None;
355 }
356
357 if let Some(tour) = &self.tour {
358 let tour = tour.reinsert(self.index1, self.index2);
359 return Some(tour);
360 } else {
361 None
362 }
363 }
364}
365
366impl Operator for Insertion {
367 type Solution = Tour;
368 fn construct_neighborhood(&self, solution: Tour) -> Box<dyn Iterator<Item = Tour>> {
369 let mut neighborhood = Self::new(self.cities.as_ref());
370 neighborhood.tour = Some(solution.clone());
371 Box::new(neighborhood)
372 }
373}
374
375impl City {
376 fn new(id: usize, x: f32, y: f32) -> Self {
377 Self { id, x, y }
378 }
379
380 fn x(&self) -> f32 {
381 self.x
382 }
383
384 fn y(&self) -> f32 {
385 self.y
386 }
387}
388
389impl Eq for City {}
390
391impl PartialEq for City {
392 fn eq(&self, other: &Self) -> bool {
393 self.id == other.id
394 }
395}
396
397impl Hash for City {
398 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
399 self.id.hash(state)
400 }
401}
402
403impl Tour {
404 fn new(cities: Vec<City>) -> Self {
405 Self { cities }
406 }
407
408 fn swap(&self, index1: usize, index2: usize) -> Tour {
417 let mut solution = self.clone();
418 solution.cities.swap(index1, index2);
419 solution
420 }
421
422 fn reinsert(&self, from: usize, to: usize) -> Tour {
423 let mut solution = self.clone();
424 let city = solution.cities.remove(from);
425 solution.cities.insert(to, city);
426 solution
427 }
428}
429
430impl Evaluate for Tour {
431 fn evaluate(&self) -> f32 {
432 if self.cities.is_empty() {
433 return 0.;
434 }
435
436 let mut sum = 0.;
437
438 for i in 0..self.cities.len() - 1 {
439 let ref city1 = self.cities[i];
440 let ref city2 = self.cities[i + 1];
441 sum += distance(city1, city2);
442 }
443
444 sum
445 }
446}
447
448fn construct_greedy_tour(cities: &mut dyn Iterator<Item = City>, rng: &mut dyn RngCore) -> Tour {
449 let mut cities: Vec<City> = cities.collect();
450 let index_initial_city = rng.gen_range(0..cities.len());
451 let city = cities.remove(index_initial_city);
452 let mut cities_tour = vec![city.clone()];
453
454 while !cities.is_empty() {
455 let city = remove_closest_city(&city, &mut cities);
456 cities_tour.push(city);
457 }
458
459 Tour::new(cities_tour)
460}
461
462fn construct_random_tour(cities: &mut dyn Iterator<Item = City>, rng: &mut dyn RngCore) -> Tour {
463 let mut cities: Vec<City> = cities.collect();
464 let mut cities_tour = vec![];
465
466 while !cities.is_empty() {
467 let index_city = rng.gen_range(0..cities.len());
468 let city = cities.remove(index_city);
469 cities_tour.push(city.clone());
470 }
471
472 Tour::new(cities_tour)
473}
474
475fn remove_closest_city(reference_city: &City, cities: &mut Vec<City>) -> City {
476 let distances = cities.iter().map(|city| distance(city, reference_city));
477
478 let mut iter = distances.enumerate();
479 let init = iter.next().unwrap();
480
481 let (index_closest, _) = iter.fold(init, |(index_accum, distance_accum), (index, distance)| {
482 if distance < distance_accum {
483 (index, distance)
484 } else {
485 (index_accum, distance_accum)
486 }
487 });
488
489 cities.remove(index_closest)
490}
491
492fn create_random_city(id: usize, width: f32, height: f32, rng: &mut dyn rand::RngCore) -> City {
493 let w = rng.gen::<f32>() * width;
494 let h = rng.gen::<f32>() * height;
495 City::new(id, w, h)
496}
497
498fn distance(city1: &City, city2: &City) -> f32 {
499 let delta_x = (city1.x() - city2.x()).abs();
500 let delta_y = (city1.y() - city2.y()).abs();
501
502 (delta_x.powf(2.) + delta_y.powf(2.)).sqrt()
503}