Restructure the construction of the undirected graph

This commit is contained in:
Patrick Niklaus
2015-06-29 00:42:22 +02:00
parent 4a7451682b
commit 021a1c7a39
7 changed files with 169 additions and 230 deletions
+1 -1
View File
@@ -138,7 +138,7 @@ template <typename EdgeDataT> class DynamicGraph
unsigned degree = 0;
for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
{
if (GetEdgeData(edge).forward)
if (!GetEdgeData(edge).reversed)
{
++degree;
}
+23 -160
View File
@@ -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 <tbb/parallel_sort.h>
@@ -41,16 +41,16 @@ struct NodeBasedEdgeData
NodeBasedEdgeData()
: distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
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,
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<NodeBasedEdgeData>;
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<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,
"changing node based edge data size changes memory consumption");
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)
auto edges_list = directedEdgesFromCompressed<NodeBasedDynamicGraph::InputEdge>(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<int>(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<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());
auto graph = std::make_shared<NodeBasedDynamicGraph>(
static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
#ifndef NDEBUG
BOOST_ASSERT(validateNodeBasedGraph(*graph));
#endif
return graph;
}