diff --git a/include/customizer/edge_based_graph.hpp b/include/customizer/edge_based_graph.hpp index b45081b07..d3703d7fd 100644 --- a/include/customizer/edge_based_graph.hpp +++ b/include/customizer/edge_based_graph.hpp @@ -3,6 +3,7 @@ #include "extractor/edge_based_edge.hpp" #include "partition/edge_based_graph.hpp" +#include "partition/multi_level_graph.hpp" #include "util/static_graph.hpp" #include "util/typedefs.hpp" @@ -13,34 +14,24 @@ namespace osrm namespace customizer { -struct StaticEdgeBasedGraph; - -namespace io -{ -void read(const boost::filesystem::path &path, StaticEdgeBasedGraph &graph); -void write(const boost::filesystem::path &path, const StaticEdgeBasedGraph &graph); -} - using EdgeBasedGraphEdgeData = partition::EdgeBasedGraphEdgeData; -struct StaticEdgeBasedGraph : util::StaticGraph +struct MultiLevelEdgeBasedGraph : public partition::MultiLevelGraph { - using Base = util::StaticGraph; - using Base::Base; - - friend void io::read(const boost::filesystem::path &path, StaticEdgeBasedGraph &graph); - friend void io::write(const boost::filesystem::path &path, const StaticEdgeBasedGraph &graph); -}; - -struct StaticEdgeBasedGraphView : util::StaticGraph -{ - using Base = util::StaticGraph; + using Base = partition::MultiLevelGraph; using Base::Base; }; -struct StaticEdgeBasedGraphEdge : StaticEdgeBasedGraph::InputEdge +struct MultiLevelEdgeBasedGraphView + : public partition::MultiLevelGraph { - using Base = StaticEdgeBasedGraph::InputEdge; + using Base = partition::MultiLevelGraph; + using Base::Base; +}; + +struct StaticEdgeBasedGraphEdge : MultiLevelEdgeBasedGraph::InputEdge +{ + using Base = MultiLevelEdgeBasedGraph::InputEdge; using Base::Base; }; } diff --git a/include/customizer/io.hpp b/include/customizer/io.hpp index 782548cc5..d0704a65f 100644 --- a/include/customizer/io.hpp +++ b/include/customizer/io.hpp @@ -11,24 +11,6 @@ namespace customizer { namespace io { - -inline void read(const boost::filesystem::path &path, StaticEdgeBasedGraph &graph) -{ - const auto fingerprint = storage::io::FileReader::VerifyFingerprint; - storage::io::FileReader reader{path, fingerprint}; - - reader.DeserializeVector(graph.node_array); - reader.DeserializeVector(graph.edge_array); -} - -inline void write(const boost::filesystem::path &path, const StaticEdgeBasedGraph &graph) -{ - const auto fingerprint = storage::io::FileWriter::GenerateFingerprint; - storage::io::FileWriter writer{path, fingerprint}; - - writer.SerializeVector(graph.node_array); - writer.SerializeVector(graph.edge_array); -} } } } diff --git a/include/engine/datafacade/algorithm_datafacade.hpp b/include/engine/datafacade/algorithm_datafacade.hpp index 7a78779b4..eb3062228 100644 --- a/include/engine/datafacade/algorithm_datafacade.hpp +++ b/include/engine/datafacade/algorithm_datafacade.hpp @@ -90,6 +90,8 @@ template <> class AlgorithmDataFacade virtual const partition::CellStorageView &GetCellStorage() const = 0; + virtual EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const = 0; + // searches for a specific edge virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0; }; diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 8185af8e8..54e5213a7 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -902,10 +902,16 @@ class ContiguousInternalMemoryAlgorithmDataFacade // MLD data partition::MultiLevelPartitionView mld_partition; partition::CellStorageView mld_cell_storage; + using QueryGraph = customizer::MultiLevelEdgeBasedGraphView; + using GraphNode = QueryGraph::NodeArrayEntry; + using GraphEdge = QueryGraph::EdgeArrayEntry; + + QueryGraph query_graph; void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block) { InitializeMLDDataPointers(data_layout, memory_block); + InitializeGraphPointer(data_layout, memory_block); } void InitializeMLDDataPointers(storage::DataLayout &data_layout, char *memory_block) @@ -980,6 +986,28 @@ class ContiguousInternalMemoryAlgorithmDataFacade std::move(level_offsets)}; } } + void InitializeGraphPointer(storage::DataLayout &data_layout, char *memory_block) + { + auto graph_nodes_ptr = data_layout.GetBlockPtr( + memory_block, storage::DataLayout::MLD_GRAPH_NODE_LIST); + + auto graph_edges_ptr = data_layout.GetBlockPtr( + memory_block, storage::DataLayout::MLD_GRAPH_EDGE_LIST); + + auto graph_node_to_offset_ptr = data_layout.GetBlockPtr( + memory_block, storage::DataLayout::MLD_GRAPH_NODE_TO_OFFSET); + + util::ShM::vector node_list( + graph_nodes_ptr, data_layout.num_entries[storage::DataLayout::MLD_GRAPH_NODE_LIST]); + util::ShM::vector edge_list( + graph_edges_ptr, data_layout.num_entries[storage::DataLayout::MLD_GRAPH_EDGE_LIST]); + util::ShM::vector node_to_offset( + graph_node_to_offset_ptr, + data_layout.num_entries[storage::DataLayout::MLD_GRAPH_NODE_TO_OFFSET]); + + query_graph = + QueryGraph(std::move(node_list), std::move(edge_list), std::move(node_to_offset)); + } // allocator that keeps the allocation data std::shared_ptr allocator; @@ -992,86 +1020,63 @@ class ContiguousInternalMemoryAlgorithmDataFacade InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory()); } - const partition::MultiLevelPartitionView &GetMultiLevelPartition() const + const partition::MultiLevelPartitionView &GetMultiLevelPartition() const override { return mld_partition; } - const partition::CellStorageView &GetCellStorage() const { return mld_cell_storage; } + const partition::CellStorageView &GetCellStorage() const override { return mld_cell_storage; } + + // search graph access + unsigned GetNumberOfNodes() const override final { return query_graph.GetNumberOfNodes(); } + + unsigned GetNumberOfEdges() const override final { return query_graph.GetNumberOfEdges(); } + + unsigned GetOutDegree(const NodeID n) const override final + { + return query_graph.GetOutDegree(n); + } + + NodeID GetTarget(const EdgeID e) const override final { return query_graph.GetTarget(e); } + + const EdgeData &GetEdgeData(const EdgeID e) const override final + { + return query_graph.GetEdgeData(e); + } + + EdgeID BeginEdges(const NodeID n) const override final { return query_graph.BeginEdges(n); } + + EdgeID EndEdges(const NodeID n) const override final { return query_graph.EndEdges(n); } + + EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final + { + return query_graph.GetAdjacentEdgeRange(node); + } + + EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const override final + { + return query_graph.GetBorderEdgeRange(level, node); + } + + // searches for a specific edge + EdgeID FindEdge(const NodeID from, const NodeID to) const override final + { + return query_graph.FindEdge(from, to); + } }; template <> -class ContiguousInternalMemoryDataFacade +class ContiguousInternalMemoryDataFacade final : public ContiguousInternalMemoryDataFacadeBase, public ContiguousInternalMemoryAlgorithmDataFacade { private: - using QueryGraph = customizer::StaticEdgeBasedGraphView; - using GraphNode = QueryGraph::NodeArrayEntry; - using GraphEdge = QueryGraph::EdgeArrayEntry; - - std::unique_ptr m_query_graph; - - void InitializeGraphPointer(storage::DataLayout &data_layout, char *memory_block) - { - auto graph_nodes_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_GRAPH_NODE_LIST); - - auto graph_edges_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_GRAPH_EDGE_LIST); - - util::ShM::vector node_list( - graph_nodes_ptr, data_layout.num_entries[storage::DataLayout::MLD_GRAPH_NODE_LIST]); - util::ShM::vector edge_list( - graph_edges_ptr, data_layout.num_entries[storage::DataLayout::MLD_GRAPH_EDGE_LIST]); - - m_query_graph.reset(new QueryGraph(node_list, edge_list)); - } - public: ContiguousInternalMemoryDataFacade(std::shared_ptr allocator) : ContiguousInternalMemoryDataFacadeBase(allocator), ContiguousInternalMemoryAlgorithmDataFacade(allocator) { - InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory()); - } - - void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block) - { - InitializeGraphPointer(data_layout, memory_block); - } - - // search graph access - unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); } - - unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); } - - unsigned GetOutDegree(const NodeID n) const override final - { - return m_query_graph->GetOutDegree(n); - } - - NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); } - - EdgeData &GetEdgeData(const EdgeID e) const override final - { - return m_query_graph->GetEdgeData(e); - } - - EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); } - - EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); } - - EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final - { - return m_query_graph->GetAdjacentEdgeRange(node); - } - - // searches for a specific edge - EdgeID FindEdge(const NodeID from, const NodeID to) const override final - { - return m_query_graph->FindEdge(from, to); } }; } diff --git a/include/engine/routing_algorithms/routing_base_mld.hpp b/include/engine/routing_algorithms/routing_base_mld.hpp index 8e38d5023..e705f106d 100644 --- a/include/engine/routing_algorithms/routing_base_mld.hpp +++ b/include/engine/routing_algorithms/routing_base_mld.hpp @@ -143,15 +143,14 @@ void routingStep(const datafacade::ContiguousInternalMemoryDataFacade= level) + if (checkParentCellRestriction(partition.GetCell(level + 1, to), args...)) { BOOST_ASSERT_MSG(edge_data.weight > 0, "edge_weight invalid"); const EdgeWeight to_weight = weight + edge_data.weight; diff --git a/include/partition/io.hpp b/include/partition/io.hpp index ec01c1af7..00a03835d 100644 --- a/include/partition/io.hpp +++ b/include/partition/io.hpp @@ -3,6 +3,7 @@ #include "partition/cell_storage.hpp" #include "partition/edge_based_graph.hpp" +#include "partition/multi_level_graph.hpp" #include "partition/multi_level_partition.hpp" #include "storage/io.hpp" @@ -14,6 +15,30 @@ namespace partition namespace io { +template +inline void read(const boost::filesystem::path &path, + MultiLevelGraph &graph) +{ + const auto fingerprint = storage::io::FileReader::VerifyFingerprint; + storage::io::FileReader reader{path, fingerprint}; + + reader.DeserializeVector(graph.node_array); + reader.DeserializeVector(graph.edge_array); + reader.DeserializeVector(graph.edge_to_level); +} + +template +inline void write(const boost::filesystem::path &path, + const MultiLevelGraph &graph) +{ + const auto fingerprint = storage::io::FileWriter::GenerateFingerprint; + storage::io::FileWriter writer{path, fingerprint}; + + writer.SerializeVector(graph.node_array); + writer.SerializeVector(graph.edge_array); + writer.SerializeVector(graph.node_to_edge_offset); +} + template <> inline void read(const boost::filesystem::path &path, MultiLevelPartition &mlp) { const auto fingerprint = storage::io::FileReader::VerifyFingerprint; diff --git a/include/partition/multi_level_graph.hpp b/include/partition/multi_level_graph.hpp new file mode 100644 index 000000000..52b284ff1 --- /dev/null +++ b/include/partition/multi_level_graph.hpp @@ -0,0 +1,191 @@ +#ifndef OSRM_PARTITION_MULTI_LEVEL_GRAPH_HPP +#define OSRM_PARTITION_MULTI_LEVEL_GRAPH_HPP + +#include "partition/multi_level_partition.hpp" + +#include "util/static_graph.hpp" + +#include + +#include +#include + +namespace osrm +{ +namespace partition +{ +template class MultiLevelGraph; + +namespace io +{ +template +void read(const boost::filesystem::path &path, MultiLevelGraph &graph); + +template +void write(const boost::filesystem::path &path, + const MultiLevelGraph &graph); +} + +template +class MultiLevelGraph : public util::StaticGraph +{ + private: + using SuperT = util::StaticGraph; + template using Vector = typename util::ShM::vector; + + public: + // We limit each node to have 255 edges + // this is very generous, we could probably pack this + using EdgeOffset = std::uint8_t; + + MultiLevelGraph() = default; + + MultiLevelGraph(Vector node_array_, + Vector edge_array_, + Vector node_to_edge_offset_) + : SuperT(std::move(node_array_), std::move(edge_array_)), + node_to_edge_offset(std::move(node_to_edge_offset_)) + { + } + + template + MultiLevelGraph(const MultiLevelPartition &mlp, + const std::uint32_t num_nodes, + const ContainerT &edges) + { + auto highest_border_level = GetHighestBorderLevel(mlp, edges); + auto permutation = SortEdgesByHighestLevel(highest_border_level, edges); + auto sorted_edges_begin = + boost::make_permutation_iterator(edges.begin(), permutation.begin()); + auto sorted_edges_end = boost::make_permutation_iterator(edges.begin(), permutation.end()); + SuperT::InitializeFromSortedEdgeRange(num_nodes, sorted_edges_begin, sorted_edges_end); + + // if the node ordering is sorting the border nodes first, + // the id of the maximum border node will be rather low + // enabling us to save some memory here + auto max_border_node_id = 0u; + for (auto edge_index : util::irange(0, edges.size())) + { + if (highest_border_level[edge_index] > 0) + { + max_border_node_id = + std::max(max_border_node_id, + std::max(edges[edge_index].source, edges[edge_index].target)); + } + } + BOOST_ASSERT(max_border_node_id < num_nodes); + + auto edge_and_level_range = boost::combine(edges, highest_border_level); + auto sorted_edge_and_level_begin = + boost::make_permutation_iterator(edge_and_level_range.begin(), permutation.begin()); + auto sorted_edge_and_level_end = + boost::make_permutation_iterator(edge_and_level_range.begin(), permutation.end()); + InitializeOffsetsFromSortedEdges( + mlp, max_border_node_id, sorted_edge_and_level_begin, sorted_edge_and_level_end); + } + + // Fast scan over all relevant border edges + auto GetBorderEdgeRange(const LevelID level, const NodeID node) const + { + auto begin = BeginBorderEdges(level, node); + auto end = SuperT::EndEdges(node); + return util::irange(begin, end); + } + + // Fast scan over all relevant internal edges, that is edges that will not + // leave the cell of that node at the given level + auto GetInternalEdgeRange(const LevelID level, const NodeID node) const + { + auto begin = SuperT::BeginEdges(node); + auto end = SuperT::BeginEdges(node) + node_to_edge_offset[node + level]; + return util::irange(begin, end); + } + + EdgeID BeginBorderEdges(const LevelID level, const NodeID node) const + { + auto index = node * GetNumberOfLevels(); + if (index >= node_to_edge_offset.size() - 1) + return SuperT::BeginEdges(node); + else + return SuperT::BeginEdges(node) + node_to_edge_offset[index + level]; + } + + // We save the level as senitel at the end + LevelID GetNumberOfLevels() const { return node_to_edge_offset.back(); } + + private: + template + auto GetHighestBorderLevel(const MultiLevelPartition &mlp, const ContainerT &edges) const + { + std::vector highest_border_level(edges.size()); + std::transform( + edges.begin(), edges.end(), highest_border_level.begin(), [&mlp](const auto &edge) { + return mlp.GetHighestDifferentLevel(edge.source, edge.target); + }); + return highest_border_level; + } + + template + auto SortEdgesByHighestLevel(const std::vector &highest_border_level, + const ContainerT &edges) const + { + std::vector permutation(edges.size()); + std::iota(permutation.begin(), permutation.end(), 0); + tbb::parallel_sort( + permutation.begin(), + permutation.end(), + [&edges, &highest_border_level](const auto &lhs, const auto &rhs) { + // sort by source node and then by level in acending order + return std::tie(edges[lhs].source, highest_border_level[lhs], edges[lhs].target) < + std::tie(edges[rhs].source, highest_border_level[rhs], edges[rhs].target); + }); + + return permutation; + } + + template + auto InitializeOffsetsFromSortedEdges(const MultiLevelPartition &mlp, + const NodeID max_border_node_id, + ZipIterT edge_and_level_begin, + ZipIterT edge_and_level_end) + { + + auto num_levels = mlp.GetNumberOfLevels(); + // we save one senitel element at the end + node_to_edge_offset.reserve(num_levels * (max_border_node_id + 1) + 1); + auto iter = edge_and_level_begin; + for (auto node : util::irange(0, max_border_node_id + 1)) + { + node_to_edge_offset.push_back(0); + auto level_begin = iter; + for (auto level : util::irange(0, mlp.GetNumberOfLevels())) + { + iter = std::find_if( + iter, edge_and_level_end, [node, level](const auto &edge_and_level) { + return boost::get<0>(edge_and_level).source != node || + boost::get<1>(edge_and_level) != level; + }); + EdgeOffset offset = std::distance(level_begin, iter); + node_to_edge_offset.push_back(offset); + } + node_to_edge_offset.pop_back(); + } + BOOST_ASSERT(node_to_edge_offset.size() == + mlp.GetNumberOfLevels() * (max_border_node_id + 1)); + // save number of levels as last element so we can reconstruct the stride + node_to_edge_offset.push_back(mlp.GetNumberOfLevels()); + } + + friend void + io::read(const boost::filesystem::path &path, + MultiLevelGraph &graph); + friend void + io::write(const boost::filesystem::path &path, + const MultiLevelGraph &graph); + + Vector node_to_edge_offset; +}; +} +} + +#endif diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp index 0846ee3b6..966d00938 100644 --- a/include/storage/shared_datatype.hpp +++ b/include/storage/shared_datatype.hpp @@ -64,7 +64,8 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA", "MLD_CELLS", "MLD_CELL_LEVEL_OFFSETS", "MLD_GRAPH_NODE_LIST", - "MLD_GRAPH_EDGE_LIST"}; + "MLD_GRAPH_EDGE_LIST", + "MLD_GRAPH_NODE_TO_OFFSET"}; struct DataLayout { @@ -117,6 +118,7 @@ struct DataLayout MLD_CELL_LEVEL_OFFSETS, MLD_GRAPH_NODE_LIST, MLD_GRAPH_EDGE_LIST, + MLD_GRAPH_NODE_TO_OFFSET, NUM_BLOCKS }; diff --git a/include/util/static_graph.hpp b/include/util/static_graph.hpp index 014fd9d4a..24c03c159 100644 --- a/include/util/static_graph.hpp +++ b/include/util/static_graph.hpp @@ -112,6 +112,8 @@ template class StaticGraph return irange(BeginEdges(node), EndEdges(node)); } + StaticGraph() {} + template StaticGraph(const int nodes, const ContainerT &edges) { BOOST_ASSERT(std::is_sorted(const_cast(edges).begin(), @@ -120,18 +122,15 @@ template class StaticGraph InitializeFromSortedEdgeRange(nodes, edges.begin(), edges.end()); } - StaticGraph(typename ShM::vector &nodes, - typename ShM::vector &edges) + StaticGraph(typename ShM::vector node_array_, + typename ShM::vector edge_array_) + : node_array(std::move(node_array_)), edge_array(std::move(edge_array_)) { - BOOST_ASSERT(!nodes.empty()); + BOOST_ASSERT(!node_array.empty()); - number_of_nodes = static_cast(nodes.size() - 1); - number_of_edges = static_cast(nodes.back().first_edge); - BOOST_ASSERT(number_of_edges <= edges.size()); - - using std::swap; - swap(node_array, nodes); - swap(edge_array, edges); + number_of_nodes = static_cast(node_array.size() - 1); + number_of_edges = static_cast(node_array.back().first_edge); + BOOST_ASSERT(number_of_edges <= edge_array.size()); } unsigned GetNumberOfNodes() const { return number_of_nodes; } @@ -255,7 +254,7 @@ template class StaticGraph }); } - private: + // private: NodeIterator number_of_nodes; EdgeIterator number_of_edges; diff --git a/src/customize/customizer.cpp b/src/customize/customizer.cpp index 3723ce742..f6f5f987f 100644 --- a/src/customize/customizer.cpp +++ b/src/customize/customizer.cpp @@ -6,7 +6,6 @@ #include "partition/cell_storage.hpp" #include "partition/edge_based_graph_reader.hpp" #include "partition/io.hpp" -#include "partition/io.hpp" #include "partition/multi_level_partition.hpp" #include "updater/updater.hpp" @@ -71,7 +70,8 @@ void CellStorageStatistics(const Graph &graph, } } -auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config) +auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config, + const partition::MultiLevelPartition &mlp) { updater::Updater updater(config.updater_config); @@ -82,7 +82,9 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config) auto directed = partition::splitBidirectionalEdges(edge_based_edge_list); auto tidied = partition::prepareEdgesForUsageInGraph(std::move(directed)); - auto edge_based_graph = std::make_unique(num_nodes, std::move(tidied)); + auto edge_based_graph = + std::make_unique>( + mlp, num_nodes, std::move(tidied)); util::Log() << "Loaded edge based graph for mapping partition ids: " << edge_based_graph->GetNumberOfEdges() << " edges, " @@ -95,11 +97,11 @@ int Customizer::Run(const CustomizationConfig &config) { TIMER_START(loading_data); - auto edge_based_graph = LoadAndUpdateEdgeExpandedGraph(config); - partition::MultiLevelPartition mlp; partition::io::read(config.mld_partition_path, mlp); + auto edge_based_graph = LoadAndUpdateEdgeExpandedGraph(config, mlp); + partition::CellStorage storage; partition::io::read(config.mld_storage_path, storage); TIMER_STOP(loading_data); @@ -117,7 +119,7 @@ int Customizer::Run(const CustomizationConfig &config) util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds"; TIMER_START(writing_graph); - io::write(config.mld_graph_path, *edge_based_graph); + partition::io::write(config.mld_graph_path, *edge_based_graph); TIMER_STOP(writing_graph); util::Log() << "Graph writing took " << TIMER_SEC(writing_graph) << " seconds"; diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index bf3634962..8e9652f46 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -447,21 +447,27 @@ void Storage::PopulateLayout(DataLayout &layout) io::FileReader reader(config.mld_graph_path, io::FileReader::VerifyFingerprint); const auto num_nodes = - reader.ReadVectorSize(); + reader.ReadVectorSize(); const auto num_edges = - reader.ReadVectorSize(); + reader.ReadVectorSize(); + const auto num_node_offsets = + reader.ReadVectorSize(); - layout.SetBlockSize( + layout.SetBlockSize( DataLayout::MLD_GRAPH_NODE_LIST, num_nodes); - layout.SetBlockSize( + layout.SetBlockSize( DataLayout::MLD_GRAPH_EDGE_LIST, num_edges); + layout.SetBlockSize( + DataLayout::MLD_GRAPH_NODE_TO_OFFSET, num_node_offsets); } else { - layout.SetBlockSize( + layout.SetBlockSize( DataLayout::MLD_GRAPH_NODE_LIST, 0); - layout.SetBlockSize( + layout.SetBlockSize( DataLayout::MLD_GRAPH_EDGE_LIST, 0); + layout.SetBlockSize( + DataLayout::MLD_GRAPH_NODE_TO_OFFSET, 0); } } } @@ -938,16 +944,21 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr) io::FileReader reader(config.mld_graph_path, io::FileReader::VerifyFingerprint); auto nodes_ptr = - layout.GetBlockPtr( + layout.GetBlockPtr( memory_ptr, DataLayout::MLD_GRAPH_NODE_LIST); auto edges_ptr = - layout.GetBlockPtr( + layout.GetBlockPtr( memory_ptr, DataLayout::MLD_GRAPH_EDGE_LIST); + auto node_to_offset_ptr = + layout.GetBlockPtr( + memory_ptr, DataLayout::MLD_GRAPH_NODE_TO_OFFSET); auto num_nodes = reader.ReadElementCount64(); reader.ReadInto(nodes_ptr, num_nodes); auto num_edges = reader.ReadElementCount64(); reader.ReadInto(edges_ptr, num_edges); + auto num_node_to_offset = reader.ReadElementCount64(); + reader.ReadInto(node_to_offset_ptr, num_node_to_offset); } } } diff --git a/unit_tests/partition/multi_level_graph.cpp b/unit_tests/partition/multi_level_graph.cpp new file mode 100644 index 000000000..8336f5d2f --- /dev/null +++ b/unit_tests/partition/multi_level_graph.cpp @@ -0,0 +1,178 @@ +#include "partition/multi_level_graph.hpp" +#include "util/typedefs.hpp" + +#include "../common/range_tools.hpp" + +#include +#include + +#include +#include +#include + +using namespace osrm; +using namespace osrm::partition; + +namespace +{ +struct MockEdge +{ + NodeID source; + NodeID target; +}; + +auto makeGraph(const MultiLevelPartition &mlp, const std::vector &mock_edges) +{ + struct EdgeData + { + bool forward; + bool backward; + }; + using Edge = util::static_graph_details::SortableEdgeWithData; + std::vector edges; + std::size_t max_id = 0; + for (const auto &m : mock_edges) + { + max_id = std::max(max_id, std::max(m.source, m.target)); + edges.push_back(Edge{m.source, m.target, true, false}); + edges.push_back(Edge{m.target, m.source, false, true}); + } + std::sort(edges.begin(), edges.end()); + return MultiLevelGraph(mlp, max_id + 1, edges); +} +} + +BOOST_AUTO_TEST_SUITE(multi_level_graph) + +BOOST_AUTO_TEST_CASE(check_edges_sorting) +{ + // node: 0 1 2 3 4 5 6 7 8 9 10 11 12 + std::vector l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6}}; + std::vector l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4}}; + std::vector l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2}}; + std::vector l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}; + MultiLevelPartition mlp{{l1, l2, l3, l4}, {7, 5, 3, 2}}; + + std::vector edges = { + // edges sorted into border/internal by level + // level: (1) (2) (3) (4) + {0, 1}, // i i i i + {2, 3}, // i i i i + {3, 7}, // b b b i + {4, 0}, // b b b i + {4, 5}, // i i i i + {5, 6}, // b i i i + {6, 4}, // b i i i + {6, 7}, // i i i i + {7, 11}, // b b i i + {8, 9}, // i i i i + {9, 8}, // i i i i + {10, 11}, // i i i i + {11, 10}, // i i i i + {11, 12} // b b b b + }; + + auto graph = makeGraph(mlp, edges); + + for (auto from : util::irange(0u, graph.GetNumberOfNodes())) + { + LevelID level = 0; + for (auto edge : graph.GetAdjacentEdgeRange(from)) + { + auto to = graph.GetTarget(edge); + BOOST_CHECK(mlp.GetHighestDifferentLevel(from, to) >= level); + level = mlp.GetHighestDifferentLevel(from, to); + } + } + + // on level 0 every edge is a border edge + for (auto node : util::irange(0, 13)) + CHECK_EQUAL_COLLECTIONS(graph.GetBorderEdgeRange(0, node), + graph.GetAdjacentEdgeRange(node)); + + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 0).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 1).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 2).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 3).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 4).size(), 2); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 5).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 6).size(), 2); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 7).size(), 2); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 8).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 9).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 10).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 11).size(), 2); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 12).size(), 1); + + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 0).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 1).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 2).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 3).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 4).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 5).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 6).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 7).size(), 2); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 8).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 9).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 10).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 11).size(), 2); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 12).size(), 1); + + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 0).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 1).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 2).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 3).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 4).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 5).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 6).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 7).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 8).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 9).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 10).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 11).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 12).size(), 1); + + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 0).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 1).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 2).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 3).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 4).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 5).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 6).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 7).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 8).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 9).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 10).size(), 0); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 11).size(), 1); + BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 12).size(), 1); + + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 0), graph.FindEdge(0, 4)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 3), graph.FindEdge(3, 7)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 4), graph.FindEdge(4, 6), graph.FindEdge(4, 0)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 5), graph.FindEdge(5, 6)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 6), graph.FindEdge(6, 4), graph.FindEdge(6, 5)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 7), graph.FindEdge(7, 11), graph.FindEdge(7, 3)); + CHECK_EQUAL_RANGE( + graph.GetBorderEdgeRange(1, 11), graph.FindEdge(11, 7), graph.FindEdge(11, 12)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 12), graph.FindEdge(12, 11)); + + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(2, 0), graph.FindEdge(0, 4)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(2, 3), graph.FindEdge(3, 7)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(2, 4), graph.FindEdge(4, 0)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(2, 7), graph.FindEdge(7, 11), graph.FindEdge(7, 3)); + CHECK_EQUAL_RANGE( + graph.GetBorderEdgeRange(2, 11), graph.FindEdge(11, 7), graph.FindEdge(11, 12)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(2, 12), graph.FindEdge(12, 11)); + + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(3, 0), graph.FindEdge(0, 4)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(3, 3), graph.FindEdge(3, 7)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(3, 4), graph.FindEdge(4, 0)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(3, 7), graph.FindEdge(7, 3)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(3, 11), graph.FindEdge(11, 12)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(3, 12), graph.FindEdge(12, 11)); + + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(4, 11), graph.FindEdge(11, 12)); + CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(4, 12), graph.FindEdge(12, 11)); +} + +BOOST_AUTO_TEST_SUITE_END()