KShortestPaths.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. //
  2. // Created by wrede on 28.06.16.
  3. //
  4. #include <boost/graph/named_function_params.hpp>
  5. #include <boost/graph/dijkstra_shortest_paths.hpp>
  6. #include <boost/graph/copy.hpp>
  7. #include <boost/graph/bellman_ford_shortest_paths.hpp>
  8. #include <iomanip>
  9. #include "KShortestPaths.h"
  10. #include "../util/Logger.h"
  11. namespace algo
  12. {
  13. KShortestPaths::KShortestPaths(DirectedGraph input_graph, Vertex source, Vertex sink)
  14. {
  15. orig_graph_ = input_graph;
  16. source_ = source;
  17. sink_ = sink;
  18. }
  19. void KShortestPaths::Run(size_t max_path_count)
  20. {
  21. paths_.clear();
  22. sink_neighbors_.clear();
  23. switch (max_path_count)
  24. {
  25. case 0:
  26. break;
  27. case 1:
  28. FindPath(orig_graph_, source_, sink_, paths_);
  29. sink_neighbors_.push_back(paths_[sink_]);
  30. break;
  31. case 2:
  32. FindPathPair();
  33. break;
  34. default:
  35. FindPaths(max_path_count);
  36. break;
  37. }
  38. util::Logger::LogDebug(std::to_string(sink_neighbors_.size()) + " paths have been found");
  39. }
  40. bool KShortestPaths::FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
  41. VertexPredecessorMap& predecessors, VertexDistanceMap& distances)
  42. {
  43. // The predecessors and the distances
  44. std::vector<Vertex> p(boost::num_vertices(graph));
  45. std::vector<Weight> d(boost::num_vertices(graph));
  46. util::Logger::LogDebug("scan the graph for negative edge weights");
  47. // Scan the graph for negative edge weights to use the proper algorithm
  48. bool negative_edges = false;
  49. EdgeIter ei, ei_end;
  50. for (boost::tie(ei, ei_end) = boost::edges(graph); ei != ei_end; ++ei)
  51. {
  52. if (boost::get(boost::edge_weight, graph, *ei) < 0)
  53. {
  54. negative_edges = true;
  55. break;
  56. }
  57. }
  58. if (negative_edges)
  59. util::Logger::LogDebug("the graph contains negative edges");
  60. else
  61. util::Logger::LogDebug("the graph contains only positive edges");
  62. util::Logger::LogDebug("run a single-source shortest paths algorithm");
  63. if (negative_edges)
  64. {
  65. // Run bellman ford to find the single-source shortest paths
  66. boost::bellman_ford_shortest_paths(
  67. graph,
  68. boost::num_vertices(graph),
  69. boost::root_vertex(source)
  70. .predecessor_map(
  71. boost::make_iterator_property_map(
  72. p.begin(), boost::get(boost::vertex_index, graph)))
  73. .distance_map(
  74. boost::make_iterator_property_map(
  75. d.begin(), boost::get(boost::vertex_index, graph))));
  76. }
  77. else
  78. {
  79. // Run dijkstra to find the single-source shortest paths
  80. boost::dijkstra_shortest_paths(
  81. graph,
  82. source,
  83. boost::predecessor_map(
  84. boost::make_iterator_property_map(
  85. p.begin(),
  86. boost::get(boost::vertex_index, graph)))
  87. .distance_map(
  88. boost::make_iterator_property_map(
  89. d.begin(),
  90. boost::get(boost::vertex_index, graph))));
  91. }
  92. util::Logger::LogDebug("prepare a map of visited vertices to detect negative cycles");
  93. // Record the vertices already visited to detect negative cycles (and store the distances)
  94. std::unordered_map<Vertex, bool> visited_vertices;
  95. VertexIter vi, vi_end;
  96. for (boost::tie(vi, vi_end) = boost::vertices(graph); vi != vi_end; ++vi)
  97. {
  98. visited_vertices[*vi] = false;
  99. distances[*vi] = d[*vi];
  100. }
  101. util::Logger::LogDebug("insert the path into the output map (and detect negative cycles)");
  102. // Insert the path from the specified source to target into the specified map
  103. for (auto u = sink, v = p[u]; u != source; u = v, v = p[u])
  104. {
  105. if (visited_vertices[u])
  106. {
  107. util::Logger::LogError("negative cycle at vertex " + std::to_string(u));
  108. return false;
  109. }
  110. predecessors[u] = v;
  111. visited_vertices[u] = true;
  112. }
  113. return true;
  114. }
  115. bool KShortestPaths::FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
  116. VertexPredecessorMap& predecessors)
  117. {
  118. VertexDistanceMap d;
  119. return FindPath(graph, source, sink, predecessors, d);
  120. }
  121. void KShortestPaths::FindPathPair()
  122. {
  123. VertexIter vi, vi_end;
  124. EdgeIter ei, ei_end;
  125. util::Logger::LogDebug("find the first path (in the original graph)");
  126. // Find the first path
  127. VertexPredecessorMap orig_first_path;
  128. FindPath(orig_graph_, source_, sink_, orig_first_path);
  129. // Transform the graph, invert the direction and weight of every edge in the first path
  130. // found, then add concomitant vertices for every vertex on the path, eventually check that
  131. // every edge pointing on the path should end in the newly created vertex in the splitting
  132. // process
  133. util::Logger::LogDebug("copy the original graph");
  134. // Create the graph to transform and create the map to map from vertices in the transformed
  135. // graph to vertices in the original graph, at first every vertex is mapped to itself
  136. DirectedGraph trans_graph;
  137. for (boost::tie(vi, vi_end) = boost::vertices(orig_graph_); vi != vi_end; ++vi)
  138. {
  139. boost::add_vertex(trans_graph);
  140. }
  141. // Transform the first path by inverting edges (and weights) and splitting nodes along the
  142. // path
  143. util::Logger::LogDebug("reverse the first path");
  144. // Reverse the first path
  145. VertexPredecessorMap trans_first_path;
  146. for (auto u = sink_, v = orig_first_path[u]; u != source_; u = v, v = orig_first_path[u])
  147. {
  148. trans_first_path[v] = u;
  149. }
  150. util::Logger::LogDebug("invert the edges along the first path");
  151. // Invert edges
  152. for (auto u = sink_, v = orig_first_path[u]; u != source_; u = v, v = orig_first_path[u])
  153. {
  154. Edge edge;
  155. bool e_found;
  156. boost::tie(edge, e_found) = boost::edge(v, u, orig_graph_);
  157. if (e_found)
  158. {
  159. Weight w = boost::get(boost::edge_weight, orig_graph_, edge);
  160. boost::add_edge(u, v, -w, trans_graph);
  161. }
  162. else
  163. {
  164. util::Logger::LogError("edge not found " + std::to_string(v) + " -> " +
  165. std::to_string(u));
  166. }
  167. }
  168. util::Logger::LogDebug("split the nodes along the first path");
  169. // Split nodes
  170. VertexPredecessorMap old_to_new;
  171. VertexPredecessorMap new_to_old;
  172. for (auto u = orig_first_path[sink_], v = orig_first_path[u];
  173. v != source_;
  174. u = v, v = orig_first_path[u])
  175. {
  176. // Create the concomitant vertex
  177. Vertex new_u = boost::add_vertex(trans_graph);
  178. old_to_new[u] = new_u;
  179. new_to_old[new_u] = u;
  180. // Retrieve the weight from the original path in the original graph
  181. Weight w = 0.0;
  182. Edge edge;
  183. bool e_found;
  184. boost::tie(edge, e_found) = boost::edge(v, u, orig_graph_);
  185. if (e_found)
  186. {
  187. w = boost::get(boost::edge_weight, orig_graph_, edge);
  188. }
  189. else
  190. {
  191. util::Logger::LogError("edge not found " + std::to_string(v) + " -> " +
  192. std::to_string(u));
  193. }
  194. // Create the edge from the concomitant vertex to the path predecessor
  195. boost::add_edge(new_u, v, -w, trans_graph);
  196. }
  197. util::Logger::LogDebug("extend the copied graph with the remaining edges");
  198. // Add all remaining edges
  199. for (boost::tie(ei, ei_end) = boost::edges(orig_graph_); ei != ei_end; ++ei)
  200. {
  201. Vertex source = boost::source(*ei, orig_graph_);
  202. Vertex target = boost::target(*ei, orig_graph_);
  203. Weight weight = boost::get(boost::edge_weight, orig_graph_, *ei);
  204. // Ignore vertices on the path (they are already added)
  205. if (orig_first_path.count(target) > 0 && orig_first_path[target] == source)
  206. continue;
  207. // If the edge points to source or sink add the edge unchanged
  208. if (target == source_ || target == sink_)
  209. {
  210. boost::add_edge(source, target, weight, trans_graph);
  211. continue;
  212. }
  213. // If the edge points to split vertices (vertices on the path except source and sink),
  214. // point the edge towards the concomitant vertex
  215. if (trans_first_path.count(target) > 0 && old_to_new.count(target) > 0)
  216. {
  217. boost::add_edge(source, old_to_new[target], weight, trans_graph);
  218. continue;
  219. }
  220. // Add every other edge unchanged
  221. boost::add_edge(source, target, weight, trans_graph);
  222. }
  223. util::Logger::LogDebug("find the second path (in the copied and transformed graph)");
  224. // Find the second path in the transformed graph
  225. VertexPredecessorMap trans_second_path;
  226. FindPath(trans_graph, source_, sink_, trans_second_path);
  227. util::Logger::LogDebug("map the second path into the original graph");
  228. // Map the second path from the transformed graph into the original graph
  229. VertexPredecessorMap orig_second_path;
  230. for (auto u = sink_, v = trans_second_path[u];
  231. u != source_;
  232. u = v, v = trans_second_path[u])
  233. {
  234. Vertex orig_u = new_to_old.count(u) > 0 ? new_to_old[u] : u;
  235. Vertex orig_v = new_to_old.count(v) > 0 ? new_to_old[v] : v;
  236. orig_second_path[orig_u] = orig_v;
  237. }
  238. util::Logger::LogDebug("check if the two paths are already vertex disjoint");
  239. // Check if the two paths have vertices (except source and sink) in common
  240. bool vertex_disjoint = true;
  241. for (auto u = orig_first_path[sink_]; u != source_; u = orig_first_path[u])
  242. {
  243. if (orig_second_path.count(u) > 0)
  244. {
  245. vertex_disjoint = false;
  246. break;
  247. }
  248. }
  249. // If the paths are not vertex disjoint, we need to remove the edges common to both paths
  250. if (!vertex_disjoint)
  251. {
  252. util::Logger::LogDebug("remove edges used by both paths to guarantee vertex disjointness");
  253. for (auto u = sink_, v = orig_first_path[u];
  254. u != source_;
  255. u = v, v = orig_first_path[u])
  256. {
  257. if (orig_second_path.count(v) > 0 && orig_second_path[v] == u)
  258. {
  259. orig_first_path.erase(u);
  260. orig_second_path.erase(v);
  261. }
  262. }
  263. }
  264. util::Logger::LogDebug("add the first and second path to the map of all paths");
  265. // Store the paths
  266. AddPath(orig_first_path);
  267. AddPath(orig_second_path);
  268. }
  269. void KShortestPaths::AddPath(VertexPredecessorMap& path)
  270. {
  271. for (auto edge : path)
  272. {
  273. if (edge.first == edge.second)
  274. continue;
  275. if (edge.first == sink_)
  276. sink_neighbors_.push_back(edge.second);
  277. else
  278. paths_[edge.first] = edge.second;
  279. }
  280. }
  281. void KShortestPaths::AddPath(VertexPredecessorMap& in, MultiPredecessorMap& out)
  282. {
  283. for (auto edge : in)
  284. {
  285. if (edge.first != edge.second)
  286. out[edge.first].insert(edge.second);
  287. }
  288. }
  289. void KShortestPaths::AddPaths(MultiPredecessorMap& paths)
  290. {
  291. for (auto pair : paths)
  292. {
  293. Vertex t = pair.first;
  294. for (auto s : pair.second)
  295. {
  296. if (t == sink_)
  297. sink_neighbors_.push_back(s);
  298. else
  299. paths_[t] = s;
  300. }
  301. }
  302. }
  303. void KShortestPaths::FindPaths(size_t count)
  304. {
  305. VertexIter vi, vi_end;
  306. EdgeIter ei, ei_end;
  307. // The edge weights of the original graph
  308. EdgeWeightMap orig_weights = boost::get(boost::edge_weight, orig_graph_);
  309. // All found paths
  310. MultiPredecessorMap k_orig_paths;
  311. util::Logger::LogDebug("find the 1. path (in the original graph)");
  312. // Find the first path (only path found in the original graph)
  313. VertexDistanceMap orig_distances;
  314. VertexPredecessorMap orig_first_path;
  315. if (!FindPath(orig_graph_, source_, sink_, orig_first_path, orig_distances))
  316. {
  317. util::Logger::LogInfo("Not even a single path could have been found!");
  318. return;
  319. }
  320. AddPath(orig_first_path, k_orig_paths);
  321. // Transform the original edge weights
  322. for (boost::tie(ei, ei_end) = boost::edges(orig_graph_); ei != ei_end; ++ei)
  323. {
  324. Vertex source = boost::source(*ei, orig_graph_);
  325. Vertex target = boost::target(*ei, orig_graph_);
  326. orig_weights[*ei] = orig_distances[source] + orig_weights[*ei] - orig_distances[target];
  327. }
  328. // Find the specified amount of paths iteratively
  329. for (size_t i = 1; i < count; ++i)
  330. {
  331. util::Logger::LogDebug("copy the original graph");
  332. // Create a graph used for transformations and start by copying the vertices
  333. DirectedGraph trans_graph;
  334. for (boost::tie(vi, vi_end) = boost::vertices(orig_graph_); vi != vi_end; ++vi)
  335. {
  336. boost::add_vertex(trans_graph);
  337. }
  338. util::Logger::LogDebug("invert the edges along all previous found paths");
  339. // Invert edges for all previous paths (also invert their weight)
  340. std::vector<EdgeIter> edge_queue;
  341. for (boost::tie(ei, ei_end) = boost::edges(orig_graph_); ei != ei_end; ++ei)
  342. {
  343. Vertex source = boost::source(*ei, orig_graph_);
  344. Vertex target = boost::target(*ei, orig_graph_);
  345. if (k_orig_paths.count(target) > 0 && k_orig_paths[target].count(source) > 0)
  346. {
  347. Weight weight = orig_weights[*ei];
  348. boost::add_edge(target, source, -weight, trans_graph);
  349. }
  350. else
  351. {
  352. edge_queue.push_back(ei);
  353. }
  354. }
  355. util::Logger::LogDebug("split the nodes along all previous found path");
  356. // Split nodes
  357. VertexPredecessorMap old_to_new;
  358. VertexPredecessorMap new_to_old;
  359. for (auto orig_edge : k_orig_paths)
  360. {
  361. Vertex source = *orig_edge.second.begin();
  362. Vertex target = orig_edge.first;
  363. // Create the concomitant vertex
  364. Vertex new_target = boost::add_vertex(trans_graph);
  365. old_to_new[target] = new_target;
  366. new_to_old[new_target] = target;
  367. // Retrieve the weight from the original path in the original graph
  368. Weight weight = 0.0;
  369. Edge edge;
  370. bool e_found;
  371. boost::tie(edge, e_found) = boost::edge(source, target, orig_graph_);
  372. if (e_found)
  373. {
  374. weight = orig_weights[edge];
  375. }
  376. else
  377. {
  378. util::Logger::LogError("error: edge not found " + std::to_string(source) +
  379. " -> " + std::to_string(target));
  380. }
  381. // Create the edge from the concomitant vertex to the path predecessor
  382. boost::add_edge(new_target, source, -weight, trans_graph);
  383. }
  384. util::Logger::LogDebug("extend the copied graph with the remaining edges");
  385. // Add all remaining edges
  386. for (auto e : edge_queue)
  387. {
  388. Vertex source = boost::source(*e, orig_graph_);
  389. Vertex target = boost::target(*e, orig_graph_);
  390. Weight weight = orig_weights[*e];
  391. // If the edge points to source or sink add the edge unchanged
  392. if (target == source_ || target == sink_)
  393. {
  394. boost::add_edge(source, target, weight, trans_graph);
  395. continue;
  396. }
  397. // If the edge points to split vertices (vertices on the path except source and
  398. // sink), point the edge towards the concomitant vertex
  399. if (k_orig_paths.count(target) > 0 && old_to_new.count(target) > 0)
  400. {
  401. boost::add_edge(source, old_to_new[target], weight, trans_graph);
  402. continue;
  403. }
  404. // Add every other edge unchanged
  405. boost::add_edge(source, target, weight, trans_graph);
  406. }
  407. util::Logger::LogDebug("find the " + std::to_string(i + 1) +
  408. ". path (in the copied and transformed graph)");
  409. // Find the next path in the transformed graph
  410. VertexPredecessorMap trans_next_path;
  411. if (!FindPath(trans_graph, source_, sink_, trans_next_path))
  412. {
  413. util::Logger::LogInfo("No more paths may be found!");
  414. return;
  415. }
  416. util::Logger::LogDebug("map the second path into the original graph");
  417. // Map the second path from the transformed graph into the original graph
  418. VertexPredecessorMap orig_next_path;
  419. for (auto u = sink_, v = trans_next_path[u]; u != source_; u = v, v = trans_next_path[u])
  420. {
  421. Vertex orig_u = new_to_old.count(u) > 0 ? new_to_old[u] : u;
  422. Vertex orig_v = new_to_old.count(v) > 0 ? new_to_old[v] : v;
  423. orig_next_path[orig_u] = orig_v;
  424. }
  425. AddPath(orig_next_path, k_orig_paths);
  426. util::Logger::LogDebug("remove edges used by multiple paths to guarantee vertex disjointness");
  427. // Remove edges used by multiple paths
  428. for (auto pair : k_orig_paths)
  429. {
  430. Vertex target = pair.first;
  431. for (auto source : pair.second)
  432. {
  433. if (k_orig_paths.count(source) > 0 && k_orig_paths[source].count(target) > 0)
  434. {
  435. k_orig_paths[source].erase(target);
  436. k_orig_paths[target].erase(source);
  437. }
  438. }
  439. }
  440. util::Logger::LogDebug("remove vertices with no edges from the path");
  441. // Remove empty vertices from the paths
  442. for (auto iter = k_orig_paths.begin(); iter != k_orig_paths.end(); )
  443. {
  444. auto pair = *iter;
  445. if (pair.second.empty())
  446. {
  447. iter = k_orig_paths.erase(iter);
  448. }
  449. else
  450. {
  451. ++iter;
  452. }
  453. }
  454. }
  455. // Store the paths
  456. AddPaths(k_orig_paths);
  457. }
  458. void KShortestPaths::GetPaths(std::vector<std::vector<Vertex>>& paths)
  459. {
  460. for (auto v : sink_neighbors_)
  461. {
  462. std::vector<Vertex> path;
  463. path.push_back(sink_);
  464. for (auto u = v; u != source_; u = paths_[u])
  465. {
  466. path.insert(path.begin(), u);
  467. }
  468. path.insert(path.begin(), source_);
  469. paths.push_back(path);
  470. }
  471. }
  472. }