Restructure the construction of the undirected graph
This commit is contained in:
parent
4a7451682b
commit
021a1c7a39
@ -6,6 +6,8 @@
|
|||||||
#include "../data_structures/restriction_map.hpp"
|
#include "../data_structures/restriction_map.hpp"
|
||||||
#include "../data_structures/percent.hpp"
|
#include "../data_structures/percent.hpp"
|
||||||
|
|
||||||
|
#include "../util/simple_logger.hpp"
|
||||||
|
|
||||||
GraphCompressor::GraphCompressor(const SpeedProfileProperties& speed_profile)
|
GraphCompressor::GraphCompressor(const SpeedProfileProperties& speed_profile)
|
||||||
: speed_profile(speed_profile)
|
: speed_profile(speed_profile)
|
||||||
{
|
{
|
||||||
@ -59,8 +61,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
|
|||||||
//
|
//
|
||||||
// If the edges are compatible.
|
// If the edges are compatible.
|
||||||
|
|
||||||
const bool reverse_edge_order =
|
const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
|
||||||
!(graph.GetEdgeData(graph.BeginEdges(node_v)).forward);
|
|
||||||
const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
|
const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
|
||||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
|
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
|
||||||
BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
|
BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
|
||||||
|
@ -180,20 +180,20 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
|
|||||||
|
|
||||||
if (forward_data.edge_id != SPECIAL_NODEID)
|
if (forward_data.edge_id != SPECIAL_NODEID)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(forward_data.forward);
|
BOOST_ASSERT(!forward_data.reversed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!forward_data.forward);
|
BOOST_ASSERT(forward_data.reversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reverse_data.edge_id != SPECIAL_NODEID)
|
if (reverse_data.edge_id != SPECIAL_NODEID)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(reverse_data.forward);
|
BOOST_ASSERT(!reverse_data.reversed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!reverse_data.forward);
|
BOOST_ASSERT(reverse_data.reversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID ||
|
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);
|
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
|
||||||
|
|
||||||
// this edge is an incoming edge
|
// only number incoming edges
|
||||||
if (!edge_data.forward)
|
if (edge_data.reversed)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -379,7 +379,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
progress.printStatus(node_u);
|
progress.printStatus(node_u);
|
||||||
for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(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;
|
continue;
|
||||||
}
|
}
|
||||||
@ -392,7 +392,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
|
|
||||||
for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v))
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
@ -439,8 +439,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
|
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
|
||||||
|
|
||||||
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
||||||
BOOST_ASSERT(edge_data1.forward);
|
BOOST_ASSERT(!edge_data1.reversed);
|
||||||
BOOST_ASSERT(edge_data2.forward);
|
BOOST_ASSERT(!edge_data2.reversed);
|
||||||
|
|
||||||
// the following is the core of the loop.
|
// the following is the core of the loop.
|
||||||
unsigned distance = edge_data1.distance;
|
unsigned distance = edge_data1.distance;
|
||||||
|
@ -355,7 +355,7 @@ Prepare::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
|||||||
return std::shared_ptr<NodeBasedDynamicGraph>();
|
return std::shared_ptr<NodeBasedDynamicGraph>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
|
return NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
unsigned degree = 0;
|
unsigned degree = 0;
|
||||||
for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
|
for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
|
||||||
{
|
{
|
||||||
if (GetEdgeData(edge).forward)
|
if (!GetEdgeData(edge).reversed)
|
||||||
{
|
{
|
||||||
++degree;
|
++degree;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#include "dynamic_graph.hpp"
|
#include "dynamic_graph.hpp"
|
||||||
#include "import_edge.hpp"
|
#include "import_edge.hpp"
|
||||||
#include "../util/simple_logger.hpp"
|
#include "../util/graph_utils.hpp"
|
||||||
|
|
||||||
#include <tbb/parallel_sort.h>
|
#include <tbb/parallel_sort.h>
|
||||||
|
|
||||||
@ -41,16 +41,16 @@ struct NodeBasedEdgeData
|
|||||||
NodeBasedEdgeData()
|
NodeBasedEdgeData()
|
||||||
: distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
|
: distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
|
||||||
name_id(std::numeric_limits<unsigned>::max()), access_restricted(false),
|
name_id(std::numeric_limits<unsigned>::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,
|
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)
|
bool roundabout, TravelMode travel_mode)
|
||||||
: distance(distance), edge_id(edge_id),
|
: distance(distance), edge_id(edge_id), name_id(name_id),
|
||||||
name_id(name_id), access_restricted(access_restricted),
|
access_restricted(access_restricted), reversed(reversed),
|
||||||
forward(forward), backward(backward), roundabout(roundabout), travel_mode(travel_mode)
|
roundabout(roundabout), travel_mode(travel_mode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,180 +58,43 @@ struct NodeBasedEdgeData
|
|||||||
unsigned edge_id;
|
unsigned edge_id;
|
||||||
unsigned name_id;
|
unsigned name_id;
|
||||||
bool access_restricted : 1;
|
bool access_restricted : 1;
|
||||||
bool forward : 1;
|
bool reversed : 1;
|
||||||
bool backward : 1;
|
|
||||||
bool roundabout : 1;
|
bool roundabout : 1;
|
||||||
TravelMode travel_mode : 4;
|
TravelMode travel_mode : 4;
|
||||||
|
|
||||||
void SwapDirectionFlags()
|
|
||||||
{
|
|
||||||
bool temp_flag = forward;
|
|
||||||
forward = backward;
|
|
||||||
backward = temp_flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsCompatibleTo(const NodeBasedEdgeData &other) const
|
bool IsCompatibleTo(const NodeBasedEdgeData &other) const
|
||||||
{
|
{
|
||||||
return (forward == other.forward) && (backward == other.backward) &&
|
return (reversed == other.reversed) && (name_id == other.name_id) &&
|
||||||
(name_id == other.name_id) && (travel_mode == other.travel_mode);
|
(travel_mode == other.travel_mode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
|
using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
|
||||||
|
|
||||||
inline bool validateNeighborHood(const NodeBasedDynamicGraph& graph, const NodeID source)
|
/// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
|
||||||
{
|
/// The since DynamicGraph expects directed edges, we need to insert
|
||||||
for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge)
|
/// two edges for undirected edges.
|
||||||
{
|
|
||||||
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.
|
|
||||||
inline std::shared_ptr<NodeBasedDynamicGraph>
|
inline std::shared_ptr<NodeBasedDynamicGraph>
|
||||||
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<NodeBasedEdge> &input_edge_list)
|
NodeBasedDynamicGraphFromEdges(int number_of_nodes, const std::vector<NodeBasedEdge> &input_edge_list)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(NodeBasedEdgeData) == 16,
|
auto edges_list = directedEdgesFromCompressed<NodeBasedDynamicGraph::InputEdge>(input_edge_list,
|
||||||
"changing node based edge data size changes memory consumption");
|
[](NodeBasedDynamicGraph::InputEdge& output_edge, const NodeBasedEdge& input_edge)
|
||||||
|
|
||||||
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> 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)
|
|
||||||
{
|
{
|
||||||
edge.source = import_edge.source;
|
output_edge.data.distance = static_cast<int>(input_edge.weight);
|
||||||
edge.target = import_edge.target;
|
BOOST_ASSERT(output_edge.data.distance > 0);
|
||||||
edge.data.forward = import_edge.forward;
|
|
||||||
edge.data.backward = import_edge.backward;
|
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<int>(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());
|
tbb::parallel_sort(edges_list.begin(), edges_list.end());
|
||||||
|
|
||||||
auto graph = std::make_shared<NodeBasedDynamicGraph>(
|
auto graph = std::make_shared<NodeBasedDynamicGraph>(
|
||||||
static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
|
static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
BOOST_ASSERT(validateNodeBasedGraph(*graph));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,25 +12,6 @@
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(graph_compressor)
|
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)
|
BOOST_AUTO_TEST_CASE(long_road_test)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@ -46,15 +27,15 @@ BOOST_AUTO_TEST_CASE(long_road_test)
|
|||||||
|
|
||||||
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
||||||
std::vector<InputEdge> edges = {
|
std::vector<InputEdge> edges = {
|
||||||
// source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
|
// source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode
|
||||||
{0, 1, 1, SPECIAL_EDGEID, 0, 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, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{2, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{3, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{3, 4, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{4, 3, 1, SPECIAL_EDGEID, 0, false, true, true, 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));
|
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[2].data));
|
||||||
@ -89,18 +70,18 @@ BOOST_AUTO_TEST_CASE(loop_test)
|
|||||||
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
||||||
std::vector<InputEdge> edges = {
|
std::vector<InputEdge> edges = {
|
||||||
// source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
|
// 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, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{0, 5, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{0, 5, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{2, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{3, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{3, 4, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{4, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{4, 5, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{4, 5, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{5, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{5, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{5, 4, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{5, 4, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOST_ASSERT(edges.size() == 12);
|
BOOST_ASSERT(edges.size() == 12);
|
||||||
@ -145,13 +126,13 @@ BOOST_AUTO_TEST_CASE(t_intersection)
|
|||||||
|
|
||||||
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
||||||
std::vector<InputEdge> edges = {
|
std::vector<InputEdge> edges = {
|
||||||
// source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
|
// source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode
|
||||||
{0, 1, 1, SPECIAL_EDGEID, 0, 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, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 3, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 3, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{3, 1, 1, SPECIAL_EDGEID, 0, false, true, true, 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));
|
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
|
||||||
@ -184,10 +165,10 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
|
|||||||
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
||||||
std::vector<InputEdge> edges = {
|
std::vector<InputEdge> edges = {
|
||||||
// source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
|
// 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, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 0, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 2, 1, SPECIAL_EDGEID, 1, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 2, 1, SPECIAL_EDGEID, 1, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{2, 1, 1, SPECIAL_EDGEID, 1, false, true, true, 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));
|
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
|
||||||
@ -215,11 +196,11 @@ BOOST_AUTO_TEST_CASE(direction_changes)
|
|||||||
|
|
||||||
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
using InputEdge = NodeBasedDynamicGraph::InputEdge;
|
||||||
std::vector<InputEdge> edges = {
|
std::vector<InputEdge> edges = {
|
||||||
// source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
|
// source, target, distance, edge_id, name_id, access_restricted, reverse, roundabout, travel_mode
|
||||||
{0, 1, 1, SPECIAL_EDGEID, 0, false, true, false, false, TRAVEL_MODE_DEFAULT},
|
{0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 0, 1, SPECIAL_EDGEID, 0, false, false, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 0, 1, SPECIAL_EDGEID, 0, false, true, false, TRAVEL_MODE_DEFAULT},
|
||||||
{1, 2, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
{2, 1, 1, SPECIAL_EDGEID, 0, false, true, true, false, TRAVEL_MODE_DEFAULT},
|
{2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, TRAVEL_MODE_DEFAULT},
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeBasedDynamicGraph graph(5, edges);
|
NodeBasedDynamicGraph graph(5, edges);
|
||||||
|
94
util/graph_utils.hpp
Normal file
94
util/graph_utils.hpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#ifndef GRAPH_UTILS_HPP
|
||||||
|
#define GRAPH_UTILS_HPP
|
||||||
|
|
||||||
|
#include "../typedefs.h"
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/// This function checks if the graph (consisting of directed edges) is undirected
|
||||||
|
template<typename GraphT>
|
||||||
|
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<typename OutputEdgeT, typename InputEdgeT, typename FunctorT>
|
||||||
|
std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdgeT>& input_edge_list, FunctorT copy_data)
|
||||||
|
{
|
||||||
|
std::vector<OutputEdgeT> 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
|
Loading…
Reference in New Issue
Block a user