235 lines
9.4 KiB
C++
235 lines
9.4 KiB
C++
#include "partition/partitioner.hpp"
|
|
#include "partition/bisection_graph.hpp"
|
|
#include "partition/bisection_to_partition.hpp"
|
|
#include "partition/cell_storage.hpp"
|
|
#include "partition/compressed_node_based_graph_reader.hpp"
|
|
#include "partition/edge_based_graph_reader.hpp"
|
|
#include "partition/files.hpp"
|
|
#include "partition/multi_level_partition.hpp"
|
|
#include "partition/recursive_bisection.hpp"
|
|
#include "partition/remove_unconnected.hpp"
|
|
#include "partition/renumber.hpp"
|
|
|
|
#include "extractor/files.hpp"
|
|
|
|
#include "util/coordinate.hpp"
|
|
#include "util/geojson_debug_logger.hpp"
|
|
#include "util/geojson_debug_policies.hpp"
|
|
#include "util/integer_range.hpp"
|
|
#include "util/json_container.hpp"
|
|
#include "util/log.hpp"
|
|
#include "util/mmap_file.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <vector>
|
|
|
|
#include <boost/assert.hpp>
|
|
#include <boost/filesystem/operations.hpp>
|
|
|
|
#include "util/geojson_debug_logger.hpp"
|
|
#include "util/geojson_debug_policies.hpp"
|
|
#include "util/json_container.hpp"
|
|
#include "util/timing_util.hpp"
|
|
|
|
namespace osrm
|
|
{
|
|
namespace partition
|
|
{
|
|
|
|
void LogGeojson(const std::string &filename, const std::vector<std::uint32_t> &bisection_ids)
|
|
{
|
|
// reload graph, since we destroyed the old one
|
|
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)));
|
|
|
|
const auto get_level = [](const std::uint32_t lhs, const std::uint32_t rhs) {
|
|
auto xored = lhs ^ rhs;
|
|
std::uint32_t level = log(xored) / log(2.0);
|
|
return level;
|
|
};
|
|
|
|
std::vector<std::vector<util::Coordinate>> border_vertices(33);
|
|
|
|
for (NodeID nid = 0; nid < graph.NumberOfNodes(); ++nid)
|
|
{
|
|
const auto source_id = bisection_ids[nid];
|
|
for (const auto &edge : graph.Edges(nid))
|
|
{
|
|
const auto target_id = bisection_ids[edge.target];
|
|
if (source_id != target_id)
|
|
{
|
|
auto level = get_level(source_id, target_id);
|
|
border_vertices[level].push_back(graph.Node(nid).coordinate);
|
|
border_vertices[level].push_back(graph.Node(edge.target).coordinate);
|
|
}
|
|
}
|
|
}
|
|
|
|
util::ScopedGeojsonLoggerGuard<util::CoordinateVectorToMultiPoint> guard(
|
|
"border_vertices.geojson");
|
|
std::size_t level = 0;
|
|
for (auto &bv : border_vertices)
|
|
{
|
|
if (!bv.empty())
|
|
{
|
|
std::sort(bv.begin(), bv.end(), [](const auto lhs, const auto rhs) {
|
|
return std::tie(lhs.lon, lhs.lat) < std::tie(rhs.lon, rhs.lat);
|
|
});
|
|
bv.erase(std::unique(bv.begin(), bv.end()), bv.end());
|
|
|
|
util::json::Object jslevel;
|
|
jslevel.values["level"] = util::json::Number(level++);
|
|
guard.Write(bv, jslevel);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto getGraphBisection(const PartitionConfig &config)
|
|
{
|
|
auto compressed_node_based_graph =
|
|
LoadCompressedNodeBasedGraph(config.GetPath(".osrm.cnbg").string());
|
|
|
|
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)));
|
|
|
|
util::Log() << " running partition: " << config.max_cell_sizes.front() << " " << config.balance
|
|
<< " " << config.boundary_factor << " " << config.num_optimizing_cuts << " "
|
|
<< config.small_component_size
|
|
<< " # max_cell_size balance boundary cuts small_component_size";
|
|
RecursiveBisection recursive_bisection(graph,
|
|
config.max_cell_sizes.front(),
|
|
config.balance,
|
|
config.boundary_factor,
|
|
config.num_optimizing_cuts,
|
|
config.small_component_size);
|
|
|
|
// Return bisection ids, keyed by node based graph nodes
|
|
return recursive_bisection.BisectionIDs();
|
|
}
|
|
|
|
int Partitioner::Run(const PartitionConfig &config)
|
|
{
|
|
const std::vector<BisectionID> &node_based_partition_ids = getGraphBisection(config);
|
|
|
|
// 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.
|
|
// Then loads the edge based graph tanslates the partition and modifies it.
|
|
// For details see #3205
|
|
|
|
std::vector<extractor::NBGToEBG> mapping;
|
|
extractor::files::readNBGMapping(config.GetPath(".osrm.cnbg_to_ebg").string(), mapping);
|
|
util::Log() << "Loaded node based graph to edge based graph mapping";
|
|
|
|
auto edge_based_graph = LoadEdgeBasedGraph(config.GetPath(".osrm.ebg").string());
|
|
util::Log() << "Loaded edge based graph for mapping partition ids: "
|
|
<< edge_based_graph.GetNumberOfEdges() << " edges, "
|
|
<< edge_based_graph.GetNumberOfNodes() << " nodes";
|
|
|
|
// Partition ids, keyed by edge based graph nodes
|
|
std::vector<NodeID> edge_based_partition_ids(edge_based_graph.GetNumberOfNodes(),
|
|
SPECIAL_NODEID);
|
|
|
|
// Only resolve all easy cases in the first pass
|
|
for (const auto &entry : mapping)
|
|
{
|
|
const auto u = entry.u;
|
|
const auto v = entry.v;
|
|
const auto forward_node = entry.forward_ebg_node;
|
|
const auto backward_node = entry.backward_ebg_node;
|
|
|
|
// This heuristic strategy seems to work best, even beating chosing the minimum
|
|
// border edge bisection ID
|
|
edge_based_partition_ids[forward_node] = node_based_partition_ids[u];
|
|
if (backward_node != SPECIAL_NODEID)
|
|
edge_based_partition_ids[backward_node] = node_based_partition_ids[v];
|
|
}
|
|
|
|
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, config.max_cell_sizes);
|
|
|
|
auto num_unconnected = removeUnconnectedBoundaryNodes(edge_based_graph, partitions);
|
|
util::Log() << "Fixed " << num_unconnected << " unconnected nodes";
|
|
|
|
util::Log() << "Edge-based-graph annotation:";
|
|
for (std::size_t level = 0; level < level_to_num_cells.size(); ++level)
|
|
{
|
|
util::Log() << " level " << level + 1 << " #cells " << level_to_num_cells[level]
|
|
<< " bit size " << std::ceil(std::log2(level_to_num_cells[level] + 1));
|
|
}
|
|
|
|
TIMER_START(renumber);
|
|
auto permutation = makePermutation(edge_based_graph, partitions);
|
|
renumber(edge_based_graph, permutation);
|
|
renumber(partitions, permutation);
|
|
{
|
|
renumber(mapping, permutation);
|
|
extractor::files::writeNBGMapping(config.GetPath(".osrm.cnbg_to_ebg").string(), mapping);
|
|
}
|
|
{
|
|
boost::iostreams::mapped_file segment_region;
|
|
auto segments = util::mmapFile<extractor::EdgeBasedNodeSegment>(
|
|
config.GetPath(".osrm.fileIndex"), segment_region);
|
|
renumber(segments, permutation);
|
|
}
|
|
{
|
|
extractor::EdgeBasedNodeDataContainer node_data;
|
|
extractor::files::readNodeData(config.GetPath(".osrm.ebg_nodes"), node_data);
|
|
renumber(node_data, permutation);
|
|
extractor::files::writeNodeData(config.GetPath(".osrm.ebg_nodes"), node_data);
|
|
}
|
|
if (boost::filesystem::exists(config.GetPath(".osrm.hsgr")))
|
|
{
|
|
util::Log(logWARNING) << "Found existing .osrm.hsgr file, removing. You need to re-run "
|
|
"osrm-contract after osrm-partition.";
|
|
boost::filesystem::remove(config.GetPath(".osrm.hsgr"));
|
|
}
|
|
TIMER_STOP(renumber);
|
|
util::Log() << "Renumbered data in " << TIMER_SEC(renumber) << " seconds";
|
|
|
|
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);
|
|
files::writePartition(config.GetPath(".osrm.partition"), mlp);
|
|
files::writeCells(config.GetPath(".osrm.cells"), storage);
|
|
extractor::files::writeEdgeBasedGraph(config.GetPath(".osrm.ebg"),
|
|
edge_based_graph.GetNumberOfNodes(),
|
|
graphToEdges(edge_based_graph));
|
|
TIMER_STOP(writing_mld_data);
|
|
util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds";
|
|
|
|
return 0;
|
|
}
|
|
|
|
} // namespace partition
|
|
} // namespace osrm
|