Refactor contractor to pass in graph directly

This commit is contained in:
Patrick Niklaus 2017-08-18 22:31:04 +00:00 committed by Patrick Niklaus
parent acb7916996
commit 26c909b64b
5 changed files with 123 additions and 129 deletions

View File

@ -95,10 +95,9 @@ class GraphContractor
};
public:
GraphContractor(int nodes, std::vector<ContractorEdge> input_edge_list);
GraphContractor(ContractorGraph graph);
GraphContractor(int nodes,
std::vector<ContractorEdge> edges,
GraphContractor(ContractorGraph graph,
std::vector<float> node_levels_,
std::vector<EdgeWeight> node_weights_);
@ -119,18 +118,18 @@ class GraphContractor
util::UnbufferedLog log;
log << "Getting edges of minimized graph ";
util::Percent p(log, contractor_graph->GetNumberOfNodes());
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
if (contractor_graph->GetNumberOfNodes())
util::Percent p(log, graph.GetNumberOfNodes());
const NodeID number_of_nodes = graph.GetNumberOfNodes();
if (graph.GetNumberOfNodes())
{
Edge new_edge;
for (const auto node : util::irange(0u, number_of_nodes))
{
p.PrintStatus(node);
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto edge : graph.GetAdjacentEdgeRange(node))
{
const NodeID target = contractor_graph->GetTarget(edge);
const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge);
const NodeID target = graph.GetTarget(edge);
const ContractorGraph::EdgeData &data = graph.GetEdgeData(edge);
if (!orig_node_id_from_new_node_id_map.empty())
{
new_edge.source = orig_node_id_from_new_node_id_map[node];
@ -163,7 +162,7 @@ class GraphContractor
}
}
}
contractor_graph.reset();
graph = ContractorGraph{};
orig_node_id_from_new_node_id_map.clear();
orig_node_id_from_new_node_id_map.shrink_to_fit();
@ -198,10 +197,10 @@ class GraphContractor
constexpr bool REVERSE_DIRECTION_ENABLED = true;
constexpr bool REVERSE_DIRECTION_DISABLED = false;
for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto in_edge : graph.GetAdjacentEdgeRange(node))
{
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
const NodeID source = contractor_graph->GetTarget(in_edge);
const ContractorEdgeData &in_data = graph.GetEdgeData(in_edge);
const NodeID source = graph.GetTarget(in_edge);
if (source == node)
continue;
@ -221,14 +220,14 @@ class GraphContractor
EdgeWeight max_weight = 0;
unsigned number_of_targets = 0;
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto out_edge : graph.GetAdjacentEdgeRange(node))
{
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
const ContractorEdgeData &out_data = graph.GetEdgeData(out_edge);
if (!out_data.forward)
{
continue;
}
const NodeID target = contractor_graph->GetTarget(out_edge);
const NodeID target = graph.GetTarget(out_edge);
if (node == target)
{
continue;
@ -298,22 +297,22 @@ class GraphContractor
SIMULATION_SEARCH_SPACE_SIZE,
max_weight,
node,
*contractor_graph);
graph);
}
else
{
const int constexpr FULL_SEARCH_SPACE_SIZE = 2000;
dijkstra.Run(
number_of_targets, FULL_SEARCH_SPACE_SIZE, max_weight, node, *contractor_graph);
number_of_targets, FULL_SEARCH_SPACE_SIZE, max_weight, node, graph);
}
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto out_edge : graph.GetAdjacentEdgeRange(node))
{
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
const ContractorEdgeData &out_data = graph.GetEdgeData(out_edge);
if (!out_data.forward)
{
continue;
}
const NodeID target = contractor_graph->GetTarget(out_edge);
const NodeID target = graph.GetTarget(out_edge);
if (target == node)
continue;
@ -408,7 +407,7 @@ class GraphContractor
// This bias function takes up 22 assembly instructions in total on X86
bool Bias(const NodeID a, const NodeID b) const;
std::shared_ptr<ContractorGraph> contractor_graph;
ContractorGraph graph;
ExternalVector<QueryEdge> external_edge_list;
std::vector<NodeID> orig_node_id_from_new_node_id_map;
std::vector<float> node_levels;

View File

@ -4,6 +4,8 @@
#include "contractor/contractor_graph.hpp"
#include "util/log.hpp"
#include <tbb/parallel_sort.h>
#include <vector>
namespace osrm
@ -13,15 +15,14 @@ namespace contractor
// Make sure to move in the input edge list!
template <typename InputEdgeContainer>
std::vector<ContractorEdge> adaptToContractorInput(InputEdgeContainer input_edge_list)
ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer input_edge_list)
{
std::vector<ContractorEdge> edges;
edges.reserve(input_edge_list.size() * 2);
for (const auto &input_edge : input_edge_list)
{
if (input_edge.data.weight == INVALID_EDGE_WEIGHT)
continue;
BOOST_ASSERT(input_edge.data.weight < INVALID_EDGE_WEIGHT);
#ifndef NDEBUG
const unsigned int constexpr DAY_IN_DECI_SECONDS = 24 * 60 * 60 * 10;
@ -52,10 +53,74 @@ std::vector<ContractorEdge> adaptToContractorInput(InputEdgeContainer input_edge
false,
input_edge.data.backward ? true : false,
input_edge.data.forward ? true : false);
};
tbb::parallel_sort(edges.begin(), edges.end());
NodeID edge = 0;
for (NodeID i = 0; i < edges.size();)
{
const NodeID source = edges[i].source;
const NodeID target = edges[i].target;
const NodeID id = edges[i].data.id;
// remove eigenloops
if (source == target)
{
++i;
continue;
}
ContractorEdge forward_edge;
ContractorEdge reverse_edge;
forward_edge.source = reverse_edge.source = source;
forward_edge.target = reverse_edge.target = target;
forward_edge.data.forward = reverse_edge.data.backward = true;
forward_edge.data.backward = reverse_edge.data.forward = false;
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
forward_edge.data.id = reverse_edge.data.id = id;
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT;
forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION;
// remove parallel edges
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
{
if (edges[i].data.forward)
{
forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight);
forward_edge.data.duration =
std::min(edges[i].data.duration, forward_edge.data.duration);
}
if (edges[i].data.backward)
{
reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight);
reverse_edge.data.duration =
std::min(edges[i].data.duration, reverse_edge.data.duration);
}
++i;
}
// merge edges (s,t) and (t,s) into bidirectional edge
if (forward_edge.data.weight == reverse_edge.data.weight)
{
if ((int)forward_edge.data.weight != INVALID_EDGE_WEIGHT)
{
forward_edge.data.backward = true;
edges[edge++] = forward_edge;
}
}
else
{ // insert seperate edges
if (((int)forward_edge.data.weight) != INVALID_EDGE_WEIGHT)
{
edges[edge++] = forward_edge;
}
if ((int)reverse_edge.data.weight != INVALID_EDGE_WEIGHT)
{
edges[edge++] = reverse_edge;
}
}
}
// FIXME not sure if we need this
edges.shrink_to_fit();
return edges;
util::Log() << "merged " << edges.size() - edge << " edges out of " << edges.size();
edges.resize(edge);
return ContractorGraph{number_of_nodes, edges};
}
} // namespace contractor

