Add storage for cell weights used in the MLD algorithm
This commit is contained in:
parent
b2b5e2bb4d
commit
e06ffabf21
321
include/util/cell_storage.hpp
Normal file
321
include/util/cell_storage.hpp
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
#ifndef OSRM_UTIL_CELL_STORAGE_HPP
|
||||||
|
#define OSRM_UTIL_CELL_STORAGE_HPP
|
||||||
|
|
||||||
|
#include "util/assert.hpp"
|
||||||
|
#include "util/for_each_range.hpp"
|
||||||
|
#include "util/multi_level_partition.hpp"
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
#include <tbb/parallel_sort.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
class CellStorage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using WeightOffset = std::uint32_t;
|
||||||
|
using BoundaryOffset = std::uint32_t;
|
||||||
|
using BoundarySize = std::uint32_t;
|
||||||
|
using SourceIndex = std::uint32_t;
|
||||||
|
using DestinationIndex = std::uint32_t;
|
||||||
|
|
||||||
|
static constexpr auto INVALID_WEIGHT_OFFSET = std::numeric_limits<WeightOffset>::max();
|
||||||
|
static constexpr auto INVALID_BOUNDARY_OFFSET = std::numeric_limits<BoundaryOffset>::max();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CellData
|
||||||
|
{
|
||||||
|
WeightOffset weight_offset = INVALID_WEIGHT_OFFSET;
|
||||||
|
BoundaryOffset source_boundary_offset = INVALID_BOUNDARY_OFFSET;
|
||||||
|
BoundaryOffset destination_boundary_offset = INVALID_BOUNDARY_OFFSET;
|
||||||
|
BoundarySize num_source_nodes = 0;
|
||||||
|
BoundarySize num_destination_nodes = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation of the cell view. We need a template parameter here
|
||||||
|
// because we need to derive a read-only and read-write view from this.
|
||||||
|
template <typename WeightValueT> class CellImpl
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using WeightPtrT = WeightValueT *;
|
||||||
|
using WeightRefT = WeightValueT &;
|
||||||
|
BoundarySize num_source_nodes;
|
||||||
|
BoundarySize num_destination_nodes;
|
||||||
|
|
||||||
|
WeightPtrT const weights;
|
||||||
|
const NodeID *const source_boundary;
|
||||||
|
const NodeID *const destination_boundary;
|
||||||
|
|
||||||
|
using RowIterator = WeightPtrT;
|
||||||
|
// Possibly replace with
|
||||||
|
// http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html
|
||||||
|
class ColumnIterator : public std::iterator<std::random_access_iterator_tag, EdgeWeight>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ColumnIterator(WeightPtrT begin, std::size_t row_length)
|
||||||
|
: current(begin), stride(row_length)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(begin != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
WeightRefT operator*() const { return *current; }
|
||||||
|
|
||||||
|
ColumnIterator &operator++()
|
||||||
|
{
|
||||||
|
current += stride;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnIterator &operator+=(int amount)
|
||||||
|
{
|
||||||
|
current += stride * amount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const ColumnIterator &other) const { return current == other.current; }
|
||||||
|
|
||||||
|
bool operator!=(const ColumnIterator &other) const { return current != other.current; }
|
||||||
|
|
||||||
|
std::int64_t operator-(const ColumnIterator &other) const
|
||||||
|
{
|
||||||
|
return (current - other.current) / stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
WeightPtrT current;
|
||||||
|
std::size_t stride;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t GetRow(NodeID node) const
|
||||||
|
{
|
||||||
|
auto iter = std::find(source_boundary, source_boundary + num_source_nodes, node);
|
||||||
|
BOOST_ASSERT(iter != source_boundary + num_source_nodes);
|
||||||
|
return iter - source_boundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t GetColumn(NodeID node) const
|
||||||
|
{
|
||||||
|
auto iter =
|
||||||
|
std::find(destination_boundary, destination_boundary + num_destination_nodes, node);
|
||||||
|
BOOST_ASSERT(iter != destination_boundary + num_destination_nodes);
|
||||||
|
return iter - destination_boundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
auto GetOutWeight(NodeID node) const
|
||||||
|
{
|
||||||
|
auto row = GetRow(node);
|
||||||
|
auto begin = weights + num_destination_nodes * row;
|
||||||
|
auto end = begin + num_destination_nodes;
|
||||||
|
return boost::make_iterator_range(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetInWeight(NodeID node) const
|
||||||
|
{
|
||||||
|
auto column = GetColumn(node);
|
||||||
|
auto begin = ColumnIterator{weights + column, num_destination_nodes};
|
||||||
|
auto end = ColumnIterator{weights + column + num_source_nodes * num_destination_nodes,
|
||||||
|
num_destination_nodes};
|
||||||
|
return boost::make_iterator_range(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetSourceNodes() const
|
||||||
|
{
|
||||||
|
return boost::make_iterator_range(source_boundary, source_boundary + num_source_nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetDestinationNodes() const
|
||||||
|
{
|
||||||
|
return boost::make_iterator_range(destination_boundary,
|
||||||
|
destination_boundary + num_destination_nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
CellImpl(const CellData &data,
|
||||||
|
WeightPtrT const all_weight,
|
||||||
|
const NodeID *const all_sources,
|
||||||
|
const NodeID *const all_destinations)
|
||||||
|
: num_source_nodes{data.num_source_nodes},
|
||||||
|
num_destination_nodes{data.num_destination_nodes},
|
||||||
|
weights{all_weight + data.weight_offset},
|
||||||
|
source_boundary{all_sources + data.source_boundary_offset},
|
||||||
|
destination_boundary{all_destinations + data.destination_boundary_offset}
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(all_weight != nullptr);
|
||||||
|
BOOST_ASSERT(all_sources != nullptr);
|
||||||
|
BOOST_ASSERT(all_destinations != nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t LevelIDToIndex(LevelID level) const { return level - 1; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Cell = CellImpl<EdgeWeight>;
|
||||||
|
using ConstCell = CellImpl<const EdgeWeight>;
|
||||||
|
|
||||||
|
template <typename GraphT>
|
||||||
|
CellStorage(const MultiLevelPartition &partition, const GraphT &base_graph)
|
||||||
|
{
|
||||||
|
// pre-allocate storge for CellData so we can have random access to it by cell id
|
||||||
|
unsigned number_of_cells = 0;
|
||||||
|
for (LevelID level = 1u; level < partition.GetNumberOfLevels(); ++level)
|
||||||
|
{
|
||||||
|
level_to_cell_offset.push_back(number_of_cells);
|
||||||
|
number_of_cells += partition.GetNumberOfCells(level);
|
||||||
|
}
|
||||||
|
level_to_cell_offset.push_back(number_of_cells);
|
||||||
|
cells.resize(number_of_cells);
|
||||||
|
|
||||||
|
std::vector<std::pair<CellID, NodeID>> level_source_boundary;
|
||||||
|
std::vector<std::pair<CellID, NodeID>> level_destination_boundary;
|
||||||
|
|
||||||
|
for (LevelID level = 1u; level < partition.GetNumberOfLevels(); ++level)
|
||||||
|
{
|
||||||
|
auto level_offset = level_to_cell_offset[LevelIDToIndex(level)];
|
||||||
|
|
||||||
|
level_source_boundary.clear();
|
||||||
|
level_destination_boundary.clear();
|
||||||
|
|
||||||
|
for (auto node = 0u; node < base_graph.GetNumberOfNodes(); ++node)
|
||||||
|
{
|
||||||
|
const CellID cell_id = partition.GetCell(level, node);
|
||||||
|
bool is_source_node = false;
|
||||||
|
bool is_destination_node = false;
|
||||||
|
bool is_boundary_node = false;
|
||||||
|
|
||||||
|
for (auto edge : base_graph.GetAdjacentEdgeRange(node))
|
||||||
|
{
|
||||||
|
auto other = base_graph.GetTarget(edge);
|
||||||
|
const auto &data = base_graph.GetEdgeData(edge);
|
||||||
|
|
||||||
|
is_boundary_node |= partition.GetCell(level, other) != cell_id;
|
||||||
|
is_source_node |= partition.GetCell(level, other) == cell_id && data.forward;
|
||||||
|
is_destination_node |=
|
||||||
|
partition.GetCell(level, other) == cell_id && data.backward;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_boundary_node)
|
||||||
|
{
|
||||||
|
if (is_source_node)
|
||||||
|
level_source_boundary.emplace_back(cell_id, node);
|
||||||
|
if (is_destination_node)
|
||||||
|
level_destination_boundary.emplace_back(cell_id, node);
|
||||||
|
// a partition that contains boundary nodes that have no arcs going into
|
||||||
|
// the cells or coming out of it is invalid. These nodes should be reassigned
|
||||||
|
// to a different cell.
|
||||||
|
BOOST_ASSERT_MSG(
|
||||||
|
is_source_node || is_destination_node,
|
||||||
|
"Node needs to either have incoming or outgoing edges in cell");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tbb::parallel_sort(level_source_boundary.begin(), level_source_boundary.end());
|
||||||
|
tbb::parallel_sort(level_destination_boundary.begin(),
|
||||||
|
level_destination_boundary.end());
|
||||||
|
|
||||||
|
const auto insert_cell_boundary = [this, level_offset](auto &boundary,
|
||||||
|
auto set_num_nodes_fn,
|
||||||
|
auto set_boundary_offset_fn,
|
||||||
|
auto begin,
|
||||||
|
auto end) {
|
||||||
|
BOOST_ASSERT(std::distance(begin, end) > 0);
|
||||||
|
|
||||||
|
const auto cell_id = begin->first;
|
||||||
|
BOOST_ASSERT(level_offset + cell_id < cells.size());
|
||||||
|
auto &cell = cells[level_offset + cell_id];
|
||||||
|
set_num_nodes_fn(cell, std::distance(begin, end));
|
||||||
|
set_boundary_offset_fn(cell, boundary.size());
|
||||||
|
|
||||||
|
std::transform(begin,
|
||||||
|
end,
|
||||||
|
std::back_inserter(boundary),
|
||||||
|
[](const auto &cell_and_node) { return cell_and_node.second; });
|
||||||
|
};
|
||||||
|
|
||||||
|
util::for_each_range(
|
||||||
|
level_source_boundary.begin(),
|
||||||
|
level_source_boundary.end(),
|
||||||
|
[this, insert_cell_boundary](auto begin, auto end) {
|
||||||
|
insert_cell_boundary(
|
||||||
|
source_boundary,
|
||||||
|
[](auto &cell, auto value) { cell.num_source_nodes = value; },
|
||||||
|
[](auto &cell, auto value) { cell.source_boundary_offset = value; },
|
||||||
|
begin,
|
||||||
|
end);
|
||||||
|
});
|
||||||
|
util::for_each_range(
|
||||||
|
level_destination_boundary.begin(),
|
||||||
|
level_destination_boundary.end(),
|
||||||
|
[this, insert_cell_boundary](auto begin, auto end) {
|
||||||
|
insert_cell_boundary(
|
||||||
|
destination_boundary,
|
||||||
|
[](auto &cell, auto value) { cell.num_destination_nodes = value; },
|
||||||
|
[](auto &cell, auto value) { cell.destination_boundary_offset = value; },
|
||||||
|
begin,
|
||||||
|
end);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set weight offsets and calculate total storage size
|
||||||
|
WeightOffset weight_offset = 0;
|
||||||
|
for (auto &cell : cells)
|
||||||
|
{
|
||||||
|
cell.weight_offset = weight_offset;
|
||||||
|
weight_offset += cell.num_source_nodes * cell.num_destination_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
weights.resize(weight_offset + 1, INVALID_EDGE_WEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
CellStorage(std::vector<EdgeWeight> weights_,
|
||||||
|
std::vector<NodeID> source_boundary_,
|
||||||
|
std::vector<NodeID> destination_boundary_,
|
||||||
|
std::vector<CellData> cells_,
|
||||||
|
std::vector<std::size_t> level_to_cell_offset_)
|
||||||
|
: weights(std::move(weights_)), source_boundary(std::move(source_boundary_)),
|
||||||
|
destination_boundary(std::move(destination_boundary_)), cells(std::move(cells_)),
|
||||||
|
level_to_cell_offset(std::move(level_to_cell_offset_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstCell GetCell(LevelID level, CellID id) const
|
||||||
|
{
|
||||||
|
const auto level_index = LevelIDToIndex(level);
|
||||||
|
BOOST_ASSERT(level_index < level_to_cell_offset.size());
|
||||||
|
const auto offset = level_to_cell_offset[level_index];
|
||||||
|
const auto cell_index = offset + id;
|
||||||
|
BOOST_ASSERT(cell_index < cells.size());
|
||||||
|
return ConstCell{
|
||||||
|
cells[cell_index], weights.data(), source_boundary.data(), destination_boundary.data()};
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell GetCell(LevelID level, CellID id)
|
||||||
|
{
|
||||||
|
const auto level_index = LevelIDToIndex(level);
|
||||||
|
BOOST_ASSERT(level_index < level_to_cell_offset.size());
|
||||||
|
const auto offset = level_to_cell_offset[level_index];
|
||||||
|
const auto cell_index = offset + id;
|
||||||
|
BOOST_ASSERT(cell_index < cells.size());
|
||||||
|
return Cell{
|
||||||
|
cells[cell_index], weights.data(), source_boundary.data(), destination_boundary.data()};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<EdgeWeight> weights;
|
||||||
|
std::vector<NodeID> source_boundary;
|
||||||
|
std::vector<NodeID> destination_boundary;
|
||||||
|
std::vector<CellData> cells;
|
||||||
|
std::vector<std::size_t> level_to_cell_offset;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
26
include/util/for_each_range.hpp
Normal file
26
include/util/for_each_range.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef OSRM_UTIL_FOR_EACH_RANGE_HPP
|
||||||
|
#define OSRM_UTIL_FOR_EACH_RANGE_HPP
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Iter, typename Func> void for_each_range(Iter begin, Iter end, Func f)
|
||||||
|
{
|
||||||
|
auto iter = begin;
|
||||||
|
while (iter != end)
|
||||||
|
{
|
||||||
|
const auto key = iter->first;
|
||||||
|
auto begin_range = iter;
|
||||||
|
while (iter != end && iter->first == key)
|
||||||
|
{
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
f(begin_range, iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
32
include/util/multi_level_partition.hpp
Normal file
32
include/util/multi_level_partition.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef OSRM_UTIL_MULTI_LEVEL_PARTITION_HPP
|
||||||
|
#define OSRM_UTIL_MULTI_LEVEL_PARTITION_HPP
|
||||||
|
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
using LevelID = std::uint8_t;
|
||||||
|
using CellID = std::uint32_t;
|
||||||
|
|
||||||
|
// Mock interface, can be removed when we have an actual implementation
|
||||||
|
class MultiLevelPartition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Returns the cell id of `node` at `level`
|
||||||
|
virtual CellID GetCell(LevelID level, NodeID node) const = 0;
|
||||||
|
|
||||||
|
// Returns the highest level in which `first` and `second` are still in different cells
|
||||||
|
virtual LevelID GetHighestDifferentLevel(NodeID first, NodeID second) const = 0;
|
||||||
|
|
||||||
|
virtual std::size_t GetNumberOfLevels() const = 0;
|
||||||
|
|
||||||
|
virtual std::size_t GetNumberOfCells(LevelID level) const = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
357
unit_tests/util/cell_storage.cpp
Normal file
357
unit_tests/util/cell_storage.cpp
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
#include <boost/numeric/conversion/cast.hpp>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include "util/cell_storage.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::util;
|
||||||
|
|
||||||
|
class MockMLP final : public MultiLevelPartition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CellID GetCell(LevelID level, NodeID node) const { return levels[level - 1][node]; };
|
||||||
|
|
||||||
|
LevelID GetHighestDifferentLevel(NodeID, NodeID) const { return 3; };
|
||||||
|
|
||||||
|
std::size_t GetNumberOfLevels() const { return levels.size() + 1; }
|
||||||
|
|
||||||
|
std::size_t GetNumberOfCells(LevelID level) const
|
||||||
|
{
|
||||||
|
auto max_id = 0;
|
||||||
|
for (auto cell : levels[level - 1])
|
||||||
|
max_id = std::max<CellID>(max_id, cell);
|
||||||
|
return max_id + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MockMLP(std::vector<std::vector<CellID>> levels_) : levels(std::move(levels_)) {}
|
||||||
|
|
||||||
|
std::vector<std::vector<CellID>> levels;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MockEdge
|
||||||
|
{
|
||||||
|
NodeID start;
|
||||||
|
NodeID target;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto makeGraph(const std::vector<MockEdge> &mock_edges)
|
||||||
|
{
|
||||||
|
struct EdgeData
|
||||||
|
{
|
||||||
|
bool forward;
|
||||||
|
bool backward;
|
||||||
|
};
|
||||||
|
using Edge = util::StaticGraph<EdgeData>::InputEdge;
|
||||||
|
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, EdgeData{true, false}});
|
||||||
|
edges.push_back(Edge{m.target, m.start, EdgeData{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}};
|
||||||
|
MockMLP mlp{{l1, l2, l3, l4}};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Level 1
|
||||||
|
auto cell_1_0 = storage.GetCell(1, 0);
|
||||||
|
auto cell_1_1 = storage.GetCell(1, 1);
|
||||||
|
auto cell_1_2 = storage.GetCell(1, 2);
|
||||||
|
auto cell_1_3 = storage.GetCell(1, 3);
|
||||||
|
auto cell_1_4 = storage.GetCell(1, 4);
|
||||||
|
auto cell_1_5 = storage.GetCell(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_RANGE(in_range_1_1_3, std::vector<EdgeWeight>{});
|
||||||
|
CHECK_EQUAL_RANGE(in_range_1_2_5, std::vector<EdgeWeight>{1});
|
||||||
|
CHECK_EQUAL_RANGE(in_range_1_3_7, std::vector<EdgeWeight>{2});
|
||||||
|
CHECK_EQUAL_RANGE(in_range_1_5_11, std::vector<EdgeWeight>{3});
|
||||||
|
|
||||||
|
// Level 2
|
||||||
|
auto cell_2_0 = storage.GetCell(2, 0);
|
||||||
|
auto cell_2_1 = storage.GetCell(2, 1);
|
||||||
|
auto cell_2_2 = storage.GetCell(2, 2);
|
||||||
|
auto cell_2_3 = storage.GetCell(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, std::vector<EdgeWeight>{1});
|
||||||
|
CHECK_EQUAL_RANGE(in_range_2_1_4, std::vector<EdgeWeight>{2});
|
||||||
|
CHECK_EQUAL_RANGE(in_range_2_1_7, std::vector<EdgeWeight>{3});
|
||||||
|
CHECK_EQUAL_RANGE(in_range_2_3_11, std::vector<EdgeWeight>{4});
|
||||||
|
|
||||||
|
// Level 3
|
||||||
|
auto cell_3_0 = storage.GetCell(3, 0);
|
||||||
|
auto cell_3_1 = storage.GetCell(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, std::vector<EdgeWeight>({1}));
|
||||||
|
CHECK_EQUAL_RANGE(in_range_3_1_4, std::vector<EdgeWeight>({2, 4}));
|
||||||
|
CHECK_EQUAL_RANGE(in_range_3_1_7, std::vector<EdgeWeight>({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}};
|
||||||
|
MockMLP mlp{{l1, l2, l3, l4}};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
auto const_cell_1_0 = const_storage.GetCell(1, 0);
|
||||||
|
auto const_cell_1_1 = const_storage.GetCell(1, 1);
|
||||||
|
auto const_cell_1_2 = const_storage.GetCell(1, 2);
|
||||||
|
auto const_cell_1_3 = const_storage.GetCell(1, 3);
|
||||||
|
auto const_cell_1_4 = const_storage.GetCell(1, 4);
|
||||||
|
auto const_cell_1_5 = const_storage.GetCell(1, 5);
|
||||||
|
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_0.GetSourceNodes(), std::vector<NodeID>({0}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_1.GetSourceNodes(), std::vector<NodeID>({}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_2.GetSourceNodes(), std::vector<NodeID>({4}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_3.GetSourceNodes(), std::vector<NodeID>({6}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_4.GetSourceNodes(), std::vector<NodeID>({}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_5.GetSourceNodes(), std::vector<NodeID>({11}));
|
||||||
|
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_0.GetDestinationNodes(), std::vector<NodeID>({}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_1.GetDestinationNodes(), std::vector<NodeID>({3}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_2.GetDestinationNodes(), std::vector<NodeID>({5}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_3.GetDestinationNodes(), std::vector<NodeID>({7}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_4.GetDestinationNodes(), std::vector<NodeID>({}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_1_5.GetDestinationNodes(), std::vector<NodeID>({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);
|
||||||
|
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_1_0_0, 0);
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_1_2_4, 1);
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_1_3_6, 1);
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_1_5_11, 1);
|
||||||
|
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_1_1_3, 0);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_1_2_5, 1);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_1_3_7, 1);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_1_5_11, 1);
|
||||||
|
|
||||||
|
// Level 2
|
||||||
|
auto const_cell_2_0 = const_storage.GetCell(2, 0);
|
||||||
|
auto const_cell_2_1 = const_storage.GetCell(2, 1);
|
||||||
|
auto const_cell_2_2 = const_storage.GetCell(2, 2);
|
||||||
|
auto const_cell_2_3 = const_storage.GetCell(2, 3);
|
||||||
|
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_0.GetSourceNodes(), std::vector<NodeID>({0}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_1.GetSourceNodes(), std::vector<NodeID>({4}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_2.GetSourceNodes(), std::vector<NodeID>({}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_3.GetSourceNodes(), std::vector<NodeID>({11}));
|
||||||
|
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_0.GetDestinationNodes(), std::vector<NodeID>({3}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_1.GetDestinationNodes(), std::vector<NodeID>({4, 7}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_2.GetDestinationNodes(), std::vector<NodeID>({}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_2_3.GetDestinationNodes(), std::vector<NodeID>({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);
|
||||||
|
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_2_0_0, 1);
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_2_1_4, 2);
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_2_3_11, 1);
|
||||||
|
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_2_0_3, 1);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_2_1_4, 1);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_2_1_7, 1);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_2_3_7, 1);
|
||||||
|
|
||||||
|
// Level 3
|
||||||
|
auto const_cell_3_0 = const_storage.GetCell(3, 0);
|
||||||
|
auto const_cell_3_1 = const_storage.GetCell(3, 1);
|
||||||
|
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_3_0.GetSourceNodes(), std::vector<NodeID>({0}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_3_1.GetSourceNodes(), std::vector<NodeID>({4, 7}));
|
||||||
|
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_3_0.GetDestinationNodes(), std::vector<NodeID>({3}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_3_1.GetDestinationNodes(), std::vector<NodeID>({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);
|
||||||
|
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_3_0_0, 1);
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_3_1_4, 2);
|
||||||
|
CHECK_SIZE_RANGE(out_const_range_3_1_7, 2);
|
||||||
|
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_3_0_3, 1);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_3_1_4, 2);
|
||||||
|
CHECK_SIZE_RANGE(in_const_range_3_1_7, 2);
|
||||||
|
|
||||||
|
auto const_cell_4_0 = const_storage.GetCell(4, 0);
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_4_0.GetSourceNodes(), std::vector<NodeID>({}));
|
||||||
|
CHECK_EQUAL_RANGE(const_cell_4_0.GetDestinationNodes(), std::vector<NodeID>({}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user