Implementacja tabu search dla TSP
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pea2plus.cpp 23KB

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