Implementacja tabu search dla TSP
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

pea2plus.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. #include <fstream>
  2. #include <iostream>
  3. #include <string>
  4. #include <vector>
  5. #include <cmath>
  6. #include "Stopwatch.h"
  7. #include "ArrayGraph.h"
  8. #include "ListGraph.h"
  9. using namespace std;
  10. // USTAWIENIA
  11. // Liczba powtorzen automatycznych pomiarow do usrednienia
  12. const int measureIterations = 10;
  13. // liczba automatycznych pomiarow
  14. const int measureNumber = 4;
  15. // Czas zatrzymania algorytmu tabu search w kazdym z automatycznych pomiarow
  16. const int measureTabuStop[4] = {1, 5, 10, 15};
  17. // Maksymalna odleglosc miast przy automatycznym generowaniu
  18. const int measureSalesmanDistance = 400;
  19. // Wykorzystanie reprezentacji grafu w postaci list sasiedztwa...
  20. // ...zamiast (domyslnie) macierzy sasiedztwa
  21. // (wolniejsze obliczenia, mniejsze uzycie pamieci)
  22. const bool useListGraph = false;
  23. // Domyslna kadencja tabu search - wybor automatyczny
  24. unsigned tabuLength = 0;
  25. // Domyslny stan dywersyfikacji
  26. bool tabuDiversification = true;
  27. // Domyslne kryterium dywersyfikacji, liczba iteracji bez poprawy
  28. int tabuIterationsToRestart = 10000;
  29. // Domyslny czas zatrzymania algorytmu tabu search [s]
  30. unsigned tabuStopTime = 60;
  31. // Domyslna liczba watkow tabu search
  32. unsigned tabuThreadsNumber = 2;
  33. int main()
  34. {
  35. Stopwatch clock; // czasomierz
  36. Graph *graph = NULL; // <- tu bedziemy zapisywac adresy przez caly program
  37. cout << "PEA Projekt 2 Plus v2.0ALPHA" << endl;
  38. cout << "Jan Potocki 2017-2019" << endl;
  39. cout << "(beerware)" << endl;
  40. if(useListGraph)
  41. cout << "Uzycie listowej reprezentacji grafu" << endl;
  42. else
  43. cout << "Uzycie macierzowej reprezentacji grafu" << endl;
  44. cout << endl;
  45. int salesmanSelection;
  46. do
  47. {
  48. cout << "1. Wygeneruj losowe dane" << endl;
  49. cout << "2. Wyswietl dane" << endl;
  50. cout << "3. Ustawienia TS" << endl;
  51. cout << "4. Tabu search" << endl;
  52. cout << "5. Podzial i ograniczenia" << endl;
  53. cout << "6. Przeglad zupelny" << endl;
  54. cout << "7. Automatyczne pomiary (tabu search)" << endl;
  55. cout << "8. Wczytaj dane z pliku TSPLIB FULL_MATRIX" << endl;
  56. cout << "9. Wczytaj dane z pliku TSPLIB EUC_2D" << endl;
  57. cout << "Aby zakonczyc - 0" << endl;
  58. cout << "Wybierz: ";
  59. cin >> salesmanSelection;
  60. cout << endl;
  61. switch(salesmanSelection)
  62. {
  63. case 1:
  64. {
  65. int vertex;
  66. cout << "Liczba miast: ";
  67. cin >> vertex;
  68. cout << endl;
  69. if(graph != NULL)
  70. delete graph;
  71. if(useListGraph)
  72. graph = new ListGraph(vertex);
  73. else
  74. graph = new ArrayGraph(vertex);
  75. Graph::randomGenerateFullGraph(*graph, measureSalesmanDistance);
  76. }
  77. break;
  78. case 2:
  79. {
  80. if(graph != NULL)
  81. graph->displayGraph();
  82. else
  83. cout << "Brak wygenerowanych danych" << endl;
  84. cout << endl;
  85. }
  86. break;
  87. case 3:
  88. {
  89. int settingsSelection;
  90. do
  91. {
  92. if(tabuDiversification == true)
  93. cout << "1. Przelacz dywersyfikacje" << "\t" << "(wlaczona)" << endl;
  94. else
  95. cout << "1. Przelacz dywersyfikacje" << "\t" << "(wylaczona)" << endl;
  96. cout << "2. Kryterium dywersyfikacji" << "\t" << "(" << tabuIterationsToRestart << " iteracji)" << endl;
  97. if(tabuLength == 0)
  98. cout << "3. Kadencja na liscie tabu" << "\t" << "(auto)" << endl;
  99. else
  100. cout << "3. Kadencja na liscie tabu" << "\t" << "(" << tabuLength << ")" << endl;
  101. cout << "4. Czas zatrzymania" << "\t\t" << "(" << tabuStopTime << " s)" << endl;
  102. cout << "Powrot - 0" << endl;
  103. cout << "Wybierz: ";
  104. cin >> settingsSelection;
  105. cout << endl;
  106. switch(settingsSelection)
  107. {
  108. case 1:
  109. {
  110. tabuDiversification = !tabuDiversification;
  111. if(tabuDiversification == true)
  112. cout << "Dywersyfikacja zostala wlaczona" << endl;
  113. else
  114. cout << "Dywersyfikacja zostala wylaczona" << endl;
  115. cout << endl;
  116. }
  117. break;
  118. case 2:
  119. {
  120. cout << "Podaj nowa liczbe iteracji bez poprawy: ";
  121. cin >> tabuIterationsToRestart;
  122. cout << endl;
  123. }
  124. break;
  125. case 3:
  126. {
  127. cout << "Podaj nowa kadencje (0 -> auto): ";
  128. cin >> tabuLength;
  129. cout << endl;
  130. }
  131. break;
  132. case 4:
  133. {
  134. cout << "Podaj nowy czas pracy [s]: ";
  135. cin >> tabuStopTime;
  136. cout << endl;
  137. }
  138. break;
  139. case 0:
  140. {
  141. }
  142. break;
  143. default:
  144. {
  145. cout << "Nieprawidlowy wybor" << endl;
  146. cout << endl;
  147. }
  148. }
  149. } while(settingsSelection != 0);
  150. }
  151. break;
  152. case 4:
  153. {
  154. if(graph != NULL)
  155. {
  156. if(tabuStopTime != 0)
  157. {
  158. unsigned effectiveTabuLength;
  159. if(tabuLength == 0)
  160. {
  161. effectiveTabuLength = (graph->getVertexNumber() / 10) * 10;
  162. if(effectiveTabuLength == 0)
  163. effectiveTabuLength = 10;
  164. }
  165. else
  166. {
  167. effectiveTabuLength = tabuLength;
  168. }
  169. if(tabuLength == 0)
  170. cout << "Kadencja: " << effectiveTabuLength << " (auto)" << endl;
  171. else
  172. cout << "Kadencja: " << effectiveTabuLength << endl;
  173. cout << "Czas zatrzymania algorytmu [s]: " << tabuStopTime << endl;
  174. if(tabuDiversification == true)
  175. cout << "Dywersyfikacja wlaczona, kryterium: " << tabuIterationsToRestart << " iteracji bez poprawy" << endl;
  176. else
  177. cout << "Dywersyfikacja wylaczona" << endl;
  178. cout << "Liczba watkow: " << tabuThreadsNumber << endl;
  179. cout << endl;
  180. clock.start();
  181. vector<unsigned> route = Graph::travellingSalesmanTabuSearch(*graph, effectiveTabuLength, tabuDiversification, tabuIterationsToRestart, tabuStopTime, tabuThreadsNumber);
  182. clock.stop();
  183. // Wyswietlenie trasy
  184. unsigned distFromStart = 0;
  185. unsigned length = 0;
  186. cout << route.at(0) << '\t' << length << '\t' << distFromStart << endl;
  187. for(int i = 1; i < route.size(); i++)
  188. {
  189. length = graph->getWeight(route.at(i - 1), route.at(i));
  190. distFromStart += length;
  191. cout << route.at(i) << '\t' << length << '\t' << distFromStart << endl;
  192. }
  193. cout << "Dlugosc trasy: " << distFromStart << endl;
  194. cout << endl;
  195. cout << "Czas wykonania algorytmu [s]: " << clock.read() << endl;
  196. }
  197. else
  198. {
  199. // Easter egg ;-)
  200. cout << "+++ MELON MELON MELON +++ Blad: Brak Sera! +++ !!!!! +++" << endl;
  201. }
  202. }
  203. else
  204. cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
  205. cout << endl;
  206. }
  207. break;
  208. case 5:
  209. {
  210. if(graph != NULL)
  211. {
  212. clock.start();
  213. vector<unsigned> route = Graph::travellingSalesmanBranchAndBound(*graph);
  214. clock.stop();
  215. // Wyswietlenie trasy
  216. unsigned distFromStart = 0;
  217. unsigned length = 0;
  218. cout << route.at(0) << '\t' << length << '\t' << distFromStart << endl;
  219. for(int i = 1; i < route.size(); i++)
  220. {
  221. length = graph->getWeight(route.at(i - 1), route.at(i));
  222. distFromStart += length;
  223. cout << route.at(i) << '\t' << length << '\t' << distFromStart << endl;
  224. }
  225. cout << "Dlugosc trasy: " << distFromStart << endl;
  226. cout << endl;
  227. cout << "Czas wykonania algorytmu [s]: " << clock.read() << endl;
  228. }
  229. else
  230. cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
  231. cout << endl;
  232. }
  233. break;
  234. case 6:
  235. {
  236. if(graph != NULL)
  237. {
  238. clock.start();
  239. vector<unsigned> route = Graph::travellingSalesmanBruteForce(*graph);
  240. clock.stop();
  241. // Wyswietlenie trasy
  242. unsigned distFromStart = 0;
  243. unsigned length = 0;
  244. cout << route.at(0) << '\t' << length << '\t' << distFromStart << endl;
  245. for(int i = 1; i < route.size(); i++)
  246. {
  247. length = graph->getWeight(route.at(i - 1), route.at(i));
  248. distFromStart += length;
  249. cout << route.at(i) << '\t' << length << '\t' << distFromStart << endl;
  250. }
  251. cout << "Dlugosc trasy: " << distFromStart << endl;
  252. cout << endl;
  253. cout << "Czas wykonania algorytmu [s]: " << clock.read() << endl;
  254. }
  255. else
  256. cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
  257. cout << endl;
  258. }
  259. break;
  260. case 7:
  261. {
  262. // PEA 2
  263. // Jan Potocki 2017
  264. if(graph != NULL)
  265. {
  266. unsigned effectiveTabuLength;
  267. if(tabuLength == 0)
  268. {
  269. effectiveTabuLength = (graph->getVertexNumber() / 10) * 10;
  270. if(effectiveTabuLength == 0)
  271. effectiveTabuLength = 10;
  272. }
  273. else
  274. {
  275. effectiveTabuLength = tabuLength;
  276. }
  277. double measureResults[measureNumber], measureResultsDiv[measureNumber];
  278. for(int i = 0; i < measureNumber; i++)
  279. {
  280. measureResults[i] = 0;
  281. measureResultsDiv[i] = 0;
  282. }
  283. cout << "Pomiary dla problemu komiwojazera, tabu search" << tabuLength << endl;
  284. if(tabuLength == 0)
  285. cout << "Kadencja: " << effectiveTabuLength << " (auto)" << endl;
  286. else
  287. cout << "Kadencja: " << effectiveTabuLength << endl;
  288. cout << "Kryterium dywersyfikacji: " << tabuIterationsToRestart << " iteracji bez poprawy" << endl;
  289. cout << "Liczba watkow: " << tabuThreadsNumber << endl;
  290. // Petla pomiarowa
  291. for(int krok = 0; krok < measureIterations; krok++)
  292. {
  293. for(int i = 0; i < measureNumber; i++)
  294. {
  295. vector<unsigned> route;
  296. unsigned routeLength;
  297. // Bez dywersyfikacji
  298. cout << "Pomiar " << measureTabuStop[i] << " [s] (" << krok + 1 << " z " << measureIterations << " bez dywersyfikacji)..." << endl;
  299. route = Graph::travellingSalesmanTabuSearch(*graph, effectiveTabuLength, false, tabuIterationsToRestart, measureTabuStop[i], tabuThreadsNumber);
  300. routeLength = 0;
  301. for(int j = 1; j < route.size(); j++)
  302. routeLength += graph->getWeight(route.at(j - 1), route.at(j));
  303. measureResults[i] += routeLength;
  304. // Z dywersyfikacja
  305. cout << "Pomiar " << measureTabuStop[i] << " [s] (" << krok + 1 << " z " << measureIterations << " z dywersyfikacja)..." << endl;
  306. route = Graph::travellingSalesmanTabuSearch(*graph, effectiveTabuLength, true, tabuIterationsToRestart, measureTabuStop[i], tabuThreadsNumber);
  307. routeLength = 0;
  308. for(int j = 1; j < route.size(); j++)
  309. routeLength += graph->getWeight(route.at(j - 1), route.at(j));
  310. measureResultsDiv[i] += routeLength;
  311. }
  312. }
  313. cout << "Opracowywanie wynikow..." << endl;
  314. for(int i = 0; i < measureNumber; i++)
  315. {
  316. measureResults[i] = nearbyint(measureResults[i] / measureIterations);
  317. measureResultsDiv[i] = nearbyint(measureResultsDiv[i] / measureIterations);
  318. }
  319. cout << "Zapis wynikow..." << endl;
  320. ofstream salesmanToFile;
  321. salesmanToFile.open("wyniki-komiwojazer-ts.txt");
  322. salesmanToFile << "czas - bez dywersyfikacji - z dywersyfikacja" << endl;
  323. for(int i = 0; i < measureNumber; i++)
  324. {
  325. salesmanToFile << measureTabuStop[i] << " [s]: " << (int)measureResults[i] << ' ' << (int)measureResultsDiv[i] << endl;
  326. }
  327. salesmanToFile.close();
  328. cout << "Gotowe!" << endl;
  329. cout << endl;
  330. }
  331. else
  332. {
  333. cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
  334. cout << endl;
  335. }
  336. }
  337. break;
  338. case 8:
  339. {
  340. // Jan Potocki 2017
  341. string filename, fileInput;
  342. ifstream salesmanDataFile;
  343. cout << "Podaj nazwe pliku: ";
  344. cin >> filename;
  345. salesmanDataFile.open(filename.c_str());
  346. if(salesmanDataFile.is_open())
  347. {
  348. do
  349. salesmanDataFile >> fileInput;
  350. while(fileInput != "DIMENSION:");
  351. salesmanDataFile >> fileInput;
  352. int vertex = stoi(fileInput);
  353. do
  354. salesmanDataFile >> fileInput;
  355. while(fileInput != "EDGE_WEIGHT_FORMAT:");
  356. salesmanDataFile >> fileInput;
  357. if(fileInput == "FULL_MATRIX")
  358. {
  359. if(graph != NULL)
  360. delete graph;
  361. if(useListGraph)
  362. graph = new ListGraph(vertex);
  363. else
  364. graph = new ArrayGraph(vertex);
  365. do
  366. salesmanDataFile >> fileInput;
  367. while(fileInput != "EDGE_WEIGHT_SECTION");
  368. for(int i = 0; i < vertex; i++)
  369. {
  370. for(int j = 0; j < vertex; j++)
  371. {
  372. salesmanDataFile >> fileInput;
  373. int weight = stoi(fileInput);
  374. if(i != j)
  375. graph->addEdge(i, j, weight);
  376. }
  377. }
  378. cout << "Wczytano - liczba wierzcholkow: " << vertex << endl;
  379. cout << endl;
  380. }
  381. else
  382. {
  383. cout << "+++ MELON MELON MELON +++ Nieobslugiwany format " << fileInput << " +++" << endl;
  384. cout << endl;
  385. }
  386. salesmanDataFile.close();
  387. }
  388. else
  389. {
  390. cout << "+++ MELON MELON MELON +++ Brak pliku " << filename << " +++" << endl;
  391. cout << endl;
  392. }
  393. }
  394. break;
  395. case 9:
  396. {
  397. // Jan Potocki 2017
  398. string filename, fileInput;
  399. vector<float> xCoord, yCoord;
  400. ifstream salesmanDataFile;
  401. cout << "Podaj nazwe pliku: ";
  402. cin >> filename;
  403. salesmanDataFile.open(filename.c_str());
  404. if(salesmanDataFile.is_open())
  405. {
  406. do
  407. salesmanDataFile >> fileInput;
  408. while(fileInput != "DIMENSION:");
  409. salesmanDataFile >> fileInput;
  410. int vertex = stoi(fileInput);
  411. do
  412. salesmanDataFile >> fileInput;
  413. while(fileInput != "EDGE_WEIGHT_TYPE:");
  414. salesmanDataFile >> fileInput;
  415. if(fileInput == "EUC_2D")
  416. {
  417. if(graph != NULL)
  418. delete graph;
  419. if(useListGraph)
  420. graph = new ListGraph(vertex);
  421. else
  422. graph = new ArrayGraph(vertex);
  423. do
  424. salesmanDataFile >> fileInput;
  425. while(fileInput != "NODE_COORD_SECTION");
  426. for(int i = 0; i < vertex; i++)
  427. {
  428. salesmanDataFile >> fileInput;
  429. salesmanDataFile >> fileInput;
  430. xCoord.push_back(stof(fileInput));
  431. salesmanDataFile >> fileInput;
  432. yCoord.push_back(stof(fileInput));
  433. }
  434. // To daloby sie zrobic optymalniej (macierz symetryczna), ale nie chce mi sie ...
  435. // ..wole zoptymalizować czas programowania ;-)
  436. for(int i = 0; i < vertex; i++)
  437. {
  438. for(int j = 0; j < vertex; j++)
  439. {
  440. if(i != j)
  441. {
  442. float xDiff = xCoord.at(i) - xCoord.at(j);
  443. float yDiff = yCoord.at(i) - yCoord.at(j);
  444. int weight = nearbyint(sqrt(xDiff * xDiff + yDiff * yDiff));
  445. graph->addEdge(i, j, weight);
  446. }
  447. }
  448. }
  449. cout << "Wczytano - liczba wierzcholkow: " << vertex << endl;
  450. cout << endl;
  451. }
  452. else
  453. {
  454. cout << "+++ MELON MELON MELON +++ Nieobslugiwany format " << fileInput << " +++" << endl;
  455. cout << endl;
  456. }
  457. salesmanDataFile.close();
  458. }
  459. else
  460. {
  461. cout << "+++ MELON MELON MELON +++ Brak pliku " << filename << " +++" << endl;
  462. cout << endl;
  463. }
  464. }
  465. break;
  466. case 0:
  467. {
  468. }
  469. break;
  470. default:
  471. {
  472. cout << "Nieprawidlowy wybor" << endl;
  473. cout << endl;
  474. }
  475. }
  476. } while(salesmanSelection != 0);
  477. if(graph != NULL)
  478. delete graph;
  479. cout << "Konczenie..." << endl;
  480. // Easter egg :-P
  481. cout << '"' << "Myslak Stibbons niepokoil sie HEX-em." << endl;
  482. cout << "Nie wiedzial, jak dziala, chociaz wszyscy uwazali, ze wie." << endl;
  483. cout << "Oczywiscie, calkiem niezle orientowal sie w niektorych elementach;" << endl;
  484. cout << "byl tez pewien, ze HEX mysli o problemach, przeksztalcajac je" << endl;
  485. cout << "w liczby i mielac ..." << '"' << endl;
  486. cout << "(Terry Pratchett, " << '"' << "Wiedzmikolaj" << '"' << ", tlumaczenie Piotr Cholewa)" << endl;
  487. cout << endl;
  488. return 0;
  489. }