123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- //
- // Created by wrede on 25.05.16.
- //
- #include "KShortestPaths.h"
- #include "../util/Logger.h"
- #include "../util/FileIO.h"
- #include <boost/graph/dijkstra_shortest_paths.hpp>
- #include <boost/graph/bellman_ford_shortest_paths.hpp>
- #include <boost/graph/copy.hpp>
- namespace algo
- {
- KShortestPaths::KShortestPaths(DirectedGraph graph, Vertex source, Vertex sink)
- : original_graph_(graph), source_(source), sink_(sink)
- {
- }
- MultiPredecessorMap KShortestPaths::Run(size_t max_path_count)
- {
- util::Logger::LogInfo("Running k-shortest-paths");
- // Clear all data from previous runs
- i_shortest_paths_.clear();
- util::Logger::LogDebug("find shortest path #0");
- util::Logger::LogDebug("find");
- FindAndAugmentPath(0, true);
- // Find the k shortest paths
- for (size_t i = 0; i < max_path_count - 1; ++i)
- {
- if (i > 0)
- {
- // If the costs are increasing, no further shortest paths will
- // be found
- if (OverallCosts(i) > OverallCosts(i - 1))
- {
- return i_shortest_paths_[i];
- }
- }
- util::Logger::LogDebug("find shortest path #" + std::to_string(i + 1));
- util::Logger::LogDebug("copy");
- // Create a copy of the original graph which is used
- // for the graph and edge transformations
- CopyOriginalGraph();
- util::FileIO::WriteCSVMatlab(copied_graph_,
- "/home/wrede/Dokumente/graph_" +
- std::to_string(i) + "_c.csv");
- util::Logger::LogDebug("extend");
- // Extend the graph (has negative and positive edge weights)
- ExtendGraph(i);
- util::FileIO::WriteCSVMatlab(copied_graph_,
- "/home/wrede/Dokumente/graph_" +
- std::to_string(i) + "_e.csv");
- util::Logger::LogDebug("transform");
- // Transforms the edge costs (has only positive edge weights)
- if (i > 0)
- {
- TransformEdgeCosts(i - 1, false);
- }
- else
- {
- TransformEdgeCosts(0, true);
- }
- util::FileIO::WriteCSVMatlab(copied_graph_,
- "/home/wrede/Dokumente/graph_" +
- std::to_string(i) + "_t.csv");
- util::Logger::LogDebug("find");
- // Finds the next path and adds it to the found paths
- FindAndAugmentPath(i + 1, false);
- util::Logger::LogDebug("interlace");
- // Removes the duplicate edges to make the paths node-disjoint
- Interlace(i + 1);
- }
- // All k shortest paths have been found
- return i_shortest_paths_[max_path_count - 1];
- }
- void KShortestPaths::ExtendGraph(size_t i)
- {
- boost::graph_traits<DirectedGraph>::out_edge_iterator oei, oei_end;
- boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
- boost::graph_traits<DirectedGraph>::vertex_iterator vi, vi_end;
- VertexValueMap graph_values = boost::get(boost::vertex_name, copied_graph_);
- // Split all vertices within the paths
- for (boost::tie(vi, vi_end) = boost::vertices(original_graph_);
- vi != vi_end; ++vi)
- {
- // Create a copy of each vertex for easy index matching with
- // preceding and succeeding iterations
- Vertex v_original = (*vi);
- Vertex v_in = original_to_copy_[v_original];
- Vertex v_out = boost::add_vertex(graph_values[v_in], copied_graph_);
- // Ignore vertices off the paths, the source and the sink
- if (i_shortest_paths_[i].count(v_original) == 0 ||
- v_original == source_ || v_original == sink_)
- {
- continue;
- }
- copy_to_original_[v_out] = v_original;
- // Copy outgoing edges to v_out
- for (boost::tie(oei, oei_end) = boost::out_edges(v_in, copied_graph_);
- oei != oei_end; ++oei)
- {
- QueueAddEdge(v_out, boost::target(*oei, copied_graph_),
- boost::get(boost::edge_weight, copied_graph_, *oei));
- }
- // Remove outgoing edges from vertex
- for (boost::tie(oei, oei_end) = boost::out_edges(v_in, copied_graph_);
- oei != oei_end; ++oei)
- {
- QueueRemoveEdge(v_in, boost::target(*oei, copied_graph_));
- }
- // Create auxiliary edge (inverted -> won't be iterated in the next step)
- QueueAddEdge(v_out, v_in, 0.0);
- }
- UpdateEdges();
- // Iterate all edges within the copied graph
- EdgeWeightMap weights = boost::get(boost::edge_weight, copied_graph_);
- for (boost::tie(ei, ei_end) = boost::edges(copied_graph_);
- ei != ei_end; ++ei)
- {
- Vertex s_copy = boost::source(*ei, copied_graph_);
- Vertex t_copy = boost::target(*ei, copied_graph_);
- Vertex s_orig = copy_to_original_[s_copy];
- Vertex t_orig = copy_to_original_[t_copy];
- double weight = weights[*ei];
- // If the edge is part of the paths
- if (i_shortest_paths_[i].count(t_orig) > 0 &&
- i_shortest_paths_[i][t_orig].count(s_orig) > 0)
- {
- // Add the edge with direction and weight inverted
- QueueAddEdge(t_copy, s_copy, -weight);
- // Remove the old edge
- QueueRemoveEdge(s_copy, t_copy);
- }
- }
- UpdateEdges();
- util::Logger::LogDebug("num vertices original " + std::to_string(boost::num_vertices(original_graph_)));
- util::Logger::LogDebug("num vertices copy " + std::to_string(boost::num_vertices(copied_graph_)));
- }
- double KShortestPaths::OverallCosts(size_t i)
- {
- double value = 0.0;
- EdgeWeightMap weights = boost::get(boost::edge_weight, original_graph_);
- // Iterate all edges
- boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(original_graph_);
- ei != ei_end; ++ei)
- {
- Vertex source = boost::source(*ei, original_graph_);
- Vertex target = boost::target(*ei, original_graph_);
- if (i_shortest_paths_[i].count(target) > 0 &&
- i_shortest_paths_[i][target].count(source) > 0)
- {
- value += weights[*ei];
- }
- }
- // for (size_t cost_i = 0; cost_i <= i; ++cost_i)
- // {
- // value += i_distances_[cost_i][sink_];
- // }
- util::Logger::LogDebug("cost in " + std::to_string(i) + " : " + std::to_string(value));
- return value;
- }
- void KShortestPaths::CopyOriginalGraph()
- {
- // Clear all previous data
- copied_graph_.clear();
- original_to_copy_.clear();
- copy_to_original_.clear();
- // Copy the graph and store the vertex map temporarily
- std::vector<Vertex> original_to_copy_vector(boost::num_vertices(original_graph_));
- VertexVertexMap temp_map(original_to_copy_vector.begin());
- boost::copy_graph(original_graph_,
- copied_graph_,
- boost::orig_to_copy(temp_map));
- // Copy the vertex map into the two persistent maps, one for each
- // mapping direction
- boost::graph_traits<DirectedGraph>::vertex_iterator vi, vi_end;
- for (boost::tie(vi, vi_end) = boost::vertices(original_graph_);
- vi != vi_end; ++vi)
- {
- Vertex v_original = (*vi);
- Vertex v_copy = temp_map[v_original];
- original_to_copy_[v_original] = v_copy;
- copy_to_original_[v_copy] = v_original;
- }
- }
- void KShortestPaths::Interlace(size_t i)
- {
- boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(original_graph_);
- ei != ei_end; ++ei)
- {
- Vertex source = boost::source(*ei, original_graph_);
- Vertex target = boost::target(*ei, original_graph_);
- // Ignore source and sink
- if (source == source_ || target == sink_)
- {
- continue;
- }
- // Is edge within paths?
- if (i_shortest_paths_[i].count(target) > 0 &&
- i_shortest_paths_[i][target].count(source) > 0)
- {
- // Is edge duplicate?
- if (i_shortest_paths_[i].count(source) > 0 &&
- i_shortest_paths_[i][source].count(target) > 0)
- {
- i_shortest_paths_[i][target].erase(source);
- i_shortest_paths_[i][source].erase(target);
- }
- }
- }
- }
- void KShortestPaths::FindAndAugmentPath(size_t i, bool original)
- {
- // Add new path maps until the needed iteration is reached
- while (i_shortest_paths_.size() < (i + 1))
- {
- i_shortest_paths_.push_back(MultiPredecessorMap());
- }
- // Add new distance maps until the needed iteration is reached
- while (i_distances_.size() < (i + 1))
- {
- i_distances_.push_back(std::unordered_map<Vertex, double>());
- }
- // Only copy old paths if old paths exist
- if (i > 0)
- {
- // Copy the old paths
- for (auto it = i_shortest_paths_[i - 1].begin();
- it != i_shortest_paths_[i - 1].end(); ++it)
- {
- i_shortest_paths_[i][it->first] = it->second;
- }
- }
- if (original)
- {
- // Prepare variables for path finding
- size_t graph_size = boost::num_vertices(original_graph_);
- std::vector<Vertex> pred_list(graph_size);
- std::vector<double> dist_list(graph_size);
- VertexIndexMap graph_indices = boost::get(boost::vertex_index,
- original_graph_);
- EdgeWeightMap weight_map = boost::get(boost::edge_weight,
- original_graph_);
- PredecessorMap pred_map(&pred_list[0], graph_indices);
- DistanceMap dist_map(&dist_list[0], graph_indices);
- // Find the shortest path
- boost::bellman_ford_shortest_paths(original_graph_,
- graph_size,
- boost::root_vertex(source_)
- .weight_map(weight_map)
- .predecessor_map(pred_map)
- .distance_map(dist_map));
- // Add the new distances
- boost::graph_traits<DirectedGraph>::vertex_iterator vi, vi_end;
- for (boost::tie(vi, vi_end) = boost::vertices(original_graph_);
- vi != vi_end; ++vi)
- {
- i_distances_[i][*vi] = dist_map[*vi];
- }
- // Add the new path
- size_t path_length = 0;
- for (Vertex u = sink_, v = pred_map[u];
- u != v; u = v, v = pred_map[v])
- {
- i_shortest_paths_[i][u].insert(v);
- ++path_length;
- }
- util::Logger::LogDebug("path length " + std::to_string(path_length));
- }
- else
- {
- // Prepare variables for path finding
- size_t graph_size = boost::num_vertices(copied_graph_);
- std::vector<Vertex> pred_list(graph_size);
- std::vector<double> dist_list(graph_size);
- VertexIndexMap graph_indices = boost::get(boost::vertex_index,
- copied_graph_);
- PredecessorMap pred_map(&pred_list[0], graph_indices);
- DistanceMap dist_map(&dist_list[0], graph_indices);
- // Find the shortest path
- boost::dijkstra_shortest_paths(copied_graph_,
- original_to_copy_[source_],
- boost::predecessor_map(pred_map)
- .distance_map(dist_map));
- util::Logger::LogDebug("add the path");
- // Add the new distances
- boost::graph_traits<DirectedGraph>::vertex_iterator vi, vi_end;
- for (boost::tie(vi, vi_end) = boost::vertices(copied_graph_);
- vi != vi_end; ++vi)
- {
- Vertex v_copy = *vi;
- i_distances_[i][v_copy] = dist_map[v_copy];
- }
- // Add the new path (the given path is in the copied graph, so the
- // vertices need to be mapped to the original graph)
- size_t path_length = 0;
- Vertex sink_copy = original_to_copy_[sink_];
- std::cout << sink_;
- for (Vertex u_copy = sink_copy, v_copy = pred_map[u_copy];
- u_copy != v_copy; u_copy = v_copy, v_copy = pred_map[v_copy])
- {
- Vertex u_original = copy_to_original_[u_copy];
- Vertex v_original = copy_to_original_[v_copy];
- // Ignore loops
- if (u_original == v_original)
- {
- continue;
- }
- std::cout << "->" << v_original;
- i_shortest_paths_[i][u_original].insert(v_original);
- ++path_length;
- }
- std::cout << std::endl;
- util::Logger::LogDebug("path length " + std::to_string(path_length));
- }
- // Add source
- i_shortest_paths_[i][source_].insert(source_);
- }
- void KShortestPaths::TransformEdgeCosts(size_t i, bool original)
- {
- EdgeWeightMap weights = boost::get(boost::edge_weight, copied_graph_);
- boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
- if (original)
- {
- for (boost::tie(ei, ei_end) = boost::edges(copied_graph_);
- ei != ei_end; ++ei)
- {
- Vertex s_copy = boost::source(*ei, copied_graph_);
- Vertex t_copy = boost::target(*ei, copied_graph_);
- Vertex s_orig = copy_to_original_[s_copy];
- Vertex t_orig = copy_to_original_[t_copy];
- if (i_distances_[i].count(s_orig) > 0 &&
- i_distances_[i].count(t_orig) > 0)
- {
- weights[*ei] +=
- i_distances_[i][s_orig] - i_distances_[i][t_orig];
- util::Logger::LogDebug(std::to_string(weights[*ei]));
- }
- }
- }
- else
- {
- for (boost::tie(ei, ei_end) = boost::edges(copied_graph_);
- ei != ei_end; ++ei)
- {
- Vertex s_copy = boost::source(*ei, copied_graph_);
- Vertex t_copy = boost::target(*ei, copied_graph_);
- if (i_distances_[i].count(s_copy) > 0 &&
- i_distances_[i].count(t_copy) > 0)
- {
- weights[*ei] +=
- i_distances_[i][s_copy] - i_distances_[i][t_copy];
- util::Logger::LogDebug(std::to_string(weights[*ei]));
- }
- }
- }
- }
- void KShortestPaths::UpdateEdges()
- {
- // Remove the old edges, needs to be done without any iterator since
- // the removal invalidates any iterators
- for (auto edge : edges_to_remove_)
- {
- boost::remove_edge(edge.first, edge.second, copied_graph_);
- }
- edges_to_remove_.clear();
- // Add the new edges, needs to be done without any iterator since
- // the addition invalidates any iterators
- for (auto edge : edges_to_add_)
- {
- boost::add_edge(edge.first.first, edge.first.second,
- edge.second, copied_graph_);
- }
- edges_to_add_.clear();
- }
- void KShortestPaths::QueueAddEdge(Vertex source, Vertex target, double weight)
- {
- edges_to_add_.push_back(
- std::pair<std::pair<Vertex, Vertex>, double>(
- std::pair<Vertex, Vertex>(source, target), weight));
- }
- void KShortestPaths::QueueRemoveEdge(Vertex source, Vertex target)
- {
- edges_to_remove_.push_back(std::pair<Vertex, Vertex>(source, target));
- }
- }
|