From 1d1be10f16c8a8e74c4a0b56902218e2d98812ca Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Wed, 2 Jul 2014 14:36:20 +0200 Subject: [PATCH] add functions to load graph into simplified data structures --- DataStructures/DynamicGraph.h | 2 +- DataStructures/NodeBasedGraph.h | 80 +++++++++++++++++++++++ Util/GraphLoader.h | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) diff --git a/DataStructures/DynamicGraph.h b/DataStructures/DynamicGraph.h index 3dc48b6a6..d48fe4c30 100644 --- a/DataStructures/DynamicGraph.h +++ b/DataStructures/DynamicGraph.h @@ -104,7 +104,7 @@ template class DynamicGraph { m_edges[i].target = graph[edge].target; m_edges[i].data = graph[edge].data; - BOOST_ASSERT_MSG(graph[edge].data.distance > 0, "edge distance invalid"); + // BOOST_ASSERT_MSG(graph[edge].data.distance > 0, "edge distance invalid"); ++edge; } } diff --git a/DataStructures/NodeBasedGraph.h b/DataStructures/NodeBasedGraph.h index 98393fbd8..5caef1923 100644 --- a/DataStructures/NodeBasedGraph.h +++ b/DataStructures/NodeBasedGraph.h @@ -46,7 +46,14 @@ struct NodeBasedEdgeData } }; +struct SimpleEdgeData +{ + SimpleEdgeData() : capacity(0) {} + EdgeWeight capacity; +}; + typedef DynamicGraph NodeBasedDynamicGraph; +typedef DynamicGraph SimpleNodeBasedDynamicGraph; // Factory method to create NodeBasedDynamicGraph from ImportEdges inline std::shared_ptr @@ -163,4 +170,77 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector +inline std::shared_ptr +SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector &input_edge_list) +{ + static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption"); + tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end()); + + DeallocatingVector edges_list; + SimpleNodeBasedDynamicGraph::InputEdge edge; + edge.data.capacity = 1; + for (const SimpleEdgeT &import_edge : input_edge_list) + { + if (import_edge.source == import_edge.target) + { + continue; + } + edge.source = import_edge.source; + edge.target = import_edge.target; + edges_list.push_back(edge); + std::swap(edge.source, edge.target); + edges_list.push_back(edge); + } + + // remove duplicate edges + std::sort(edges_list.begin(), edges_list.end()); + NodeID edge_count = 0; + for (NodeID i = 0; i < edges_list.size(); ) + { + const NodeID source = edges_list[i].source; + const NodeID target = edges_list[i].target; + // remove eigenloops + if (source == target) + { + i++; + continue; + } + SimpleNodeBasedDynamicGraph::InputEdge forward_edge; + SimpleNodeBasedDynamicGraph::InputEdge reverse_edge; + forward_edge = reverse_edge = edges_list[i]; + forward_edge.data.capacity = reverse_edge.data.capacity = INVALID_EDGE_WEIGHT; + // remove parallel edges + while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target) + { + forward_edge.data.capacity = std::min(edges_list[i].data.capacity, forward_edge.data.capacity); + reverse_edge.data.capacity = std::min(edges_list[i].data.capacity, reverse_edge.data.capacity); + ++i; + } + // merge edges (s,t) and (t,s) into bidirectional edge + if (forward_edge.data.capacity == reverse_edge.data.capacity) + { + if ((int)forward_edge.data.capacity != INVALID_EDGE_WEIGHT) + { + edges_list[edge_count++] = forward_edge; + } + } + else + { // insert seperate edges + if (((int)forward_edge.data.capacity) != INVALID_EDGE_WEIGHT) + { + edges_list[edge_count++] = forward_edge; + } + if ((int)reverse_edge.data.capacity != INVALID_EDGE_WEIGHT) + { + edges_list[edge_count++] = reverse_edge; + } + } + } + SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size(); + + auto graph = std::make_shared(number_of_nodes, edges_list); + return graph; +} + #endif // __NODE_BASED_GRAPH_H__ diff --git a/Util/GraphLoader.h b/Util/GraphLoader.h index 612332b61..0f4497158 100644 --- a/Util/GraphLoader.h +++ b/Util/GraphLoader.h @@ -268,6 +268,118 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream, return n; } +template +NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream, std::vector &edge_list) +{ + const FingerPrint fingerprint_orig; + FingerPrint fingerprint_loaded; + input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint)); + + if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig)) + { + SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n" + "Reprocess to get rid of this warning."; + } + + NodeID n, source, target; + EdgeID m; + short dir; // direction (0 = open, 1 = forward, 2+ = open) + std::unordered_map ext_to_int_id_map; + std::vector int_to_ext_node_id_map; + + input_stream.read((char *)&n, sizeof(NodeID)); + SimpleLogger().Write() << "Importing n = " << n << " nodes "; + ExternalMemoryNode current_node; + for (NodeID i = 0; i < n; ++i) + { + input_stream.read((char *)¤t_node, sizeof(ExternalMemoryNode)); + int_to_ext_node_id_map.emplace_back(current_node.lat, current_node.lon, current_node.node_id); + ext_to_int_id_map.emplace(current_node.node_id, i); + } + + input_stream.read((char *)&m, sizeof(unsigned)); + SimpleLogger().Write() << " and " << m << " edges "; + + edge_list.reserve(m); + EdgeWeight weight; + short type; + NodeID nameID; + int length; + bool is_roundabout, ignore_in_grid, is_access_restricted, is_contra_flow, is_split; + + for (EdgeID i = 0; i < m; ++i) + { + input_stream.read((char *)&source, sizeof(unsigned)); + input_stream.read((char *)&target, sizeof(unsigned)); + input_stream.read((char *)&length, sizeof(int)); + input_stream.read((char *)&dir, sizeof(short)); + input_stream.read((char *)&weight, sizeof(int)); + input_stream.read((char *)&type, sizeof(short)); + input_stream.read((char *)&nameID, sizeof(unsigned)); + input_stream.read((char *)&is_roundabout, sizeof(bool)); + input_stream.read((char *)&ignore_in_grid, sizeof(bool)); + input_stream.read((char *)&is_access_restricted, sizeof(bool)); + input_stream.read((char *)&is_contra_flow, sizeof(bool)); + input_stream.read((char *)&is_split, sizeof(bool)); + + BOOST_ASSERT_MSG(length > 0, "loaded null length edge"); + BOOST_ASSERT_MSG(weight > 0, "loaded null weight"); + BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction"); + + BOOST_ASSERT(type >= 0); + + // translate the external NodeIDs to internal IDs + auto internal_id_iter = ext_to_int_id_map.find(source); + if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end()) + { +#ifndef NDEBUG + SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source; +#endif + continue; + } + source = internal_id_iter->second; + internal_id_iter = ext_to_int_id_map.find(target); + if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end()) + { +#ifndef NDEBUG + SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target; +#endif + continue; + } + target = internal_id_iter->second; + BOOST_ASSERT_MSG(source != UINT_MAX && target != UINT_MAX, "nonexisting source or target"); + + if (source > target) + { + std::swap(source, target); + } + + edge_list.emplace_back(source, + target); + } + + tbb::parallel_sort(edge_list.begin(), edge_list.end()); + for (unsigned i = 1; i < edge_list.size(); ++i) + { + if ((edge_list[i - 1].target == edge_list[i].target) && + (edge_list[i - 1].source == edge_list[i].source)) + { + edge_list[i].capacity = std::min(edge_list[i - 1].capacity, edge_list[i].capacity); + edge_list[i - 1].source = UINT_MAX; + } + } + const auto new_end_iter = std::remove_if(edge_list.begin(), + edge_list.end(), + [](const EdgeT &edge) + { return edge.source == SPECIAL_NODEID; }); + ext_to_int_id_map.clear(); + edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates. + edge_list.shrink_to_fit(); + SimpleLogger().Write() << "Graph loaded ok and has " << n << " nodes and " << edge_list.size() << " edges"; + return n; +} + + template unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file, std::vector &node_list,