Implement exclude flags on CH using shared core

The core is fully contracted for each exclude flag
and stored in a merged graph data structure.
This commit is contained in:
Patrick Niklaus
2017-08-20 23:24:05 +00:00
committed by Patrick Niklaus
parent 4b75cb8b0e
commit 61c430c098
42 changed files with 1468 additions and 418 deletions
+32 -27
View File
@@ -1,4 +1,6 @@
#include "contractor/contractor.hpp"
#include "contractor/contract_excludable_graph.hpp"
#include "contractor/contracted_edge_container.hpp"
#include "contractor/crc32_processor.hpp"
#include "contractor/files.hpp"
#include "contractor/graph_contractor.hpp"
@@ -6,6 +8,7 @@
#include "extractor/compressed_edge_container.hpp"
#include "extractor/edge_based_graph_factory.hpp"
#include "extractor/files.hpp"
#include "extractor/node_based_edge.hpp"
#include "storage/io.hpp"
@@ -14,6 +17,8 @@
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/exclude_flag.hpp"
#include "util/filtered_graph.hpp"
#include "util/graph_loader.hpp"
#include "util/integer_range.hpp"
#include "util/log.hpp"
@@ -42,6 +47,11 @@ int Contractor::Run()
throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)" + SOURCE_REF);
}
if (config.use_cached_priority)
{
util::Log(logWARNING) << "Using cached priorities is deprecated and they will be ignored.";
}
TIMER_START(preparing);
util::Log() << "Reading node weights.";
@@ -63,41 +73,36 @@ int Contractor::Run()
// Contracting the edge-expanded graph
TIMER_START(contraction);
std::vector<bool> is_core_node;
std::vector<float> node_levels;
if (config.use_cached_priority)
std::vector<std::vector<bool>> node_filters;
{
files::readLevels(config.GetPath(".osrm.level"), node_levels);
extractor::EdgeBasedNodeDataContainer node_data;
extractor::files::readNodeData(config.GetPath(".osrm.ebg_nodes"), node_data);
extractor::ProfileProperties properties;
extractor::files::readProfileProperties(config.GetPath(".osrm.properties"), properties);
node_filters = util::excludeFlagsToNodeFilter(max_edge_id + 1, node_data, properties);
}
util::DeallocatingVector<QueryEdge> contracted_edge_list;
{ // own scope to not keep the contractor around
auto contractor_graph = toContractorGraph(max_edge_id+1, std::move(edge_based_edge_list));
std::tie(node_levels, is_core_node) = contractGraph(contractor_graph,
std::move(node_levels),
std::move(node_weights),
config.core_factor);
RangebasedCRC32 crc32_calculator;
const unsigned checksum = crc32_calculator(edge_based_edge_list);
contracted_edge_list = toEdges<QueryEdge>(std::move(contractor_graph));
}
QueryGraph query_graph;
std::vector<std::vector<bool>> edge_filters;
std::vector<std::vector<bool>> cores;
std::tie(query_graph, edge_filters, cores) =
contractExcludableGraph(toContractorGraph(max_edge_id + 1, std::move(edge_based_edge_list)),
std::move(node_weights),
std::move(node_filters),
config.core_factor);
TIMER_STOP(contraction);
util::Log() << "Contracted graph has " << query_graph.GetNumberOfEdges() << " edges.";
util::Log() << "Contraction took " << TIMER_SEC(contraction) << " sec";
{
RangebasedCRC32 crc32_calculator;
const unsigned checksum = crc32_calculator(contracted_edge_list);
files::writeGraph(config.GetPath(".osrm.hsgr"), checksum, query_graph, edge_filters);
files::writeGraph(config.GetPath(".osrm.hsgr"),
checksum,
QueryGraph{max_edge_id + 1, std::move(contracted_edge_list)});
}
files::writeCoreMarker(config.GetPath(".osrm.core"), is_core_node);
if (!config.use_cached_priority)
{
files::writeLevels(config.GetPath(".osrm.level"), node_levels);
}
files::writeCoreMarker(config.GetPath(".osrm.core"), cores);
TIMER_STOP(preparing);
@@ -1,23 +1,65 @@
#include "contractor/contractor_dijkstra.hpp"
#include "contractor/contractor_search.hpp"
#include "contractor/contractor_graph.hpp"
#include "contractor/contractor_heap.hpp"
namespace osrm
{
namespace contractor
{
ContractorDijkstra::ContractorDijkstra(const std::size_t heap_size) : heap(heap_size) {}
namespace
{
void relaxNode(ContractorHeap &heap,
const ContractorGraph &graph,
const NodeID node,
const EdgeWeight node_weight,
const NodeID forbidden_node)
{
const short current_hop = heap.GetData(node).hop + 1;
for (auto edge : graph.GetAdjacentEdgeRange(node))
{
const auto &data = graph.GetEdgeData(edge);
if (!data.forward)
{
continue;
}
const NodeID to = graph.GetTarget(edge);
BOOST_ASSERT(to != SPECIAL_NODEID);
if (forbidden_node == to)
{
continue;
}
const EdgeWeight to_weight = node_weight + data.weight;
void ContractorDijkstra::Run(const unsigned number_of_targets,
const int node_limit,
const EdgeWeight weight_limit,
const NodeID forbidden_node,
const ContractorGraph &graph)
// New Node discovered -> Add to Heap + Node Info Storage
if (!heap.WasInserted(to))
{
heap.Insert(to, to_weight, ContractorHeapData{current_hop, false});
}
// Found a shorter Path -> Update weight
else if (to_weight < heap.GetKey(to))
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to).hop = current_hop;
}
}
}
}
void search(ContractorHeap &heap,
const ContractorGraph &graph,
const unsigned number_of_targets,
const int node_limit,
const EdgeWeight weight_limit,
const NodeID forbidden_node)
{
int nodes = 0;
unsigned number_of_targets_found = 0;
while (!heap.Empty())
{
const NodeID node = heap.DeleteMin();
BOOST_ASSERT(node != SPECIAL_NODEID);
const auto node_weight = heap.GetKey(node);
if (++nodes > node_limit)
{
@@ -38,59 +80,8 @@ void ContractorDijkstra::Run(const unsigned number_of_targets,
}
}
RelaxNode(node, node_weight, forbidden_node, graph);
relaxNode(heap, graph, node, node_weight, forbidden_node);
}
}
void ContractorDijkstra::RelaxNode(const NodeID node,
const EdgeWeight node_weight,
const NodeID forbidden_node,
const ContractorGraph &graph)
{
const short current_hop = heap.GetData(node).hop + 1;
for (auto edge : graph.GetAdjacentEdgeRange(node))
{
const ContractorEdgeData &data = graph.GetEdgeData(edge);
if (!data.forward)
{
continue;
}
const NodeID to = graph.GetTarget(edge);
if (forbidden_node == to)
{
continue;
}
const EdgeWeight to_weight = node_weight + data.weight;
// New Node discovered -> Add to Heap + Node Info Storage
if (!heap.WasInserted(to))
{
heap.Insert(to, to_weight, ContractorHeapData{current_hop, false});
}
// Found a shorter Path -> Update weight
else if (to_weight < GetKey(to))
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to).hop = current_hop;
}
}
}
void ContractorDijkstra::Clear() { heap.Clear(); }
bool ContractorDijkstra::WasInserted(const NodeID node) const { return heap.WasInserted(node); }
void ContractorDijkstra::Insert(const NodeID node,
const ContractorHeap::WeightType weight,
const ContractorHeap::DataType &data)
{
heap.Insert(node, weight, data);
}
ContractorHeap::WeightType ContractorDijkstra::GetKey(const NodeID node)
{
return heap.GetKey(node);
}
} // namespace contractor
} // namespace osrm
+124 -125
View File
@@ -1,6 +1,6 @@
#include "contractor/graph_contractor.hpp"
#include "contractor/contractor_dijkstra.hpp"
#include "contractor/contractor_graph.hpp"
#include "contractor/contractor_search.hpp"
#include "contractor/query_edge.hpp"
#include "util/deallocating_vector.hpp"
#include "util/integer_range.hpp"
@@ -14,6 +14,7 @@
#include <tbb/enumerable_thread_specific.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_invoke.h>
#include <tbb/parallel_sort.h>
#include <algorithm>
@@ -29,10 +30,10 @@ namespace
{
struct ContractorThreadData
{
ContractorDijkstra dijkstra;
ContractorHeap heap;
std::vector<ContractorEdge> inserted_edges;
std::vector<NodeID> neighbours;
explicit ContractorThreadData(NodeID nodes) : dijkstra(nodes) {}
explicit ContractorThreadData(NodeID nodes) : heap(nodes) {}
};
struct ContractorNodeData
@@ -42,34 +43,37 @@ struct ContractorNodeData
using NodeLevel = float;
ContractorNodeData(std::size_t number_of_nodes,
std::vector<NodePriority> priorities_,
std::vector<bool> uncontracted_nodes_,
std::vector<bool> contractable_,
std::vector<EdgeWeight> weights_)
: is_core(number_of_nodes, true), priorities(std::move(priorities_)),
weights(std::move(weights_))
: is_core(std::move(uncontracted_nodes_)), contractable(std::move(contractable_)),
priorities(number_of_nodes), weights(std::move(weights_)), depths(number_of_nodes, 0)
{
// no cached priorities
if (priorities.empty())
if (contractable.empty())
{
depths.resize(number_of_nodes, 0);
levels.resize(number_of_nodes);
priorities.resize(number_of_nodes);
contractable.resize(number_of_nodes, true);
}
if (is_core.empty())
{
is_core.resize(number_of_nodes, true);
}
}
void Renumber(const std::vector<NodeID> &old_to_new)
{
util::inplacePermutation(priorities.begin(), priorities.end(), old_to_new);
util::inplacePermutation(weights.begin(), weights.end(), old_to_new);
util::inplacePermutation(levels.begin(), levels.end(), old_to_new);
util::inplacePermutation(is_core.begin(), is_core.end(), old_to_new);
util::inplacePermutation(depths.begin(), depths.end(), old_to_new);
tbb::parallel_invoke(
[&] { util::inplacePermutation(priorities.begin(), priorities.end(), old_to_new); },
[&] { util::inplacePermutation(weights.begin(), weights.end(), old_to_new); },
[&] { util::inplacePermutation(is_core.begin(), is_core.end(), old_to_new); },
[&] { util::inplacePermutation(contractable.begin(), contractable.end(), old_to_new); },
[&] { util::inplacePermutation(depths.begin(), depths.end(), old_to_new); });
}
std::vector<bool> is_core;
std::vector<bool> contractable;
std::vector<NodePriority> priorities;
std::vector<EdgeWeight> weights;
std::vector<NodeDepth> depths;
std::vector<NodeLevel> levels;
};
struct ContractionStats
@@ -87,7 +91,8 @@ struct ContractionStats
struct RemainingNodeData
{
RemainingNodeData() : id(0), is_independent(false) {}
RemainingNodeData() = default;
RemainingNodeData(NodeID id, bool is_independent) : id(id), is_independent(is_independent) {}
NodeID id : 31;
bool is_independent : 1;
};
@@ -102,8 +107,7 @@ struct ThreadDataContainer
auto &ref = data.local(exists);
if (!exists)
{
// ref = std::make_shared<ContractorThreadData>(number_of_nodes);
ref = std::make_shared<ContractorThreadData>(4000);
ref = std::make_shared<ContractorThreadData>(number_of_nodes);
}
return ref.get();
@@ -130,14 +134,14 @@ inline bool Bias(const util::XORFastHash<> &fast_hash, const NodeID a, const Nod
return a < b;
}
template <bool RUNSIMULATION>
template <bool RUNSIMULATION, typename ContractorGraph>
void ContractNode(ContractorThreadData *data,
const ContractorGraph &graph,
const NodeID node,
std::vector<EdgeWeight> &node_weights,
ContractionStats *stats = nullptr)
{
auto &dijkstra = data->dijkstra;
auto &heap = data->heap;
std::size_t inserted_edges_size = data->inserted_edges.size();
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
constexpr bool SHORTCUT_ARC = true;
@@ -164,8 +168,8 @@ void ContractNode(ContractorThreadData *data,
continue;
}
dijkstra.Clear();
dijkstra.Insert(source, 0, ContractorHeapData{});
heap.Clear();
heap.Insert(source, 0, ContractorHeapData{});
EdgeWeight max_weight = 0;
unsigned number_of_targets = 0;
@@ -230,9 +234,9 @@ void ContractNode(ContractorThreadData *data,
continue;
}
max_weight = std::max(max_weight, path_weight);
if (!dijkstra.WasInserted(target))
if (!heap.WasInserted(target))
{
dijkstra.Insert(target, INVALID_EDGE_WEIGHT, ContractorHeapData{0, true});
heap.Insert(target, INVALID_EDGE_WEIGHT, ContractorHeapData{0, true});
++number_of_targets;
}
}
@@ -240,12 +244,12 @@ void ContractNode(ContractorThreadData *data,
if (RUNSIMULATION)
{
const int constexpr SIMULATION_SEARCH_SPACE_SIZE = 1000;
dijkstra.Run(number_of_targets, SIMULATION_SEARCH_SPACE_SIZE, max_weight, node, graph);
search(heap, graph, number_of_targets, SIMULATION_SEARCH_SPACE_SIZE, max_weight, node);
}
else
{
const int constexpr FULL_SEARCH_SPACE_SIZE = 2000;
dijkstra.Run(number_of_targets, FULL_SEARCH_SPACE_SIZE, max_weight, node, graph);
search(heap, graph, number_of_targets, FULL_SEARCH_SPACE_SIZE, max_weight, node);
}
for (auto out_edge : graph.GetAdjacentEdgeRange(node))
{
@@ -259,7 +263,7 @@ void ContractNode(ContractorThreadData *data,
continue;
const EdgeWeight path_weight = in_data.weight + out_data.weight;
const EdgeWeight weight = dijkstra.GetKey(target);
const EdgeWeight weight = heap.GetKey(target);
if (path_weight < weight)
{
if (RUNSIMULATION)
@@ -371,9 +375,9 @@ void RenumberGraph(ContractorGraph &graph, const std::vector<NodeID> &old_to_new
/* Reorder nodes for better locality during contraction */
void RenumberData(std::vector<RemainingNodeData> &remaining_nodes,
std::vector<NodeID> &new_to_old_node_id,
ContractorNodeData &node_data,
ContractorGraph &graph)
std::vector<NodeID> &new_to_old_node_id,
ContractorNodeData &node_data,
ContractorGraph &graph)
{
std::vector<NodeID> current_to_new_node_id(graph.GetNumberOfNodes(), SPECIAL_NODEID);
@@ -407,7 +411,8 @@ void RenumberData(std::vector<RemainingNodeData> &remaining_nodes,
RenumberGraph(graph, current_to_new_node_id);
}
float EvaluateNodePriority(const ContractionStats &stats, const ContractorNodeData::NodeDepth node_depth)
float EvaluateNodePriority(const ContractionStats &stats,
const ContractorNodeData::NodeDepth node_depth)
{
// Result will contain the priority
float result;
@@ -476,14 +481,18 @@ bool UpdateNodeNeighbours(ContractorNodeData &node_data,
// re-evaluate priorities of neighboring nodes
for (const NodeID u : neighbours)
{
node_data.priorities[u] = EvaluateNodePriority(
SimulateNodeContraction(data, graph, u, node_data.weights), node_data.depths[u]);
if (node_data.contractable[u])
{
node_data.priorities[u] = EvaluateNodePriority(
SimulateNodeContraction(data, graph, u, node_data.weights), node_data.depths[u]);
}
}
return true;
}
bool IsNodeIndependent(const util::XORFastHash<> &hash,
const std::vector<float> &priorities,
const std::vector<NodeID> &new_to_old_node_id,
const ContractorGraph &graph,
ContractorThreadData *const data,
const NodeID node)
@@ -509,7 +518,7 @@ bool IsNodeIndependent(const util::XORFastHash<> &hash,
}
// tie breaking
if (std::abs(priority - target_priority) < std::numeric_limits<float>::epsilon() &&
Bias(hash, node, target))
Bias(hash, new_to_old_node_id[node], new_to_old_node_id[target]))
{
return false;
}
@@ -538,7 +547,7 @@ bool IsNodeIndependent(const util::XORFastHash<> &hash,
}
// tie breaking
if (std::abs(priority - target_priority) < std::numeric_limits<float>::epsilon() &&
Bias(hash, node, target))
Bias(hash, new_to_old_node_id[node], new_to_old_node_id[target]))
{
return false;
}
@@ -548,15 +557,16 @@ bool IsNodeIndependent(const util::XORFastHash<> &hash,
}
}
LevelAndCore contractGraph(ContractorGraph &graph,
std::vector<float> cached_node_levels_,
std::vector<EdgeWeight> node_weights_,
double core_factor)
std::vector<bool> contractGraph(ContractorGraph &graph,
std::vector<bool> node_is_uncontracted_,
std::vector<bool> node_is_contractable_,
std::vector<EdgeWeight> node_weights_,
double core_factor)
{
BOOST_ASSERT(node_weights_.size() == graph.GetNumberOfNodes());
util::XORFastHash<> fast_hash;
// for the preperation we can use a big grain size, which is much faster (probably cache)
const constexpr size_t InitGrainSize = 100000;
const constexpr size_t PQGrainSize = 100000;
// auto_partitioner will automatically increase the blocksize if we have
// a lot of data. It is *important* for the last loop iterations
@@ -575,56 +585,71 @@ LevelAndCore contractGraph(ContractorGraph &graph,
// Fill the map with an identiy mapping
std::iota(new_to_old_node_id.begin(), new_to_old_node_id.end(), 0);
bool use_cached_node_priorities = !cached_node_levels_.empty();
ContractorNodeData node_data{
graph.GetNumberOfNodes(), std::move(cached_node_levels_), std::move(node_weights_)};
ContractorNodeData node_data{graph.GetNumberOfNodes(),
std::move(node_is_uncontracted_),
std::move(node_is_contractable_),
std::move(node_weights_)};
std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
// initialize priorities in parallel
tbb::parallel_for(tbb::blocked_range<NodeID>(0, number_of_nodes, InitGrainSize),
[&remaining_nodes](const tbb::blocked_range<NodeID> &range) {
for (auto x = range.begin(), end = range.end(); x != end; ++x)
{
remaining_nodes[x].id = x;
}
});
std::vector<RemainingNodeData> remaining_nodes;
remaining_nodes.reserve(number_of_nodes);
for (auto node : util::irange<NodeID>(0, number_of_nodes))
{
if (node_data.is_core[node])
{
if (node_data.contractable[node])
{
remaining_nodes.emplace_back(node, false);
}
else
{
node_data.priorities[node] =
std::numeric_limits<ContractorNodeData::NodePriority>::max();
}
}
else
{
node_data.priorities[node] = 0;
}
}
if (!use_cached_node_priorities)
{
util::UnbufferedLog log;
log << "initializing node priorities...";
tbb::parallel_for(
tbb::blocked_range<NodeID>(0, number_of_nodes, PQGrainSize),
[&node_data, &graph, &thread_data_list](const tbb::blocked_range<NodeID> &range) {
ContractorThreadData *data = thread_data_list.GetThreadData();
for (auto x = range.begin(), end = range.end(); x != end; ++x)
{
node_data.priorities[x] = EvaluateNodePriority(
SimulateNodeContraction(data, graph, x, node_data.weights),
node_data.depths[x]);
}
});
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), PQGrainSize),
[&](const auto &range) {
ContractorThreadData *data = thread_data_list.GetThreadData();
for (auto x = range.begin(), end = range.end(); x != end; ++x)
{
auto node = remaining_nodes[x].id;
BOOST_ASSERT(node_data.contractable[node]);
node_data.priorities[node] = EvaluateNodePriority(
SimulateNodeContraction(data, graph, node, node_data.weights),
node_data.depths[node]);
}
});
log << " ok.";
}
util::Log() << "preprocessing " << number_of_nodes << " nodes...";
auto number_of_core_nodes = std::max<std::size_t>(0, (1 - core_factor) * number_of_nodes);
auto number_of_nodes_to_contract = remaining_nodes.size() - number_of_core_nodes;
util::Log() << "preprocessing " << number_of_nodes_to_contract << " ("
<< (number_of_nodes_to_contract / (float)number_of_nodes * 100.) << "%) nodes...";
util::UnbufferedLog log;
util::Percent p(log, number_of_nodes);
util::Percent p(log, remaining_nodes.size());
const util::XORFastHash<> hash;
unsigned current_level = 0;
std::size_t next_renumbering = number_of_nodes * 0.65 * core_factor;
while (remaining_nodes.size() > 1 &&
number_of_contracted_nodes < static_cast<NodeID>(number_of_nodes * core_factor))
std::size_t next_renumbering = number_of_nodes * 0.35;
while (remaining_nodes.size() > number_of_core_nodes)
{
if (number_of_contracted_nodes > next_renumbering)
if (remaining_nodes.size() < next_renumbering)
{
RenumberData(remaining_nodes, new_to_old_node_id, node_data, graph);
log << "[renumbered]";
// only one renumbering for now
next_renumbering = number_of_nodes;
next_renumbering = 0;
}
tbb::parallel_for(
@@ -635,8 +660,8 @@ LevelAndCore contractGraph(ContractorGraph &graph,
for (auto i = range.begin(), end = range.end(); i != end; ++i)
{
const NodeID node = remaining_nodes[i].id;
remaining_nodes[i].is_independent =
IsNodeIndependent(hash, node_data.priorities, graph, data, node);
remaining_nodes[i].is_independent = IsNodeIndependent(
hash, node_data.priorities, new_to_old_node_id, graph, data, node);
}
});
@@ -649,21 +674,6 @@ LevelAndCore contractGraph(ContractorGraph &graph,
std::distance(remaining_nodes.begin(), begin_independent_nodes);
auto end_independent_nodes_idx = remaining_nodes.size();
if (!use_cached_node_priorities)
{
// write out contraction level
tbb::parallel_for(
tbb::blocked_range<NodeID>(
begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
[&](const auto &range) {
for (auto position = range.begin(), end = range.end(); position != end;
++position)
{
node_data.levels[remaining_nodes[position].id] = current_level;
}
});
}
// contract independent nodes
tbb::parallel_for(
tbb::blocked_range<NodeID>(
@@ -673,11 +683,17 @@ LevelAndCore contractGraph(ContractorGraph &graph,
for (auto position = range.begin(), end = range.end(); position != end; ++position)
{
const NodeID node = remaining_nodes[position].id;
node_data.is_core[node] = false;
ContractNode(data, graph, node, node_data.weights);
}
});
// core flags need to be set in serial since vector<bool> is not thread safe
for (auto position :
util::irange<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx))
{
node_data.is_core[remaining_nodes[position].id] = false;
}
tbb::parallel_for(
tbb::blocked_range<NodeID>(
begin_independent_nodes_idx, end_independent_nodes_idx, DeleteGrainSize),
@@ -691,12 +707,10 @@ LevelAndCore contractGraph(ContractorGraph &graph,
});
// make sure we really sort each block
tbb::parallel_for(thread_data_list.data.range(),
[&](const auto &range) {
for (auto &data : range)
tbb::parallel_sort(data->inserted_edges.begin(),
data->inserted_edges.end());
});
tbb::parallel_for(thread_data_list.data.range(), [&](const auto &range) {
for (auto &data : range)
tbb::parallel_sort(data->inserted_edges.begin(), data->inserted_edges.end());
});
// insert new edges
for (auto &data : thread_data_list.data)
@@ -706,7 +720,7 @@ LevelAndCore contractGraph(ContractorGraph &graph,
const EdgeID current_edge_ID = graph.FindEdge(edge.source, edge.target);
if (current_edge_ID != SPECIAL_EDGEID)
{
ContractorGraph::EdgeData &current_data = graph.GetEdgeData(current_edge_ID);
auto &current_data = graph.GetEdgeData(current_edge_ID);
if (current_data.shortcut && edge.data.forward == current_data.forward &&
edge.data.backward == current_data.backward)
{
@@ -724,22 +738,17 @@ LevelAndCore contractGraph(ContractorGraph &graph,
data->inserted_edges.clear();
}
if (!use_cached_node_priorities)
{
tbb::parallel_for(
tbb::blocked_range<NodeID>(
begin_independent_nodes_idx, end_independent_nodes_idx, NeighboursGrainSize),
[&](
const auto &range) {
ContractorThreadData *data = thread_data_list.GetThreadData();
for (auto position = range.begin(), end = range.end(); position != end;
++position)
{
NodeID node = remaining_nodes[position].id;
UpdateNodeNeighbours(node_data, data, graph, node);
}
});
}
tbb::parallel_for(
tbb::blocked_range<NodeID>(
begin_independent_nodes_idx, end_independent_nodes_idx, NeighboursGrainSize),
[&](const auto &range) {
ContractorThreadData *data = thread_data_list.GetThreadData();
for (auto position = range.begin(), end = range.end(); position != end; ++position)
{
NodeID node = remaining_nodes[position].id;
UpdateNodeNeighbours(node_data, data, graph, node);
}
});
// remove contracted nodes from the pool
BOOST_ASSERT(end_independent_nodes_idx - begin_independent_nodes_idx > 0);
@@ -749,21 +758,11 @@ LevelAndCore contractGraph(ContractorGraph &graph,
p.PrintStatus(number_of_contracted_nodes);
++current_level;
}
log << "\n";
util::Log() << "[core] " << remaining_nodes.size() << " nodes " << graph.GetNumberOfEdges()
<< " edges.";
node_data.Renumber(new_to_old_node_id);
RenumberGraph(graph, new_to_old_node_id);
if (remaining_nodes.size() <= 2)
{
// in this case we don't need core markers since we fully contracted the graph
node_data.is_core.clear();
}
return LevelAndCore {std::move(node_data.levels), std::move(node_data.is_core)};
return std::move(node_data.is_core);
}
} // namespace contractor
+2 -22
View File
@@ -14,6 +14,7 @@
#include "updater/updater.hpp"
#include "util/exclude_flag.hpp"
#include "util/log.hpp"
#include "util/timing_util.hpp"
@@ -94,27 +95,6 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
return edge_based_graph;
}
std::vector<std::vector<bool>>
excludeFlagsToNodeFilter(const MultiLevelEdgeBasedGraph &graph,
const extractor::EdgeBasedNodeDataContainer &node_data,
const extractor::ProfileProperties &properties)
{
std::vector<std::vector<bool>> filters;
for (auto mask : properties.excludable_classes)
{
if (mask != extractor::INAVLID_CLASS_DATA)
{
std::vector<bool> allowed_nodes(graph.GetNumberOfNodes(), true);
for (const auto node : util::irange<NodeID>(0, graph.GetNumberOfNodes()))
{
allowed_nodes[node] = (node_data.GetClassData(node) & mask) == 0;
}
filters.push_back(std::move(allowed_nodes));
}
}
return filters;
}
std::vector<CellMetric> customizeFilteredMetrics(const MultiLevelEdgeBasedGraph &graph,
const partition::CellStorage &storage,
const CellCustomizer &customizer,
@@ -157,7 +137,7 @@ int Customizer::Run(const CustomizationConfig &config)
util::Log() << "Loading partition data took " << TIMER_SEC(loading_data) << " seconds";
TIMER_START(cell_customize);
auto filter = excludeFlagsToNodeFilter(graph, node_data, properties);
auto filter = util::excludeFlagsToNodeFilter(graph.GetNumberOfNodes(), node_data, properties);
auto metrics = customizeFilteredMetrics(graph, storage, CellCustomizer{mlp}, filter);
TIMER_STOP(cell_customize);
util::Log() << "Cells customization took " << TIMER_SEC(cell_customize) << " seconds";
+8 -5
View File
@@ -16,15 +16,15 @@ BisectionGraphView::BisectionGraphView(const BisectionGraph &bisection_graph_)
}
BisectionGraphView::BisectionGraphView(const BisectionGraph &bisection_graph_,
const BisectionGraph::ConstNodeIterator begin_,
const BisectionGraph::ConstNodeIterator end_)
const BisectionGraph::ConstNodeIterator begin_,
const BisectionGraph::ConstNodeIterator end_)
: bisection_graph(bisection_graph_), begin(begin_), end(end_)
{
}
BisectionGraphView::BisectionGraphView(const BisectionGraphView &other_view,
const BisectionGraph::ConstNodeIterator begin_,
const BisectionGraph::ConstNodeIterator end_)
const BisectionGraph::ConstNodeIterator begin_,
const BisectionGraph::ConstNodeIterator end_)
: BisectionGraphView(other_view.bisection_graph, begin_, end_)
{
}
@@ -42,7 +42,10 @@ BisectionGraph::ConstNodeIterator BisectionGraphView::Begin() const { return beg
BisectionGraph::ConstNodeIterator BisectionGraphView::End() const { return end; }
const BisectionGraphView::NodeT &BisectionGraphView::Node(const NodeID nid) const { return *(begin + nid); }
const BisectionGraphView::NodeT &BisectionGraphView::Node(const NodeID nid) const
{
return *(begin + nid);
}
const BisectionGraphView::EdgeT &BisectionGraphView::Edge(const EdgeID eid) const
{
+2 -1
View File
@@ -18,7 +18,8 @@ namespace
const auto constexpr INVALID_LEVEL = std::numeric_limits<DinicMaxFlow::Level>::max();
auto makeHasNeighborNotInCheck(const DinicMaxFlow::SourceSinkNodes &set, const BisectionGraphView &view)
auto makeHasNeighborNotInCheck(const DinicMaxFlow::SourceSinkNodes &set,
const BisectionGraphView &view)
{
return [&](const NodeID nid) {
const auto is_not_contained = [&set](const BisectionEdge &edge) {
+6 -3
View File
@@ -33,7 +33,8 @@ struct SpatialOrder
// Creates a spatial order of n * sources "first" and n * sink "last" node ids.
// The slope determines the spatial order for sorting node coordinates.
SpatialOrder makeSpatialOrder(const BisectionGraphView &view, const double ratio, const double slope)
SpatialOrder
makeSpatialOrder(const BisectionGraphView &view, const double ratio, const double slope)
{
struct NodeWithCoordinate
{
@@ -89,8 +90,10 @@ SpatialOrder makeSpatialOrder(const BisectionGraphView &view, const double ratio
}
// Makes n cuts with different spatial orders and returns the best.
DinicMaxFlow::MinCut
bestMinCut(const BisectionGraphView &view, const std::size_t n, const double ratio, const double balance)
DinicMaxFlow::MinCut bestMinCut(const BisectionGraphView &view,
const std::size_t n,
const double ratio,
const double balance)
{
DinicMaxFlow::MinCut best;
best.num_edges = -1;
+2 -1
View File
@@ -149,7 +149,8 @@ RecursiveBisectionState::PrePartitionWithSCC(const std::size_t small_component_s
}();
if (!has_small_component)
views.push_back(BisectionGraphView(bisection_graph, bisection_graph.CEnd(), bisection_graph.CEnd()));
views.push_back(
BisectionGraphView(bisection_graph, bisection_graph.CEnd(), bisection_graph.CEnd()));
// apply scc as bisections, we need scc_level bits for this with scc_levels =
// ceil(log_2(components))
+71 -8
View File
@@ -268,12 +268,30 @@ void Storage::PopulateLayout(DataLayout &layout)
reader.Skip<std::uint32_t>(1); // checksum
auto num_nodes = reader.ReadVectorSize<contractor::QueryGraph::NodeArrayEntry>();
auto num_edges = reader.ReadVectorSize<contractor::QueryGraph::EdgeArrayEntry>();
auto num_metrics = reader.ReadElementCount64();
if (num_metrics > NUM_METRICS)
{
throw util::exception("Only " + std::to_string(NUM_METRICS) +
" metrics are supported at the same time.");
}
layout.SetBlockSize<unsigned>(DataLayout::HSGR_CHECKSUM, 1);
layout.SetBlockSize<contractor::QueryGraph::NodeArrayEntry>(DataLayout::CH_GRAPH_NODE_LIST,
num_nodes);
layout.SetBlockSize<contractor::QueryGraph::EdgeArrayEntry>(DataLayout::CH_GRAPH_EDGE_LIST,
num_edges);
for (const auto index : util::irange<std::size_t>(0, num_metrics))
{
layout.SetBlockSize<unsigned>(
static_cast<DataLayout::BlockID>(DataLayout::CH_EDGE_FILTER_0 + index), num_edges);
}
for (const auto index : util::irange<std::size_t>(num_metrics, NUM_METRICS))
{
layout.SetBlockSize<unsigned>(
static_cast<DataLayout::BlockID>(DataLayout::CH_EDGE_FILTER_0 + index), 0);
}
}
else
{
@@ -282,6 +300,11 @@ void Storage::PopulateLayout(DataLayout &layout)
0);
layout.SetBlockSize<contractor::QueryGraph::EdgeArrayEntry>(DataLayout::CH_GRAPH_EDGE_LIST,
0);
for (const auto index : util::irange<std::size_t>(0, NUM_METRICS))
{
layout.SetBlockSize<unsigned>(
static_cast<DataLayout::BlockID>(DataLayout::CH_EDGE_FILTER_0 + index), 0);
}
}
// load rsearch tree size
@@ -313,12 +336,36 @@ void Storage::PopulateLayout(DataLayout &layout)
{
io::FileReader core_marker_file(config.GetPath(".osrm.core"),
io::FileReader::VerifyFingerprint);
const auto num_metrics = core_marker_file.ReadElementCount64();
if (num_metrics > NUM_METRICS)
{
throw util::exception("Only " + std::to_string(NUM_METRICS) +
" metrics are supported at the same time.");
}
const auto number_of_core_markers = core_marker_file.ReadElementCount64();
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER, number_of_core_markers);
for (const auto index : util::irange<std::size_t>(0, num_metrics))
{
layout.SetBlockSize<unsigned>(
static_cast<DataLayout::BlockID>(DataLayout::CH_CORE_MARKER_0 + index),
number_of_core_markers);
}
for (const auto index : util::irange<std::size_t>(num_metrics, NUM_METRICS))
{
layout.SetBlockSize<unsigned>(
static_cast<DataLayout::BlockID>(DataLayout::CH_CORE_MARKER_0 + index), 0);
}
}
else
{
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_0, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_1, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_2, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_3, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_4, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_5, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_6, 0);
layout.SetBlockSize<unsigned>(DataLayout::CH_CORE_MARKER_7, 0);
}
// load turn weight penalties
@@ -577,8 +624,19 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
util::vector_view<contractor::QueryGraphView::EdgeArrayEntry> edge_list(
graph_edges_ptr, layout.num_entries[storage::DataLayout::CH_GRAPH_EDGE_LIST]);
std::vector<util::vector_view<bool>> edge_filter;
for (auto index : util::irange<std::size_t>(0, NUM_METRICS))
{
auto block_id =
static_cast<DataLayout::BlockID>(storage::DataLayout::CH_EDGE_FILTER_0 + index);
auto data_ptr = layout.GetBlockPtr<unsigned, true>(memory_ptr, block_id);
auto num_entries = layout.num_entries[block_id];
edge_filter.emplace_back(data_ptr, num_entries);
}
contractor::QueryGraphView graph_view(std::move(node_list), std::move(edge_list));
contractor::files::readGraph(config.GetPath(".osrm.hsgr"), *checksum, graph_view);
contractor::files::readGraph(
config.GetPath(".osrm.hsgr"), *checksum, graph_view, edge_filter);
}
else
{
@@ -872,12 +930,17 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
if (boost::filesystem::exists(config.GetPath(".osrm.core")))
{
auto core_marker_ptr =
layout.GetBlockPtr<unsigned, true>(memory_ptr, storage::DataLayout::CH_CORE_MARKER);
util::vector_view<bool> is_core_node(
core_marker_ptr, layout.num_entries[storage::DataLayout::CH_CORE_MARKER]);
std::vector<util::vector_view<bool>> cores;
for (auto index : util::irange<std::size_t>(0, NUM_METRICS))
{
auto block_id =
static_cast<DataLayout::BlockID>(storage::DataLayout::CH_CORE_MARKER_0 + index);
auto data_ptr = layout.GetBlockPtr<unsigned, true>(memory_ptr, block_id);
auto num_entries = layout.num_entries[block_id];
cores.emplace_back(data_ptr, num_entries);
}
contractor::files::readCoreMarker(config.GetPath(".osrm.core"), is_core_node);
contractor::files::readCoreMarker(config.GetPath(".osrm.core"), cores);
}
// load profile properties