From c03aec364cf4fe0314e663ea8414db24d32f6e1d Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Thu, 16 Apr 2015 11:25:43 +0200 Subject: [PATCH] add comparison tool for graph classes --- CMakeLists.txt | 2 + data_structures/dynamic_graph.hpp | 60 ++++----- data_structures/static_graph.hpp | 6 +- tools/graph_compare.cpp | 199 ++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+), 34 deletions(-) create mode 100644 tools/graph_compare.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9770a0227..503171a59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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_link_libraries(osrm-springclean ${Boost_LIBRARIES}) + add_executable(osrm-graph-compare tools/graph_compare.cpp $ $ $ $ $ $ $) + target_link_libraries(osrm-graph-compare ${Boost_LIBRARIES} ${TBB_LIBRARIES}) install(TARGETS osrm-cli DESTINATION bin) install(TARGETS osrm-io-benchmark DESTINATION bin) diff --git a/data_structures/dynamic_graph.hpp b/data_structures/dynamic_graph.hpp index 3a8f520c6..b39c7f2d7 100644 --- a/data_structures/dynamic_graph.hpp +++ b/data_structures/dynamic_graph.hpp @@ -76,8 +76,8 @@ template 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 class DynamicGraph { number_of_nodes = nodes; number_of_edges = static_cast(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(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 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 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 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 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 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::max() != node.edges); - const unsigned last = node.firstEdge + node.edges; + const unsigned last = node.first_edge + node.edges; BOOST_ASSERT(std::numeric_limits::max() != last); // swap with last edge edge_list[e] = edge_list[last]; @@ -245,7 +245,7 @@ template class DynamicGraph } number_of_edges -= deleted; - node_list[source].edges -= deleted; + node_array[source].edges -= deleted; return deleted; } @@ -277,7 +277,7 @@ template class DynamicGraph struct Node { // index of the first edge - EdgeIterator firstEdge; + EdgeIterator first_edge; // amount of edges unsigned edges; }; @@ -291,7 +291,7 @@ template class DynamicGraph NodeIterator number_of_nodes; std::atomic_uint number_of_edges; - std::vector node_list; + std::vector node_array; DeallocatingVector edge_list; }; diff --git a/data_structures/static_graph.hpp b/data_structures/static_graph.hpp index 2a5f6481e..d4fcdf7a5 100644 --- a/data_structures/static_graph.hpp +++ b/data_structures/static_graph.hpp @@ -91,7 +91,6 @@ template class StaticGraph StaticGraph(const int nodes, std::vector &graph) { - tbb::parallel_sort(graph.begin(), graph.end()); number_of_nodes = nodes; number_of_edges = static_cast(graph.size()); node_array.resize(number_of_nodes + 1); @@ -112,11 +111,10 @@ template 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 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; } diff --git a/tools/graph_compare.cpp b/tools/graph_compare.cpp new file mode 100644 index 000000000..2bc7f0b6e --- /dev/null +++ b/tools/graph_compare.cpp @@ -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 +#include + +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; +using DynamicTestGraph = StaticGraph; +using StaticEdge = StaticTestGraph::InputEdge; +using DynamicEdge = DynamicTestGraph::InputEdge; + +int main(int argc, char *argv[]) +{ + std::vector coordinate_list; + std::vector restriction_list; + std::vector bollard_node_list; + std::vector traffic_lights_list; + + LogPolicy::GetInstance().Unmute(); + try + { + // enable logging + if (argc < 3) + { + SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] + << " "; + 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(&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 files"); + } + uint32_t usable_restrictions = 0; + restriction_ifstream.read(reinterpret_cast(&usable_restrictions), sizeof(uint32_t)); + restriction_list.resize(usable_restrictions); + + // load restrictions + if (usable_restrictions > 0) + { + restriction_ifstream.read(reinterpret_cast(&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 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 static_graph_edge_list; + std::vector 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(number_of_nodes, static_graph_edge_list); + auto dynamic_graph = + osrm::make_unique(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 static_target_ids, dynamic_target_ids; + std::vector 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; +}