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

pea2plus.cpp 22KB

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