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:
committed by
Patrick Niklaus
parent
03f598b93d
commit
8114104a43
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user