diff --git a/algorithms/graph_compressor.cpp b/algorithms/graph_compressor.cpp index c924360b6..d375a588b 100644 --- a/algorithms/graph_compressor.cpp +++ b/algorithms/graph_compressor.cpp @@ -6,6 +6,8 @@ #include "../data_structures/restriction_map.hpp" #include "../data_structures/percent.hpp" +#include "../util/simple_logger.hpp" + GraphCompressor::GraphCompressor(const SpeedProfileProperties& speed_profile) : speed_profile(speed_profile) { @@ -59,8 +61,7 @@ void GraphCompressor::Compress(const std::unordered_set& barrier_nodes, // // If the edges are compatible. - const bool reverse_edge_order = - !(graph.GetEdgeData(graph.BeginEdges(node_v)).forward); + const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed; const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order; BOOST_ASSERT(SPECIAL_EDGEID != forward_e2); BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) && diff --git a/contractor/edge_based_graph_factory.cpp b/contractor/edge_based_graph_factory.cpp index 76880ce9e..35f2f3074 100644 --- a/contractor/edge_based_graph_factory.cpp +++ b/contractor/edge_based_graph_factory.cpp @@ -180,20 +180,20 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, if (forward_data.edge_id != SPECIAL_NODEID) { - BOOST_ASSERT(forward_data.forward); + BOOST_ASSERT(!forward_data.reversed); } else { - BOOST_ASSERT(!forward_data.forward); + BOOST_ASSERT(forward_data.reversed); } if (reverse_data.edge_id != SPECIAL_NODEID) { - BOOST_ASSERT(reverse_data.forward); + BOOST_ASSERT(!reverse_data.reversed); } else { - BOOST_ASSERT(!reverse_data.forward); + BOOST_ASSERT(reverse_data.reversed); } BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID || @@ -253,8 +253,8 @@ void EdgeBasedGraphFactory::RenumberEdges() { EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge); - // this edge is an incoming edge - if (!edge_data.forward) + // only number incoming edges + if (edge_data.reversed) { continue; } @@ -379,7 +379,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( progress.printStatus(node_u); for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u)) { - if (!m_node_based_graph->GetEdgeData(e1).forward) + if (m_node_based_graph->GetEdgeData(e1).reversed) { continue; } @@ -392,7 +392,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v)) { - if (!m_node_based_graph->GetEdgeData(e2).forward) + if (m_node_based_graph->GetEdgeData(e2).reversed) { continue; } @@ -439,8 +439,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2); BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id); - BOOST_ASSERT(edge_data1.forward); - BOOST_ASSERT(edge_data2.forward); + BOOST_ASSERT(!edge_data1.reversed); + BOOST_ASSERT(!edge_data2.reversed); // the following is the core of the loop. unsigned distance = edge_data1.distance; diff --git a/contractor/processing_chain.cpp b/contractor/processing_chain.cpp index 461d38afe..f9ea4c1b3 100644 --- a/contractor/processing_chain.cpp +++ b/contractor/processing_chain.cpp @@ -355,7 +355,7 @@ Prepare::LoadNodeBasedGraph(std::unordered_set &barrier_nodes, return std::shared_ptr(); } - return NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list); + return NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list); } diff --git a/data_structures/dynamic_graph.hpp b/data_structures/dynamic_graph.hpp index f96eb1992..b8c3e42a8 100644 --- a/data_structures/dynamic_graph.hpp +++ b/data_structures/dynamic_graph.hpp @@ -138,7 +138,7 @@ template class DynamicGraph unsigned degree = 0; for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n))) { - if (GetEdgeData(edge).forward) + if (!GetEdgeData(edge).reversed) { ++degree; } diff --git a/data_structures/node_based_graph.hpp b/data_structures/node_based_graph.hpp index 60d05d15b..efdacb998 100644 --- a/data_structures/node_based_graph.hpp +++ b/data_structures/node_based_graph.hpp @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "dynamic_graph.hpp" #include "import_edge.hpp" -#include "../util/simple_logger.hpp" +#include "../util/graph_utils.hpp" #include @@ -41,16 +41,16 @@ struct NodeBasedEdgeData NodeBasedEdgeData() : distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID), name_id(std::numeric_limits::max()), access_restricted(false), - forward(false), backward(false), roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE) + reversed(false), roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE) { } NodeBasedEdgeData(int distance, unsigned edge_id, unsigned name_id, - bool access_restricted, bool forward, bool backward, + bool access_restricted, bool reversed, bool roundabout, TravelMode travel_mode) - : distance(distance), edge_id(edge_id), - name_id(name_id), access_restricted(access_restricted), - forward(forward), backward(backward), roundabout(roundabout), travel_mode(travel_mode) + : distance(distance), edge_id(edge_id), name_id(name_id), + access_restricted(access_restricted), reversed(reversed), + roundabout(roundabout), travel_mode(travel_mode) { } @@ -58,180 +58,43 @@ struct NodeBasedEdgeData unsigned edge_id; unsigned name_id; bool access_restricted : 1; - bool forward : 1; - bool backward : 1; + bool reversed : 1; bool roundabout : 1; TravelMode travel_mode : 4; - void SwapDirectionFlags() - { - bool temp_flag = forward; - forward = backward; - backward = temp_flag; - } - bool IsCompatibleTo(const NodeBasedEdgeData &other) const { - return (forward == other.forward) && (backward == other.backward) && - (name_id == other.name_id) && (travel_mode == other.travel_mode); + return (reversed == other.reversed) && (name_id == other.name_id) && + (travel_mode == other.travel_mode); } }; using NodeBasedDynamicGraph = DynamicGraph; -inline bool validateNeighborHood(const NodeBasedDynamicGraph& graph, const NodeID source) -{ - for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge) - { - const auto& data = graph.GetEdgeData(edge); - if (!data.forward && !data.backward) - { - SimpleLogger().Write(logWARNING) << "Invalid edge directions"; - return false; - } - - auto target = graph.GetTarget(edge); - if (target == SPECIAL_NODEID) - { - SimpleLogger().Write(logWARNING) << "Invalid edge target"; - return false; - } - - bool found_reverse = false; - for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target); ++rev_edge) - { - auto rev_target = graph.GetTarget(rev_edge); - if (rev_target == SPECIAL_NODEID) - { - SimpleLogger().Write(logWARNING) << "Invalid reverse edge target"; - return false; - } - - if (rev_target != source) - { - continue; - } - - if (found_reverse) - { - SimpleLogger().Write(logWARNING) << "Found more than one reverse edge"; - return false; - } - - const auto& rev_data = graph.GetEdgeData(rev_edge); - - // edge is incoming, this must be an outgoing edge - if (data.backward && !rev_data.forward) - { - SimpleLogger().Write(logWARNING) << "Found no outgoing edge to an incoming edge!"; - return false; - } - - // edge is bi-directional, reverse must be as well - if (data.forward && data.backward && (!rev_data.forward || !rev_data.backward)) - { - SimpleLogger().Write(logWARNING) << "Found bi-directional edge that is not bi-directional to both ends"; - return false; - } - - found_reverse = true; - - } - - if (!found_reverse) - { - SimpleLogger().Write(logWARNING) << "Could not find reverse edge"; - return false; - } - } - - return true; -} - -// This function checks if the overal graph is undirected (has an edge in each direction). -inline bool validateNodeBasedGraph(const NodeBasedDynamicGraph& graph) -{ - for (auto source = 0u; source < graph.GetNumberOfNodes(); ++source) - { - if (!validateNeighborHood(graph, source)) - { - return false; - } - } - - return true; -} - -// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges -// The since DynamicGraph expects directed edges, we need to insert -// two edges for undirected edges. +/// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges +/// The since DynamicGraph expects directed edges, we need to insert +/// two edges for undirected edges. inline std::shared_ptr -NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector &input_edge_list) +NodeBasedDynamicGraphFromEdges(int number_of_nodes, const std::vector &input_edge_list) { - static_assert(sizeof(NodeBasedEdgeData) == 16, - "changing node based edge data size changes memory consumption"); - - DeallocatingVector edges_list; - NodeBasedDynamicGraph::InputEdge edge; - - // Since DynamicGraph assumes directed edges we have to make sure we transformed - // the compressed edge format into single directed edges. We do this to make sure - // every node also knows its incoming edges, not only its outgoing edges and use the backward=true - // flag to indicate which is which. - // - // We do the transformation in the following way: - // - // if the edge (a, b) is split: - // 1. this edge must be in only one direction, so its a --> b - // 2. there must be another directed edge b --> a somewhere in the data - // if the edge (a, b) is not split: - // 1. this edge be on of a --> b od a <-> b - // (a <-- b gets reducted to b --> a) - // 2. a --> b will be transformed to a --> b and b <-- a - // 3. a <-> b will be transformed to a <-> b and b <-> a (I think a --> b and b <-- a would work as well though) - for (const NodeBasedEdge &import_edge : input_edge_list) - { - // edges that are not forward get converted by flipping the end points - BOOST_ASSERT(import_edge.forward); - - if (import_edge.forward) + auto edges_list = directedEdgesFromCompressed(input_edge_list, + [](NodeBasedDynamicGraph::InputEdge& output_edge, const NodeBasedEdge& input_edge) { - edge.source = import_edge.source; - edge.target = import_edge.target; - edge.data.forward = import_edge.forward; - edge.data.backward = import_edge.backward; + output_edge.data.distance = static_cast(input_edge.weight); + BOOST_ASSERT(output_edge.data.distance > 0); + + output_edge.data.roundabout = input_edge.roundabout; + output_edge.data.name_id = input_edge.name_id; + output_edge.data.access_restricted = input_edge.access_restricted; + output_edge.data.travel_mode = input_edge.travel_mode; } - - BOOST_ASSERT(edge.source != edge.target); - - edge.data.distance = static_cast(import_edge.weight); - BOOST_ASSERT(edge.data.distance > 0); - edge.data.roundabout = import_edge.roundabout; - edge.data.name_id = import_edge.name_id; - edge.data.access_restricted = import_edge.access_restricted; - edge.data.travel_mode = import_edge.travel_mode; - - edges_list.push_back(edge); - - if (!import_edge.is_split) - { - using std::swap; // enable ADL - swap(edge.source, edge.target); - edge.data.SwapDirectionFlags(); - edges_list.push_back(edge); - } - } + ); tbb::parallel_sort(edges_list.begin(), edges_list.end()); auto graph = std::make_shared( static_cast(number_of_nodes), edges_list); - -#ifndef NDEBUG - BOOST_ASSERT(validateNodeBasedGraph(*graph)); -#endif - return graph; } diff --git a/unit_tests/algorithms/graph_compressor.cpp b/unit_tests/algorithms/graph_compressor.cpp index 540631879..8f500eba5 100644 --- a/unit_tests/algorithms/graph_compressor.cpp +++ b/unit_tests/algorithms/graph_compressor.cpp @@ -12,25 +12,6 @@ BOOST_AUTO_TEST_SUITE(graph_compressor) -void dumpGraph(const NodeBasedDynamicGraph& graph) -{ - for (auto i = 0u; i < graph.GetNumberOfNodes(); ++i) - { - std::cout << "## node " << i << " degree: " << graph.GetOutDegree(i) << std::endl; - for (auto e = graph.BeginEdges(i); e < graph.EndEdges(i); ++e) - { - const auto& data = graph.GetEdgeData(e); - auto target = graph.GetTarget(e); - if (data.forward && !data.backward) - std::cout << i << "->" << target << std::endl; - if (!data.forward && data.backward) - std::cout << i << "<-" << target << std::endl; - if (data.forward && data.backward) - std::cout << i << "--" << target << std::endl; - } - } -} - BOOST_AUTO_TEST_CASE(long_road_test) { // @@ -46,15 +27,15 @@ BOOST_AUTO_TEST_CASE(long_road_test) using InputEdge = NodeBasedDynamicGraph::InputEdge; std::vector edges = { - // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {2, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {3, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {3, 4, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {4, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT} + // source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode + {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT} }; BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[2].data)); @@ -89,18 +70,18 @@ BOOST_AUTO_TEST_CASE(loop_test) using InputEdge = NodeBasedDynamicGraph::InputEdge; std::vector edges = { // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {0, 5, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {2, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {3, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {3, 4, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {4, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {4, 5, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {5, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {5, 4, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, + {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {0, 5, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {4, 5, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {5, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {5, 4, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, }; BOOST_ASSERT(edges.size() == 12); @@ -145,13 +126,13 @@ BOOST_AUTO_TEST_CASE(t_intersection) using InputEdge = NodeBasedDynamicGraph::InputEdge; std::vector edges = { - // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {3, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, + // source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode + {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {3, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, }; BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data)); @@ -184,10 +165,10 @@ BOOST_AUTO_TEST_CASE(street_name_changes) using InputEdge = NodeBasedDynamicGraph::InputEdge; std::vector edges = { // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {1, 2, 1, SPECIAL_EDGEID, 1, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {2, 1, 1, SPECIAL_EDGEID, 1, false, true, true, false, TRAVEL_MODE_DEFAULT}, + {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 2, 1, SPECIAL_EDGEID, 1, false, false, false, TRAVEL_MODE_DEFAULT}, + {2, 1, 1, SPECIAL_EDGEID, 1, false, false, false, TRAVEL_MODE_DEFAULT}, }; BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data)); @@ -215,11 +196,11 @@ BOOST_AUTO_TEST_CASE(direction_changes) using InputEdge = NodeBasedDynamicGraph::InputEdge; std::vector edges = { - // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, true, false, false, TRAVEL_MODE_DEFAULT}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, false, true, false, TRAVEL_MODE_DEFAULT}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT}, + // source, target, distance, edge_id, name_id, access_restricted, reverse, roundabout, travel_mode + {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {1, 0, 1, SPECIAL_EDGEID, 0, false, true, false, TRAVEL_MODE_DEFAULT}, + {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, + {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT}, }; NodeBasedDynamicGraph graph(5, edges); diff --git a/util/graph_utils.hpp b/util/graph_utils.hpp new file mode 100644 index 000000000..9af8dbc07 --- /dev/null +++ b/util/graph_utils.hpp @@ -0,0 +1,94 @@ +#ifndef GRAPH_UTILS_HPP +#define GRAPH_UTILS_HPP + +#include "../typedefs.h" + +#include +#include + +/// This function checks if the graph (consisting of directed edges) is undirected +template +bool isUndirectedGraph(const GraphT& graph) +{ + for (auto source = 0u; source < graph.GetNumberOfNodes(); ++source) + { + for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge) + { + const auto& data = graph.GetEdgeData(edge); + + auto target = graph.GetTarget(edge); + BOOST_ASSERT(target != SPECIAL_NODEID); + + bool found_reverse = false; + for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target); ++rev_edge) + { + auto rev_target = graph.GetTarget(rev_edge); + BOOST_ASSERT(rev_target != SPECIAL_NODEID); + + if (rev_target != source) + { + continue; + } + + BOOST_ASSERT_MSG(!found_reverse, "Found more than one reverse edge"); + found_reverse = true; + } + + if (!found_reverse) + { + return false; + } + } + } + + return true; +} + + +/// Since DynamicGraph assumes directed edges we have to make sure we transformed +/// the compressed edge format into single directed edges. We do this to make sure +/// every node also knows its incoming edges, not only its outgoing edges and use the reversed=true +/// flag to indicate which is which. +/// +/// We do the transformation in the following way: +/// +/// if the edge (a, b) is split: +/// 1. this edge must be in only one direction, so its a --> b +/// 2. there must be another directed edge b --> a somewhere in the data +/// if the edge (a, b) is not split: +/// 1. this edge be on of a --> b od a <-> b +/// (a <-- b gets reducted to b --> a) +/// 2. a --> b will be transformed to a --> b and b <-- a +/// 3. a <-> b will be transformed to a --> b and b --> a +template +std::vector directedEdgesFromCompressed(const std::vector& input_edge_list, FunctorT copy_data) +{ + std::vector output_edge_list; + + OutputEdgeT edge; + for (const auto& input_edge : input_edge_list) + { + // edges that are not forward get converted by flipping the end points + BOOST_ASSERT(input_edge.forward); + + edge.source = input_edge.source; + edge.target = input_edge.target; + edge.data.reversed = false; + + BOOST_ASSERT(edge.source != edge.target); + + copy_data(edge, input_edge); + + output_edge_list.push_back(edge); + + if (!input_edge.is_split) + { + std::swap(edge.source, edge.target); + edge.data.reversed = !input_edge.backward; + output_edge_list.push_back(edge); + } + } + + return output_edge_list; +} +#endif