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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  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-2020
  371. std::vector<unsigned> startVertexVector;
  372. std::vector<std::thread> threadsVector;
  373. std::mutex globalOptimumMutex;
  374. std::vector<unsigned> globalOptimum;
  375. unsigned globalOptimumLength = -1;
  376. std::random_device randomSrc;
  377. std::default_random_engine randomGen(randomSrc());
  378. std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  379. // Petla uruchamiajaca watki
  380. for(int i = 0; i < threadsNumber; i++)
  381. {
  382. // Generowanie startowego rozwiazania...
  383. std::vector<unsigned> startRoute;
  384. unsigned startVertex;
  385. bool startVertexUsed;
  386. if(i < graph.vertexNumber)
  387. {
  388. // ...dopoki ma to sens - algorytmem zachlannym z innym wierzcholkiem startowym
  389. // (dla kazdego watku)
  390. do
  391. {
  392. startVertex = vertexDist(randomGen);
  393. startVertexUsed = false;
  394. for(int j = 0; j < startVertexVector.size(); j++)
  395. {
  396. if(startVertexVector.at(j) == startVertex)
  397. {
  398. startVertexUsed = true;
  399. break;
  400. }
  401. }
  402. } while(startVertexUsed == true);
  403. // PEA 2 Plus
  404. // Jan Potocki 2019
  405. startVertexVector.push_back(startVertex);
  406. startRoute = Graph::travellingSalesmanGreedy(graph, startVertex);
  407. }
  408. else
  409. {
  410. // ...jezeli wszystkie wierzcholki sa juz wykorzystane - w pelni losowo
  411. startRoute = Graph::travellingSalesmanRandom(graph);
  412. }
  413. // Uruchomienie watku
  414. threadsVector.push_back(std::thread(Graph::travellingSalesmanTabuSearchEngine, std::ref(graph), tabuSteps, diversification, iterationsToRestart, minStopTime, startRoute, std::ref(globalOptimum), std::ref(globalOptimumLength), std::ref(globalOptimumMutex)));
  415. }
  416. // Petla potwierdzajaca zakonczenie watkow
  417. for(int i = 0; i < threadsNumber; i++)
  418. threadsVector.at(i).join();
  419. return globalOptimum;
  420. }
  421. void Graph::travellingSalesmanTabuSearchEngine(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, std::vector<unsigned> startRoute, std::vector<unsigned> &globalOptimum, unsigned &globalOptimumLength, std::mutex &globalOptimumMutex)
  422. {
  423. // ALGORYTM oparty na metaheurystyce tabu search z dywersyfikacja i sasiedztwem typu swap
  424. // Rdzen przeznaczony do uruchamiania jako jeden watek
  425. // Projekt i implementacja: Jan Potocki 2017
  426. // (refactoring 2019-2020)
  427. Stopwatch onboardClock;
  428. std::vector<unsigned> optimalRoute; // Tu bedziemy zapisywac optymalne (w danej chwili) rozwiazanie
  429. int optimalRouteLength = -1; // -1 - bedziemy odtad uznawac, ze to jest nieskonczonosc ;-)
  430. std::vector<unsigned> currentRoute; // Rozpatrywane rozwiazanie
  431. currentRoute = startRoute;
  432. // Inicjalizacja glownej petli...
  433. std::vector< std::vector<unsigned> > tabuArray;
  434. unsigned currentTabuSteps = tabuSteps;
  435. int stopCounter = 0;
  436. bool timeNotExceeded = true;
  437. onboardClock.start();
  438. // Rdzen algorytmu
  439. while(timeNotExceeded == true)
  440. {
  441. bool cheeseSupplied = true;
  442. bool intensification = false;
  443. while(cheeseSupplied == true)
  444. {
  445. std::vector<unsigned> nextRoute = currentRoute;
  446. // ...na wszelki wypadek, gdyby cale sasiedztwo bylo na liscie tabu
  447. // (zeby algorytm sie nie wywalil)
  448. int nextRouteLength = -1;
  449. std::vector<unsigned> nextTabu(3, 0);
  450. nextTabu.at(0) = currentTabuSteps;
  451. // Generowanie sasiedztwa typu swap przez zamiane wierzcholkow
  452. // (wierzcholka startowego i zarazem ostatniego nie ruszamy,
  453. // pomijamy tez od razu aktualny wierzcholek)
  454. for(int i = 1; i < graph.vertexNumber - 1; i++)
  455. {
  456. for(int j = i + 1; j < graph.vertexNumber; j++)
  457. {
  458. std::vector<unsigned> neighbourRoute = currentRoute;
  459. // Zamiana
  460. unsigned buffer = neighbourRoute.at(j);
  461. neighbourRoute.at(j) = neighbourRoute.at(i);
  462. neighbourRoute.at(i) = buffer;
  463. unsigned neighbourRouteLength = 0;
  464. for(int i = 1; i < neighbourRoute.size(); i++)
  465. neighbourRouteLength += graph.getWeight(neighbourRoute.at(i - 1), neighbourRoute.at(i));
  466. // Sprawdzenie, czy dany ruch nie jest na liscie tabu
  467. // (dwa wierzcholki)
  468. bool tabu = false;
  469. for(int k = 0; k < tabuArray.size(); k++)
  470. {
  471. if(tabuArray.at(k).at(1) == i && tabuArray.at(k).at(2) == j)
  472. {
  473. tabu = true;
  474. break;
  475. }
  476. if(tabuArray.at(k).at(1) == j && tabuArray.at(k).at(2) == i)
  477. {
  478. tabu = true;
  479. break;
  480. }
  481. }
  482. // Kryterium aspiracji...
  483. if(tabu == true && neighbourRouteLength >= optimalRouteLength)
  484. // ...jezeli niespelnione - pomijamy ruch
  485. continue;
  486. if(nextRouteLength == -1 || nextRouteLength > neighbourRouteLength)
  487. {
  488. nextRouteLength = neighbourRouteLength;
  489. nextRoute = neighbourRoute;
  490. nextTabu.at(1) = i;
  491. nextTabu.at(2) = j;
  492. }
  493. }
  494. }
  495. currentRoute = nextRoute;
  496. // PEA 2 Plus
  497. // Jan Potocki 2019
  498. if(optimalRouteLength == -1)
  499. {
  500. optimalRouteLength = nextRouteLength;
  501. optimalRoute = nextRoute;
  502. // Reset licznika
  503. stopCounter = 0;
  504. }
  505. else if(optimalRouteLength > nextRouteLength)
  506. {
  507. optimalRouteLength = nextRouteLength;
  508. optimalRoute = nextRoute;
  509. // Zaplanowanie intensyfikacji przy znalezieniu nowego optimum
  510. intensification = true;
  511. // Reset licznika
  512. stopCounter = 0;
  513. }
  514. // Synchronizacja globalnie najlepszej trasy
  515. globalOptimumMutex.lock();
  516. if(globalOptimumLength == -1 || globalOptimumLength > nextRouteLength)
  517. {
  518. globalOptimumLength = nextRouteLength;
  519. globalOptimum = nextRoute;
  520. onboardClock.stop();
  521. std::cout << "Nowa najlepsza trasa: " << globalOptimumLength;
  522. std::cout << " (w czasie " << onboardClock.read() << " s)" << std::endl;
  523. }
  524. globalOptimumMutex.unlock();
  525. // Weryfikacja listy tabu...
  526. int tabuPos = 0;
  527. while(tabuPos < tabuArray.size())
  528. {
  529. // ...aktualizacja kadencji na liscie tabu
  530. tabuArray.at(tabuPos).at(0)--;
  531. //...usuniecie zerowych kadencji
  532. if(tabuArray.at(tabuPos).at(0) == 0)
  533. tabuArray.erase(tabuArray.begin() + tabuPos);
  534. else
  535. tabuPos++;
  536. }
  537. // ...dopisanie ostatniego ruchu do listy tabu
  538. tabuArray.push_back(nextTabu);
  539. // Zliczenie iteracji
  540. stopCounter++;
  541. // Zmierzenie czasu
  542. onboardClock.stop();
  543. if(onboardClock.read() > minStopTime)
  544. timeNotExceeded = false;
  545. // Sprawdzenie warunku zatrzymania
  546. if(diversification == true)
  547. {
  548. // Przy aktywowanej dywersyfikacji - po zadanej liczbie iteracji bez poprawy
  549. if(stopCounter >= iterationsToRestart || timeNotExceeded == false)
  550. cheeseSupplied = false;
  551. }
  552. else
  553. {
  554. // Przy nieaktywowanej dywersyfikacji - po uplynieciu okreslonego czasu
  555. if(timeNotExceeded == false)
  556. cheeseSupplied = false;
  557. }
  558. }
  559. // Dywersyfikacja
  560. if(diversification == true)
  561. {
  562. if(intensification == true)
  563. {
  564. // Intensyfikacja przeszukiwania przez skrócenie kadencji
  565. // (jezeli w ostatnim przebiegu znaleziono nowe minimum)
  566. currentRoute = optimalRoute;
  567. currentTabuSteps = tabuSteps; /// 4;
  568. intensification = false;
  569. // PEA 2 Plus
  570. // Jan Potocki 2019
  571. }
  572. else
  573. {
  574. // W innym przypadku wlasciwa dywersyfikacja przez wygenerowanie nowego
  575. // rozwiazania startowego algorytmem hybrydowym losowo-zachlannym
  576. currentRoute = Graph::travellingSalesmanHybrid(graph);
  577. currentTabuSteps = tabuSteps;
  578. intensification = false;
  579. }
  580. }
  581. // Reset licznika iteracji przed restartem
  582. stopCounter = 0;
  583. }
  584. }