View File

@ -66,6 +66,8 @@ template <typename EdgeDataT> class DynamicGraph
}
};
DynamicGraph() : DynamicGraph(0) {}
// Constructs an empty graph with a given number of nodes.
explicit DynamicGraph(NodeIterator nodes) : number_of_nodes(nodes), number_of_edges(0)
{

View File

@ -72,8 +72,7 @@ int Contractor::Run()
util::DeallocatingVector<QueryEdge> contracted_edge_list;
{ // own scope to not keep the contractor around
GraphContractor graph_contractor(max_edge_id + 1,
adaptToContractorInput(std::move(edge_based_edge_list)),
GraphContractor graph_contractor(toContractorGraph(max_edge_id+1, std::move(edge_based_edge_list)),
std::move(node_levels),
std::move(node_weights));
graph_contractor.Run(config.core_factor);

View File

@ -5,87 +5,17 @@ namespace osrm
namespace contractor
{
GraphContractor::GraphContractor(int nodes, std::vector<ContractorEdge> input_edge_list)
: GraphContractor(nodes, std::move(input_edge_list), {}, {})
GraphContractor::GraphContractor(ContractorGraph graph_)
: GraphContractor(std::move(graph_), {}, {})
{
}
GraphContractor::GraphContractor(int nodes,
std::vector<ContractorEdge> edges,
GraphContractor::GraphContractor(ContractorGraph graph_,
std::vector<float> node_levels_,
std::vector<EdgeWeight> node_weights_)
: node_levels(std::move(node_levels_)), node_weights(std::move(node_weights_))
: graph(std::move(graph_)), node_levels(std::move(node_levels_)),
node_weights(std::move(node_weights_))
{
tbb::parallel_sort(edges.begin(), edges.end());
NodeID edge = 0;
for (NodeID i = 0; i < edges.size();)
{
const NodeID source = edges[i].source;
const NodeID target = edges[i].target;
const NodeID id = edges[i].data.id;
// remove eigenloops
if (source == target)
{
++i;
continue;
}
ContractorEdge forward_edge;
ContractorEdge reverse_edge;
forward_edge.source = reverse_edge.source = source;
forward_edge.target = reverse_edge.target = target;
forward_edge.data.forward = reverse_edge.data.backward = true;
forward_edge.data.backward = reverse_edge.data.forward = false;
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
forward_edge.data.id = reverse_edge.data.id = id;
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT;
forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION;
// remove parallel edges
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
{
if (edges[i].data.forward)
{
forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight);
forward_edge.data.duration =
std::min(edges[i].data.duration, forward_edge.data.duration);
}
if (edges[i].data.backward)
{
reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight);
reverse_edge.data.duration =
std::min(edges[i].data.duration, reverse_edge.data.duration);
}
++i;
}
// merge edges (s,t) and (t,s) into bidirectional edge
if (forward_edge.data.weight == reverse_edge.data.weight)
{
if ((int)forward_edge.data.weight != INVALID_EDGE_WEIGHT)
{
forward_edge.data.backward = true;
edges[edge++] = forward_edge;
}
}
else
{ // insert seperate edges
if (((int)forward_edge.data.weight) != INVALID_EDGE_WEIGHT)
{
edges[edge++] = forward_edge;
}
if ((int)reverse_edge.data.weight != INVALID_EDGE_WEIGHT)
{
edges[edge++] = reverse_edge;
}
}
}
util::Log() << "merged " << edges.size() - edge << " edges out of " << edges.size();
edges.resize(edge);
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
edges.clear();
edges.shrink_to_fit();
BOOST_ASSERT(0 == edges.capacity());
util::Log() << "contractor finished initalization";
}
/* Flush all data from the contraction to disc and reorder stuff for better locality */
@ -107,7 +37,7 @@ void GraphContractor::FlushDataAndRebuildContractorGraph(
orig_node_id_from_new_node_id_map.resize(remaining_nodes.size());
// this map gives the new IDs from the old ones, necessary to remap targets from the
// remaining graph
const auto number_of_nodes = contractor_graph->GetNumberOfNodes();
const auto number_of_nodes = graph.GetNumberOfNodes();
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, SPECIAL_NODEID);
for (const auto new_node_id : util::irange<std::size_t>(0UL, remaining_nodes.size()))
{
@ -127,12 +57,12 @@ void GraphContractor::FlushDataAndRebuildContractorGraph(
node.id = new_node_id;
}
// walk over all nodes
for (const auto source : util::irange<NodeID>(0UL, contractor_graph->GetNumberOfNodes()))
for (const auto source : util::irange<NodeID>(0UL, graph.GetNumberOfNodes()))
{
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
for (auto current_edge : graph.GetAdjacentEdgeRange(source))
{
ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(current_edge);
const NodeID target = contractor_graph->GetTarget(current_edge);
ContractorGraph::EdgeData &data = graph.GetEdgeData(current_edge);
const NodeID target = graph.GetTarget(current_edge);
if (SPECIAL_NODEID == new_node_id_from_orig_id_map[source])
{
external_edge_list.push_back({source, target, data});
@ -158,14 +88,14 @@ void GraphContractor::FlushDataAndRebuildContractorGraph(
// Delete old node_priorities vector
node_weights.swap(new_node_weights);
// old Graph is removed
contractor_graph.reset();
graph = ContractorGraph{};
// create new graph
tbb::parallel_sort(new_edge_set.begin(), new_edge_set.end());
contractor_graph = std::make_shared<ContractorGraph>(remaining_nodes.size(), new_edge_set);
graph = ContractorGraph{static_cast<NodeID>(remaining_nodes.size()), new_edge_set};
new_edge_set.clear();
// INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
// reinitialize heaps and ThreadData objects with appropriate size
thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
thread_data_list.number_of_nodes = graph.GetNumberOfNodes();
}
void GraphContractor::Run(double core_factor)
@ -181,7 +111,7 @@ void GraphContractor::Run(double core_factor)
const constexpr size_t NeighboursGrainSize = 1;
const constexpr size_t DeleteGrainSize = 1;
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
const NodeID number_of_nodes = graph.GetNumberOfNodes();
ThreadDataContainer thread_data_list(number_of_nodes);
@ -340,11 +270,10 @@ void GraphContractor::Run(double core_factor)
{
for (const ContractorEdge &edge : data->inserted_edges)
{
const EdgeID current_edge_ID = contractor_graph->FindEdge(edge.source, edge.target);
const EdgeID current_edge_ID = graph.FindEdge(edge.source, edge.target);
if (current_edge_ID != SPECIAL_EDGEID)
{
ContractorGraph::EdgeData &current_data =
contractor_graph->GetEdgeData(current_edge_ID);
ContractorGraph::EdgeData &current_data = graph.GetEdgeData(current_edge_ID);
if (current_data.shortcut && edge.data.forward == current_data.forward &&
edge.data.backward == current_data.backward)
{
@ -357,7 +286,7 @@ void GraphContractor::Run(double core_factor)
continue;
}
}
contractor_graph->InsertEdge(edge.source, edge.target, edge.data);
graph.InsertEdge(edge.source, edge.target, edge.data);
}
data->inserted_edges.clear();
}
@ -421,8 +350,8 @@ void GraphContractor::Run(double core_factor)
is_core_node.clear();
}
util::Log() << "[core] " << remaining_nodes.size() << " nodes "
<< contractor_graph->GetNumberOfEdges() << " edges.";
util::Log() << "[core] " << remaining_nodes.size() << " nodes " << graph.GetNumberOfEdges()
<< " edges.";
thread_data_list.data.clear();
}
@ -465,9 +394,9 @@ void GraphContractor::DeleteIncomingEdges(ContractorThreadData *data, const Node
neighbours.clear();
// find all neighbours
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
for (auto e : graph.GetAdjacentEdgeRange(node))
{
const NodeID u = contractor_graph->GetTarget(e);
const NodeID u = graph.GetTarget(e);
if (u != node)
{
neighbours.push_back(u);
@ -479,7 +408,7 @@ void GraphContractor::DeleteIncomingEdges(ContractorThreadData *data, const Node
for (const auto i : util::irange<std::size_t>(0, neighbours.size()))
{
contractor_graph->DeleteEdgesTo(neighbours[i], node);
graph.DeleteEdgesTo(neighbours[i], node);
}
}
@ -492,9 +421,9 @@ bool GraphContractor::UpdateNodeNeighbours(std::vector<float> &priorities,
neighbours.clear();
// find all neighbours
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
for (auto e : graph.GetAdjacentEdgeRange(node))
{
const NodeID u = contractor_graph->GetTarget(e);
const NodeID u = graph.GetTarget(e);
if (u == node)
{
continue;
@ -523,9 +452,9 @@ bool GraphContractor::IsNodeIndependent(const std::vector<float> &priorities,
std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear();
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
for (auto e : graph.GetAdjacentEdgeRange(node))
{
const NodeID target = contractor_graph->GetTarget(e);
const NodeID target = graph.GetTarget(e);
if (node == target)
{
continue;
@ -552,9 +481,9 @@ bool GraphContractor::IsNodeIndependent(const std::vector<float> &priorities,
// examine all neighbours that are at most 2 hops away
for (const NodeID u : neighbours)
{
for (auto e : contractor_graph->GetAdjacentEdgeRange(u))
for (auto e : graph.GetAdjacentEdgeRange(u))
{
const NodeID target = contractor_graph->GetTarget(e);
const NodeID target = graph.GetTarget(e);
if (node == target)
{
continue;