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.

pea2plus.cpp 23KB

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