Implementacja tabu search dla TSP
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Graph.cpp 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. #include "Graph.h"
  2. #include "Stopwatch.h"
  3. #include <algorithm>
  4. #include <chrono>
  5. #include <queue>
  6. #include <random>
  7. #include <thread>
  8. #include <iostream>
  9. Graph::Graph()
  10. {
  11. //ctor
  12. }
  13. Graph::~Graph()
  14. {
  15. //dtor
  16. }
  17. unsigned Graph::getVertexNumber()
  18. {
  19. return vertexNumber;
  20. }
  21. void Graph::randomGenerateFullGraph(Graph &graph, unsigned maxWeight)
  22. {
  23. std::random_device randomSrc;
  24. std::default_random_engine randomGen(randomSrc());
  25. std::uniform_int_distribution<> weightDist(1, maxWeight);
  26. for(int i = 0; i < graph.vertexNumber; i++)
  27. {
  28. for(int j = 0; j < graph.vertexNumber; j++)
  29. {
  30. if(i != j)
  31. {
  32. // Bez warunku na krawedzie juz wygenerowane...
  33. // ...z tym radzi sobie juz metoda addEdge
  34. int randomWeight = weightDist(randomGen);
  35. graph.addEdge(i, j, randomWeight);
  36. }
  37. }
  38. }
  39. }
  40. std::vector<unsigned> Graph::travellingSalesmanBruteForce(Graph &graph)
  41. {
  42. // ALGORYTM przegladu zupelnego
  43. // Implementacja: Jan Potocki 2017
  44. // (refactoring 2019)
  45. std::vector<unsigned> vertexArray;
  46. // Generowanie "spisu" wierzcholkow
  47. // (od razu w odpowiedniej kolejnosci dla next_permutation)
  48. for(int i = 1; i < graph.vertexNumber; i++)
  49. vertexArray.push_back(i);
  50. std::vector<unsigned> minCombination;
  51. int minRoute = -1;
  52. // Petla przegladajaca kolejne permutacje
  53. do
  54. {
  55. std::vector<unsigned> combination;
  56. // Dodanie wierzcholka startowego i pierwszego na trasie
  57. combination.push_back(0);
  58. combination.push_back(vertexArray.front());
  59. // W petli reszta wiercholkow
  60. for(int i = 1; i < vertexArray.size(); i++)
  61. combination.push_back(vertexArray.at(i));
  62. // Powrot do wierzcholka startowego
  63. combination.push_back(0);
  64. // PEA 2
  65. // Jan Potocki 2017
  66. int route = 0;
  67. for(int i = 1; i < combination.size(); i++)
  68. route += graph.getWeight(combination.at(i - 1), combination.at(i));
  69. if(minRoute == -1 || route < minRoute)
  70. {
  71. minRoute = route;
  72. minCombination = combination;
  73. }
  74. }
  75. while(next_permutation(vertexArray.begin(), vertexArray.end()));
  76. return minCombination;
  77. }
  78. std::vector<unsigned> Graph::travellingSalesmanBranchAndBound(Graph &graph)
  79. {
  80. // ALGORYTM pracujacy w oparciu o kolejke priorytetowa i niejawnie utworzone drzewo
  81. // Zrodlo: www.ii.uni.wroc.pl/~prz/2011lato/ah/opracowania/met_podz_ogr.opr.pdf
  82. // Autor: Mateusz Lyczek 2011
  83. // Implementacja: Jan Potocki 2017
  84. std::priority_queue<std::vector<unsigned>, std::vector< std::vector<unsigned> >, RouteComparison> routeQueue;
  85. std::vector<unsigned> optimalRoute; // Tu bedziemy zapisywac optymalne (w danej chwili) rozwiazanie
  86. int optimalRouteLength = -1; // -1 - bedziemy odtad uznawac, ze to jest nieskonczonosc ;-)
  87. // UMOWA
  88. // Pierwszy element wektora to dlugosc trasy (trzeba ustawic "z palca"!)
  89. // Kolejne to wierzcholki na trasie
  90. std::vector<unsigned> currentRoute; // Niejawne tworzenie drzewa, tu bedzie korzen
  91. currentRoute.push_back(0); // Poczatkowe oszacowanie nie ma znaczenia
  92. currentRoute.push_back(0); // Wierzcholek startowy (korzen drzewa rozwiazan)
  93. routeQueue.push(currentRoute); // Dodanie do kolejki korzenia
  94. while(!routeQueue.empty())
  95. {
  96. // Przypisanie korzenia do dalszej roboty
  97. currentRoute = routeQueue.top();
  98. routeQueue.pop();
  99. // Sprawdzenie, czy rozwiazanie jest warte rozwijania, czy odrzucic
  100. if(optimalRouteLength == -1 || currentRoute.at(0) < optimalRouteLength)
  101. {
  102. for(int i = 0; i < graph.vertexNumber; i++)
  103. {
  104. // Petla wykonywana dla kazdego potomka rozpatrywanego wlasnie rozwiazania w drzewie
  105. // Ustalenie, czy dany wierzcholek mozna jeszcze wykorzystac, czy juz zostal uzyty
  106. bool vertexUsed = false;
  107. for(int j = 1; j < currentRoute.size(); j++)
  108. {
  109. if(currentRoute.at(j) == i)
  110. {
  111. vertexUsed = true;
  112. break;
  113. }
  114. }
  115. if(vertexUsed)
  116. continue;
  117. // Niejawne utworzenie nowego wezla reprezuntujacego rozpatrywane rozwiazanie...
  118. std::vector<unsigned> nextRoute = currentRoute;
  119. //unsigned nextLength = graph.getWeight(nextRoute.back(), i);
  120. nextRoute.push_back(i);
  121. // Dalej bedziemy postepowac roznie...
  122. if(nextRoute.size() > graph.vertexNumber)
  123. {
  124. // Doszlismy wlasnie do liscia
  125. // Dodajemy droge powrotna, nie musimy nic szacowac
  126. // (wszystko juz wiemy)
  127. nextRoute.push_back(0);
  128. nextRoute.at(0) = 0;
  129. for(int j = 1; j < nextRoute.size() - 1; j++)
  130. {
  131. // Liczymy dystans od poczatku do konca
  132. nextRoute.at(0) += graph.getWeight(nextRoute.at(j), nextRoute.at(j+ 1));
  133. }
  134. if(optimalRouteLength == -1 || nextRoute.at(0) < optimalRouteLength)
  135. {
  136. optimalRouteLength = nextRoute.at(0);
  137. nextRoute.erase(nextRoute.begin());
  138. optimalRoute = nextRoute;
  139. }
  140. }
  141. else
  142. {
  143. // Liczenie tego, co juz wiemy, od nowa...
  144. // (dystans od poczatku)
  145. nextRoute.at(0) = 0;
  146. for(int j = 1; j < nextRoute.size() - 1; j++)
  147. {
  148. nextRoute.at(0) += graph.getWeight(nextRoute.at(j), nextRoute.at(j + 1));
  149. }
  150. // Reszte szacujemy...
  151. // Pomijamy od razu wierzcholek startowy
  152. for(int j = 1; j < graph.vertexNumber; j++)
  153. {
  154. // Odrzucenie wierzcholkow juz umieszczonych na trasie
  155. bool vertexUsed = false;
  156. for(int k = 1; k < currentRoute.size(); k++)
  157. {
  158. if(j == currentRoute.at(k))
  159. {
  160. vertexUsed = true;
  161. break;
  162. }
  163. }
  164. if(vertexUsed)
  165. continue;
  166. int minEdge = -1;
  167. for(int k = 0; k < graph.vertexNumber; k++)
  168. {
  169. // Odrzucenie krawedzi do wierzcholka 0 przy ostatnim wierzcholku w czesciowym rozwiazaniu
  170. // Wyjatkiem jest ostatnia mozliwa krawedz
  171. if(j == i && k == 0)
  172. continue;
  173. // Odrzucenie krawedzi do wierzcholka umieszczonego juz na rozwazanej trasie
  174. bool vertexUsed = false;
  175. for(int l = 2; l < nextRoute.size(); l++)
  176. {
  177. if(k == nextRoute.at(l))
  178. {
  179. vertexUsed = true;
  180. break;
  181. }
  182. }
  183. if(vertexUsed)
  184. continue;
  185. // Odrzucenie samego siebie
  186. if(k == j)
  187. continue;
  188. // Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
  189. unsigned consideredLength = graph.getWeight(j, k);
  190. if(minEdge == -1)
  191. minEdge = consideredLength;
  192. else if(minEdge > consideredLength)
  193. minEdge = consideredLength;
  194. }
  195. nextRoute.at(0) += minEdge;
  196. }
  197. // ...i teraz zastanawiamy sie co dalej
  198. if(optimalRouteLength == -1 || nextRoute.at(0) < optimalRouteLength)
  199. {
  200. routeQueue.push(nextRoute);
  201. }
  202. }
  203. }
  204. }
  205. else
  206. {
  207. // Jezeli jedno rozwiazanie odrzucilismy, to wszystkie inne tez mozemy
  208. // (kolejka priorytetowa, inne nie moga byc lepsze)
  209. break;
  210. }
  211. }
  212. return optimalRoute;
  213. }
  214. std::vector<unsigned> Graph::travellingSalesmanGreedy(Graph &graph, unsigned startVertex)
  215. {
  216. // ALGORYTM zachlanny z wierzcholkiem startowym przekazanym w parametrze
  217. // Implementacja: Jan Potocki 2017
  218. std::vector<unsigned> route;
  219. // Przypisanie wierzcholka startowego
  220. route.push_back(startVertex);
  221. for(int i = 0; i < graph.vertexNumber - 1; i++)
  222. {
  223. int minEdge = -1;
  224. unsigned nextVertex;
  225. for(int j = 0; j < graph.vertexNumber; j++)
  226. {
  227. // Odrzucenie samego siebie lub wierzcholka startowego
  228. // (zeby bylo szybciej)
  229. if(route.back() == j || route.front() == j)
  230. continue;
  231. // Odrzucenie krawedzi do wierzcholka umieszczonego juz na trasie
  232. bool vertexUsed = false;
  233. for(int k = 0; k < route.size(); k++)
  234. {
  235. if(j == route.at(k))
  236. {
  237. vertexUsed = true;
  238. break;
  239. }
  240. }
  241. if(vertexUsed)
  242. continue;
  243. // Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
  244. unsigned consideredLength = graph.getWeight(route.back(), j);
  245. if(minEdge == -1)
  246. {
  247. minEdge = consideredLength;
  248. nextVertex = j;
  249. }
  250. else if(minEdge > consideredLength)
  251. {
  252. minEdge = consideredLength;
  253. nextVertex = j;
  254. }
  255. }
  256. route.push_back(nextVertex);
  257. }
  258. route.push_back(startVertex);
  259. return route;
  260. }
  261. std::vector<unsigned> Graph::travellingSalesmanHybrid(Graph &graph)
  262. {
  263. // ALGORYTM hybrydowy losowo-zachlanny
  264. // Losowa czesc wierzcholkow jest losowana, reszta zachlannie
  265. // Implementacja: Jan Potocki 2019
  266. std::vector<unsigned> route;
  267. std::random_device randomSrc;
  268. std::default_random_engine randomGen(randomSrc());
  269. std::uniform_int_distribution<> vertexNumberDist(1, graph.vertexNumber);
  270. std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  271. // Liczba losowanych wierzcholkow
  272. unsigned randomVertexNumber = vertexNumberDist(randomGen);
  273. // Czesc losowa
  274. for(int i = 0; i < randomVertexNumber; i++)
  275. {
  276. unsigned randomVertex;
  277. bool vertexUsed;
  278. do
  279. {
  280. randomVertex = vertexDist(randomGen);
  281. vertexUsed = false;
  282. for(int j = 0; j < route.size(); j++)
  283. {
  284. if(route.at(j) == randomVertex)
  285. {
  286. vertexUsed = true;
  287. break;
  288. }
  289. }
  290. } while(vertexUsed == true);
  291. route.push_back(randomVertex);
  292. }
  293. // Czesc zachlanna
  294. for(int i = 0; i < graph.vertexNumber - randomVertexNumber; i++)
  295. {
  296. int minEdge = -1;
  297. unsigned nextVertex;
  298. for(int j = 0; j < graph.vertexNumber; j++)
  299. {
  300. // Odrzucenie samego siebie lub wierzcholka startowego
  301. // (zeby bylo szybciej)
  302. if(route.back() == j || route.front() == j)
  303. continue;
  304. // Odrzucenie krawedzi do wierzcholka umieszczonego juz na trasie
  305. bool vertexUsed = false;
  306. for(int k = 0; k < route.size(); k++)
  307. {
  308. if(j == route.at(k))
  309. {
  310. vertexUsed = true;
  311. break;
  312. }
  313. }
  314. if(vertexUsed)
  315. continue;
  316. // Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
  317. unsigned consideredLength = graph.getWeight(route.back(), j);
  318. // PEA 2 Plus
  319. // Jan Potocki 2019
  320. if(minEdge == -1)
  321. {
  322. minEdge = consideredLength;
  323. nextVertex = j;
  324. }
  325. else if(minEdge > consideredLength)
  326. {
  327. minEdge = consideredLength;
  328. nextVertex = j;
  329. }
  330. }
  331. route.push_back(nextVertex);
  332. }
  333. route.push_back(route.front());
  334. return route;
  335. }
  336. std::vector<unsigned> Graph::travellingSalesmanRandom(Graph &graph)
  337. {
  338. // ALGORYTM losowy
  339. // Implementacja: Jan Potocki 2019
  340. std::vector<unsigned> route;
  341. std::random_device randomSrc;
  342. std::default_random_engine randomGen(randomSrc());
  343. std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  344. for(int i = 0; i < graph.vertexNumber; i++)
  345. {
  346. unsigned randomVertex;
  347. bool vertexUsed;
  348. do
  349. {
  350. randomVertex = vertexDist(randomGen);
  351. vertexUsed = false;
  352. for(int j = 0; j < route.size(); j++)
  353. {
  354. if(route.at(j) == randomVertex)
  355. {
  356. vertexUsed = true;
  357. break;
  358. }
  359. }
  360. } while(vertexUsed == true);
  361. route.push_back(randomVertex);
  362. }
  363. route.push_back(route.front());
  364. return route;
  365. }
  366. std::vector<unsigned> Graph::travellingSalesmanTabuSearch(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, unsigned threadsNumber)
  367. {
  368. // ALGORYTM wielawotkowy oparty na metaheurystyce tabu search
  369. // Pomocniczy kod uruchamiajacy watki wlasciwego algorytmu w najbardziej optymalny sposob
  370. // Implementacja: Jan Potocki 2019
  371. std::vector<unsigned> startVertexVector;
  372. std::vector<std::thread> threadsVector;
  373. std::vector<std::vector<unsigned>> resultsVector(threadsNumber);
  374. std::vector<int> resultsLength(threadsNumber);
  375. std::vector<unsigned> optimalResult;
  376. int optimalResultIndex;
  377. int optimalResultLength;
  378. std::random_device randomSrc;
  379. std::default_random_engine randomGen(randomSrc());
  380. std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  381. // Petla uruchamiajaca watki
  382. for(int i = 0; i < threadsNumber; i++)
  383. {
  384. // Generowanie startowego rozwiazania...
  385. std::vector<unsigned> startRoute;
  386. unsigned startVertex;
  387. bool startVertexUsed;
  388. if(i < graph.vertexNumber)
  389. {
  390. // ...dopoki ma to sens - algorytmem zachlannym z innym wierzcholkiem startowym
  391. // (dla kazdego watku)
  392. do
  393. {
  394. startVertex = vertexDist(randomGen);
  395. startVertexUsed = false;
  396. for(int j = 0; j < startVertexVector.size(); j++)
  397. {
  398. if(startVertexVector.at(j) == startVertex)
  399. {
  400. startVertexUsed = true;
  401. break;
  402. }
  403. }
  404. } while(startVertexUsed == true);
  405. // PEA 2 Plus
  406. // Jan Potocki 2019
  407. startVertexVector.push_back(startVertex);
  408. startRoute = Graph::travellingSalesmanGreedy(graph, startVertex);
  409. }
  410. else
  411. {
  412. // ...jezeli wszystkie wierzcholki sa juz wykorzystane - w pelni losowo
  413. startRoute = Graph::travellingSalesmanRandom(graph);
  414. }
  415. // Uruchomienie watku
  416. threadsVector.push_back(std::thread(Graph::travellingSalesmanTabuSearchEngine, std::ref(graph), tabuSteps, diversification, iterationsToRestart, minStopTime, startRoute, std::ref(resultsVector.at(i)), std::ref(resultsLength.at(i))));
  417. }
  418. // Petla potwierdzajaca zakonczenie watkow
  419. for(int i = 0; i < threadsNumber; i++)
  420. threadsVector.at(i).join();
  421. // Przegladanie wszystkich rozwiazan i wybor optymalnego
  422. optimalResultIndex = 0;
  423. optimalResultLength = resultsLength.at(0);
  424. for(int i = 0; i < threadsNumber; i++)
  425. {
  426. if(resultsLength.at(i) < optimalResultLength)
  427. {
  428. optimalResultIndex = i;
  429. optimalResultLength = resultsLength.at(i);
  430. }
  431. }
  432. optimalResult = resultsVector.at(optimalResultIndex);
  433. return optimalResult;
  434. }
  435. void Graph::travellingSalesmanTabuSearchEngine(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, std::vector<unsigned> startRoute, std::vector<unsigned> &result, int &resultLength)
  436. {
  437. // ALGORYTM oparty na metaheurystyce tabu search z dywersyfikacja i sasiedztwem typu swap
  438. // Rdzen przeznaczony do uruchamiania jako jeden watek
  439. // Projekt i implementacja: Jan Potocki 2017
  440. // (refactoring 2019)
  441. Stopwatch onboardClock;
  442. std::vector<unsigned> optimalRoute; // Tu bedziemy zapisywac optymalne (w danej chwili) rozwiazanie
  443. int optimalRouteLength = -1; // -1 - bedziemy odtad uznawac, ze to jest nieskonczonosc ;-)
  444. std::vector<unsigned> currentRoute; // Rozpatrywane rozwiazanie
  445. // Wyznaczenie poczatkowego rozwiazania algorytmem zachlannym
  446. //currentRoute = Graph::travellingSalesmanGreedy(graph);
  447. currentRoute = startRoute;
  448. // Inicjalizacja glownej petli...
  449. std::vector< std::vector<unsigned> > tabuArray;
  450. unsigned currentTabuSteps = tabuSteps;
  451. int stopCounter = 0;
  452. bool timeNotExceeded = true;
  453. onboardClock.start();
  454. // Rdzen algorytmu
  455. while(timeNotExceeded == true)
  456. {
  457. bool cheeseSupplied = true;
  458. bool intensification = false;
  459. while(cheeseSupplied == true)
  460. {
  461. std::vector<unsigned> nextRoute;
  462. int nextRouteLength = -1;
  463. std::vector<unsigned> nextTabu(3, 0);
  464. nextTabu.at(0) = currentTabuSteps;
  465. // Generowanie sasiedztwa typu swap przez zamiane wierzcholkow
  466. // (wierzcholka startowego i zarazem ostatniego nie ruszamy,
  467. // pomijamy tez od razu aktualny wierzcholek)
  468. for(int i = 1; i < graph.vertexNumber - 1; i++)
  469. {
  470. for(int j = i + 1; j < graph.vertexNumber; j++)
  471. {
  472. std::vector<unsigned> neighbourRoute = currentRoute;
  473. // Zamiana
  474. unsigned buffer = neighbourRoute.at(j);
  475. neighbourRoute.at(j) = neighbourRoute.at(i);
  476. neighbourRoute.at(i) = buffer;
  477. unsigned neighbourRouteLength = 0;
  478. for(int i = 1; i < neighbourRoute.size(); i++)
  479. neighbourRouteLength += graph.getWeight(neighbourRoute.at(i - 1), neighbourRoute.at(i));
  480. // Sprawdzenie, czy dany ruch nie jest na liscie tabu
  481. // (dwa wierzcholki)
  482. bool tabu = false;
  483. for(int k = 0; k < tabuArray.size(); k++)
  484. {
  485. if(tabuArray.at(k).at(1) == i && tabuArray.at(k).at(2) == j)
  486. {
  487. tabu = true;
  488. break;
  489. }
  490. if(tabuArray.at(k).at(1) == j && tabuArray.at(k).at(2) == i)
  491. {
  492. tabu = true;
  493. break;
  494. }
  495. }
  496. // Kryterium aspiracji...
  497. if(tabu == true && neighbourRouteLength >= optimalRouteLength)
  498. // ...jezeli niespelnione - pomijamy ruch
  499. continue;
  500. if(nextRouteLength == -1)
  501. {
  502. nextRouteLength = neighbourRouteLength;
  503. nextRoute = neighbourRoute;
  504. nextTabu.at(1) = i;
  505. nextTabu.at(2) = j;
  506. }
  507. else if(nextRouteLength > neighbourRouteLength)
  508. {
  509. nextRouteLength = neighbourRouteLength;
  510. nextRoute = neighbourRoute;
  511. nextTabu.at(1) = i;
  512. nextTabu.at(2) = j;
  513. }
  514. }
  515. }
  516. currentRoute = nextRoute;
  517. // PEA 2 Plus
  518. // Jan Potocki 2019
  519. if(optimalRouteLength == -1)
  520. {
  521. optimalRouteLength = nextRouteLength;
  522. optimalRoute = nextRoute;
  523. // Reset licznika
  524. stopCounter = 0;
  525. }
  526. else if(optimalRouteLength > nextRouteLength)
  527. {
  528. optimalRouteLength = nextRouteLength;
  529. optimalRoute = nextRoute;
  530. // Zaplanowanie intensyfikacji przy znalezieniu nowego optimum
  531. intensification = true;
  532. // Reset licznika
  533. stopCounter = 0;
  534. }
  535. // Weryfikacja listy tabu...
  536. int tabuPos = 0;
  537. while(tabuPos < tabuArray.size())
  538. {
  539. // ...aktualizacja kadencji na liscie tabu
  540. tabuArray.at(tabuPos).at(0)--;
  541. //...usuniecie zerowych kadencji
  542. if(tabuArray.at(tabuPos).at(0) == 0)
  543. tabuArray.erase(tabuArray.begin() + tabuPos);
  544. else
  545. tabuPos++;
  546. }
  547. // ...dopisanie ostatniego ruchu do listy tabu
  548. tabuArray.push_back(nextTabu);
  549. // Zliczenie iteracji
  550. stopCounter++;
  551. // Zmierzenie czasu
  552. onboardClock.stop();
  553. if(onboardClock.read() > minStopTime)
  554. timeNotExceeded = false;
  555. // Sprawdzenie warunku zatrzymania
  556. if(diversification == true)
  557. {
  558. // Przy aktywowanej dywersyfikacji - po zadanej liczbie iteracji bez poprawy
  559. if(stopCounter >= iterationsToRestart || timeNotExceeded == false)
  560. cheeseSupplied = false;
  561. }
  562. else
  563. {
  564. // Przy nieaktywowanej dywersyfikacji - po uplynieciu okreslonego czasu
  565. if(timeNotExceeded == false)
  566. cheeseSupplied = false;
  567. }
  568. }
  569. // Dywersyfikacja
  570. if(diversification == true)
  571. {
  572. if(intensification == true)
  573. {
  574. // Intensyfikacja przeszukiwania przez skrócenie kadencji
  575. // (jezeli w ostatnim przebiegu znaleziono nowe minimum)
  576. currentRoute = optimalRoute;
  577. currentTabuSteps = tabuSteps / 4;
  578. intensification = false;
  579. // PEA 2 Plus
  580. // Jan Potocki 2019
  581. }
  582. else
  583. {
  584. // W innym przypadku wlasciwa dywersyfikacja przez wygenerowanie nowego
  585. // rozwiazania startowego algorytmem hybrydowym losowo-zachlannym
  586. currentRoute = Graph::travellingSalesmanHybrid(graph);
  587. currentTabuSteps = tabuSteps;
  588. intensification = false;
  589. }
  590. }
  591. // Reset licznika iteracji przed restartem
  592. stopCounter = 0;
  593. }
  594. result = optimalRoute;
  595. resultLength = optimalRouteLength;
  596. }