30 #ifndef INCLUDE_TSP_PGR_TSP_HPP_
31 #define INCLUDE_TSP_PGR_TSP_HPP_
55 return static_cast< size_t >(
std::rand())/((RAND_MAX + 1u)/n);
63 return static_cast<size_t>((i + 1) % n);
69 return i == 0? n - 1: i -1;
76 template <
typename MATRIX >
77 class TSP:
public MATRIX {
79 using MATRIX::distance;
80 using MATRIX::tourCost;
81 using MATRIX::get_row;
86 explicit TSP(
const MATRIX &_costs)
107 std::ostringstream log1;
120 double initial_temperature,
121 double final_temperature,
122 double cooling_factor,
123 int64_t tries_per_temperature,
124 int64_t max_changes_per_temperature,
125 int64_t max_consecutive_non_changes,
151 const std::set<size_t> &inserted)
const;
173 template <
typename MATRIX >
176 pgassert(std::fabs(tourCost(current_tour) - current_cost) < epsilon);
177 pgassert(std::fabs(tourCost(best_tour) - bestCost) < epsilon);
183 template <
typename MATRIX >
189 if (current_cost < bestCost) {
191 best_tour = current_tour;
192 bestCost = current_cost;
200 template <
typename MATRIX >
204 const std::set<size_t> &inserted)
const {
207 auto distance_row(get_row(current_city));
211 std::ostringstream err;
212 for (
const auto &d : distance_row) {
217 size_t best_city = 0;
218 auto best_distance = (std::numeric_limits<double>::max)();
223 for (
size_t i = 0; i < distance_row.size(); ++i) {
224 if (i == current_city)
continue;
225 if (inserted.find(i) != inserted.end())
continue;
226 if (distance_row[i] < best_distance) {
228 best_distance = distance_row[i];
242 template <
typename MATRIX >
247 std::set<size_t> pending(best_tour.cities.begin(), best_tour.cities.end());
248 std::set<size_t> inserted;
249 std::vector<size_t> tour_to_be;
251 auto current_city = idx_start;
254 std::ostringstream err;
255 auto ps(pending.size());
258 pending.erase(idx_start);
261 pgassert(pending.size() == (ps - 1));
264 tour_to_be.push_back(current_city);
265 inserted.insert(current_city);
267 while (!pending.empty()) {
268 auto next_city = find_closest_city(current_city, inserted);
269 tour_to_be.push_back(next_city);
270 inserted.insert(next_city);
273 auto ps(pending.size());
275 for (
const auto p : pending) {
280 pending.erase(next_city);
283 err <<
"\nafter deleting" << next_city <<
":\t";
284 for (
const auto p : pending) {
287 pgassertwm(pending.size() == (ps - 1), err.str());
290 current_city = next_city;
294 current_tour = Tour(tour_to_be);
295 current_cost = tourCost(current_tour);
323 template <
typename MATRIX >
328 std::ostringstream err;
329 err <<
"\tplace" << place
330 <<
"\tfirst" << first
335 pgassertwm(place < first || place > last, err.str());
361 auto cityP = current_tour.cities[place];
362 auto cityF = current_tour.cities[first];
363 auto cityL = current_tour.cities[last];
364 auto cityP1 = current_tour.cities[
succ(place, n)];
365 auto cityF1 = current_tour.cities[
succ(first, n)];
366 auto cityL1 = current_tour.cities[
succ(last, n)];
369 distance(cityF, cityL1)
370 + distance(cityP, cityF1)
371 + distance(cityL, cityP1)
372 - distance(cityF, cityF1)
373 - distance(cityL, cityL1)
374 - distance(cityP, cityP1));
377 Tour new_tour(current_tour);
378 new_tour.slide(place, first, last);
380 err <<
"\ncurrent_tour:";
381 for (
const auto id : current_tour.cities) {
385 err <<
"\nnew_tour:";
386 for (
const auto id : new_tour.cities) {
390 auto exactDelta = tourCost(new_tour) - tourCost(current_tour);
395 << exactDelta - delta
397 << std::fabs(exactDelta - delta);
398 pgassertwm(std::fabs((exactDelta - delta)) < epsilon, err.str());
415 template <
typename MATRIX >
420 if (
succ(posE, n ) == posA) std::swap(posA, posE);
421 if (
succ(posA, n) == posE) {
422 auto b = current_tour.cities[
pred(posA, n)];
423 auto a = current_tour.cities[posA];
425 auto e = current_tour.cities[posE];
426 auto f = current_tour.cities[
succ(posE, n)];
427 return distance(b, e) + distance(e, a) + distance(a, f)
428 - distance(b, a) - distance(a, e) - distance(e, f);
431 auto b = current_tour.cities[
pred(posA, n)];
432 auto a = current_tour.cities[posA];
433 auto c = current_tour.cities[
succ(posA, n)];
435 auto d = current_tour.cities[
pred(posE, n)];
436 auto e = current_tour.cities[posE];
437 auto f = current_tour.cities[
succ(posE, n)];
440 auto delta = distance(b, e)
441 + distance(e, c) + distance(d, a) + distance(a, f)
442 - distance(b, a) - distance(a, c) - distance(d, e) - distance(e, f);
443 auto new_tour(current_tour);
444 new_tour.swap(posA, posE);
445 auto exactDelta = tourCost(new_tour) - tourCost(current_tour);
446 std::ostringstream log;
450 << exactDelta - delta
452 << std::fabs(exactDelta - delta);
454 pgassertwm(std::fabs((exactDelta - delta)) < epsilon, log.str());
458 return distance(b, e) + distance(e, c) + distance(d, a) + distance(a, f)
459 - distance(b, a) - distance(a, c) - distance(d, e) - distance(e, f);
468 template <
typename MATRIX >
473 if (posA == (posC - 1))
return 0;
474 auto a = current_tour.cities[posA];
475 auto b = current_tour.cities[
succ(posA, n)];
477 auto c = current_tour.cities[posC];
478 auto d = current_tour.cities[
succ(posC, n)];
483 distance(a, c) + distance(b, d) - distance(a, b) - distance(c, d);
484 auto new_tour(current_tour);
485 new_tour.reverse(posA, posC);
486 auto exactDelta = tourCost(new_tour) - tourCost(current_tour);
488 std::ostringstream log;
489 log <<
"exactDelta(" << exactDelta
490 <<
") - delta(" << delta
492 << exactDelta - delta
494 << (exactDelta - delta)
495 <<
" epsilon = " << epsilon;
496 pgassertwm(std::fabs((exactDelta - delta)) < epsilon, log.str());
500 return distance(a, c) + distance(b, d) - distance(a, b) - distance(c, d);
503 template <
typename MATRIX >
507 if (!(n > 2))
return;
512 for (
size_t first = 0; first < n; first++) {
513 for (
size_t last = first + 1; last < n; last++) {
516 auto energyChange = getDeltaSwap(first, last);
518 if (energyChange < 0 && epsilon < std::fabs(energyChange)) {
520 current_cost += energyChange;
521 current_tour.swap(first, last);
529 template <
typename MATRIX >
533 double final_temperature,
534 double cooling_factor,
535 int64_t tries_per_temperature,
536 int64_t max_changes_per_temperature,
537 int64_t max_consecutive_non_changes,
541 if (!(n > 2))
return;
543 clock_t start_time(clock());
546 std::srand(
static_cast<unsigned int>(time(NULL)));
555 for (; final_temperature < temperature; temperature *= cooling_factor) {
558 log <<
"\nCycle(" << temperature <<
") ";
565 int64_t non_change = 0;
566 for (int64_t j = 0; j < tries_per_temperature; j++) {
569 auto which =
rand(2);
579 if (c1 == c2) c2 =
succ(c2, n);
580 if (c1 == (c2 - 1)) c2 =
succ(c2, n);
581 if (c1 > c2) std::swap(c1, c2);
587 auto energyChange = getDeltaReverse(c1, c2);
589 if ( (energyChange < 0
590 && epsilon < std::fabs(energyChange))
594 static_cast<double>(RAND_MAX))
595 < exp(-energyChange / temperature))) {
596 if (energyChange < 0) ++enchg;
600 current_cost += energyChange;
601 current_tour.reverse(c1, c2);
614 auto first =
rand(n);
617 if (first == last) last =
succ(last, n);
618 if (first > last) std::swap(first, last);
619 if (first == 0 && last == (n - 1)) {
620 first =
succ(first, n);
623 pgassert((n - (last - first) - 1) > 0);
624 auto place =
rand((n - (last - first) - 1));
625 place = place < first? place :
626 last + (place - first) + 1;
633 auto energyChange = getDeltaSlide(
636 if ((energyChange < 0
637 && epsilon < std::fabs(energyChange))
640 /
static_cast<double>(RAND_MAX))
641 < exp(-energyChange / temperature))) {
642 if (energyChange < 0) ++enchg;
646 current_cost += energyChange;
647 current_tour.slide(place, first, last);
655 if (max_changes_per_temperature < pathchg
656 && max_consecutive_non_changes < non_change ) {
662 clock_t current_time(clock());
663 double elapsed_time =
static_cast<double>(
664 current_time - start_time) / CLOCKS_PER_SEC;
665 if (time_limit < elapsed_time) {
668 log <<
"\ttotal changes =" << pathchg
669 <<
"\t" << enchg <<
" were because delta energy < 0";
670 if (pathchg == 0)
break;
677 #endif // INCLUDE_TSP_PGR_TSP_HPP_