Add class to translate from bisection ids to cell ids
This commit is contained in:
parent
b2f3b901e0
commit
8f9e980945
24
include/partition/bisection_to_partition.hpp
Normal file
24
include/partition/bisection_to_partition.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef BISECTION_TO_PARTITION_HPP
|
||||
#define BISECTION_TO_PARTITION_HPP
|
||||
|
||||
#include "partition/multi_level_partition.hpp"
|
||||
#include "partition/recursive_bisection.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace partition
|
||||
{
|
||||
|
||||
using Partition = std::vector<CellID>;
|
||||
|
||||
// Converts a representation of the bisection to cell ids over multiple level
|
||||
std::tuple<std::vector<Partition>, std::vector<std::uint32_t>>
|
||||
bisectionToPartition(const std::vector<BisectionID> &node_to_bisection_id,
|
||||
const std::vector<std::size_t> &max_cell_sizes);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -5,6 +5,7 @@
|
||||
#include "util/for_each_pair.hpp"
|
||||
#include "util/shared_memory_vector_wrapper.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include "util/msb.hpp"
|
||||
|
||||
#include "storage/io.hpp"
|
||||
|
||||
@ -38,27 +39,6 @@ void write(const boost::filesystem::path &file,
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// get the msb of an integer
|
||||
// return 0 for integers without msb
|
||||
template <typename T> std::size_t highestMSB(T value)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "Integer required.");
|
||||
std::size_t msb = 0;
|
||||
while (value > 0)
|
||||
{
|
||||
value >>= 1u;
|
||||
msb++;
|
||||
}
|
||||
return msb;
|
||||
}
|
||||
|
||||
#if (defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)) && __x86_64__
|
||||
inline std::size_t highestMSB(std::uint64_t v)
|
||||
{
|
||||
BOOST_ASSERT(v > 0);
|
||||
return 63UL - __builtin_clzl(v);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
using LevelID = std::uint8_t;
|
||||
@ -132,7 +112,7 @@ template <bool UseShareMemory> class MultiLevelPartitionImpl final
|
||||
if (partition[first] == partition[second])
|
||||
return 0;
|
||||
|
||||
auto msb = detail::highestMSB(partition[first] ^ partition[second]);
|
||||
auto msb = util::msb(partition[first] ^ partition[second]);
|
||||
return level_data.bit_to_level[msb];
|
||||
}
|
||||
|
||||
|
44
include/util/msb.hpp
Normal file
44
include/util/msb.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef OSRM_UTIL_MSB_HPP
|
||||
#define OSRM_UTIL_MSB_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
// get the msb of an integer
|
||||
// return 0 for integers without msb
|
||||
template <typename T> std::size_t msb(T value)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "Integer required.");
|
||||
std::size_t msb = 0;
|
||||
while (value > 0)
|
||||
{
|
||||
value >>= 1u;
|
||||
msb++;
|
||||
}
|
||||
return msb;
|
||||
}
|
||||
|
||||
#if (defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)) && __x86_64__
|
||||
inline std::size_t msb(std::uint64_t v)
|
||||
{
|
||||
BOOST_ASSERT(v > 0);
|
||||
return 63UL - __builtin_clzl(v);
|
||||
}
|
||||
inline std::size_t msb(std::uint32_t v)
|
||||
{
|
||||
BOOST_ASSERT(v > 0);
|
||||
return 31UL - __builtin_clz(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
138
src/partition/bisection_to_partition.cpp
Normal file
138
src/partition/bisection_to_partition.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "partition/bisection_to_partition.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace partition
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CellBisection
|
||||
{
|
||||
std::uint32_t begin;
|
||||
std::uint32_t end;
|
||||
std::uint8_t depth;
|
||||
bool tabu; // we will not attempt to split this cell anymore
|
||||
};
|
||||
static constexpr std::size_t NUM_BISECTION_BITS = sizeof(BisectionID) * CHAR_BIT;
|
||||
|
||||
bool getSide(std::uint8_t depth, BisectionID id)
|
||||
{
|
||||
return id & (1UL << (NUM_BISECTION_BITS - 1 - depth));
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> getLargeCells(const std::size_t max_cell_size,
|
||||
const std::vector<CellBisection> &cells)
|
||||
{
|
||||
std::vector<std::uint32_t> large_cells;
|
||||
|
||||
for (auto index = 0u; index < cells.size(); ++index)
|
||||
{
|
||||
if (!cells[index].tabu && cells[index].end - cells[index].begin > max_cell_size)
|
||||
large_cells.push_back(index);
|
||||
}
|
||||
|
||||
return large_cells;
|
||||
}
|
||||
|
||||
Partition cellsToPartition(const std::vector<CellBisection> &cells,
|
||||
const std::vector<std::uint32_t> &permutation)
|
||||
{
|
||||
Partition partition(permutation.size(), INVALID_CELL_ID);
|
||||
CellID cell_id = 0;
|
||||
for (const auto &cell : cells)
|
||||
{
|
||||
std::for_each(permutation.begin() + cell.begin,
|
||||
permutation.begin() + cell.end,
|
||||
[&partition, cell_id](const auto node_id) { partition[node_id] = cell_id; });
|
||||
cell_id++;
|
||||
}
|
||||
|
||||
return partition;
|
||||
}
|
||||
|
||||
void partitionLevel(const std::vector<BisectionID> &node_to_bisection_id,
|
||||
std::size_t max_cell_size,
|
||||
std::vector<std::uint32_t> &permutation,
|
||||
std::vector<CellBisection> &cells)
|
||||
{
|
||||
for (auto large_cells = getLargeCells(max_cell_size, cells); large_cells.size() > 0;
|
||||
large_cells = getLargeCells(max_cell_size, cells))
|
||||
{
|
||||
for (const auto cell_index : large_cells)
|
||||
{
|
||||
auto &cell = cells[cell_index];
|
||||
BOOST_ASSERT(cell.depth < NUM_BISECTION_BITS);
|
||||
|
||||
// Go over all nodes and sum up the bits to determine at which position the first one bit is
|
||||
BisectionID sum =
|
||||
std::accumulate(permutation.begin() + cell.begin,
|
||||
permutation.begin() + cell.end,
|
||||
BisectionID{0},
|
||||
[&node_to_bisection_id](const BisectionID lhs, const NodeID rhs) {
|
||||
return lhs | node_to_bisection_id[rhs];
|
||||
});
|
||||
// masks all bit strictly higher then cell.depth
|
||||
const BisectionID mask = (1UL << (NUM_BISECTION_BITS - cell.depth)) - 1;
|
||||
const auto masked_sum = sum & mask;
|
||||
// we can't split the cell anymore, but it also doesn't conform to the max size constraint
|
||||
// -> we need to remove it from the optimization
|
||||
if (masked_sum == 0)
|
||||
{
|
||||
cell.tabu = true;
|
||||
continue;
|
||||
}
|
||||
const auto msb = util::msb(sum & mask);
|
||||
// depth counts from MSB to LSB
|
||||
const auto depth = NUM_BISECTION_BITS - 1 - msb;
|
||||
|
||||
std::uint32_t middle =
|
||||
std::partition(permutation.begin() + cell.begin,
|
||||
permutation.begin() + cell.end,
|
||||
[depth, &node_to_bisection_id](const auto node_id) {
|
||||
return getSide(depth, node_to_bisection_id[node_id]);
|
||||
}) -
|
||||
permutation.begin();
|
||||
|
||||
cell.depth = depth + 1;
|
||||
if (middle != cell.begin && middle != cell.end)
|
||||
{
|
||||
auto old_end = cell.end;
|
||||
cell.end = middle;
|
||||
cells.push_back(
|
||||
CellBisection{middle, old_end, static_cast<std::uint8_t>(depth + 1), false});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implements a greedy algorithm that split cells using the bisection until a target cell size is
|
||||
// reached
|
||||
std::tuple<std::vector<Partition>, std::vector<std::uint32_t>>
|
||||
bisectionToPartition(const std::vector<BisectionID> &node_to_bisection_id,
|
||||
const std::vector<std::size_t> &max_cell_sizes)
|
||||
{
|
||||
std::vector<std::uint32_t> permutation(node_to_bisection_id.size());
|
||||
std::iota(permutation.begin(), permutation.end(), 0);
|
||||
|
||||
std::vector<CellBisection> cells;
|
||||
cells.push_back(CellBisection{0, static_cast<std::uint32_t>(node_to_bisection_id.size()), 0, false});
|
||||
|
||||
std::vector<Partition> partitions(max_cell_sizes.size());
|
||||
std::vector<std::uint32_t> num_cells(max_cell_sizes.size());
|
||||
|
||||
auto level_idx = max_cell_sizes.size() - 1;
|
||||
for (auto max_cell_size : boost::adaptors::reverse(max_cell_sizes))
|
||||
{
|
||||
partitionLevel(node_to_bisection_id, max_cell_size, permutation, cells);
|
||||
|
||||
partitions[level_idx] = cellsToPartition(cells, permutation);
|
||||
num_cells[level_idx] = cells.size();
|
||||
level_idx--;
|
||||
}
|
||||
|
||||
return std::make_tuple(std::move(partitions), std::move(num_cells));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
#include "partition/partitioner.hpp"
|
||||
#include "partition/annotated_partition.hpp"
|
||||
#include "partition/bisection_graph.hpp"
|
||||
#include "partition/bisection_to_partition.hpp"
|
||||
#include "partition/compressed_node_based_graph_reader.hpp"
|
||||
#include "partition/edge_based_graph_reader.hpp"
|
||||
#include "partition/io.hpp"
|
||||
#include "partition/multi_level_partition.hpp"
|
||||
#include "partition/node_based_graph_to_edge_based_graph_mapping_reader.hpp"
|
||||
#include "partition/recursive_bisection.hpp"
|
||||
#include "partition/multi_level_partition.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/geojson_debug_logger.hpp"
|
||||
@ -32,27 +32,6 @@ namespace osrm
|
||||
namespace partition
|
||||
{
|
||||
|
||||
void LogStatistics(const std::string &filename, std::vector<std::uint32_t> bisection_ids)
|
||||
{
|
||||
auto compressed_node_based_graph = LoadCompressedNodeBasedGraph(filename);
|
||||
|
||||
util::Log() << "Loaded compressed node based graph: "
|
||||
<< compressed_node_based_graph.edges.size() << " edges, "
|
||||
<< compressed_node_based_graph.coordinates.size() << " nodes";
|
||||
|
||||
groupEdgesBySource(begin(compressed_node_based_graph.edges),
|
||||
end(compressed_node_based_graph.edges));
|
||||
|
||||
auto graph =
|
||||
makeBisectionGraph(compressed_node_based_graph.coordinates,
|
||||
adaptToBisectionEdge(std::move(compressed_node_based_graph.edges)));
|
||||
|
||||
TIMER_START(annotation);
|
||||
AnnotatedPartition partition(graph, bisection_ids);
|
||||
TIMER_STOP(annotation);
|
||||
std::cout << "Annotation took " << TIMER_SEC(annotation) << " seconds" << std::endl;
|
||||
}
|
||||
|
||||
void LogGeojson(const std::string &filename, const std::vector<std::uint32_t> &bisection_ids)
|
||||
{
|
||||
// reload graph, since we destroyed the old one
|
||||
@ -138,9 +117,6 @@ int Partitioner::Run(const PartitionConfig &config)
|
||||
config.num_optimizing_cuts,
|
||||
config.small_component_size);
|
||||
|
||||
LogStatistics(config.compressed_node_based_graph_path.string(),
|
||||
recursive_bisection.BisectionIDs());
|
||||
|
||||
// Up until now we worked on the compressed node based graph.
|
||||
// But what we actually need is a partition for the edge based graph to work on.
|
||||
// The following loads a mapping from node based graph to edge based graph.
|
||||
@ -184,87 +160,26 @@ int Partitioner::Run(const PartitionConfig &config)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME The CellID computation code need to be replaced by a more sophisticated method
|
||||
{
|
||||
BOOST_ASSERT(edge_based_partition_ids.size() == edge_based_graph->GetNumberOfNodes());
|
||||
std::vector<Partition> partitions;
|
||||
std::vector<std::uint32_t> level_to_num_cells;
|
||||
std::tie(partitions, level_to_num_cells) = bisectionToPartition(edge_based_partition_ids,
|
||||
{128, 128 * 32, 128 * 32 * 16, 128 * 32 * 16 * 32});
|
||||
|
||||
using namespace osrm::partition;
|
||||
TIMER_START(packed_mlp);
|
||||
MultiLevelPartition mlp{partitions, level_to_num_cells};
|
||||
TIMER_STOP(packed_mlp);
|
||||
util::Log() << "MultiLevelPartition constructed in " << TIMER_SEC(packed_mlp) << " seconds";
|
||||
|
||||
// find bit size of bisection ids
|
||||
int first_nonzero_position = sizeof(BisectionID) * CHAR_BIT;
|
||||
for (auto id : edge_based_partition_ids)
|
||||
{
|
||||
first_nonzero_position = id == 0 ? first_nonzero_position
|
||||
: std::min(first_nonzero_position, __builtin_ctz(id));
|
||||
}
|
||||
BOOST_ASSERT(first_nonzero_position != sizeof(BisectionID) * CHAR_BIT);
|
||||
TIMER_START(cell_storage);
|
||||
CellStorage storage(mlp, *edge_based_graph);
|
||||
TIMER_STOP(cell_storage);
|
||||
util::Log() << "CellStorage constructed in " << TIMER_SEC(cell_storage) << " seconds";
|
||||
|
||||
// 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();
|
||||
std::vector<BisectionID> 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
|
||||
{
|
||||
auto bit = std::max(first_nonzero_position, mask_from);
|
||||
level_masks.push_back(((1u << (sizeof(BisectionID) * CHAR_BIT - bit)) - 1) << bit);
|
||||
}
|
||||
|
||||
util::Log() << "Bisection IDs split for SCC depth " << recursive_bisection.SCCDepth()
|
||||
<< " and first non-zero bit position " << first_nonzero_position
|
||||
<< " number of levels is " << level_masks.size();
|
||||
for (auto x : level_masks)
|
||||
std::cout << std::setw(8) << std::hex << x << std::dec << "\n";
|
||||
|
||||
// collect cell ids as masked bisection ids
|
||||
std::vector<std::vector<CellID>> partitions(
|
||||
level_masks.size(), std::vector<CellID>(edge_based_partition_ids.size()));
|
||||
std::vector<std::unordered_set<CellID>> partition_sets(level_masks.size());
|
||||
for (std::size_t index = 0; index < edge_based_partition_ids.size(); ++index)
|
||||
{
|
||||
auto bisection_id = edge_based_partition_ids[index];
|
||||
for (std::size_t level = 0; level < level_masks.size(); ++level)
|
||||
{
|
||||
CellID cell_id =
|
||||
bisection_id & level_masks[level_masks.size() - 1 - level];
|
||||
partitions[level][index] = cell_id;
|
||||
partition_sets[level].insert(cell_id);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> level_to_num_cells;
|
||||
std::transform(partition_sets.begin(),
|
||||
partition_sets.end(),
|
||||
std::back_inserter(level_to_num_cells),
|
||||
[](const std::unordered_set<CellID> &partition_set) {
|
||||
return partition_set.size();
|
||||
});
|
||||
std::cout << "# of cell on levels\n";
|
||||
for (std::size_t level = 0; level < partition_sets.size(); ++level)
|
||||
{
|
||||
std::cout << level_to_num_cells[level] << ": ";
|
||||
for (auto x : partition_sets[level])
|
||||
std::cout << " " << x;
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
TIMER_START(packed_mlp);
|
||||
MultiLevelPartition mlp{partitions, level_to_num_cells};
|
||||
TIMER_STOP(packed_mlp);
|
||||
util::Log() << "MultiLevelPartition constructed in " << TIMER_SEC(packed_mlp)
|
||||
<< " seconds";
|
||||
|
||||
TIMER_START(cell_storage);
|
||||
CellStorage storage(mlp, *edge_based_graph);
|
||||
TIMER_STOP(cell_storage);
|
||||
util::Log() << "CellStorage constructed in " << TIMER_SEC(cell_storage) << " seconds";
|
||||
|
||||
TIMER_START(writing_mld_data);
|
||||
io::write(config.mld_partition_path, mlp);
|
||||
io::write(config.mld_storage_path, storage);
|
||||
TIMER_STOP(writing_mld_data);
|
||||
util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds";
|
||||
}
|
||||
TIMER_START(writing_mld_data);
|
||||
io::write(config.mld_partition_path, mlp);
|
||||
io::write(config.mld_storage_path, storage);
|
||||
TIMER_STOP(writing_mld_data);
|
||||
util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
331
unit_tests/partition/bisection_to_partition.cpp
Normal file
331
unit_tests/partition/bisection_to_partition.cpp
Normal file
@ -0,0 +1,331 @@
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "partition/bisection_to_partition.hpp"
|
||||
|
||||
#define CHECK_SIZE_RANGE(range, ref) BOOST_CHECK_EQUAL(range.end() - range.begin(), ref)
|
||||
#define CHECK_EQUAL_RANGE(range, ref) \
|
||||
do \
|
||||
{ \
|
||||
const auto &lhs = range; \
|
||||
const auto &rhs = ref; \
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); \
|
||||
} while (0)
|
||||
|
||||
using namespace osrm;
|
||||
using namespace osrm::partition;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(bisection_to_partition_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(unsplitable_case)
|
||||
{
|
||||
std::vector<Partition> partitions;
|
||||
std::vector<std::uint32_t> num_cells;
|
||||
|
||||
/*
|
||||
0 | 1
|
||||
/ \
|
||||
0 | 1 \
|
||||
/ \ |
|
||||
0 | 1 0 | 1 |
|
||||
/ \ / \ / \
|
||||
| | | | / \
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
*/
|
||||
const std::vector<BisectionID> ids_1 = {
|
||||
0b000, 0b000, 0b001, 0b001, 0b010, 0b010, 0b011, 0b011, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100,
|
||||
};
|
||||
|
||||
// If cell sizes are not a factor of two we will see sub-optimal results like below
|
||||
std::tie(partitions, num_cells) = bisectionToPartition(ids_1, {2, 4, 8, 16});
|
||||
BOOST_CHECK_EQUAL(partitions.size(), 4);
|
||||
|
||||
std::vector<std::uint32_t> reference_num_cells = {5, 3, 2, 1};
|
||||
CHECK_EQUAL_RANGE(reference_num_cells, num_cells);
|
||||
|
||||
// Four cells of size 2 and one of size 4 (could not be split)
|
||||
const std::vector<CellID> reference_l1{partitions[0][0], // 0
|
||||
partitions[0][0], // 1
|
||||
partitions[0][2], // 2
|
||||
partitions[0][2], // 3
|
||||
partitions[0][4], // 4
|
||||
partitions[0][4], // 5
|
||||
partitions[0][6], // 6
|
||||
partitions[0][6], // 7
|
||||
partitions[0][8], // 8
|
||||
partitions[0][8], // 9
|
||||
partitions[0][8], // 10
|
||||
partitions[0][8], // 11
|
||||
partitions[0][8], // 12
|
||||
partitions[0][8], // 13
|
||||
partitions[0][8], // 14
|
||||
partitions[0][8]}; // 15
|
||||
// Two cells of size 4 and one of size 8
|
||||
const std::vector<CellID> reference_l2{partitions[1][0], // 0
|
||||
partitions[1][0], // 1
|
||||
partitions[1][0], // 2
|
||||
partitions[1][0], // 3
|
||||
partitions[1][4], // 4
|
||||
partitions[1][4], // 5
|
||||
partitions[1][4], // 6
|
||||
partitions[1][4], // 7
|
||||
partitions[1][8], // 8
|
||||
partitions[1][8], // 9
|
||||
partitions[1][8], // 10
|
||||
partitions[1][8], // 11
|
||||
partitions[1][8], // 12
|
||||
partitions[1][8], // 13
|
||||
partitions[1][8], // 14
|
||||
partitions[1][8]}; // 15
|
||||
// Two cells of size 8
|
||||
const std::vector<CellID> reference_l3{partitions[2][0], // 0
|
||||
partitions[2][0], // 1
|
||||
partitions[2][0], // 2
|
||||
partitions[2][0], // 3
|
||||
partitions[2][0], // 4
|
||||
partitions[2][0], // 5
|
||||
partitions[2][0], // 6
|
||||
partitions[2][0], // 7
|
||||
partitions[2][8], // 8
|
||||
partitions[2][8], // 9
|
||||
partitions[2][8], // 10
|
||||
partitions[2][8], // 11
|
||||
partitions[2][8], // 12
|
||||
partitions[2][8], // 13
|
||||
partitions[2][8], // 14
|
||||
partitions[2][8]}; // 15
|
||||
// All in one cell
|
||||
const std::vector<CellID> reference_l4{partitions[3][0], // 0
|
||||
partitions[3][0], // 1
|
||||
partitions[3][0], // 2
|
||||
partitions[3][0], // 3
|
||||
partitions[3][0], // 4
|
||||
partitions[3][0], // 5
|
||||
partitions[3][0], // 6
|
||||
partitions[3][0], // 7
|
||||
partitions[3][0], // 8
|
||||
partitions[3][0], // 9
|
||||
partitions[3][0], // 10
|
||||
partitions[3][0], // 11
|
||||
partitions[3][0], // 12
|
||||
partitions[3][0], // 13
|
||||
partitions[3][0], // 14
|
||||
partitions[3][0]}; // 15
|
||||
|
||||
CHECK_EQUAL_RANGE(reference_l1, partitions[0]);
|
||||
CHECK_EQUAL_RANGE(reference_l2, partitions[1]);
|
||||
CHECK_EQUAL_RANGE(reference_l3, partitions[2]);
|
||||
CHECK_EQUAL_RANGE(reference_l4, partitions[3]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(power_of_two_case)
|
||||
{
|
||||
std::vector<Partition> partitions;
|
||||
std::vector<std::uint32_t> num_cells;
|
||||
|
||||
/*
|
||||
0 | 1
|
||||
/ \
|
||||
0 | 1 |
|
||||
/ \ |
|
||||
0 | 1 0 | 1 0 | 1
|
||||
/ \ / \ / \
|
||||
| | | | | |
|
||||
0 1 2 3 4 5 6 7 8 9 10 11
|
||||
*/
|
||||
const std::vector<BisectionID> ids_1 = {
|
||||
0b000, 0b000, 0b001, 0b001, 0b010, 0b010, 0b011, 0b011, 0b100, 0b100, 0b101, 0b101,
|
||||
};
|
||||
|
||||
// If cell sizes are not a factor of two we will see sub-optimal results like below
|
||||
std::tie(partitions, num_cells) = bisectionToPartition(ids_1, {2, 4, 8, 16});
|
||||
BOOST_CHECK_EQUAL(partitions.size(), 4);
|
||||
|
||||
std::vector<std::uint32_t> reference_num_cells = {6, 3, 2, 1};
|
||||
CHECK_EQUAL_RANGE(reference_num_cells, num_cells);
|
||||
|
||||
// Six cells of size 2
|
||||
const std::vector<CellID> reference_l1{partitions[0][0], // 0
|
||||
partitions[0][0], // 1
|
||||
partitions[0][2], // 2
|
||||
partitions[0][2], // 3
|
||||
partitions[0][4], // 4
|
||||
partitions[0][4], // 5
|
||||
partitions[0][6], // 6
|
||||
partitions[0][6], // 7
|
||||
partitions[0][8], // 8
|
||||
partitions[0][8], // 9
|
||||
partitions[0][10], // 10
|
||||
partitions[0][10]}; // 11
|
||||
// Three cells of size 4
|
||||
const std::vector<CellID> reference_l2{partitions[1][0], // 0
|
||||
partitions[1][0], // 1
|
||||
partitions[1][0], // 2
|
||||
partitions[1][0], // 3
|
||||
partitions[1][4], // 4
|
||||
partitions[1][4], // 5
|
||||
partitions[1][4], // 6
|
||||
partitions[1][4], // 7
|
||||
partitions[1][8], // 8
|
||||
partitions[1][8], // 9
|
||||
partitions[1][8], // 10
|
||||
partitions[1][8]}; // 11
|
||||
// Two cells of size 8 and 4
|
||||
const std::vector<CellID> reference_l3{partitions[2][0], // 0
|
||||
partitions[2][0], // 1
|
||||
partitions[2][0], // 2
|
||||
partitions[2][0], // 3
|
||||
partitions[2][0], // 4
|
||||
partitions[2][0], // 5
|
||||
partitions[2][0], // 6
|
||||
partitions[2][0], // 7
|
||||
partitions[2][8], // 8
|
||||
partitions[2][8], // 9
|
||||
partitions[2][8], // 10
|
||||
partitions[2][8]}; // 11
|
||||
// All in one cell
|
||||
const std::vector<CellID> reference_l4{partitions[3][0], // 0
|
||||
partitions[3][0], // 1
|
||||
partitions[3][0], // 2
|
||||
partitions[3][0], // 3
|
||||
partitions[3][0], // 4
|
||||
partitions[3][0], // 5
|
||||
partitions[3][0], // 6
|
||||
partitions[3][0], // 7
|
||||
partitions[3][0], // 8
|
||||
partitions[3][0], // 9
|
||||
partitions[3][0], // 10
|
||||
partitions[3][0]}; // 11
|
||||
|
||||
CHECK_EQUAL_RANGE(reference_l1, partitions[0]);
|
||||
CHECK_EQUAL_RANGE(reference_l2, partitions[1]);
|
||||
CHECK_EQUAL_RANGE(reference_l3, partitions[2]);
|
||||
CHECK_EQUAL_RANGE(reference_l4, partitions[3]);
|
||||
|
||||
// Inserting zeros at bit position 0, and 2 should not change the result
|
||||
const std::vector<BisectionID> ids_2 = {
|
||||
0b00000, 0b00000, 0b00010, 0b00010, 0b00100, 0b00100, 0b00110, 0b00110, 0b10000, 0b10000, 0b10010, 0b10010,
|
||||
};
|
||||
std::tie(partitions, num_cells) = bisectionToPartition(ids_2, {2, 4, 8, 16});
|
||||
CHECK_EQUAL_RANGE(reference_l1, partitions[0]);
|
||||
CHECK_EQUAL_RANGE(reference_l2, partitions[1]);
|
||||
CHECK_EQUAL_RANGE(reference_l3, partitions[2]);
|
||||
CHECK_EQUAL_RANGE(reference_l4, partitions[3]);
|
||||
|
||||
// Inserting a prefix should not change anything
|
||||
const std::vector<BisectionID> ids_3 = {
|
||||
0b101000, 0b101000, 0b101001, 0b101001, 0b101010, 0b101010, 0b101011, 0b101011, 0b101100, 0b101100, 0b101101, 0b101101,
|
||||
};
|
||||
std::tie(partitions, num_cells) = bisectionToPartition(ids_3, {2, 4, 8, 16});
|
||||
CHECK_EQUAL_RANGE(reference_l1, partitions[0]);
|
||||
CHECK_EQUAL_RANGE(reference_l2, partitions[1]);
|
||||
CHECK_EQUAL_RANGE(reference_l3, partitions[2]);
|
||||
CHECK_EQUAL_RANGE(reference_l4, partitions[3]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(non_factor_two_case)
|
||||
{
|
||||
std::vector<Partition> partitions;
|
||||
std::vector<std::uint32_t> num_cells;
|
||||
|
||||
/*
|
||||
0 | 1
|
||||
/ \
|
||||
0 | 1 |
|
||||
/ \ |
|
||||
0 | 1 0 | 1 0 | 1
|
||||
/ \ / \ / \
|
||||
| | | | | |
|
||||
0 1 2 3 4 5 6 7 8 9 10 11
|
||||
*/
|
||||
const std::vector<BisectionID> ids_1 = {
|
||||
0b000, 0b000, 0b001, 0b001, 0b010, 0b010, 0b011, 0b011, 0b100, 0b100, 0b101, 0b101,
|
||||
};
|
||||
|
||||
// If cell sizes are not a factor of two we will see sub-optimal results like below
|
||||
std::tie(partitions, num_cells) = bisectionToPartition(ids_1, {2, 4, 6, 12});
|
||||
BOOST_CHECK_EQUAL(partitions.size(), 4);
|
||||
|
||||
std::vector<std::uint32_t> reference_num_cells = {6, 3, 3, 1};
|
||||
CHECK_EQUAL_RANGE(reference_num_cells, num_cells);
|
||||
|
||||
// Six cells of size 2
|
||||
const std::vector<CellID> reference_l1{partitions[0][0], // 0
|
||||
partitions[0][0], // 1
|
||||
partitions[0][2], // 2
|
||||
partitions[0][2], // 3
|
||||
partitions[0][4], // 4
|
||||
partitions[0][4], // 5
|
||||
partitions[0][6], // 6
|
||||
partitions[0][6], // 7
|
||||
partitions[0][8], // 8
|
||||
partitions[0][8], // 9
|
||||
partitions[0][10], // 10
|
||||
partitions[0][10]}; // 11
|
||||
// Three cells of size 4
|
||||
const std::vector<CellID> reference_l2{partitions[1][0], // 0
|
||||
partitions[1][0], // 1
|
||||
partitions[1][0], // 2
|
||||
partitions[1][0], // 3
|
||||
partitions[1][4], // 4
|
||||
partitions[1][4], // 5
|
||||
partitions[1][4], // 6
|
||||
partitions[1][4], // 7
|
||||
partitions[1][8], // 8
|
||||
partitions[1][8], // 9
|
||||
partitions[1][8], // 10
|
||||
partitions[1][8]}; // 11
|
||||
// Again three cells of size 4 (bad)
|
||||
const std::vector<CellID> reference_l3{partitions[2][0], // 0
|
||||
partitions[2][0], // 1
|
||||
partitions[2][0], // 2
|
||||
partitions[2][0], // 3
|
||||
partitions[2][4], // 4
|
||||
partitions[2][4], // 5
|
||||
partitions[2][4], // 6
|
||||
partitions[2][4], // 7
|
||||
partitions[2][8], // 8
|
||||
partitions[2][8], // 9
|
||||
partitions[2][8], // 10
|
||||
partitions[2][8]}; // 11
|
||||
// All in one cell
|
||||
const std::vector<CellID> reference_l4{partitions[3][0], // 0
|
||||
partitions[3][0], // 1
|
||||
partitions[3][0], // 2
|
||||
partitions[3][0], // 3
|
||||
partitions[3][0], // 4
|
||||
partitions[3][0], // 5
|
||||
partitions[3][0], // 6
|
||||
partitions[3][0], // 7
|
||||
partitions[3][0], // 8
|
||||
partitions[3][0], // 9
|
||||
partitions[3][0], // 10
|
||||
partitions[3][0]}; // 11
|
||||
|
||||
CHECK_EQUAL_RANGE(reference_l1, partitions[0]);
|
||||
CHECK_EQUAL_RANGE(reference_l2, partitions[1]);
|
||||
CHECK_EQUAL_RANGE(reference_l3, partitions[2]);
|
||||
CHECK_EQUAL_RANGE(reference_l4, partitions[3]);
|
||||
|
||||
// Inserting zeros at bit position 0, and 2 should not change the result
|
||||
const std::vector<BisectionID> ids_2 = {
|
||||
0b00000, 0b00000, 0b00010, 0b00010, 0b00100, 0b00100, 0b00110, 0b00110, 0b10000, 0b10000, 0b10010, 0b10010,
|
||||
};
|
||||
std::tie(partitions, num_cells) = bisectionToPartition(ids_2, {2, 4, 6, 12});
|
||||
CHECK_EQUAL_RANGE(reference_l1, partitions[0]);
|
||||
CHECK_EQUAL_RANGE(reference_l2, partitions[1]);
|
||||
CHECK_EQUAL_RANGE(reference_l3, partitions[2]);
|
||||
CHECK_EQUAL_RANGE(reference_l4, partitions[3]);
|
||||
|
||||
// Inserting a prefix should not change anything
|
||||
const std::vector<BisectionID> ids_3 = {
|
||||
0b101000, 0b101000, 0b101001, 0b101001, 0b101010, 0b101010, 0b101011, 0b101011, 0b101100, 0b101100, 0b101101, 0b101101,
|
||||
};
|
||||
std::tie(partitions, num_cells) = bisectionToPartition(ids_3, {2, 4, 6, 12});
|
||||
CHECK_EQUAL_RANGE(reference_l1, partitions[0]);
|
||||
CHECK_EQUAL_RANGE(reference_l2, partitions[1]);
|
||||
CHECK_EQUAL_RANGE(reference_l3, partitions[2]);
|
||||
CHECK_EQUAL_RANGE(reference_l4, partitions[3]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user