Implementacja tabu search dla TSP
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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