Add class to translate from bisection ids to cell ids

This commit is contained in:
Patrick Niklaus
2017-03-05 20:31:45 +00:00
committed by Patrick Niklaus
parent b2f3b901e0
commit 8f9e980945
6 changed files with 558 additions and 126 deletions
+138
View File
@@ -0,0 +1,138 @@
#include "partition/bisection_to_partition.hpp"
namespace osrm
{
namespace partition
{
namespace
{
struct CellBisection
{
std::uint32_t begin;
std::uint32_t end;
std::uint8_t depth;
bool tabu; // we will not attempt to split this cell anymore
};
static constexpr std::size_t NUM_BISECTION_BITS = sizeof(BisectionID) * CHAR_BIT;
bool getSide(std::uint8_t depth, BisectionID id)
{
return id & (1UL << (NUM_BISECTION_BITS - 1 - depth));
}
std::vector<std::uint32_t> getLargeCells(const std::size_t max_cell_size,
const std::vector<CellBisection> &cells)
{
std::vector<std::uint32_t> large_cells;
for (auto index = 0u; index < cells.size(); ++index)
{
if (!cells[index].tabu && cells[index].end - cells[index].begin > max_cell_size)
large_cells.push_back(index);
}
return large_cells;
}
Partition cellsToPartition(const std::vector<CellBisection> &cells,
const std::vector<std::uint32_t> &permutation)
{
Partition partition(permutation.size(), INVALID_CELL_ID);
CellID cell_id = 0;
for (const auto &cell : cells)
{
std::for_each(permutation.begin() + cell.begin,
permutation.begin() + cell.end,
[&partition, cell_id](const auto node_id) { partition[node_id] = cell_id; });
cell_id++;
}
return partition;
}
void partitionLevel(const std::vector<BisectionID> &node_to_bisection_id,
std::size_t max_cell_size,
std::vector<std::uint32_t> &permutation,
std::vector<CellBisection> &cells)
{
for (auto large_cells = getLargeCells(max_cell_size, cells); large_cells.size() > 0;
large_cells = getLargeCells(max_cell_size, cells))
{
for (const auto cell_index : large_cells)
{
auto &cell = cells[cell_index];
BOOST_ASSERT(cell.depth < NUM_BISECTION_BITS);
// Go over all nodes and sum up the bits to determine at which position the first one bit is
BisectionID sum =
std::accumulate(permutation.begin() + cell.begin,
permutation.begin() + cell.end,
BisectionID{0},
[&node_to_bisection_id](const BisectionID lhs, const NodeID rhs) {
return lhs | node_to_bisection_id[rhs];
});
// masks all bit strictly higher then cell.depth
const BisectionID mask = (1UL << (NUM_BISECTION_BITS - cell.depth)) - 1;
const auto masked_sum = sum & mask;
// we can't split the cell anymore, but it also doesn't conform to the max size constraint
// -> we need to remove it from the optimization
if (masked_sum == 0)
{
cell.tabu = true;
continue;
}
const auto msb = util::msb(sum & mask);
// depth counts from MSB to LSB
const auto depth = NUM_BISECTION_BITS - 1 - msb;
std::uint32_t middle =
std::partition(permutation.begin() + cell.begin,
permutation.begin() + cell.end,
[depth, &node_to_bisection_id](const auto node_id) {
return getSide(depth, node_to_bisection_id[node_id]);
}) -
permutation.begin();
cell.depth = depth + 1;
if (middle != cell.begin && middle != cell.end)
{
auto old_end = cell.end;
cell.end = middle;
cells.push_back(
CellBisection{middle, old_end, static_cast<std::uint8_t>(depth + 1), false});
}
}
}
}
}
// Implements a greedy algorithm that split cells using the bisection until a target cell size is
// reached
std::tuple<std::vector<Partition>, std::vector<std::uint32_t>>
bisectionToPartition(const std::vector<BisectionID> &node_to_bisection_id,
const std::vector<std::size_t> &max_cell_sizes)
{
std::vector<std::uint32_t> permutation(node_to_bisection_id.size());
std::iota(permutation.begin(), permutation.end(), 0);
std::vector<CellBisection> cells;
cells.push_back(CellBisection{0, static_cast<std::uint32_t>(node_to_bisection_id.size()), 0, false});
std::vector<Partition> partitions(max_cell_sizes.size());
std::vector<std::uint32_t> num_cells(max_cell_sizes.size());
auto level_idx = max_cell_sizes.size() - 1;
for (auto max_cell_size : boost::adaptors::reverse(max_cell_sizes))
{
partitionLevel(node_to_bisection_id, max_cell_size, permutation, cells);
partitions[level_idx] = cellsToPartition(cells, permutation);
num_cells[level_idx] = cells.size();
level_idx--;
}
return std::make_tuple(std::move(partitions), std::move(num_cells));
}
}
}
+19 -104
View File
@@ -1,12 +1,12 @@
#include "partition/partitioner.hpp"
#include "partition/annotated_partition.hpp"
#include "partition/bisection_graph.hpp"
#include "partition/bisection_to_partition.hpp"
#include "partition/compressed_node_based_graph_reader.hpp"
#include "partition/edge_based_graph_reader.hpp"
#include "partition/io.hpp"
#include "partition/multi_level_partition.hpp"
#include "partition/node_based_graph_to_edge_based_graph_mapping_reader.hpp"
#include "partition/recursive_bisection.hpp"
#include "partition/multi_level_partition.hpp"
#include "util/coordinate.hpp"
#include "util/geojson_debug_logger.hpp"
@@ -32,27 +32,6 @@ namespace osrm
namespace partition
{
void LogStatistics(const std::string &filename, std::vector<std::uint32_t> bisection_ids)
{
auto compressed_node_based_graph = LoadCompressedNodeBasedGraph(filename);
util::Log() << "Loaded compressed node based graph: "
<< compressed_node_based_graph.edges.size() << " edges, "
<< compressed_node_based_graph.coordinates.size() << " nodes";
groupEdgesBySource(begin(compressed_node_based_graph.edges),
end(compressed_node_based_graph.edges));
auto graph =
makeBisectionGraph(compressed_node_based_graph.coordinates,
adaptToBisectionEdge(std::move(compressed_node_based_graph.edges)));
TIMER_START(annotation);
AnnotatedPartition partition(graph, bisection_ids);
TIMER_STOP(annotation);
std::cout << "Annotation took " << TIMER_SEC(annotation) << " seconds" << std::endl;
}
void LogGeojson(const std::string &filename, const std::vector<std::uint32_t> &bisection_ids)
{
// reload graph, since we destroyed the old one
@@ -138,9 +117,6 @@ int Partitioner::Run(const PartitionConfig &config)
config.num_optimizing_cuts,
config.small_component_size);
LogStatistics(config.compressed_node_based_graph_path.string(),
recursive_bisection.BisectionIDs());
// Up until now we worked on the compressed node based graph.
// But what we actually need is a partition for the edge based graph to work on.
// The following loads a mapping from node based graph to edge based graph.
@@ -184,87 +160,26 @@ int Partitioner::Run(const PartitionConfig &config)
}
}
// FIXME The CellID computation code need to be replaced by a more sophisticated method
{
BOOST_ASSERT(edge_based_partition_ids.size() == edge_based_graph->GetNumberOfNodes());
std::vector<Partition> partitions;
std::vector<std::uint32_t> level_to_num_cells;
std::tie(partitions, level_to_num_cells) = bisectionToPartition(edge_based_partition_ids,
{128, 128 * 32, 128 * 32 * 16, 128 * 32 * 16 * 32});
using namespace osrm::partition;
TIMER_START(packed_mlp);
MultiLevelPartition mlp{partitions, level_to_num_cells};
TIMER_STOP(packed_mlp);
util::Log() << "MultiLevelPartition constructed in " << TIMER_SEC(packed_mlp) << " seconds";
// find bit size of bisection ids
int first_nonzero_position = sizeof(BisectionID) * CHAR_BIT;
for (auto id : edge_based_partition_ids)
{
first_nonzero_position = id == 0 ? first_nonzero_position
: std::min(first_nonzero_position, __builtin_ctz(id));
}
BOOST_ASSERT(first_nonzero_position != sizeof(BisectionID) * CHAR_BIT);
TIMER_START(cell_storage);
CellStorage storage(mlp, *edge_based_graph);
TIMER_STOP(cell_storage);
util::Log() << "CellStorage constructed in " << TIMER_SEC(cell_storage) << " seconds";
// split bisection id bits into groups starting from SCC and stop at level 1
BOOST_ASSERT(recursive_bisection.SCCDepth() != 0);
int mask_from = sizeof(BisectionID) * CHAR_BIT - recursive_bisection.SCCDepth();
std::vector<BisectionID> level_masks;
for (int mask_to = sizeof(BisectionID) * CHAR_BIT; mask_to > first_nonzero_position;
mask_to = mask_from, mask_from -= 3) // TODO: find better grouping
{
auto bit = std::max(first_nonzero_position, mask_from);
level_masks.push_back(((1u << (sizeof(BisectionID) * CHAR_BIT - bit)) - 1) << bit);
}
util::Log() << "Bisection IDs split for SCC depth " << recursive_bisection.SCCDepth()
<< " and first non-zero bit position " << first_nonzero_position
<< " number of levels is " << level_masks.size();
for (auto x : level_masks)
std::cout << std::setw(8) << std::hex << x << std::dec << "\n";
// collect cell ids as masked bisection ids
std::vector<std::vector<CellID>> partitions(
level_masks.size(), std::vector<CellID>(edge_based_partition_ids.size()));
std::vector<std::unordered_set<CellID>> partition_sets(level_masks.size());
for (std::size_t index = 0; index < edge_based_partition_ids.size(); ++index)
{
auto bisection_id = edge_based_partition_ids[index];
for (std::size_t level = 0; level < level_masks.size(); ++level)
{
CellID cell_id =
bisection_id & level_masks[level_masks.size() - 1 - level];
partitions[level][index] = cell_id;
partition_sets[level].insert(cell_id);
}
}
std::vector<std::uint32_t> level_to_num_cells;
std::transform(partition_sets.begin(),
partition_sets.end(),
std::back_inserter(level_to_num_cells),
[](const std::unordered_set<CellID> &partition_set) {
return partition_set.size();
});
std::cout << "# of cell on levels\n";
for (std::size_t level = 0; level < partition_sets.size(); ++level)
{
std::cout << level_to_num_cells[level] << ": ";
for (auto x : partition_sets[level])
std::cout << " " << x;
std::cout << "\n";
}
TIMER_START(packed_mlp);
MultiLevelPartition mlp{partitions, level_to_num_cells};
TIMER_STOP(packed_mlp);
util::Log() << "MultiLevelPartition constructed in " << TIMER_SEC(packed_mlp)
<< " seconds";
TIMER_START(cell_storage);
CellStorage storage(mlp, *edge_based_graph);
TIMER_STOP(cell_storage);
util::Log() << "CellStorage constructed in " << TIMER_SEC(cell_storage) << " seconds";
TIMER_START(writing_mld_data);
io::write(config.mld_partition_path, mlp);
io::write(config.mld_storage_path, storage);
TIMER_STOP(writing_mld_data);
util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds";
}
TIMER_START(writing_mld_data);
io::write(config.mld_partition_path, mlp);
io::write(config.mld_storage_path, storage);
TIMER_STOP(writing_mld_data);
util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds";
return 0;
}