Rename namespace partition to partitioner

Rename module partition to partitioner.
This cultivates naming used in existing modules like extractor,
customizer, etc. - noun vs verb (word partition is both though).
This commit is contained in:
Mateusz Loskot
2018-02-01 16:47:43 +01:00
committed by Patrick Niklaus
parent 03f598b93d
commit 8114104a43
61 changed files with 308 additions and 305 deletions
+153
View File
@@ -0,0 +1,153 @@
#include "partitioner/bisection_graph.hpp"
#include "partitioner/graph_generator.hpp"
#include <algorithm>
#include <vector>
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
using namespace osrm::partitioner;
using namespace osrm::util;
BOOST_AUTO_TEST_SUITE(bisection_graph)
BOOST_AUTO_TEST_CASE(access_nodes)
{
// 40 entries of left/right edges
double step_size = 0.01;
int rows = 10;
int cols = 4;
const auto coordinates = makeGridCoordinates(rows, cols, step_size, 0, 0);
std::vector<EdgeWithSomeAdditionalData> grid_edges;
auto graph = makeBisectionGraph(coordinates, adaptToBisectionEdge(std::move(grid_edges)));
const auto to_row = [cols](const NodeID nid) { return nid / cols; };
const auto to_col = [cols](const NodeID nid) { return nid % cols; };
const auto get_expected = [&](const NodeID id) {
const auto expected_lon = FloatLongitude{to_col(id) * step_size};
const auto expected_lat = FloatLatitude{to_row(id) * step_size};
Coordinate compare(expected_lon, expected_lat);
return compare;
};
// check const access
BOOST_CHECK_EQUAL(graph.NumberOfNodes(), 40);
{
NodeID increasing = 0;
for (const auto &node : graph.Nodes())
{
const auto id = graph.GetID(node);
BOOST_CHECK_EQUAL(id, increasing++);
BOOST_CHECK_EQUAL(node.coordinate, get_expected(id));
}
}
// non-const access
{
NodeID increasing = 0;
for (auto &node : graph.Nodes())
{
const auto id = graph.GetID(node);
BOOST_CHECK_EQUAL(id, increasing++);
BOOST_CHECK_EQUAL(node.coordinate, get_expected(id));
}
}
// iterator access
{
const auto begin = graph.Begin();
const auto end = graph.End();
NodeID increasing = 0;
for (auto itr = begin; itr != end; ++itr)
{
const auto id = static_cast<NodeID>(std::distance(begin, itr));
BOOST_CHECK_EQUAL(id, increasing++);
BOOST_CHECK_EQUAL(itr->coordinate, get_expected(id));
}
}
// const iterator access
{
const auto begin = graph.CBegin();
const auto end = graph.CEnd();
NodeID increasing = 0;
for (auto itr = begin; itr != end; ++itr)
{
const auto id = static_cast<NodeID>(std::distance(begin, itr));
BOOST_CHECK_EQUAL(id, increasing++);
BOOST_CHECK_EQUAL(itr->coordinate, get_expected(id));
}
}
}
BOOST_AUTO_TEST_CASE(access_edges)
{
// 40 entries of left/right edges
double step_size = 0.01;
int rows = 10;
int cols = 4;
const auto coordinates = makeGridCoordinates(rows, cols, step_size, 0, 0);
auto grid_edges = makeGridEdges(rows, cols, 0);
std::random_shuffle(grid_edges.begin(), grid_edges.end());
groupEdgesBySource(grid_edges.begin(), grid_edges.end());
const auto graph = makeBisectionGraph(coordinates, adaptToBisectionEdge(std::move(grid_edges)));
const auto to_row = [cols](const NodeID nid) { return nid / cols; };
const auto to_col = [cols](const NodeID nid) { return nid % cols; };
BOOST_CHECK_EQUAL(graph.NumberOfNodes(), 40);
for (const auto &node : graph.Nodes())
{
for (const auto &edge : graph.Edges(node))
{
BOOST_CHECK(edge.target < graph.NumberOfNodes());
BOOST_CHECK(std::abs(static_cast<int>(to_row(graph.GetID(node))) -
static_cast<int>(to_row(edge.target))) <= 1);
BOOST_CHECK(std::abs(static_cast<int>(to_col(graph.GetID(node))) -
static_cast<int>(to_col(edge.target))) <= 1);
}
// itr of node
for (auto itr = graph.BeginEdges(node); itr != graph.EndEdges(node); ++itr)
{
BOOST_CHECK(itr->target < graph.NumberOfNodes());
BOOST_CHECK(std::abs(static_cast<int>(to_row(graph.GetID(node))) -
static_cast<int>(to_row(itr->target))) <= 1);
BOOST_CHECK(std::abs(static_cast<int>(to_col(graph.GetID(node))) -
static_cast<int>(to_col(itr->target))) <= 1);
}
// access via ID of ndoe
const auto id = graph.GetID(node);
for (const auto &edge : graph.Edges(id))
{
BOOST_CHECK(edge.target < graph.NumberOfNodes());
BOOST_CHECK(std::abs(static_cast<int>(to_row(graph.GetID(node))) -
static_cast<int>(to_row(edge.target))) <= 1);
BOOST_CHECK(std::abs(static_cast<int>(to_col(graph.GetID(node))) -
static_cast<int>(to_col(edge.target))) <= 1);
}
for (auto itr = graph.BeginEdges(id); itr != graph.EndEdges(id); ++itr)
{
BOOST_CHECK(itr->target < graph.NumberOfNodes());
BOOST_CHECK(std::abs(static_cast<int>(to_row(graph.GetID(node))) -
static_cast<int>(to_row(itr->target))) <= 1);
BOOST_CHECK(std::abs(static_cast<int>(to_col(graph.GetID(node))) -
static_cast<int>(to_col(itr->target))) <= 1);
}
for (auto eid = graph.BeginEdgeID(id); eid != graph.EndEdgeID(id); ++eid)
{
const auto &itr = graph.Edge(eid);
BOOST_CHECK(itr.target < graph.NumberOfNodes());
BOOST_CHECK(std::abs(static_cast<int>(to_row(graph.GetID(node))) -
static_cast<int>(to_row(itr.target))) <= 1);
BOOST_CHECK(std::abs(static_cast<int>(to_col(graph.GetID(node))) -
static_cast<int>(to_col(itr.target))) <= 1);
}
}
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,179 @@
#include "partitioner/bisection_graph_view.hpp"
#include "partitioner/graph_generator.hpp"
#include "partitioner/recursive_bisection_state.hpp"
#include <algorithm>
#include <climits>
#include <vector>
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
using namespace osrm::partitioner;
using namespace osrm::util;
BOOST_AUTO_TEST_SUITE(graph_view)
BOOST_AUTO_TEST_CASE(separate_top_bottom)
{
// 40 entries of left/right edges
double step_size = 0.01;
int rows = 2;
int cols = 4;
const auto coordinates = makeGridCoordinates(rows, cols, step_size, 0, 0);
auto grid_edges = makeGridEdges(rows, cols, 0);
std::random_shuffle(grid_edges.begin(), grid_edges.end());
groupEdgesBySource(grid_edges.begin(), grid_edges.end());
auto graph = makeBisectionGraph(coordinates, adaptToBisectionEdge(std::move(grid_edges)));
RecursiveBisectionState bisection_state(graph);
std::vector<bool> partition(8, false);
partition[4] = partition[5] = partition[6] = partition[7] = true;
const auto center = bisection_state.ApplyBisection(graph.Begin(), graph.End(), 0, partition);
BisectionGraphView left(graph, graph.Begin(), center);
BisectionGraphView right(graph, center, graph.End());
BOOST_CHECK_EQUAL(left.NumberOfNodes(), 4);
for (const auto &node : left.Nodes())
{
auto id = left.GetID(node);
const auto compare = makeCoordinate(id, 0, step_size);
BOOST_CHECK_EQUAL(compare, node.coordinate);
BOOST_CHECK(id < left.NumberOfNodes());
BOOST_CHECK_EQUAL(bisection_state.GetBisectionID(node.original_id), 0);
for (const auto &edge : left.Edges(node))
BOOST_CHECK(edge.target < left.NumberOfNodes());
}
BOOST_CHECK_EQUAL(right.NumberOfNodes(), 4);
for (const auto &node : right.Nodes())
{
BOOST_CHECK_EQUAL(bisection_state.GetBisectionID(node.original_id),
1 << (sizeof(BisectionID) * CHAR_BIT - 1));
auto id = right.GetID(node);
const auto compare = makeCoordinate(id, 1, step_size);
BOOST_CHECK_EQUAL(compare, node.coordinate);
BOOST_CHECK(id < right.NumberOfNodes());
for (const auto &edge : right.Edges(node))
BOOST_CHECK(edge.target < right.NumberOfNodes());
}
}
BOOST_AUTO_TEST_CASE(separate_top_bottom_copy)
{
// 40 entries of left/right edges
double step_size = 0.01;
int rows = 2;
int cols = 4;
const auto coordinates = makeGridCoordinates(rows, cols, step_size, 0, 0);
auto grid_edges = makeGridEdges(rows, cols, 0);
std::random_shuffle(grid_edges.begin(), grid_edges.end());
groupEdgesBySource(grid_edges.begin(), grid_edges.end());
auto graph = makeBisectionGraph(coordinates, adaptToBisectionEdge(std::move(grid_edges)));
RecursiveBisectionState bisection_state(graph);
std::vector<bool> partition(8, false);
partition[4] = partition[5] = partition[6] = partition[7] = true;
const auto center = bisection_state.ApplyBisection(graph.Begin(), graph.End(), 0, partition);
BisectionGraphView total(graph, graph.Begin(), graph.End());
BisectionGraphView left(total, total.Begin(), center);
BisectionGraphView right(total, center, total.End());
BOOST_CHECK_EQUAL(left.NumberOfNodes(), 4);
for (const auto &node : left.Nodes())
{
auto id = left.GetID(node);
const auto compare = makeCoordinate(id, 0, step_size);
BOOST_CHECK_EQUAL(compare, node.coordinate);
BOOST_CHECK(id < left.NumberOfNodes());
BOOST_CHECK_EQUAL(bisection_state.GetBisectionID(node.original_id), 0);
for (const auto &edge : left.Edges(id))
BOOST_CHECK(edge.target < left.NumberOfNodes());
}
BOOST_CHECK_EQUAL(right.NumberOfNodes(), 4);
for (NodeID id = 0; id < right.NumberOfNodes(); ++id)
{
const auto &node = right.Node(id);
BOOST_CHECK_EQUAL(bisection_state.GetBisectionID(node.original_id),
1 << (sizeof(BisectionID) * CHAR_BIT - 1));
const auto compare = makeCoordinate(id, 1, step_size);
BOOST_CHECK_EQUAL(compare, node.coordinate);
BOOST_CHECK(id < right.NumberOfNodes());
for (const auto &edge : right.Edges(id))
BOOST_CHECK(edge.target < right.NumberOfNodes());
}
}
BOOST_AUTO_TEST_CASE(separate_left_right)
{
// 40 entries of left/right edges
double step_size = 0.01;
int rows = 2;
int cols = 4;
const auto coordinates = makeGridCoordinates(rows, cols, step_size, 0, 0);
auto grid_edges = makeGridEdges(rows, cols, 0);
std::random_shuffle(grid_edges.begin(), grid_edges.end());
groupEdgesBySource(grid_edges.begin(), grid_edges.end());
auto graph = makeBisectionGraph(coordinates, adaptToBisectionEdge(std::move(grid_edges)));
// separate Left 2 nodes from rest
RecursiveBisectionState bisection_state(graph);
std::vector<bool> partition(8, true);
partition[0] = partition[4] = false;
const auto center = bisection_state.ApplyBisection(graph.Begin(), graph.End(), 0, partition);
BisectionGraphView left(graph, graph.Begin(), center);
BisectionGraphView right(graph, center, graph.End());
BOOST_CHECK_EQUAL(left.NumberOfNodes(), 2);
std::vector<Coordinate> left_coordinates;
left_coordinates.push_back(makeCoordinate(0, 0, step_size));
left_coordinates.push_back(makeCoordinate(0, 1, step_size));
auto left_compare = left_coordinates.begin();
for (const auto &node : left.Nodes())
{
auto id = left.GetID(node);
const auto compare = *left_compare++;
BOOST_CHECK_EQUAL(compare, node.coordinate);
BOOST_CHECK(id < left.NumberOfNodes());
BOOST_CHECK_EQUAL(bisection_state.GetBisectionID(node.original_id), 0);
for (const auto &edge : left.Edges(node))
BOOST_CHECK(edge.target < left.NumberOfNodes());
}
BOOST_CHECK_EQUAL(right.NumberOfNodes(), 6);
std::vector<Coordinate> right_coordinates;
right_coordinates.push_back(makeCoordinate(1, 0, step_size));
right_coordinates.push_back(makeCoordinate(2, 0, step_size));
right_coordinates.push_back(makeCoordinate(3, 0, step_size));
right_coordinates.push_back(makeCoordinate(1, 1, step_size));
right_coordinates.push_back(makeCoordinate(2, 1, step_size));
right_coordinates.push_back(makeCoordinate(3, 1, step_size));
auto right_compare = right_coordinates.begin();
for (const auto &node : right.Nodes())
{
BOOST_CHECK_EQUAL(bisection_state.GetBisectionID(node.original_id),
1 << (sizeof(BisectionID) * CHAR_BIT - 1));
auto id = right.GetID(node);
const auto compare = *right_compare++;
BOOST_CHECK_EQUAL(compare, node.coordinate);
BOOST_CHECK(id < right.NumberOfNodes());
for (const auto &edge : right.Edges(node))
BOOST_CHECK(edge.target < right.NumberOfNodes());
}
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,390 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/test/unit_test.hpp>
#include "partitioner/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::partitioner;
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()
+332
View File
@@ -0,0 +1,332 @@
#include "common/range_tools.hpp"
#include <boost/test/unit_test.hpp>
#include "partitioner/cell_storage.hpp"
#include "util/static_graph.hpp"
using namespace osrm;
using namespace osrm::partitioner;
namespace
{
struct MockEdge
{
NodeID start;
NodeID target;
};
auto makeGraph(const std::vector<MockEdge> &mock_edges)
{
struct EdgeData
{
bool forward;
bool backward;
};
using Edge = util::static_graph_details::SortableEdgeWithData<EdgeData>;
std::vector<Edge> edges;
std::size_t max_id = 0;
for (const auto &m : mock_edges)
{
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
edges.push_back(Edge{m.start, m.target, true, false});
edges.push_back(Edge{m.target, m.start, false, true});
}
std::sort(edges.begin(), edges.end());
return util::StaticGraph<EdgeData>(max_id + 1, edges);
}
}
BOOST_AUTO_TEST_SUITE(cell_storage_tests)
BOOST_AUTO_TEST_CASE(mutable_cell_storage)
{
const auto fill_range = [](auto range, const std::vector<EdgeWeight> &values) {
auto iter = range.begin();
for (auto v : values)
*iter++ = v;
BOOST_CHECK_EQUAL(range.end(), iter);
};
// node: 0 1 2 3 4 5 6 7 8 9 10 11
std::vector<CellID> l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5}};
std::vector<CellID> l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3}};
std::vector<CellID> l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}};
std::vector<CellID> l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
MultiLevelPartition mlp{{l1, l2, l3, l4}, {6, 4, 2, 1}};
std::vector<MockEdge> 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
};
auto graph = makeGraph(edges);
// test non-const storage
CellStorage storage(mlp, graph);
auto metric = storage.MakeMetric();
// Level 1
auto cell_1_0 = storage.GetCell(metric, 1, 0);
auto cell_1_1 = storage.GetCell(metric, 1, 1);
auto cell_1_2 = storage.GetCell(metric, 1, 2);
auto cell_1_3 = storage.GetCell(metric, 1, 3);
auto cell_1_4 = storage.GetCell(metric, 1, 4);
auto cell_1_5 = storage.GetCell(metric, 1, 5);
(void)cell_1_4; // does not have border nodes
auto out_range_1_0_0 = cell_1_0.GetOutWeight(0);
auto out_range_1_2_4 = cell_1_2.GetOutWeight(4);
auto out_range_1_3_6 = cell_1_3.GetOutWeight(6);
auto out_range_1_5_11 = cell_1_5.GetOutWeight(11);
auto in_range_1_1_3 = cell_1_1.GetInWeight(3);
auto in_range_1_2_5 = cell_1_2.GetInWeight(5);
auto in_range_1_3_7 = cell_1_3.GetInWeight(7);
auto in_range_1_5_11 = cell_1_5.GetInWeight(11);
fill_range(out_range_1_0_0, {});
fill_range(out_range_1_2_4, {1});
fill_range(out_range_1_3_6, {2});
fill_range(out_range_1_5_11, {3});
CHECK_EQUAL_COLLECTIONS(in_range_1_1_3, std::vector<EdgeWeight>{});
CHECK_EQUAL_RANGE(in_range_1_2_5, 1);
CHECK_EQUAL_RANGE(in_range_1_3_7, 2);
CHECK_EQUAL_RANGE(in_range_1_5_11, 3);
// Level 2
auto cell_2_0 = storage.GetCell(metric, 2, 0);
auto cell_2_1 = storage.GetCell(metric, 2, 1);
auto cell_2_2 = storage.GetCell(metric, 2, 2);
auto cell_2_3 = storage.GetCell(metric, 2, 3);
(void)cell_2_2; // does not have border nodes
auto out_range_2_0_0 = cell_2_0.GetOutWeight(0);
auto out_range_2_1_4 = cell_2_1.GetOutWeight(4);
auto out_range_2_3_11 = cell_2_3.GetOutWeight(11);
auto in_range_2_0_3 = cell_2_0.GetInWeight(3);
auto in_range_2_1_4 = cell_2_1.GetInWeight(4);
auto in_range_2_1_7 = cell_2_1.GetInWeight(7);
auto in_range_2_3_11 = cell_2_3.GetInWeight(11);
fill_range(out_range_2_0_0, {1});
fill_range(out_range_2_1_4, {2, 3});
fill_range(out_range_2_3_11, {4});
CHECK_EQUAL_RANGE(in_range_2_0_3, 1);
CHECK_EQUAL_RANGE(in_range_2_1_4, 2);
CHECK_EQUAL_RANGE(in_range_2_1_7, 3);
CHECK_EQUAL_RANGE(in_range_2_3_11, 4);
// Level 3
auto cell_3_0 = storage.GetCell(metric, 3, 0);
auto cell_3_1 = storage.GetCell(metric, 3, 1);
auto out_range_3_0_0 = cell_3_0.GetOutWeight(0);
auto out_range_3_1_4 = cell_3_1.GetOutWeight(4);
auto out_range_3_1_7 = cell_3_1.GetOutWeight(7);
auto in_range_3_0_3 = cell_3_0.GetInWeight(3);
auto in_range_3_1_4 = cell_3_1.GetInWeight(4);
auto in_range_3_1_7 = cell_3_1.GetInWeight(7);
fill_range(out_range_3_0_0, {1});
fill_range(out_range_3_1_4, {2, 3});
fill_range(out_range_3_1_7, {4, 5});
CHECK_EQUAL_RANGE(in_range_3_0_3, 1);
CHECK_EQUAL_RANGE(in_range_3_1_4, 2, 4);
CHECK_EQUAL_RANGE(in_range_3_1_7, 3, 5);
}
BOOST_AUTO_TEST_CASE(immutable_cell_storage)
{
// node: 0 1 2 3 4 5 6 7 8 9 10 11
std::vector<CellID> l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5}};
std::vector<CellID> l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3}};
std::vector<CellID> l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}};
std::vector<CellID> l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
MultiLevelPartition mlp{{l1, l2, l3, l4}, {5, 4, 2, 1}};
std::vector<MockEdge> 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
};
auto graph = makeGraph(edges);
// nodes sorted into border/internal by level
// (1) (2) (3) (4)
// 0 b b b i
// 1 i i i i
// 2 i i i i
// 3 b b b i
// 4 b b b i
// 5 b i i i
// 6 b i i i
// 7 b b i i
// 8 i i i i
// 9 i i i i
// 10 i i i i
// 11 b b i i
// 1/0: 0 : 1,1,0
// 1/2: 4 : 1,1,0
// 1/3: 6 : 1,1,0
// 1/5: 11 : 1,1,1
// 1/1: 3 : 1,0,1
// 1/2: 5 : 1,0,1
// 1/3: 7 : 1,0,1
// 2/0: 0 : 1,1,0
// 2/1: 4 : 1,1,1
// 2/3: 11 : 1,1,1
// 2/0: 3 : 1,0,1
// 2/1: 7 : 1,0,1
// 3/0: 0 : 1,1,0
// 3/1: 4 : 1,1,1
// 3/1: 7 : 1,1,1
// 3/0: 3 : 1,0,1
// test const storage
const CellStorage const_storage(mlp, graph);
const auto metric = const_storage.MakeMetric();
auto const_cell_1_0 = const_storage.GetCell(metric, 1, 0);
auto const_cell_1_1 = const_storage.GetCell(metric, 1, 1);
auto const_cell_1_2 = const_storage.GetCell(metric, 1, 2);
auto const_cell_1_3 = const_storage.GetCell(metric, 1, 3);
auto const_cell_1_4 = const_storage.GetCell(metric, 1, 4);
auto const_cell_1_5 = const_storage.GetCell(metric, 1, 5);
CHECK_EQUAL_RANGE(const_cell_1_0.GetSourceNodes(), 0);
CHECK_EQUAL_COLLECTIONS(const_cell_1_1.GetSourceNodes(), std::vector<EdgeWeight>{});
CHECK_EQUAL_RANGE(const_cell_1_2.GetSourceNodes(), 4);
CHECK_EQUAL_RANGE(const_cell_1_3.GetSourceNodes(), 6);
CHECK_EQUAL_COLLECTIONS(const_cell_1_4.GetSourceNodes(), std::vector<EdgeWeight>{});
CHECK_EQUAL_RANGE(const_cell_1_5.GetSourceNodes(), 11);
CHECK_EQUAL_COLLECTIONS(const_cell_1_0.GetDestinationNodes(), std::vector<EdgeWeight>{});
CHECK_EQUAL_RANGE(const_cell_1_1.GetDestinationNodes(), 3);
CHECK_EQUAL_RANGE(const_cell_1_2.GetDestinationNodes(), 5);
CHECK_EQUAL_RANGE(const_cell_1_3.GetDestinationNodes(), 7);
CHECK_EQUAL_COLLECTIONS(const_cell_1_4.GetDestinationNodes(), std::vector<EdgeWeight>{});
CHECK_EQUAL_RANGE(const_cell_1_5.GetDestinationNodes(), 11);
auto out_const_range_1_0_0 = const_cell_1_0.GetOutWeight(0);
auto out_const_range_1_2_4 = const_cell_1_2.GetOutWeight(4);
auto out_const_range_1_3_6 = const_cell_1_3.GetOutWeight(6);
auto out_const_range_1_5_11 = const_cell_1_5.GetOutWeight(11);
auto in_const_range_1_1_3 = const_cell_1_1.GetInWeight(3);
auto in_const_range_1_2_5 = const_cell_1_2.GetInWeight(5);
auto in_const_range_1_3_7 = const_cell_1_3.GetInWeight(7);
auto in_const_range_1_5_11 = const_cell_1_5.GetInWeight(11);
REQUIRE_SIZE_RANGE(out_const_range_1_0_0, 0);
REQUIRE_SIZE_RANGE(out_const_range_1_2_4, 1);
REQUIRE_SIZE_RANGE(out_const_range_1_3_6, 1);
REQUIRE_SIZE_RANGE(out_const_range_1_5_11, 1);
REQUIRE_SIZE_RANGE(in_const_range_1_1_3, 0);
REQUIRE_SIZE_RANGE(in_const_range_1_2_5, 1);
REQUIRE_SIZE_RANGE(in_const_range_1_3_7, 1);
REQUIRE_SIZE_RANGE(in_const_range_1_5_11, 1);
// Level 2
auto const_cell_2_0 = const_storage.GetCell(metric, 2, 0);
auto const_cell_2_1 = const_storage.GetCell(metric, 2, 1);
auto const_cell_2_2 = const_storage.GetCell(metric, 2, 2);
auto const_cell_2_3 = const_storage.GetCell(metric, 2, 3);
CHECK_EQUAL_RANGE(const_cell_2_0.GetSourceNodes(), 0);
CHECK_EQUAL_RANGE(const_cell_2_1.GetSourceNodes(), 4);
CHECK_EQUAL_COLLECTIONS(const_cell_2_2.GetSourceNodes(), std::vector<EdgeWeight>{});
CHECK_EQUAL_RANGE(const_cell_2_3.GetSourceNodes(), 11);
CHECK_EQUAL_RANGE(const_cell_2_0.GetDestinationNodes(), 3);
CHECK_EQUAL_RANGE(const_cell_2_1.GetDestinationNodes(), 4, 7);
CHECK_EQUAL_COLLECTIONS(const_cell_2_2.GetDestinationNodes(), std::vector<EdgeWeight>{});
CHECK_EQUAL_RANGE(const_cell_2_3.GetDestinationNodes(), 11);
auto out_const_range_2_0_0 = const_cell_2_0.GetOutWeight(0);
auto out_const_range_2_1_4 = const_cell_2_1.GetOutWeight(4);
auto out_const_range_2_3_11 = const_cell_2_3.GetOutWeight(11);
auto in_const_range_2_0_3 = const_cell_2_0.GetInWeight(3);
auto in_const_range_2_1_4 = const_cell_2_1.GetInWeight(4);
auto in_const_range_2_1_7 = const_cell_2_1.GetInWeight(7);
auto in_const_range_2_3_7 = const_cell_2_3.GetInWeight(11);
REQUIRE_SIZE_RANGE(out_const_range_2_0_0, 1);
REQUIRE_SIZE_RANGE(out_const_range_2_1_4, 2);
REQUIRE_SIZE_RANGE(out_const_range_2_3_11, 1);
REQUIRE_SIZE_RANGE(in_const_range_2_0_3, 1);
REQUIRE_SIZE_RANGE(in_const_range_2_1_4, 1);
REQUIRE_SIZE_RANGE(in_const_range_2_1_7, 1);
REQUIRE_SIZE_RANGE(in_const_range_2_3_7, 1);
// Level 3
auto const_cell_3_0 = const_storage.GetCell(metric, 3, 0);
auto const_cell_3_1 = const_storage.GetCell(metric, 3, 1);
CHECK_EQUAL_RANGE(const_cell_3_0.GetSourceNodes(), 0);
CHECK_EQUAL_RANGE(const_cell_3_1.GetSourceNodes(), 4, 7);
CHECK_EQUAL_RANGE(const_cell_3_0.GetDestinationNodes(), 3);
CHECK_EQUAL_RANGE(const_cell_3_1.GetDestinationNodes(), 4, 7);
auto out_const_range_3_0_0 = const_cell_3_0.GetOutWeight(0);
auto out_const_range_3_1_4 = const_cell_3_1.GetOutWeight(4);
auto out_const_range_3_1_7 = const_cell_3_1.GetOutWeight(7);
auto in_const_range_3_0_3 = const_cell_3_0.GetInWeight(3);
auto in_const_range_3_1_4 = const_cell_3_1.GetInWeight(4);
auto in_const_range_3_1_7 = const_cell_3_1.GetInWeight(7);
REQUIRE_SIZE_RANGE(out_const_range_3_0_0, 1);
REQUIRE_SIZE_RANGE(out_const_range_3_1_4, 2);
REQUIRE_SIZE_RANGE(out_const_range_3_1_7, 2);
REQUIRE_SIZE_RANGE(in_const_range_3_0_3, 1);
REQUIRE_SIZE_RANGE(in_const_range_3_1_4, 2);
REQUIRE_SIZE_RANGE(in_const_range_3_1_7, 2);
// Level 4
auto const_cell_4_0 = const_storage.GetCell(metric, 4, 0);
CHECK_EQUAL_COLLECTIONS(const_cell_4_0.GetSourceNodes(), std::vector<EdgeWeight>{});
CHECK_EQUAL_COLLECTIONS(const_cell_4_0.GetDestinationNodes(), std::vector<EdgeWeight>{});
}
BOOST_AUTO_TEST_SUITE_END()
+75
View File
@@ -0,0 +1,75 @@
#include "partitioner/bisection_graph_view.hpp"
#include "partitioner/dinic_max_flow.hpp"
#include "partitioner/graph_generator.hpp"
#include "partitioner/recursive_bisection_state.hpp"
#include <algorithm>
#include <vector>
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
using namespace osrm::partitioner;
using namespace osrm::util;
BOOST_AUTO_TEST_SUITE(dinic_algorithm)
BOOST_AUTO_TEST_CASE(horizontal_cut_between_two_grids)
{
// 40 entries of left/right edges
const double step_size = 0.01;
const int rows = 10;
const int cols = 10;
// build a small grid (10*10) and a (100 * 10) below (to make the different steps unique)
auto graph = [&]() {
std::vector<Coordinate> grid_coordinates;
std::vector<EdgeWithSomeAdditionalData> grid_edges;
const auto connect = [&grid_edges](const NodeID from, const NodeID to) {
grid_edges.push_back({from, to, 1});
grid_edges.push_back({to, from, 1});
};
// 10 rows of large components, interrupted by small disconnected components
const auto small_coordinates = makeGridCoordinates(rows, cols, step_size, 0, 0);
grid_coordinates.insert(
grid_coordinates.end(), small_coordinates.begin(), small_coordinates.end());
// connect the grid edges, starting with i * (rows * cols + 1) as first id (0,11,22...)
const auto small_edges = makeGridEdges(rows, cols, 0);
grid_edges.insert(grid_edges.end(), small_edges.begin(), small_edges.end());
const auto large_coordinates =
makeGridCoordinates(10 * rows, cols, step_size, 0, rows * step_size);
grid_coordinates.insert(
grid_coordinates.end(), large_coordinates.begin(), large_coordinates.end());
const auto large_edges = makeGridEdges(10 * rows, cols, (rows * cols));
grid_edges.insert(grid_edges.end(), large_edges.begin(), large_edges.end());
connect(45, 1001);
connect(55, 800);
connect(65, 600);
connect(75, 200);
groupEdgesBySource(grid_edges.begin(), grid_edges.end());
return makeBisectionGraph(grid_coordinates, adaptToBisectionEdge(std::move(grid_edges)));
}();
RecursiveBisectionState bisection_state(graph);
BisectionGraphView view(graph);
DinicMaxFlow::SourceSinkNodes sources, sinks;
for (int i = 0; i < 10; ++i)
{
sources.insert(static_cast<NodeID>(i));
sinks.insert(static_cast<NodeID>(1000 + i));
}
DinicMaxFlow flow;
const auto cut = flow(view, sources, sinks);
BOOST_CHECK(cut.num_edges == 4);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,80 @@
#ifndef OSRM_UNIT_TEST_PARTITION_GRAPH_GENERATOR_HPP
#define OSRM_UNIT_TEST_PARTITION_GRAPH_GENERATOR_HPP
#include "util/coordinate.hpp"
#include "util/typedefs.hpp"
#include <algorithm>
#include <vector>
using namespace osrm::util;
struct EdgeWithSomeAdditionalData
{
NodeID source;
NodeID target;
unsigned important_data;
};
inline Coordinate
makeCoordinate(int x, int y, double step_size, double offset_x = 0, double offset_y = 0)
{
return {FloatLongitude{offset_x + x * step_size}, FloatLatitude{offset_y + y * step_size}};
}
std::vector<Coordinate> inline makeGridCoordinates(
int rows, int columns, double step_size, double lon_base, double lat_base)
{
std::vector<Coordinate> result;
for (int r = 0; r < rows; ++r)
for (int c = 0; c < columns; ++c)
result.push_back(makeCoordinate(c, r, step_size, lon_base, lat_base));
return result;
}
inline std::vector<EdgeWithSomeAdditionalData> makeGridEdges(int rows, int columns, int id_base)
{
const int min_id = id_base;
const int max_id = id_base + rows * columns;
const auto get_id = [id_base, columns](int r, int c) { return id_base + r * columns + c; };
const auto valid = [min_id, max_id](int id) { return id >= min_id && id < max_id; };
std::vector<EdgeWithSomeAdditionalData> edges;
for (int r = 0; r < rows; ++r)
{
for (int c = 0; c < columns; ++c)
{
auto id = static_cast<NodeID>(get_id(r, c));
if (c > 0)
{
auto left = get_id(r, c - 1);
edges.push_back({id, static_cast<NodeID>(left), 1});
}
if (c + 1 < columns)
{
auto right = get_id(r, c + 1);
if (valid(right))
edges.push_back({id, static_cast<NodeID>(right), 1});
}
if (r > 0)
{
auto top = get_id(r - 1, c);
if (valid(top))
edges.push_back({id, static_cast<NodeID>(top), 1});
}
if (r + 1 < rows)
{
auto bottom = get_id(r + 1, c);
if (valid(bottom))
edges.push_back({id, static_cast<NodeID>(bottom), 1});
}
}
}
return edges;
}
#endif // OSRM_UNIT_TEST_PARTITION_GRAPH_GENERATOR_HPP
@@ -0,0 +1,223 @@
#include "partitioner/multi_level_graph.hpp"
#include "util/typedefs.hpp"
#include "../common/range_tools.hpp"
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
#include <algorithm>
#include <random>
#include <vector>
using namespace osrm;
using namespace osrm::partitioner;
namespace
{
struct MockEdge
{
NodeID source;
NodeID target;
};
auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock_edges)
{
struct EdgeData
{
bool forward;
bool backward;
};
using Edge = util::static_graph_details::SortableEdgeWithData<EdgeData>;
std::vector<Edge> edges;
std::size_t max_id = 0;
for (const auto &m : mock_edges)
{
max_id = std::max<std::size_t>(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<EdgeData, osrm::storage::Ownership::Container>(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 13
std::vector<CellID> l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6}};
std::vector<CellID> l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4}};
std::vector<CellID> l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2}};
std::vector<CellID> l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}};
MultiLevelPartition mlp{{l1, l2, l3, l4}, {7, 5, 3, 2}};
std::vector<MockEdge> 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
{12, 13} // i i i i
};
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<NodeID>(0, 13))
CHECK_EQUAL_COLLECTIONS(graph.GetBorderEdgeRange(0, node),
graph.GetAdjacentEdgeRange(node));
// on level 0 there are no internal edges
for (auto node : util::irange<NodeID>(0, 13))
CHECK_EQUAL_COLLECTIONS(graph.GetInternalEdgeRange(0, node), util::irange<EdgeID>(0, 0));
// the union of border and internal edge needs to equal the adjacent edges
for (auto level : util::irange<LevelID>(0, 4))
{
for (auto node : util::irange<NodeID>(0, 14))
{
const auto adjacent = graph.GetAdjacentEdgeRange(node);
const auto border = graph.GetBorderEdgeRange(level, node);
const auto internal = graph.GetInternalEdgeRange(level, node);
std::vector<EdgeID> merged;
std::copy(internal.begin(), internal.end(), std::back_inserter(merged));
std::copy(border.begin(), border.end(), std::back_inserter(merged));
CHECK_EQUAL_COLLECTIONS(adjacent, merged);
}
}
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(1, 13).size(), 0);
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(2, 13).size(), 0);
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(3, 13).size(), 0);
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);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 13).size(), 0);
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_CASE(check_last_internal_edge)
{
// a--b--c--d
std::vector<CellID> l1{{0, 0, 1, 1}};
std::vector<CellID> l2{{0, 0, 1, 1}};
MultiLevelPartition mlp{{l1, l2}, {2, 2}};
std::vector<MockEdge> edges = {{0, 1}, {1, 0}, {1, 2}, {2, 1}, {2, 3}, {3, 2}};
auto graph = makeGraph(mlp, edges);
auto all_edges = graph.GetAdjacentEdgeRange(3);
CHECK_EQUAL_COLLECTIONS(graph.GetBorderEdgeRange(0, 3), all_edges);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 3).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 3).size(), 0);
BOOST_CHECK_EQUAL(graph.GetInternalEdgeRange(0, 3).size(), 0);
CHECK_EQUAL_COLLECTIONS(graph.GetInternalEdgeRange(1, 3), all_edges);
CHECK_EQUAL_COLLECTIONS(graph.GetInternalEdgeRange(2, 3), all_edges);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,178 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/test/unit_test.hpp>
#include "partitioner/multi_level_partition.hpp"
#define CHECK_SIZE_RANGE(range, ref) BOOST_CHECK_EQUAL(range.second - range.first, ref)
#define CHECK_EQUAL_RANGE(range, ref) \
do \
{ \
const auto &lhs = range; \
const auto &rhs = ref; \
BOOST_CHECK_EQUAL_COLLECTIONS(lhs.first, lhs.second, rhs.begin(), rhs.end()); \
} while (0)
using namespace osrm;
using namespace osrm::partitioner;
BOOST_AUTO_TEST_SUITE(multi_level_partition_tests)
BOOST_AUTO_TEST_CASE(mlp_one)
{
// node: 0 1 2 3 4 5 6 7 8 9 10 11
std::vector<CellID> 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<CellID> l1{{4, 4, 2, 2, 1, 1, 3, 3, 2, 2, 5, 5}};
std::vector<CellID> l2{{3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 0, 0}};
std::vector<CellID> l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}};
std::vector<CellID> 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<CellID> l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5}};
std::vector<CellID> l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3}};
std::vector<CellID> l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}};
std::vector<CellID> 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), l1[0]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 1), l1[1]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 2), l1[2]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 3), l1[3]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 4), l1[4]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 5), l1[5]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 6), l1[6]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 7), l1[7]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 8), l1[8]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 9), l1[9]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 10), l1[10]);
BOOST_CHECK_EQUAL(mlp.GetCell(1, 11), l1[11]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 0), l2[0]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 1), l2[1]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 2), l2[2]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 3), l2[3]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 4), l2[4]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 5), l2[5]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 6), l2[6]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 7), l2[7]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 8), l2[8]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 9), l2[9]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 10), l2[10]);
BOOST_CHECK_EQUAL(mlp.GetCell(2, 11), l2[11]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 0), l3[0]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 1), l3[1]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 2), l3[2]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 3), l3[3]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 4), l3[4]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 5), l3[5]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 6), l3[6]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 7), l3[7]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 8), l3[8]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 9), l3[9]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 10), l3[10]);
BOOST_CHECK_EQUAL(mlp.GetCell(3, 11), l3[11]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 0), l4[0]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 1), l4[1]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 2), l4[2]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 3), l4[3]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 4), l4[4]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 5), l4[5]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 6), l4[6]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 7), l4[7]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 8), l4[8]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 9), l4[9]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 10), l4[10]);
BOOST_CHECK_EQUAL(mlp.GetCell(4, 11), l4[11]);
BOOST_CHECK_EQUAL(mlp.GetHighestDifferentLevel(0, 1), 0);
BOOST_CHECK_EQUAL(mlp.GetHighestDifferentLevel(0, 2), 1);
BOOST_CHECK_EQUAL(mlp.GetHighestDifferentLevel(0, 4), 3);
BOOST_CHECK_EQUAL(mlp.GetHighestDifferentLevel(7, 8), 2);
BOOST_CHECK_EQUAL(mlp.BeginChildren(2, 0), 0);
BOOST_CHECK_EQUAL(mlp.EndChildren(2, 0), 2);
BOOST_CHECK_EQUAL(mlp.BeginChildren(2, 1), 2);
BOOST_CHECK_EQUAL(mlp.EndChildren(2, 1), 4);
BOOST_CHECK_EQUAL(mlp.BeginChildren(2, 2), 4);
BOOST_CHECK_EQUAL(mlp.EndChildren(2, 2), 5);
BOOST_CHECK_EQUAL(mlp.BeginChildren(2, 3), 5);
BOOST_CHECK_EQUAL(mlp.EndChildren(2, 3), 6);
BOOST_CHECK_EQUAL(mlp.BeginChildren(3, 0), 0);
BOOST_CHECK_EQUAL(mlp.EndChildren(3, 0), 1);
BOOST_CHECK_EQUAL(mlp.BeginChildren(3, 1), 1);
BOOST_CHECK_EQUAL(mlp.EndChildren(3, 1), 4);
BOOST_CHECK_EQUAL(mlp.BeginChildren(4, 0), 0);
BOOST_CHECK_EQUAL(mlp.EndChildren(4, 0), 2);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,83 @@
#include "partitioner/recursive_bisection.hpp"
#include "partitioner/graph_generator.hpp"
#include "partitioner/recursive_bisection_state.hpp"
#include <algorithm>
#include <vector>
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
// make sure not to leak in recursive bisection
#include <tbb/task_scheduler_init.h>
tbb::task_scheduler_init init(2);
using namespace osrm::partitioner;
using namespace osrm::util;
BOOST_AUTO_TEST_SUITE(recursive_bisection)
BOOST_AUTO_TEST_CASE(dividing_four_grid_cells)
{
// 40 entries of left/right edges
const double step_size = 0.01;
const int rows = 10;
const int cols = 10;
const int cut_edges = 4;
auto graph = [&]() {
std::vector<Coordinate> grid_coordinates;
std::vector<EdgeWithSomeAdditionalData> grid_edges;
const auto connect =
[&grid_edges](int min_left, int max_left, int min_right, int max_right) {
const NodeID source = (rand() % (max_left - min_left)) + min_left;
const NodeID target = (rand() % (max_right - min_right)) + min_right;
grid_edges.push_back({source, target, 1});
grid_edges.push_back({target, source, 1});
};
// generate 10 big components
for (int i = 0; i < 4; ++i)
{
// 10 rows of large components, interrupted by small disconnected components
const auto coordinates = makeGridCoordinates(
rows, cols, step_size, cols * (i % 2), (i * rows / 2) * step_size);
grid_coordinates.insert(grid_coordinates.end(), coordinates.begin(), coordinates.end());
// connect the grid edges, starting with i * (rows * cols + 1) as first id (0,11,22...)
const auto edges = makeGridEdges(rows, cols, i * (rows * cols));
grid_edges.insert(grid_edges.end(), edges.begin(), edges.end());
}
// add cut edges between neighboring cells
int n = rows * cols;
for (int i = 0; i < cut_edges; ++i)
{
// left/right
connect(0, n, n, 2 * n);
connect(2 * n, 3 * n, 3 * n, 4 * n);
// top/bottom
connect(0, n, 2 * n, 3 * n);
connect(n, 2 * n, 3 * n, 4 * n);
}
groupEdgesBySource(grid_edges.begin(), grid_edges.end());
return makeBisectionGraph(grid_coordinates, adaptToBisectionEdge(std::move(grid_edges)));
}();
RecursiveBisection bisection(graph, 120, 1.1, 0.25, 10, 1);
const auto result = bisection.BisectionIDs();
// all same IDs withing a group
for (int i = 0; i < 4; ++i)
for (int j = 0; j < rows * cols; ++j)
BOOST_CHECK(result[i * (rows * cols)] == result[i * (rows * cols) + j]);
// different IDs for all four groups
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
BOOST_CHECK(i == j || result[i * (rows * cols)] != result[j * (rows * cols)]);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,117 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/test/unit_test.hpp>
#include "partitioner/remove_unconnected.hpp"
#include "util/static_graph.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::partitioner;
namespace
{
struct MockEdge
{
NodeID start;
NodeID target;
};
auto makeGraph(const std::vector<MockEdge> &mock_edges)
{
struct EdgeData
{
bool forward;
bool backward;
};
using Edge = util::static_graph_details::SortableEdgeWithData<EdgeData>;
std::vector<Edge> edges;
std::size_t max_id = 0;
for (const auto &m : mock_edges)
{
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
edges.push_back(Edge{m.start, m.target, true, false});
edges.push_back(Edge{m.target, m.start, false, true});
}
std::sort(edges.begin(), edges.end());
return util::StaticGraph<EdgeData>(max_id + 1, edges);
}
}
BOOST_AUTO_TEST_SUITE(remove_unconnected_tests)
BOOST_AUTO_TEST_CASE(remove_minimum_border_eges)
{
// node: 0 1 2 3 4 5 6 7 8 9 10 11 12
std::vector<CellID> l1{{0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 3, 3}};
std::vector<CellID> l2{{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2}};
std::vector<CellID> l3{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}};
/*
0---1 4---5 8---7 9
\ / \ / \ /
2 3------6
|
10
| \
11-12
*/
std::vector<MockEdge> edges = {
// first clique
{0, 1},
{1, 2},
{2, 0},
// second clique
{3, 4},
{4, 5},
{5, 3},
// third clique
{6, 7},
{7, 8},
{8, 6},
// fourth clique
{10, 11},
{11, 12},
{12, 11},
// connection 3 to thrid clique
{3, 6},
// connect 10 to first clique
{2, 10},
};
// 10 is going to be unconnected on level 2 and 1
// 3 is going to be unconnected only on level 1
auto graph = makeGraph(edges);
std::vector<Partition> partitions = {l1, l2, l3};
std::vector<Partition> reference_partitions = partitions;
// 3 get's merged into cell 1 on first level
reference_partitions[0][3] = 1;
reference_partitions[1][3] = 0;
// 10 get's merged into cell 0 on both levels and not with 11 (different parent cell)
// even though there are would be less boundary edges
reference_partitions[0][10] = 0;
reference_partitions[1][10] = 0;
auto num_unconnected = removeUnconnectedBoundaryNodes(graph, partitions);
BOOST_CHECK_EQUAL(num_unconnected, 2);
CHECK_EQUAL_RANGE(partitions[0], reference_partitions[0]);
CHECK_EQUAL_RANGE(partitions[1], reference_partitions[1]);
CHECK_EQUAL_RANGE(partitions[2], reference_partitions[2]);
}
BOOST_AUTO_TEST_SUITE_END()
+86
View File
@@ -0,0 +1,86 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/test/unit_test.hpp>
#include "partitioner/renumber.hpp"
#include "../common/range_tools.hpp"
using namespace osrm;
using namespace osrm::partitioner;
namespace
{
struct MockEdge
{
NodeID start;
NodeID target;
};
auto makeGraph(const std::vector<MockEdge> &mock_edges)
{
struct EdgeData
{
EdgeWeight weight;
bool forward;
bool backward;
};
using InputEdge = DynamicEdgeBasedGraph::InputEdge;
std::vector<InputEdge> edges;
std::size_t max_id = 0;
for (const auto &m : mock_edges)
{
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
edges.push_back(InputEdge{
m.start, m.target, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, true, false}});
edges.push_back(InputEdge{
m.target, m.start, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, false, true}});
}
std::sort(edges.begin(), edges.end());
return DynamicEdgeBasedGraph(max_id + 1, edges);
}
}
BOOST_AUTO_TEST_SUITE(renumber_tests)
BOOST_AUTO_TEST_CASE(unsplitable_case)
{
// node: 0 1 2 3 4 5 6 7 8 9 10 11
// border: x x x x x x x
// permutation by cells: 0 1 2 5 6 10 11 7 8 9 3 4
// order by cell: 0 1 2 10 11 3 4 7 8 9 5 6
// x x x x x x x
// border level: 3 3 3 2 2 1 1 0 0 0 0 0
// order: 0 10 11 7 6 3 4 1 2 8 9 5
// permutation: 0 7 8 5 6 11 4 3 9 10 1 2
std::vector<CellID> l1{{0, 0, 1, 2, 3, 5, 5, 3, 4, 4, 1, 2}};
std::vector<CellID> l2{{0, 0, 0, 1, 1, 3, 3, 1, 2, 2, 0, 1}};
std::vector<CellID> l3{{0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1}};
std::vector<CellID> l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
std::vector<MockEdge> edges = {
// edges sorted into border/internal by level
// level: (1) (2) (3) (4)
{0, 1}, // i i i i
{2, 10}, // i i i i
{10, 7}, // b b b i
{11, 0}, // b b b i
{11, 3}, // i i i i
{3, 4}, // b i i i
{4, 11}, // b i i i
{4, 7}, // i i i i
{7, 6}, // b b i i
{8, 9}, // i i i i
{9, 8}, // i i i i
{5, 6}, // i i i i
{6, 5} // i i i i
};
auto graph = makeGraph(edges);
std::vector<Partition> partitions{l1, l2, l3, l4};
auto permutation = makePermutation(graph, partitions);
CHECK_EQUAL_RANGE(permutation, 0, 7, 8, 5, 6, 11, 4, 3, 9, 10, 1, 2);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,54 @@
#include "partitioner/reorder_first_last.hpp"
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
#include <algorithm>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
using namespace osrm::partitioner;
BOOST_AUTO_TEST_SUITE(reorder_first_last)
BOOST_AUTO_TEST_CASE(reordering_one_is_equivalent_to_min_and_max)
{
std::vector<int> range{9, 0, 8, 1, 7, 2, 6, 3, 5, 4};
reorderFirstLast(begin(range), end(range), 1, std::less<>{});
BOOST_CHECK_EQUAL(range.front(), 0);
BOOST_CHECK_EQUAL(range.back(), 9);
reorderFirstLast(begin(range), end(range), 1, std::greater<>{});
BOOST_CHECK_EQUAL(range.front(), 9);
BOOST_CHECK_EQUAL(range.back(), 0);
}
BOOST_AUTO_TEST_CASE(reordering_n_shuffles_n_smallest_to_front_n_largest_to_back)
{
std::vector<int> range{9, 3, 8, 2};
reorderFirstLast(begin(range), end(range), 2, std::less<>{});
// Smallest at front, but: no ordering guarantee in that subrange!
BOOST_CHECK((range[0] == 2 && range[1] == 3) || (range[0] == 3 && range[1] == 2));
// Largest at back, but: no ordering guarantee in that subrange!
BOOST_CHECK((range[2] == 8 && range[3] == 9) || (range[2] == 9 && range[3] == 8));
}
BOOST_AUTO_TEST_CASE(reordering_n_with_iterators)
{
std::vector<int> range{9, 3, 8, 2};
reorderFirstLast(begin(range), end(range), 1, std::less<>{});
BOOST_CHECK_EQUAL(range.front(), 2);
BOOST_CHECK_EQUAL(range.back(), 9);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -0,0 +1,80 @@
#include "partitioner/bisection_graph_view.hpp"
#include "partitioner/graph_generator.hpp"
#include "partitioner/recursive_bisection_state.hpp"
#include <algorithm>
#include <vector>
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
using namespace osrm::partitioner;
using namespace osrm::util;
BOOST_AUTO_TEST_SUITE(scc_integration)
BOOST_AUTO_TEST_CASE(graph_views_on_components)
{
// 40 entries of left/right edges
const double step_size = 0.01;
const int rows = 1;
const int cols = 10;
const int num_components = 10;
auto graph = [&]() {
std::vector<Coordinate> grid_coordinates;
std::vector<EdgeWithSomeAdditionalData> grid_edges;
// generate 10 big components
for (int i = 0; i < num_components; ++i)
{
// 10 rows of large components, interrupted by small disconnected components
const auto coordinates = makeGridCoordinates(rows, cols, step_size, 0, i * step_size);
grid_coordinates.insert(grid_coordinates.end(), coordinates.begin(), coordinates.end());
// add a single disconnected node to have ids between large components
if (i + 1 < num_components)
grid_coordinates.push_back(
makeCoordinate(1, 1, 0.5 * step_size, 0, (i + 1) * step_size));
// connect the grid edges, starting with i * (rows * cols + 1) as first id (0,11,22...)
const auto edges = makeGridEdges(rows, cols, i * (rows * cols + 1));
grid_edges.insert(grid_edges.end(), edges.begin(), edges.end());
}
groupEdgesBySource(grid_edges.begin(), grid_edges.end());
return makeBisectionGraph(grid_coordinates, adaptToBisectionEdge(std::move(grid_edges)));
}();
RecursiveBisectionState bisection_state(graph);
auto views = bisection_state.PrePartitionWithSCC(2);
BOOST_CHECK_EQUAL(views.size(), num_components + 1); // big components + 1 small one
for (std::size_t comp = 0; comp < num_components; ++comp)
{
const auto &view = views[comp];
BOOST_CHECK(views[comp].NumberOfNodes() == 10);
const auto to_component_id = [&](const auto &node) {
return node.original_id / (rows * cols + 1);
};
std::size_t expected_component_id = to_component_id(view.Node(0));
BOOST_CHECK(std::all_of(view.Begin(), view.End(), [&](const auto &node) {
return to_component_id(node) == expected_component_id;
}));
for (const auto &node : view.Nodes())
{
for (const auto &edge : view.Edges(node))
{
BOOST_CHECK(edge.target < view.NumberOfNodes());
}
}
}
BOOST_CHECK(views.back().NumberOfNodes() == 9);
}
BOOST_AUTO_TEST_SUITE_END()