From 108fce896b5a972e84f3ac8b94b7d763947150b8 Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Wed, 1 Mar 2017 22:55:18 +0000 Subject: [PATCH] Pull everthing in the facades --- include/engine/algorithm.hpp | 8 +- .../datafacade/algorithm_datafacade.hpp | 10 + .../contiguous_internalmem_datafacade.hpp | 110 +++++--- include/engine/engine_config.hpp | 8 +- include/engine/routing_algorithms.hpp | 139 +++++++-- include/partition/io.hpp | 28 ++ include/partition/partition_config.hpp | 9 +- include/storage/io.hpp | 7 + include/storage/shared_datatype.hpp | 20 +- include/util/multi_level_partition.hpp | 265 +++++++----------- src/osrm/osrm.cpp | 3 + src/partition/partitioner.cpp | 8 +- src/storage/storage.cpp | 35 ++- src/storage/storage_config.cpp | 4 +- src/tools/routed.cpp | 4 +- unit_tests/util/cell_storage.cpp | 30 +- unit_tests/util/multi_level_partition.cpp | 73 ++++- 17 files changed, 478 insertions(+), 283 deletions(-) create mode 100644 include/partition/io.hpp diff --git a/include/engine/algorithm.hpp b/include/engine/algorithm.hpp index f731f35c7..d6a8dd337 100644 --- a/include/engine/algorithm.hpp +++ b/include/engine/algorithm.hpp @@ -23,10 +23,10 @@ struct MLD final { }; -template const char* name(); -template<> inline const char* name() { return "CH"; } -template<> inline const char* name() { return "CoreCH"; } -template<> inline const char* name() { return "MLD"; } +template const char *name(); +template <> inline const char *name() { return "CH"; } +template <> inline const char *name() { return "CoreCH"; } +template <> inline const char *name() { return "MLD"; } } namespace algorithm_trais diff --git a/include/engine/datafacade/algorithm_datafacade.hpp b/include/engine/datafacade/algorithm_datafacade.hpp index ac7de6916..dcd38b800 100644 --- a/include/engine/datafacade/algorithm_datafacade.hpp +++ b/include/engine/datafacade/algorithm_datafacade.hpp @@ -3,7 +3,9 @@ #include "contractor/query_edge.hpp" #include "engine/algorithm.hpp" +#include "util/cell_storage.hpp" #include "util/integer_range.hpp" +#include "util/multi_level_partition.hpp" namespace osrm { @@ -58,6 +60,14 @@ template <> class AlgorithmDataFacade virtual bool IsCoreNode(const NodeID id) const = 0; }; + +template <> class AlgorithmDataFacade +{ + public: + virtual const util::MultiLevelPartitionView &GetMultiLevelPartition() const = 0; + + virtual const util::CellStorage &GetCellStorage() const = 0; +}; } } } diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 3bc2ce660..acb91c9b4 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -251,10 +251,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade std::shared_ptr> m_bearing_ranges_table; util::ShM::vector m_bearing_values_table; - // MLD data - util::PackedMultiLevelPartition mld_partition; - util::CellStorage mld_cell_storage; - // allocator that keeps the allocation data std::shared_ptr allocator; @@ -540,27 +536,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade m_entry_class_table = std::move(entry_class_table); } - void InitializeMLDDataPointers(storage::DataLayout &data_layout, char *memory_block) - { - if (data_layout.GetBlockSize(storage::DataLayout::MLD_CELL_PARTITION) > 0) - { - auto mld_partition_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::MLD_CELL_PARTITION); - mld_partition.InitializePointers( - mld_partition_ptr, - mld_partition_ptr + data_layout.num_entries[storage::DataLayout::MLD_CELL_PARTITION]); - } - - if (data_layout.GetBlockSize(storage::DataLayout::MLD_CELL_STORAGE) > 0) - { - auto mld_cell_storage_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::MLD_CELL_STORAGE); - mld_cell_storage.InitializePointers( - mld_cell_storage_ptr, - mld_cell_storage_ptr + data_layout.num_entries[storage::DataLayout::MLD_CELL_STORAGE]); - } - } - void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block) { InitializeChecksumPointer(data_layout, memory_block); @@ -574,7 +549,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade InitializeProfilePropertiesPointer(data_layout, memory_block); InitializeRTreePointers(data_layout, memory_block); InitializeIntersectionClassPointers(data_layout, memory_block); - InitializeMLDDataPointers(data_layout, memory_block); } public: @@ -1077,13 +1051,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade m_lane_description_masks.begin() + m_lane_description_offsets[lane_description_id + 1]); } - - const util::PackedMultiLevelPartition &GetMultiLevelPartition() const - { - return mld_partition; - } - - const util::CellStorage &GetCellStorage() const { return mld_cell_storage; } }; template class ContiguousInternalMemoryDataFacade; @@ -1115,6 +1082,83 @@ class ContiguousInternalMemoryDataFacade final { } }; + +template <> +class ContiguousInternalMemoryAlgorithmDataFacade + : public datafacade::AlgorithmDataFacade +{ + // MLD data + util::MultiLevelPartitionView mld_partition; + util::CellStorage mld_cell_storage; + + void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block) + { + InitializeMLDDataPointers(data_layout, memory_block); + } + + void InitializeMLDDataPointers(storage::DataLayout &data_layout, char *memory_block) + { + if (data_layout.GetBlockSize(storage::DataLayout::MLD_PARTITION) > 0) + { + BOOST_ASSERT(data_layout.GetBlockSize(storage::DataLayout::MLD_LEVEL_DATA) > 0); + BOOST_ASSERT(data_layout.GetBlockSize(storage::DataLayout::MLD_CELL_TO_CHILDREN) > 0); + + auto level_data = *data_layout.GetBlockPtr(memory_block, storage::DataLayout::MLD_PARTITION); + + auto mld_partition_ptr = data_layout.GetBlockPtr(memory_block, storage::DataLayout::MLD_PARTITION); + auto partition_entries_count = data_layout.GetBlockEntries(storage::DataLayout::MLD_PARTITION); + util::ShM::vector partition(mld_partition_ptr, partition_entries_count); + + auto mld_chilren_ptr = data_layout.GetBlockPtr(memory_block, storage::DataLayout::MLD_CELL_TO_CHILDREN); + auto children_entries_count = data_layout.GetBlockEntries(storage::DataLayout::MLD_CELL_TO_CHILDREN); + util::ShM::vector cell_to_children(mld_chilren_ptr, children_entries_count); + + mld_partition = util::MultiLevelPartitionView{level_data, partition, cell_to_children}; + } + + if (data_layout.GetBlockSize(storage::DataLayout::MLD_CELL_STORAGE) > 0) + { + auto mld_cell_storage_ptr = + data_layout.GetBlockPtr(memory_block, storage::DataLayout::MLD_CELL_STORAGE); + mld_cell_storage.InitializePointers( + mld_cell_storage_ptr, + mld_cell_storage_ptr + + data_layout.num_entries[storage::DataLayout::MLD_CELL_STORAGE]); + } + } + + // allocator that keeps the allocation data + std::shared_ptr allocator; + + public: + ContiguousInternalMemoryAlgorithmDataFacade( + std::shared_ptr allocator_) + : allocator(std::move(allocator_)) + { + InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory()); + } + + const util::MultiLevelPartitionView &GetMultiLevelPartition() const + { + return mld_partition; + } + + const util::CellStorage &GetCellStorage() const { return mld_cell_storage; } +}; + +template <> +class ContiguousInternalMemoryDataFacade + : public ContiguousInternalMemoryDataFacadeBase, + public ContiguousInternalMemoryAlgorithmDataFacade +{ + public: + ContiguousInternalMemoryDataFacade(std::shared_ptr allocator) + : ContiguousInternalMemoryDataFacadeBase(allocator), + ContiguousInternalMemoryAlgorithmDataFacade(allocator) + + { + } +}; } } } diff --git a/include/engine/engine_config.hpp b/include/engine/engine_config.hpp index 31de15514..e2e8d8ae8 100644 --- a/include/engine/engine_config.hpp +++ b/include/engine/engine_config.hpp @@ -61,6 +61,9 @@ namespace engine * now. * - Algorithm::CoreCH * Contractoin Hierachies with partial contraction for faster pre-processing but slower queries. + * - Algorithm::MLD + * Multi Level Dijkstra which is experimental and moderately fast in both pre-processing and + * query. * * Algorithm::CH is specified we will automatically upgrade to CoreCH if we find the data for it. * If Algorithm::CoreCH is specified and we don't find the speedup data, we fail hard. @@ -73,8 +76,9 @@ struct EngineConfig final enum class Algorithm { - CH, // will upgrade to CoreCH if it finds core data - CoreCH // will fail hard if there is no core data + CH, // will upgrade to CoreCH if it finds core data + CoreCH, // will fail hard if there is no core data + MLD }; storage::StorageConfig storage_config; diff --git a/include/engine/routing_algorithms.hpp b/include/engine/routing_algorithms.hpp index 706d35326..5b9fd553e 100644 --- a/include/engine/routing_algorithms.hpp +++ b/include/engine/routing_algorithms.hpp @@ -65,54 +65,29 @@ template class RoutingAlgorithms final : public RoutingAlg virtual ~RoutingAlgorithms() = default; InternalRouteResult - AlternativePathSearch(const PhantomNodes &phantom_node_pair) const final override - { - return routing_algorithms::alternativePathSearch(heaps, facade, phantom_node_pair); - } + AlternativePathSearch(const PhantomNodes &phantom_node_pair) const final override; InternalRouteResult ShortestPathSearch( const std::vector &phantom_node_pair, - const boost::optional continue_straight_at_waypoint) const final override - { - return routing_algorithms::shortestPathSearch( - heaps, facade, phantom_node_pair, continue_straight_at_waypoint); - } + const boost::optional continue_straight_at_waypoint) const final override; InternalRouteResult - DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override - { - return routing_algorithms::directShortestPathSearch(heaps, facade, phantom_nodes); - } + DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override; std::vector ManyToManySearch(const std::vector &phantom_nodes, const std::vector &source_indices, - const std::vector &target_indices) const final override - { - return routing_algorithms::manyToManySearch( - heaps, facade, phantom_nodes, source_indices, target_indices); - } + const std::vector &target_indices) const final override; routing_algorithms::SubMatchingList MapMatching( const routing_algorithms::CandidateLists &candidates_list, const std::vector &trace_coordinates, const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision) const final override - { - return routing_algorithms::mapMatching(heaps, - facade, - candidates_list, - trace_coordinates, - trace_timestamps, - trace_gps_precision); - } + const std::vector> &trace_gps_precision) const final override; std::vector GetTileTurns(const std::vector &edges, - const std::vector &sorted_edge_indexes) const final override - { - return routing_algorithms::getTileTurns(facade, edges, sorted_edge_indexes); - } + const std::vector &sorted_edge_indexes) const final override; bool HasAlternativePathSearch() const final override { @@ -149,6 +124,108 @@ template class RoutingAlgorithms final : public RoutingAlg // Owned by shared-ptr passed to the query const datafacade::ContiguousInternalMemoryDataFacade &facade; }; + +template +InternalRouteResult +RoutingAlgorithms::AlternativePathSearch(const PhantomNodes &phantom_node_pair) const +{ + return routing_algorithms::alternativePathSearch(heaps, facade, phantom_node_pair); +} + +template +InternalRouteResult RoutingAlgorithms::ShortestPathSearch( + const std::vector &phantom_node_pair, + const boost::optional continue_straight_at_waypoint) const +{ + return routing_algorithms::shortestPathSearch( + heaps, facade, phantom_node_pair, continue_straight_at_waypoint); +} + +template +InternalRouteResult +RoutingAlgorithms::DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const +{ + return routing_algorithms::directShortestPathSearch(heaps, facade, phantom_nodes); +} + +template +std::vector RoutingAlgorithms::ManyToManySearch( + const std::vector &phantom_nodes, + const std::vector &source_indices, + const std::vector &target_indices) const +{ + return routing_algorithms::manyToManySearch( + heaps, facade, phantom_nodes, source_indices, target_indices); +} + +template +inline routing_algorithms::SubMatchingList RoutingAlgorithms::MapMatching( + const routing_algorithms::CandidateLists &candidates_list, + const std::vector &trace_coordinates, + const std::vector &trace_timestamps, + const std::vector> &trace_gps_precision) const +{ + return routing_algorithms::mapMatching( + heaps, facade, candidates_list, trace_coordinates, trace_timestamps, trace_gps_precision); +} + +template +inline std::vector RoutingAlgorithms::GetTileTurns( + const std::vector &edges, + const std::vector &sorted_edge_indexes) const +{ + return routing_algorithms::getTileTurns(facade, edges, sorted_edge_indexes); +} + +// MLD overrides for not implemented +template <> +InternalRouteResult inline RoutingAlgorithms::AlternativePathSearch( + const PhantomNodes &) const +{ + throw util::exception("AlternativePathSearch is not implemented"); +} + +template <> +inline InternalRouteResult +RoutingAlgorithms::ShortestPathSearch(const std::vector &, + const boost::optional) const +{ + throw util::exception("ShortestPathSearch is not implemented"); +} + +template <> +InternalRouteResult inline RoutingAlgorithms::DirectShortestPathSearch( + const PhantomNodes &) const +{ + throw util::exception("DirectShortestPathSearch is not implemented"); +} + +template <> +inline std::vector +RoutingAlgorithms::ManyToManySearch(const std::vector &, + const std::vector &, + const std::vector &) const +{ + throw util::exception("ManyToManySearch is not implemented"); +} + +template <> +inline routing_algorithms::SubMatchingList +RoutingAlgorithms::MapMatching(const routing_algorithms::CandidateLists &, + const std::vector &, + const std::vector &, + const std::vector> &) const +{ + throw util::exception("MapMatching is not implemented"); +} + +template <> +inline std::vector RoutingAlgorithms::GetTileTurns( + const std::vector &, + const std::vector &) const +{ + throw util::exception("GetTileTurns is not implemented"); +} } } diff --git a/include/partition/io.hpp b/include/partition/io.hpp new file mode 100644 index 000000000..b71283f0d --- /dev/null +++ b/include/partition/io.hpp @@ -0,0 +1,28 @@ +#ifndef OSRM_PARTITION_IO_HPP +#define OSRM_PARTITION_IO_HPP + +#include "storage/io.hpp" +#include "util/multi_level_partition.hpp" + +namespace osrm +{ +namespace partition +{ +namespace io +{ + +template <> +inline void write(const boost::filesystem::path &path, const util::MultiLevelPartition &mlp) +{ + const auto fingerprint = storage::io::FileWriter::GenerateFingerprint; + storage::io::FileWriter writer{path, fingerprint}; + + writer.WriteOne(mlp.level_data); + writer.SerializeVector(mlp.partition); + writer.SerializeVector(mlp.cell_to_children); +} +} +} +} + +#endif diff --git a/include/partition/partition_config.hpp b/include/partition/partition_config.hpp index 81679168b..15e3cf926 100644 --- a/include/partition/partition_config.hpp +++ b/include/partition/partition_config.hpp @@ -13,10 +13,7 @@ namespace partition struct PartitionConfig { - PartitionConfig() - : requested_num_threads(0) - { - } + PartitionConfig() : requested_num_threads(0) {} void UseDefaults() { @@ -37,8 +34,8 @@ struct PartitionConfig compressed_node_based_graph_path = basepath + ".osrm.cnbg"; cnbg_ebg_mapping_path = basepath + ".osrm.cnbg_to_ebg"; partition_path = basepath + ".osrm.partition"; - mld_partition_path = basepath + ".osrm.mld_partition"; - mld_storage_path = basepath + ".osrm.mld_storage"; + mld_partition_path = basepath + ".osrm.partition"; + mld_storage_path = basepath + ".osrm.cells"; } // might be changed to the node based graph at some point diff --git a/include/storage/io.hpp b/include/storage/io.hpp index 220639752..a30b3fbe0 100644 --- a/include/storage/io.hpp +++ b/include/storage/io.hpp @@ -141,6 +141,13 @@ class FileReader return sizeof(count) + sizeof(T) * count; } + template std::size_t ReadVectorSize() + { + const auto count = ReadElementCount64(); + Skip(count); + return count; + } + template void *DeserializeVector(void *begin, const void *end) { auto count = ReadElementCount64(); diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp index 141a70cd0..d2b27cd9c 100644 --- a/include/storage/shared_datatype.hpp +++ b/include/storage/shared_datatype.hpp @@ -57,7 +57,9 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA", "LANE_DESCRIPTION_MASKS", "TURN_WEIGHT_PENALTIES", "TURN_DURATION_PENALTIES", - "MLD_CELL_PARTITION", + "MLD_LEVEL_DATA", + "MLD_PARTITION", + "MLD_CELL_TO_CHILDREN", "MLD_CELL_STORAGE"}; struct DataLayout @@ -103,7 +105,9 @@ struct DataLayout LANE_DESCRIPTION_MASKS, TURN_WEIGHT_PENALTIES, TURN_DURATION_PENALTIES, - MLD_CELL_PARTITION, + MLD_LEVEL_DATA, + MLD_PARTITION, + MLD_CELL_TO_CHILDREN, MLD_CELL_STORAGE, NUM_BLOCKS }; @@ -122,6 +126,11 @@ struct DataLayout entry_align[bid] = alignof(T); } + inline uint64_t GetBlockEntries(BlockID bid) const + { + return num_entries[bid]; + } + inline uint64_t GetBlockSize(BlockID bid) const { // special bit encoding @@ -169,6 +178,13 @@ struct DataLayout return ptr; } + template + inline T *GetBlockEnd(char *shared_memory, BlockID bid) const + { + auto begin = GetBlockPtr(shared_memory, bid); + return begin + GetBlockEntries(bid); + } + template inline T *GetBlockPtr(char *shared_memory, BlockID bid) const { diff --git a/include/util/multi_level_partition.hpp b/include/util/multi_level_partition.hpp index a7deb0baa..483203502 100644 --- a/include/util/multi_level_partition.hpp +++ b/include/util/multi_level_partition.hpp @@ -20,6 +20,27 @@ namespace osrm { + +namespace util +{ +namespace detail +{ +template class MultiLevelPartitionImpl; +} +using MultiLevelPartition = detail::MultiLevelPartitionImpl; +using MultiLevelPartitionView = detail::MultiLevelPartitionImpl; +} + +namespace partition +{ +namespace io +{ +template +void write(const boost::filesystem::path &file, + const util::detail::MultiLevelPartitionImpl &mlp); +} +} + namespace util { namespace detail @@ -49,187 +70,121 @@ inline std::size_t highestMSB(std::uint64_t v) using LevelID = std::uint8_t; using CellID = std::uint32_t; +using PartitionID = std::uint64_t; static constexpr CellID INVALID_CELL_ID = std::numeric_limits::max(); -// Mock interface, can be removed when we have an actual implementation -class MultiLevelPartition +namespace detail { - public: - // Returns the cell id of `node` at `level` - virtual CellID GetCell(LevelID level, NodeID node) const = 0; - // Returns the lowest cell id (at `level - 1`) of all children `cell` at `level` - virtual CellID BeginChildren(LevelID level, CellID cell) const = 0; - - // Returns the highest cell id (at `level - 1`) of all children `cell` at `level` - virtual CellID EndChildren(LevelID level, CellID cell) const = 0; - - // Returns the highest level in which `first` and `second` are still in different cells - virtual LevelID GetHighestDifferentLevel(NodeID first, NodeID second) const = 0; - - // Returns the level at which a `node` is relevant for a query from start to target - virtual LevelID GetQueryLevel(NodeID start, NodeID target, NodeID node) const = 0; - - virtual std::uint8_t GetNumberOfLevels() const = 0; - - virtual std::uint32_t GetNumberOfCells(LevelID level) const = 0; -}; - -template class PackedMultiLevelPartition final : public MultiLevelPartition +template class MultiLevelPartitionImpl final { - using PartitionID = std::uint64_t; + // we will support at most 16 levels + static const constexpr std::uint8_t MAX_NUM_LEVEL = 16; static const constexpr std::uint8_t NUM_PARTITION_BITS = sizeof(PartitionID) * CHAR_BIT; + template using Vector = typename util::ShM::vector; + public: - PackedMultiLevelPartition() {} + // Contains all data necessary to describe the level hierarchy + struct LevelData + { + + std::uint32_t num_level; + std::array lidx_to_offset; + std::array lidx_to_mask; + std::array bit_to_level; + std::array lidx_to_children_offsets; + }; + + MultiLevelPartitionImpl() = default; // cell_sizes is index by level (starting at 0, the base graph). // However level 0 always needs to have cell size 1, since it is the // basegraph. - PackedMultiLevelPartition(const std::vector> &partitions, - const std::vector &level_to_num_cells) - : level_offsets(makeLevelOffsets(level_to_num_cells)), level_masks(makeLevelMasks()), - bit_to_level(makeBitToLevel()) + template > + MultiLevelPartitionImpl(const std::vector> &partitions, + const std::vector &lidx_to_num_cells) + : level_data(MakeLevelData(lidx_to_num_cells)) { - initializePartitionIDs(partitions); + InitializePartitionIDs(partitions); } - PackedMultiLevelPartition(const boost::filesystem::path &file_name) { Read(file_name); } + template > + MultiLevelPartitionImpl(LevelData level_data, + Vector partition_, + Vector cell_to_children_) + : level_data(std::move(level_data)), partition(std::move(partition_)), + cell_to_children(std::move(cell_to_children_)) + { + } // returns the index of the cell the vertex is contained at level l - CellID GetCell(LevelID l, NodeID node) const final override + CellID GetCell(LevelID l, NodeID node) const { auto p = partition[node]; auto lidx = LevelIDToIndex(l); - auto masked = p & level_masks[lidx]; - return masked >> level_offsets[lidx]; + auto masked = p & level_data.lidx_to_mask[lidx]; + return masked >> level_data.lidx_to_offset[lidx]; } - LevelID GetQueryLevel(NodeID start, NodeID target, NodeID node) const final override + LevelID GetQueryLevel(NodeID start, NodeID target, NodeID node) const { return std::min(GetHighestDifferentLevel(start, node), GetHighestDifferentLevel(target, node)); } - LevelID GetHighestDifferentLevel(NodeID first, NodeID second) const final override + LevelID GetHighestDifferentLevel(NodeID first, NodeID second) const { if (partition[first] == partition[second]) return 0; auto msb = detail::highestMSB(partition[first] ^ partition[second]); - return bit_to_level[msb]; + return level_data.bit_to_level[msb]; } - std::uint8_t GetNumberOfLevels() const final override { return level_offsets.size(); } + std::uint8_t GetNumberOfLevels() const { return level_data.num_level; } - std::uint32_t GetNumberOfCells(LevelID level) const final override + std::uint32_t GetNumberOfCells(LevelID level) const { return GetCell(level, GetSenitileNode()); } // Returns the lowest cell id (at `level - 1`) of all children `cell` at `level` - CellID BeginChildren(LevelID level, CellID cell) const final override + CellID BeginChildren(LevelID level, CellID cell) const { BOOST_ASSERT(level > 1); auto lidx = LevelIDToIndex(level); - auto offset = level_to_children_offset[lidx]; + auto offset = level_data.lidx_to_children_offsets[lidx]; return cell_to_children[offset + cell]; } // Returns the highest cell id (at `level - 1`) of all children `cell` at `level` - CellID EndChildren(LevelID level, CellID cell) const final override + CellID EndChildren(LevelID level, CellID cell) const { BOOST_ASSERT(level > 1); auto lidx = LevelIDToIndex(level); - auto offset = level_to_children_offset[lidx]; + auto offset = level_data.lidx_to_children_offsets[lidx]; return cell_to_children[offset + cell + 1]; } - std::size_t GetRequiredMemorySize(const boost::filesystem::path &path) const - { - const auto fingerprint = storage::io::FileReader::VerifyFingerprint; - storage::io::FileReader reader{path, fingerprint}; - - std::size_t memory_size = 0; - memory_size += reader.GetVectorMemorySize(); - memory_size += reader.GetVectorMemorySize(); - memory_size += reader.GetVectorMemorySize(); - memory_size += reader.GetVectorMemorySize(); - return memory_size; - } - - template - typename std::enable_if::type - Read(const boost::filesystem::path &path, void *begin, const void *end) const - { - const auto fingerprint = storage::io::FileReader::VerifyFingerprint; - storage::io::FileReader reader{path, fingerprint}; - - begin = reader.DeserializeVector(begin, end); - begin = reader.DeserializeVector(begin, end); - begin = reader.DeserializeVector( - begin, end); - begin = - reader.DeserializeVector(begin, end); - } - - template - typename std::enable_if::type InitializePointers(char *begin, const char *end) - { - auto level_offsets_size = *reinterpret_cast(begin); - begin += sizeof(level_offsets_size); - level_offsets.reset(begin, level_offsets_size); - begin += sizeof(decltype(level_offsets[0])) * level_offsets_size; - - auto partition_size = *reinterpret_cast(begin); - begin += sizeof(partition_size); - partition.reset(begin, partition_size); - begin += sizeof(decltype(partition[0])) * partition_size; - - auto level_to_children_offset_size = *reinterpret_cast(begin); - begin += sizeof(level_to_children_offset_size); - level_to_children_offset.reset(begin, level_to_children_offset_size); - begin += sizeof(decltype(level_to_children_offset[0])) * level_to_children_offset_size; - - auto cell_to_children_size = *reinterpret_cast(begin); - begin += sizeof(cell_to_children_size); - cell_to_children.reset(begin, cell_to_children_size); - begin += sizeof(decltype(cell_to_children[0])) * level_to_children_offset_size; - - BOOST_ASSERT(begin <= end); - - level_masks = makeLevelMasks(); - bit_to_level = makeBitToLevel(); - } - - template - typename std::enable_if::type Read(const boost::filesystem::path &path) - { - const auto fingerprint = storage::io::FileReader::VerifyFingerprint; - storage::io::FileReader reader{path, fingerprint}; - - reader.DeserializeVector(level_offsets); - reader.DeserializeVector(partition); - reader.DeserializeVector(level_to_children_offset); - reader.DeserializeVector(cell_to_children); - - level_masks = makeLevelMasks(); - bit_to_level = makeBitToLevel(); - } - - void Write(const boost::filesystem::path &path) const - { - const auto fingerprint = storage::io::FileWriter::GenerateFingerprint; - storage::io::FileWriter writer{path, fingerprint}; - - writer.SerializeVector(level_offsets); - writer.SerializeVector(partition); - writer.SerializeVector(level_to_children_offset); - writer.SerializeVector(cell_to_children); - } + friend void partition::io::write(const boost::filesystem::path &file, + const MultiLevelPartitionImpl &mlp); private: + auto MakeLevelData(const std::vector &lidx_to_num_cells) + { + std::uint32_t num_level = lidx_to_num_cells.size() + 1; + auto offsets = MakeLevelOffsets(lidx_to_num_cells); + auto masks = MakeLevelMasks(offsets, num_level); + auto bits = MakeBitToLevel(offsets, num_level); + return LevelData{num_level, + offsets, + masks, + bits, + {0}}; + } + inline std::size_t LevelIDToIndex(LevelID l) const { return l - 1; } // We save the sentinel as last node in the partition information. @@ -241,46 +196,45 @@ template class PackedMultiLevelPartition final : public Mu { auto lidx = LevelIDToIndex(l); - auto shifted_id = cell_id << level_offsets[lidx]; - auto cleared_cell = partition[node] & ~level_masks[lidx]; + auto shifted_id = cell_id << level_data.lidx_to_offset[lidx]; + auto cleared_cell = partition[node] & ~level_data.lidx_to_mask[lidx]; partition[node] = cleared_cell | shifted_id; } // If we have N cells per level we need log_2 bits for every cell ID - std::vector - makeLevelOffsets(const std::vector &level_to_num_cells) const + auto MakeLevelOffsets(const std::vector &lidx_to_num_cells) const { - std::vector offsets; - offsets.reserve(level_to_num_cells.size()); + std::array offsets; + auto lidx = 0UL; auto sum_bits = 0; - for (auto num_cells : level_to_num_cells) + for (auto num_cells : lidx_to_num_cells) { // bits needed to number all contained vertexes auto bits = static_cast(std::ceil(std::log2(num_cells + 1))); - offsets.push_back(sum_bits); + offsets[lidx++] = sum_bits; sum_bits += bits; if (sum_bits > 64) { - throw util::exception("Can't pack the partition information at level " + - std::to_string(offsets.size()) + - " into a 64bit integer. Would require " + - std::to_string(sum_bits) + " bits."); + throw util::exception( + "Can't pack the partition information at level " + std::to_string(lidx) + + " into a 64bit integer. Would require " + std::to_string(sum_bits) + " bits."); } } // sentinel - offsets.push_back(sum_bits); + offsets[lidx++] = sum_bits; + BOOST_ASSERT(lidx < MAX_NUM_LEVEL); return offsets; } - std::vector makeLevelMasks() const + auto MakeLevelMasks(const std::array &level_offsets, std::uint32_t num_level) const { - std::vector masks; - masks.reserve(level_offsets.size()); + std::array masks; + auto lidx = 0UL; util::for_each_pair(level_offsets.begin(), - level_offsets.end(), + level_offsets.begin() + num_level, [&](const auto offset, const auto next_offset) { // create mask that has `bits` ones at its LSBs. // 000011 @@ -290,31 +244,30 @@ template class PackedMultiLevelPartition final : public Mu BOOST_ASSERT(next_offset < NUM_PARTITION_BITS); PartitionID next_mask = (1UL << next_offset) - 1UL; // 001100 - masks.push_back(next_mask ^ mask); + masks[lidx++] = next_mask ^ mask; }); return masks; } - std::array makeBitToLevel() const + auto MakeBitToLevel(const std::array &level_offsets, std::uint32_t num_level) const { std::array bit_to_level; - LevelID l = 1; - for (auto bits : level_offsets) + for (auto l = 1u; l < num_level; ++l) { + auto bits = level_offsets[l-1]; // set all bits to point to the correct level. for (auto idx = bits; idx < NUM_PARTITION_BITS; ++idx) { bit_to_level[idx] = l; } - l++; } return bit_to_level; } - void initializePartitionIDs(const std::vector> &partitions) + void InitializePartitionIDs(const std::vector> &partitions) { auto num_nodes = partitions.front().size(); std::vector permutation(num_nodes); @@ -370,14 +323,13 @@ template class PackedMultiLevelPartition final : public Mu level--; } - // level 1 does not have child cells - level_to_children_offset.push_back(0); + level_data.lidx_to_children_offsets[0] = 0; for (auto level_idx = 0UL; level_idx < partitions.size() - 1; ++level_idx) { const auto &parent_partition = partitions[level_idx + 1]; - level_to_children_offset.push_back(cell_to_children.size()); + level_data.lidx_to_children_offsets[level_idx+1] = cell_to_children.size(); CellID last_parent_id = parent_partition[permutation.front()]; cell_to_children.push_back(GetCell(level_idx + 1, permutation.front())); @@ -396,14 +348,13 @@ template class PackedMultiLevelPartition final : public Mu } } - typename util::ShM::vector level_offsets; - typename util::ShM::vector partition; - typename util::ShM::vector level_to_children_offset; - typename util::ShM::vector cell_to_children; - std::vector level_masks; - std::array bit_to_level; + //! this is always owned by this class because it is so small + LevelData level_data; + Vector partition; + Vector cell_to_children; }; } } +} #endif diff --git a/src/osrm/osrm.cpp b/src/osrm/osrm.cpp index 3a5da0689..61b5644e9 100644 --- a/src/osrm/osrm.cpp +++ b/src/osrm/osrm.cpp @@ -45,6 +45,9 @@ OSRM::OSRM(engine::EngineConfig &config) case EngineConfig::Algorithm::CoreCH: engine_ = std::make_unique>(config); break; + case EngineConfig::Algorithm::MLD: + engine_ = std::make_unique>(config); + break; default: util::exception("Algorithm not implemented!"); } diff --git a/src/partition/partitioner.cpp b/src/partition/partitioner.cpp index 66fc450a2..19786e741 100644 --- a/src/partition/partitioner.cpp +++ b/src/partition/partitioner.cpp @@ -5,6 +5,7 @@ #include "partition/edge_based_graph_reader.hpp" #include "partition/node_based_graph_to_edge_based_graph_mapping_reader.hpp" #include "partition/recursive_bisection.hpp" +#include "partition/io.hpp" #include "util/cell_storage.hpp" #include "util/coordinate.hpp" @@ -21,7 +22,6 @@ #include #include -#include #include "util/geojson_debug_logger.hpp" #include "util/geojson_debug_policies.hpp" @@ -203,7 +203,7 @@ int Partitioner::Run(const PartitionConfig &config) // split bisection id bits into groups starting from SCC and stop at level 1 BOOST_ASSERT(recursive_bisection.SCCDepth() != 0); int mask_from = sizeof(BisectionID) * CHAR_BIT - recursive_bisection.SCCDepth(); - boost::container::small_vector level_masks; + std::vector level_masks; for (int mask_to = sizeof(BisectionID) * CHAR_BIT; mask_to > first_nonzero_position; mask_to = mask_from, mask_from -= 3) // TODO: find better grouping { @@ -250,7 +250,7 @@ int Partitioner::Run(const PartitionConfig &config) } TIMER_START(packed_mlp); - osrm::util::PackedMultiLevelPartition mlp{partitions, level_to_num_cells}; + osrm::util::MultiLevelPartition mlp{partitions, level_to_num_cells}; TIMER_STOP(packed_mlp); util::Log() << "PackedMultiLevelPartition constructed in " << TIMER_SEC(packed_mlp) << " seconds"; @@ -261,7 +261,7 @@ int Partitioner::Run(const PartitionConfig &config) util::Log() << "CellStorage constructed in " << TIMER_SEC(cell_storage) << " seconds"; TIMER_START(writing_mld_data); - mlp.Write(config.mld_partition_path); + io::write(config.mld_partition_path, mlp); storage.Write(config.mld_storage_path); TIMER_STOP(writing_mld_data); util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds"; diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index c49c4929f..8f92c7330 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -400,12 +400,21 @@ void Storage::PopulateLayout(DataLayout &layout) // Loading MLD Data if (boost::filesystem::exists(config.mld_partition_path)) { - auto mld_partition_size = util::PackedMultiLevelPartition().GetRequiredMemorySize( - config.mld_partition_path); - layout.SetBlockSize(DataLayout::MLD_CELL_PARTITION, mld_partition_size); + io::FileReader reader(config.mld_partition_path, io::FileReader::VerifyFingerprint); + + reader.Skip(1); + layout.SetBlockSize(DataLayout::MLD_LEVEL_DATA, 1); + const auto partition_entries_count = reader.ReadVectorSize(); + layout.SetBlockSize(DataLayout::MLD_PARTITION, partition_entries_count); + const auto children_entries_count = reader.ReadVectorSize(); + layout.SetBlockSize(DataLayout::MLD_CELL_TO_CHILDREN, children_entries_count); } else - layout.SetBlockSize(DataLayout::MLD_CELL_PARTITION, 0); + { + layout.SetBlockSize(DataLayout::MLD_LEVEL_DATA, 0); + layout.SetBlockSize(DataLayout::MLD_PARTITION, 0); + layout.SetBlockSize(DataLayout::MLD_CELL_TO_CHILDREN, 0); + } if (boost::filesystem::exists(config.mld_storage_path)) { @@ -866,13 +875,17 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr) { // Loading MLD Data - const auto mld_partition_ptr = - layout.GetBlockPtr(memory_ptr, DataLayout::MLD_CELL_PARTITION); - const auto mld_partition_size = layout.GetBlockSize(DataLayout::MLD_CELL_PARTITION); if (boost::filesystem::exists(config.mld_partition_path)) { - util::PackedMultiLevelPartition().Read( - config.mld_partition_path, mld_partition_ptr, mld_partition_ptr + mld_partition_size); + auto mld_level_data_ptr = layout.GetBlockPtr(memory_ptr, DataLayout::MLD_LEVEL_DATA); + auto mld_partition_ptr = layout.GetBlockPtr(memory_ptr, DataLayout::MLD_PARTITION); + auto mld_chilren_ptr = layout.GetBlockPtr(memory_ptr, DataLayout::MLD_CELL_TO_CHILDREN); + + io::FileReader reader(config.mld_partition_path, io::FileReader::VerifyFingerprint); + + reader.ReadInto(mld_level_data_ptr); + reader.ReadInto(mld_partition_ptr, layout.GetBlockEntries(DataLayout::MLD_PARTITION)); + reader.ReadInto(mld_chilren_ptr, layout.GetBlockEntries(DataLayout::MLD_CELL_TO_CHILDREN)); } const auto mld_cell_storage_ptr = @@ -881,8 +894,8 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr) if (boost::filesystem::exists(config.mld_storage_path)) { util::CellStorage().Read(config.mld_storage_path, - mld_cell_storage_ptr, - mld_cell_storage_ptr + mld_cell_storage_size); + mld_cell_storage_ptr, + mld_cell_storage_ptr + mld_cell_storage_size); } } } diff --git a/src/storage/storage_config.cpp b/src/storage/storage_config.cpp index 4f8743f3b..cf8407487 100644 --- a/src/storage/storage_config.cpp +++ b/src/storage/storage_config.cpp @@ -20,8 +20,8 @@ StorageConfig::StorageConfig(const boost::filesystem::path &base) names_data_path{base.string() + ".names"}, properties_path{base.string() + ".properties"}, intersection_class_path{base.string() + ".icd"}, turn_lane_data_path{base.string() + ".tld"}, turn_lane_description_path{base.string() + ".tls"}, - mld_partition_path{base.string() + ".mld_partition"}, - mld_storage_path{base.string() + ".mld_storage"} + mld_partition_path{base.string() + ".partition"}, + mld_storage_path{base.string() + ".cell"} { } diff --git a/src/tools/routed.cpp b/src/tools/routed.cpp index 7eba3dee3..a66f61f7f 100644 --- a/src/tools/routed.cpp +++ b/src/tools/routed.cpp @@ -55,6 +55,8 @@ EngineConfig::Algorithm stringToAlgorithm(const std::string &algorithm) return EngineConfig::Algorithm::CH; if (algorithm == "CoreCH") return EngineConfig::Algorithm::CoreCH; + if (algorithm == "MLD") + return EngineConfig::Algorithm::MLD; throw util::exception("Invalid algorithm name: " + algorithm); } @@ -100,7 +102,7 @@ inline unsigned generateServerProgramOptions(const int argc, "Load data from shared memory") // ("algorithm,a", value(&algorithm)->default_value("CH"), - "Algorithm to use for the data. Can be CH, CoreCH") // + "Algorithm to use for the data. Can be CH, CoreCH, MLD.") // ("max-viaroute-size", value(&max_locations_viaroute)->default_value(500), "Max. locations supported in viaroute query") // diff --git a/unit_tests/util/cell_storage.cpp b/unit_tests/util/cell_storage.cpp index bf8fafbff..81cca0f00 100644 --- a/unit_tests/util/cell_storage.cpp +++ b/unit_tests/util/cell_storage.cpp @@ -16,32 +16,6 @@ using namespace osrm; using namespace osrm::util; -class MockMLP final : public MultiLevelPartition -{ - public: - CellID GetCell(LevelID level, NodeID node) const { return levels[level - 1][node]; }; - - LevelID GetHighestDifferentLevel(NodeID, NodeID) const { return 3; }; - LevelID GetQueryLevel(NodeID, NodeID, NodeID) const { return 3; }; - - std::uint8_t GetNumberOfLevels() const { return levels.size() + 1; } - - std::uint32_t GetNumberOfCells(LevelID level) const - { - auto max_id = 0; - for (auto cell : levels[level - 1]) - max_id = std::max(max_id, cell); - return max_id + 1; - } - - CellID BeginChildren(LevelID, CellID) const { return 0; } - CellID EndChildren(LevelID, CellID) const { return 0; } - - MockMLP(std::vector> levels_) : levels(std::move(levels_)) {} - - std::vector> levels; -}; - struct MockEdge { NodeID start; @@ -84,7 +58,7 @@ BOOST_AUTO_TEST_CASE(mutable_cell_storage) std::vector l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3}}; std::vector l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}}; std::vector l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; - MockMLP mlp{{l1, l2, l3, l4}}; + MultiLevelPartition mlp{{l1, l2, l3, l4}, {2, 4, 8, 12}}; std::vector edges = { // edges sorted into border/internal by level @@ -193,7 +167,7 @@ BOOST_AUTO_TEST_CASE(immutable_cell_storage) std::vector l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3}}; std::vector l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}}; std::vector l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; - MockMLP mlp{{l1, l2, l3, l4}}; + MultiLevelPartition mlp{{l1, l2, l3, l4}, {2, 4, 8, 12}}; std::vector edges = { // edges sorted into border/internal by level diff --git a/unit_tests/util/multi_level_partition.cpp b/unit_tests/util/multi_level_partition.cpp index a874dad22..84525f03e 100644 --- a/unit_tests/util/multi_level_partition.cpp +++ b/unit_tests/util/multi_level_partition.cpp @@ -17,14 +17,83 @@ using namespace osrm::util; BOOST_AUTO_TEST_SUITE(multi_level_partition_tests) -BOOST_AUTO_TEST_CASE(packed_mlp) +BOOST_AUTO_TEST_CASE(mlp_one) +{ + // node: 0 1 2 3 4 5 6 7 8 9 10 11 + std::vector l1{{4, 4, 2, 2, 1, 1, 3, 3, 2, 2, 5, 5}}; + MultiLevelPartition mlp{{l1}, {6}}; + + BOOST_CHECK_EQUAL(mlp.GetCell(1, 0), mlp.GetCell(1, 1)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 2), mlp.GetCell(1, 3)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 4), mlp.GetCell(1, 5)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 6), mlp.GetCell(1, 7)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 8), mlp.GetCell(1, 9)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 10), mlp.GetCell(1, 11)); +} + +BOOST_AUTO_TEST_CASE(mlp_shuffled) +{ + // node: 0 1 2 3 4 5 6 7 8 9 10 11 + std::vector l1{{4, 4, 2, 2, 1, 1, 3, 3, 2, 2, 5, 5}}; + std::vector l2{{3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 0, 0}}; + std::vector l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}}; + std::vector l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + MultiLevelPartition mlp{{l1, l2, l3, l4}, {6, 4, 2, 1}}; + + BOOST_CHECK_EQUAL(mlp.GetNumberOfCells(1), 6); + BOOST_CHECK_EQUAL(mlp.GetNumberOfCells(2), 4); + BOOST_CHECK_EQUAL(mlp.GetNumberOfCells(3), 2); + BOOST_CHECK_EQUAL(mlp.GetNumberOfCells(4), 1); + + BOOST_CHECK_EQUAL(mlp.GetCell(1, 0), mlp.GetCell(1, 1)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 2), mlp.GetCell(1, 3)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 4), mlp.GetCell(1, 5)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 6), mlp.GetCell(1, 7)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 8), mlp.GetCell(1, 9)); + BOOST_CHECK_EQUAL(mlp.GetCell(1, 10), mlp.GetCell(1, 11)); + + BOOST_CHECK_EQUAL(mlp.GetCell(2, 0), mlp.GetCell(2, 1)); + BOOST_CHECK_EQUAL(mlp.GetCell(2, 0), mlp.GetCell(2, 2)); + BOOST_CHECK_EQUAL(mlp.GetCell(2, 0), mlp.GetCell(2, 3)); + BOOST_CHECK_EQUAL(mlp.GetCell(2, 4), mlp.GetCell(2, 5)); + BOOST_CHECK_EQUAL(mlp.GetCell(2, 4), mlp.GetCell(2, 6)); + BOOST_CHECK_EQUAL(mlp.GetCell(2, 4), mlp.GetCell(2, 7)); + BOOST_CHECK_EQUAL(mlp.GetCell(2, 8), mlp.GetCell(2, 9)); + BOOST_CHECK_EQUAL(mlp.GetCell(2, 10), mlp.GetCell(2, 11)); + + BOOST_CHECK_EQUAL(mlp.GetCell(3, 0), mlp.GetCell(3, 1)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 0), mlp.GetCell(3, 2)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 0), mlp.GetCell(3, 3)); + + BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), mlp.GetCell(3, 5)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), mlp.GetCell(3, 6)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), mlp.GetCell(3, 7)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), mlp.GetCell(3, 8)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), mlp.GetCell(3, 9)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), mlp.GetCell(3, 10)); + BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), mlp.GetCell(3, 11)); + + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 1)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 2)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 3)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 4)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 5)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 6)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 7)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 8)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 9)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 10)); + BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), mlp.GetCell(4, 11)); +} + +BOOST_AUTO_TEST_CASE(mlp_sorted) { // node: 0 1 2 3 4 5 6 7 8 9 10 11 std::vector l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5}}; std::vector l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3}}; std::vector l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}}; std::vector l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; - PackedMultiLevelPartition mlp{{l1, l2, l3, l4}, {6, 4, 2, 1}}; + MultiLevelPartition mlp{{l1, l2, l3, l4}, {6, 4, 2, 1}}; BOOST_CHECK_EQUAL(mlp.GetNumberOfCells(1), 6); BOOST_CHECK_EQUAL(mlp.GetNumberOfCells(2), 4);