add comparison tool for graph classes

This commit is contained in:
Dennis Luxen 2015-04-16 11:25:43 +02:00
parent f2cdb97867
commit c03aec364c
4 changed files with 233 additions and 34 deletions

View File

@ -332,6 +332,8 @@ if(WITH_TOOLS OR BUILD_TOOLS)
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:EXCEPTION>)
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
add_executable(osrm-graph-compare tools/graph_compare.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
target_link_libraries(osrm-graph-compare ${Boost_LIBRARIES} ${TBB_LIBRARIES})
install(TARGETS osrm-cli DESTINATION bin)
install(TARGETS osrm-io-benchmark DESTINATION bin)

View File

@ -76,8 +76,8 @@ template <typename EdgeDataT> class DynamicGraph
// Constructs an empty graph with a given number of nodes.
explicit DynamicGraph(NodeIterator nodes) : number_of_nodes(nodes), number_of_edges(0)
{
node_list.reserve(number_of_nodes);
node_list.resize(number_of_nodes);
node_array.reserve(number_of_nodes);
node_array.resize(number_of_nodes);
edge_list.reserve(number_of_nodes * 1.1);
edge_list.resize(number_of_nodes);
@ -87,29 +87,29 @@ template <typename EdgeDataT> class DynamicGraph
{
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(graph.size());
node_list.reserve(number_of_nodes + 1);
node_list.resize(number_of_nodes + 1);
// node_array.reserve(number_of_nodes + 1);
node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
for (const auto node : osrm::irange(0u, number_of_nodes))
{
EdgeIterator lastEdge = edge;
EdgeIterator last_edge = edge;
while (edge < number_of_edges && graph[edge].source == node)
{
++edge;
}
node_list[node].firstEdge = position;
node_list[node].edges = edge - lastEdge;
position += node_list[node].edges;
node_array[node].first_edge = position;
node_array[node].edges = edge - last_edge;
position += node_array[node].edges;
}
node_list.back().firstEdge = position;
node_array.back().first_edge = position;
edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
edge_list.resize(position);
edge = 0;
for (const auto node : osrm::irange(0u, number_of_nodes))
{
for (const auto i : osrm::irange(node_list[node].firstEdge,
node_list[node].firstEdge + node_list[node].edges))
for (const auto i : osrm::irange(node_array[node].first_edge,
node_array[node].first_edge + node_array[node].edges))
{
edge_list[i].target = graph[edge].target;
edge_list[i].data = graph[edge].data;
@ -124,7 +124,7 @@ template <typename EdgeDataT> class DynamicGraph
unsigned GetNumberOfEdges() const { return number_of_edges; }
unsigned GetOutDegree(const NodeIterator n) const { return node_list[n].edges; }
unsigned GetOutDegree(const NodeIterator n) const { return node_array[n].edges; }
unsigned GetDirectedOutDegree(const NodeIterator n) const
{
@ -149,12 +149,12 @@ template <typename EdgeDataT> class DynamicGraph
EdgeIterator BeginEdges(const NodeIterator n) const
{
return EdgeIterator(node_list[n].firstEdge);
return EdgeIterator(node_array[n].first_edge);
}
EdgeIterator EndEdges(const NodeIterator n) const
{
return EdgeIterator(node_list[n].firstEdge + node_list[n].edges);
return EdgeIterator(node_array[n].first_edge + node_array[n].edges);
}
EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
@ -164,7 +164,7 @@ template <typename EdgeDataT> class DynamicGraph
NodeIterator InsertNode()
{
node_list.emplace_back(node_list.back());
node_array.emplace_back(node_array.back());
number_of_nodes += 1;
return number_of_nodes;
@ -173,14 +173,14 @@ template <typename EdgeDataT> class DynamicGraph
// adds an edge. Invalidates edge iterators for the source node
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
{
Node &node = node_list[from];
EdgeIterator newFirstEdge = node.edges + node.firstEdge;
Node &node = node_array[from];
EdgeIterator newFirstEdge = node.edges + node.first_edge;
if (newFirstEdge >= edge_list.size() || !isDummy(newFirstEdge))
{
if (node.firstEdge != 0 && isDummy(node.firstEdge - 1))
if (node.first_edge != 0 && isDummy(node.first_edge - 1))
{
node.firstEdge--;
edge_list[node.firstEdge] = edge_list[node.firstEdge + node.edges];
node.first_edge--;
edge_list[node.first_edge] = edge_list[node.first_edge + node.edges];
}
else
{
@ -195,32 +195,32 @@ template <typename EdgeDataT> class DynamicGraph
edge_list.resize(edge_list.size() + newSize);
for (const auto i : osrm::irange(0u, node.edges))
{
edge_list[newFirstEdge + i] = edge_list[node.firstEdge + i];
makeDummy(node.firstEdge + i);
edge_list[newFirstEdge + i] = edge_list[node.first_edge + i];
makeDummy(node.first_edge + i);
}
for (const auto i : osrm::irange(node.edges + 1, newSize))
{
makeDummy(newFirstEdge + i);
}
node.firstEdge = newFirstEdge;
node.first_edge = newFirstEdge;
}
}
Edge &edge = edge_list[node.firstEdge + node.edges];
Edge &edge = edge_list[node.first_edge + node.edges];
edge.target = to;
edge.data = data;
++number_of_edges;
++node.edges;
return EdgeIterator(node.firstEdge + node.edges);
return EdgeIterator(node.first_edge + node.edges);
}
// removes an edge. Invalidates edge iterators for the source node
void DeleteEdge(const NodeIterator source, const EdgeIterator e)
{
Node &node = node_list[source];
Node &node = node_array[source];
--number_of_edges;
--node.edges;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
const unsigned last = node.firstEdge + node.edges;
const unsigned last = node.first_edge + node.edges;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
// swap with last edge
edge_list[e] = edge_list[last];
@ -245,7 +245,7 @@ template <typename EdgeDataT> class DynamicGraph
}
number_of_edges -= deleted;
node_list[source].edges -= deleted;
node_array[source].edges -= deleted;
return deleted;
}
@ -277,7 +277,7 @@ template <typename EdgeDataT> class DynamicGraph
struct Node
{
// index of the first edge
EdgeIterator firstEdge;
EdgeIterator first_edge;
// amount of edges
unsigned edges;
};
@ -291,7 +291,7 @@ template <typename EdgeDataT> class DynamicGraph
NodeIterator number_of_nodes;
std::atomic_uint number_of_edges;
std::vector<Node> node_list;
std::vector<Node> node_array;
DeallocatingVector<Edge> edge_list;
};

View File

@ -91,7 +91,6 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
StaticGraph(const int nodes, std::vector<InputEdge> &graph)
{
tbb::parallel_sort(graph.begin(), graph.end());
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(graph.size());
node_array.resize(number_of_nodes + 1);
@ -112,11 +111,10 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
for (const auto node : osrm::irange(0u, number_of_nodes))
{
EdgeIterator e = node_array[node + 1].first_edge;
for (EdgeIterator i = node_array[node].first_edge; i != e; ++i)
for (const auto i : osrm::irange(node_array[node].first_edge, e))
{
edge_array[i].target = graph[edge].target;
edge_array[i].data = graph[edge].data;
BOOST_ASSERT(edge_array[i].data.distance > 0);
edge++;
}
}
@ -143,7 +141,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
return NodeIterator(edge_array[e].target);
}
inline EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; }

199
tools/graph_compare.cpp Normal file
View File

@ -0,0 +1,199 @@
#include "../data_structures/dynamic_graph.hpp"
#include "../data_structures/import_edge.hpp"
#include "../data_structures/query_node.hpp"
#include "../data_structures/restriction.hpp"
#include "../data_structures/static_graph.hpp"
#include "../util/fingerprint.hpp"
#include "../util/graph_loader.hpp"
#include "../util/integer_range.hpp"
#include "../util/make_unique.hpp"
#include "../util/osrm_exception.hpp"
#include "../util/simple_logger.hpp"
#include "../typedefs.h"
#include <algorithm>
#include <fstream>
struct TarjanEdgeData
{
TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
TarjanEdgeData(unsigned distance, unsigned name_id) : distance(distance), name_id(name_id) {}
unsigned distance;
unsigned name_id;
};
using StaticTestGraph = StaticGraph<TarjanEdgeData>;
using DynamicTestGraph = StaticGraph<TarjanEdgeData>;
using StaticEdge = StaticTestGraph::InputEdge;
using DynamicEdge = DynamicTestGraph::InputEdge;
int main(int argc, char *argv[])
{
std::vector<QueryNode> coordinate_list;
std::vector<TurnRestriction> restriction_list;
std::vector<NodeID> bollard_node_list;
std::vector<NodeID> traffic_lights_list;
LogPolicy::GetInstance().Unmute();
try
{
// enable logging
if (argc < 3)
{
SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0]
<< " <osrm> <osrm.restrictions>";
return -1;
}
SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
std::ifstream restriction_ifstream(argv[2], std::ios::binary);
const FingerPrint fingerprint_orig;
FingerPrint fingerprint_loaded;
restriction_ifstream.read(reinterpret_cast<char *>(&fingerprint_loaded),
sizeof(FingerPrint));
// check fingerprint and warn if necessary
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
{
SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
"Reprocess to get rid of this warning.";
}
if (!restriction_ifstream.good())
{
throw osrm::exception("Could not access <osrm-restrictions> files");
}
uint32_t usable_restrictions = 0;
restriction_ifstream.read(reinterpret_cast<char *>(&usable_restrictions), sizeof(uint32_t));
restriction_list.resize(usable_restrictions);
// load restrictions
if (usable_restrictions > 0)
{
restriction_ifstream.read(reinterpret_cast<char *>(&restriction_list[0]),
usable_restrictions * sizeof(TurnRestriction));
}
restriction_ifstream.close();
std::ifstream input_stream(argv[1], std::ifstream::in | std::ifstream::binary);
if (!input_stream.is_open())
{
throw osrm::exception("Cannot open osrm file");
}
// load graph data
std::vector<ImportEdge> edge_list;
const NodeID number_of_nodes =
readBinaryOSRMGraphFromStream(input_stream, edge_list, bollard_node_list,
traffic_lights_list, &coordinate_list, restriction_list);
input_stream.close();
BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
"size of restriction_list changed");
SimpleLogger().Write() << restriction_list.size() << " restrictions, "
<< bollard_node_list.size() << " bollard nodes, "
<< traffic_lights_list.size() << " traffic lights";
traffic_lights_list.clear();
traffic_lights_list.shrink_to_fit();
// Building an node-based graph
std::vector<StaticEdge> static_graph_edge_list;
std::vector<DynamicEdge> dynamic_graph_edge_list;
for (const auto &input_edge : edge_list)
{
if (input_edge.source == input_edge.target)
{
continue;
}
if (input_edge.forward)
{
static_graph_edge_list.emplace_back(input_edge.source, input_edge.target,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
dynamic_graph_edge_list.emplace_back(input_edge.source, input_edge.target,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
}
if (input_edge.backward)
{
dynamic_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
static_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
}
}
edge_list.clear();
edge_list.shrink_to_fit();
BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(),
"input edge vector not properly deallocated");
tbb::parallel_sort(static_graph_edge_list.begin(), static_graph_edge_list.end());
tbb::parallel_sort(dynamic_graph_edge_list.begin(), dynamic_graph_edge_list.end());
auto static_graph =
osrm::make_unique<StaticTestGraph>(number_of_nodes, static_graph_edge_list);
auto dynamic_graph =
osrm::make_unique<DynamicTestGraph>(number_of_nodes, dynamic_graph_edge_list);
SimpleLogger().Write() << "Starting static/dynamic graph comparison";
BOOST_ASSERT(static_graph->GetNumberOfNodes() == dynamic_graph->GetNumberOfNodes());
BOOST_ASSERT(static_graph->GetNumberOfEdges() == dynamic_graph->GetNumberOfEdges());
for (const auto node : osrm::irange(0u, static_graph->GetNumberOfNodes()))
{
const auto static_range = static_graph->GetAdjacentEdgeRange(node);
const auto dynamic_range = dynamic_graph->GetAdjacentEdgeRange(node);
SimpleLogger().Write() << "checking node " << node << "/"
<< static_graph->GetNumberOfNodes();
BOOST_ASSERT(static_range.size() == dynamic_range.size());
const auto static_begin = static_graph->BeginEdges(node);
const auto dynamic_begin = dynamic_graph->BeginEdges(node);
// check raw interface
for (int i = 0; i < static_range.size(); ++i)
{
const auto static_target = static_graph->GetTarget(static_begin + i);
const auto dynamic_target = dynamic_graph->GetTarget(dynamic_begin + i);
BOOST_ASSERT(static_target == dynamic_target);
const auto static_data = static_graph->GetEdgeData(static_begin + i);
const auto dynamic_data = dynamic_graph->GetEdgeData(dynamic_begin + i);
BOOST_ASSERT(static_data.distance == dynamic_data.distance);
BOOST_ASSERT(static_data.name_id == dynamic_data.name_id);
}
// check range interface
std::vector<EdgeID> static_target_ids, dynamic_target_ids;
std::vector<TarjanEdgeData> static_edge_data, dynamic_edge_data;
for (const auto static_id : static_range)
{
static_target_ids.push_back(static_graph->GetTarget(static_id));
static_edge_data.push_back(static_graph->GetEdgeData(static_id));
}
for (const auto dynamic_id : dynamic_range)
{
dynamic_target_ids.push_back(dynamic_graph->GetTarget(dynamic_id));
dynamic_edge_data.push_back(dynamic_graph->GetEdgeData(dynamic_id));
}
BOOST_ASSERT(static_target_ids.size() == dynamic_target_ids.size());
BOOST_ASSERT(std::equal(std::begin(static_target_ids), std::end(static_target_ids),
std::begin(dynamic_target_ids)));
}
SimpleLogger().Write() << "Graph comparison finished successfully";
}
catch (const std::exception &e)
{
SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
}
return 0;
}