Merge pull request #5894 from xlaussel/avoid_samelookup_in_heap_map

Avoid samelookup in heap map
This commit is contained in:
Denis Chapligin
2020-12-20 22:17:49 +02:00
committed by GitHub
7 changed files with 292 additions and 236 deletions
+6 -4
View File
@@ -32,16 +32,18 @@ void relaxNode(ContractorHeap &heap,
}
const EdgeWeight to_weight = node_weight + data.weight;
const auto toHeapNode = heap.GetHeapNodeIfWasInserted(to);
// New Node discovered -> Add to Heap + Node Info Storage
if (!heap.WasInserted(to))
if (!toHeapNode)
{
heap.Insert(to, to_weight, ContractorHeapData{current_hop, false});
}
// Found a shorter Path -> Update weight
else if (to_weight < heap.GetKey(to))
else if (to_weight < toHeapNode->weight)
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to).hop = current_hop;
toHeapNode->weight = to_weight;
heap.DecreaseKey(*toHeapNode);
toHeapNode->data.hop = current_hop;
}
}
}
@@ -62,11 +62,12 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
QueryHeap &forward_heap = DIRECTION == FORWARD_DIRECTION ? heap1 : heap2;
QueryHeap &reverse_heap = DIRECTION == FORWARD_DIRECTION ? heap2 : heap1;
const NodeID node = forward_heap.DeleteMin();
const EdgeWeight weight = forward_heap.GetKey(node);
// Take a copy (no ref &) of the extracted node because otherwise could be modified later if
// toHeapNode is the same
const auto heapNode = forward_heap.DeleteMinGetHeapNode();
const auto scaled_weight =
static_cast<EdgeWeight>((weight + min_edge_offset) / (1. + VIAPATH_EPSILON));
static_cast<EdgeWeight>((heapNode.weight + min_edge_offset) / (1. + VIAPATH_EPSILON));
if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_weight) &&
(scaled_weight > *upper_bound_to_shortest_path_weight))
{
@@ -74,35 +75,36 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
return;
}
search_space.emplace_back(forward_heap.GetData(node).parent, node);
search_space.emplace_back(heapNode.data.parent, heapNode.node);
if (reverse_heap.WasInserted(node))
const auto reverseHeapNode = reverse_heap.GetHeapNodeIfWasInserted(heapNode.node);
if (reverseHeapNode)
{
search_space_intersection.emplace_back(node);
const EdgeWeight new_weight = reverse_heap.GetKey(node) + weight;
search_space_intersection.emplace_back(heapNode.node);
const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight;
if (new_weight < *upper_bound_to_shortest_path_weight)
{
if (new_weight >= 0)
{
*middle_node = node;
*middle_node = heapNode.node;
*upper_bound_to_shortest_path_weight = new_weight;
}
else
{
// check whether there is a loop present at the node
const auto loop_weight = std::get<0>(getLoopWeight<false>(facade, node));
const auto loop_weight = std::get<0>(getLoopWeight<false>(facade, heapNode.node));
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
if (loop_weight != INVALID_EDGE_WEIGHT &&
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
{
*middle_node = node;
*middle_node = heapNode.node;
*upper_bound_to_shortest_path_weight = loop_weight;
}
}
}
}
for (auto edge : facade.GetAdjacentEdgeRange(node))
for (auto edge : facade.GetAdjacentEdgeRange(heapNode.node))
{
const auto &data = facade.GetEdgeData(edge);
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
@@ -111,20 +113,22 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
const EdgeWeight edge_weight = data.weight;
BOOST_ASSERT(edge_weight > 0);
const EdgeWeight to_weight = weight + edge_weight;
const EdgeWeight to_weight = heapNode.weight + edge_weight;
const auto toHeapNode = forward_heap.GetHeapNodeIfWasInserted(to);
// New Node discovered -> Add to Heap + Node Info Storage
if (!forward_heap.WasInserted(to))
if (!toHeapNode)
{
forward_heap.Insert(to, to_weight, node);
forward_heap.Insert(to, to_weight, heapNode.node);
}
// Found a shorter Path -> Update weight
else if (to_weight < forward_heap.GetKey(to))
else if (to_weight < toHeapNode->weight)
{
// new parent
forward_heap.GetData(to).parent = node;
toHeapNode->data.parent = heapNode.node;
// decreased weight
forward_heap.DecreaseKey(to, to_weight);
toHeapNode->weight = to_weight;
forward_heap.DecreaseKey(*toHeapNode);
}
}
}
@@ -45,20 +45,18 @@ inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade,
}
template <bool DIRECTION>
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
const NodeID node,
const EdgeWeight weight,
const EdgeDuration duration,
const EdgeDistance distance,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const PhantomNode &)
void relaxOutgoingEdges(
const DataFacade<Algorithm> &facade,
const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const PhantomNode &)
{
if (stallAtNode<DIRECTION>(facade, node, weight, query_heap))
if (stallAtNode<DIRECTION>(facade, heapNode, query_heap))
{
return;
}
for (auto edge : facade.GetAdjacentEdgeRange(node))
for (auto edge : facade.GetAdjacentEdgeRange(heapNode.node))
{
const auto &data = facade.GetEdgeData(edge);
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
@@ -70,21 +68,23 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
const auto edge_distance = data.distance;
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
const auto to_weight = weight + edge_weight;
const auto to_duration = duration + edge_duration;
const auto to_distance = distance + edge_distance;
const auto to_weight = heapNode.weight + edge_weight;
const auto to_duration = heapNode.data.duration + edge_duration;
const auto to_distance = heapNode.data.distance + edge_distance;
const auto toHeapNode = query_heap.GetHeapNodeIfWasInserted(to);
// New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to))
if (!toHeapNode)
{
query_heap.Insert(to, to_weight, {node, to_duration, to_distance});
query_heap.Insert(to, to_weight, {heapNode.node, to_duration, to_distance});
}
// Found a shorter Path -> Update weight and set new parent
else if (std::tie(to_weight, to_duration) <
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
std::tie(toHeapNode->weight, toHeapNode->data.duration))
{
query_heap.GetData(to) = {node, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
toHeapNode->data = {heapNode.node, to_duration, to_distance};
toHeapNode->weight = to_weight;
query_heap.DecreaseKey(*toHeapNode);
}
}
}
@@ -101,15 +101,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node)
{
const auto node = query_heap.DeleteMin();
const auto source_weight = query_heap.GetKey(node);
const auto source_duration = query_heap.GetData(node).duration;
const auto source_distance = query_heap.GetData(node).distance;
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same
const auto heapNode = query_heap.DeleteMinGetHeapNode();
// Check if each encountered node has an entry
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
search_space_with_buckets.end(),
node,
heapNode.node,
NodeBucket::Compare());
for (const auto &current_bucket : boost::make_iterator_range(bucket_list))
{
@@ -129,18 +128,18 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
: distances_table[row_index * number_of_targets + column_index];
// Check if new weight is better
auto new_weight = source_weight + target_weight;
auto new_duration = source_duration + target_duration;
auto new_distance = source_distance + target_distance;
auto new_weight = heapNode.weight + target_weight;
auto new_duration = heapNode.data.duration + target_duration;
auto new_distance = heapNode.data.distance + target_distance;
if (new_weight < 0)
{
if (addLoopWeight(facade, node, new_weight, new_duration, new_distance))
if (addLoopWeight(facade, heapNode.node, new_weight, new_duration, new_distance))
{
current_weight = std::min(current_weight, new_weight);
current_duration = std::min(current_duration, new_duration);
current_distance = std::min(current_distance, new_distance);
middle_nodes_table[row_index * number_of_targets + column_index] = node;
middle_nodes_table[row_index * number_of_targets + column_index] = heapNode.node;
}
}
else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration))
@@ -148,12 +147,11 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
current_weight = new_weight;
current_duration = new_duration;
current_distance = new_distance;
middle_nodes_table[row_index * number_of_targets + column_index] = node;
middle_nodes_table[row_index * number_of_targets + column_index] = heapNode.node;
}
}
relaxOutgoingEdges<FORWARD_DIRECTION>(
facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node);
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, phantom_node);
}
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
@@ -162,18 +160,19 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<NodeBucket> &search_space_with_buckets,
const PhantomNode &phantom_node)
{
const auto node = query_heap.DeleteMin();
const auto target_weight = query_heap.GetKey(node);
const auto target_duration = query_heap.GetData(node).duration;
const auto target_distance = query_heap.GetData(node).distance;
const auto parent = query_heap.GetData(node).parent;
// Take a copy (no ref &) of the extracted node because otherwise could be modified later if
// toHeapNode is the same
const auto heapNode = query_heap.DeleteMinGetHeapNode();
// Store settled nodes in search space bucket
search_space_with_buckets.emplace_back(
node, parent, column_index, target_weight, target_duration, target_distance);
search_space_with_buckets.emplace_back(heapNode.node,
heapNode.data.parent,
column_index,
heapNode.weight,
heapNode.data.duration,
heapNode.data.distance);
relaxOutgoingEdges<REVERSE_DIRECTION>(
facade, node, target_weight, target_duration, target_distance, query_heap, phantom_node);
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, phantom_node);
}
} // namespace ch
@@ -71,38 +71,38 @@ void relaxBorderEdges(const DataFacade<mld::Algorithm> &facade,
const auto to_distance = distance + node_distance;
// New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to))
const auto toHeapNode = query_heap.GetHeapNodeIfWasInserted(to);
if (!toHeapNode)
{
query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance});
}
// Found a shorter Path -> Update weight and set new parent
else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent))
std::tie(toHeapNode->weight,
toHeapNode->data.duration,
toHeapNode->data.distance,
toHeapNode->data.parent))
{
query_heap.GetData(to) = {node, false, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
toHeapNode->data = {node, false, to_duration, to_distance};
toHeapNode->weight = to_weight;
query_heap.DecreaseKey(*toHeapNode);
}
}
}
}
template <bool DIRECTION, typename... Args>
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const NodeID node,
const EdgeWeight weight,
const EdgeDuration duration,
const EdgeDistance distance,
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
Args... args)
void relaxOutgoingEdges(
const DataFacade<mld::Algorithm> &facade,
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
Args... args)
{
BOOST_ASSERT(!facade.ExcludeNode(node));
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
const auto &partition = facade.GetMultiLevelPartition();
const auto level = getNodeQueryLevel(partition, node, args...);
const auto level = getNodeQueryLevel(partition, heapNode.node, args...);
// Break outgoing edges relaxation if node at the restricted level
if (level == INVALID_LEVEL_ID)
@@ -110,40 +110,42 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const auto &cells = facade.GetCellStorage();
const auto &metric = facade.GetCellMetric();
const auto &node_data = query_heap.GetData(node);
if (level >= 1 && !node_data.from_clique_arc)
if (level >= 1 && !heapNode.data.from_clique_arc)
{
const auto &cell = cells.GetCell(metric, level, partition.GetCell(level, node));
const auto &cell = cells.GetCell(metric, level, partition.GetCell(level, heapNode.node));
if (DIRECTION == FORWARD_DIRECTION)
{ // Shortcuts in forward direction
auto destination = cell.GetDestinationNodes().begin();
auto shortcut_durations = cell.GetOutDuration(node);
auto shortcut_distances = cell.GetOutDistance(node);
for (auto shortcut_weight : cell.GetOutWeight(node))
auto shortcut_durations = cell.GetOutDuration(heapNode.node);
auto shortcut_distances = cell.GetOutDistance(heapNode.node);
for (auto shortcut_weight : cell.GetOutWeight(heapNode.node))
{
BOOST_ASSERT(destination != cell.GetDestinationNodes().end());
BOOST_ASSERT(!shortcut_durations.empty());
BOOST_ASSERT(!shortcut_distances.empty());
const NodeID to = *destination;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
if (shortcut_weight != INVALID_EDGE_WEIGHT && heapNode.node != to)
{
const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front();
const auto to_distance = distance + shortcut_distances.front();
if (!query_heap.WasInserted(to))
const auto to_weight = heapNode.weight + shortcut_weight;
const auto to_duration = heapNode.data.duration + shortcut_durations.front();
const auto to_distance = heapNode.data.distance + shortcut_distances.front();
const auto toHeapNode = query_heap.GetHeapNodeIfWasInserted(to);
if (!toHeapNode)
{
query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
query_heap.Insert(
to, to_weight, {heapNode.node, true, to_duration, to_distance});
}
else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent))
else if (std::tie(to_weight, to_duration, to_distance, heapNode.node) <
std::tie(toHeapNode->weight,
toHeapNode->data.duration,
toHeapNode->data.distance,
toHeapNode->data.parent))
{
query_heap.GetData(to) = {node, true, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
toHeapNode->data = {heapNode.node, true, to_duration, to_distance};
toHeapNode->weight = to_weight;
query_heap.DecreaseKey(*toHeapNode);
}
}
++destination;
@@ -156,32 +158,35 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
else
{ // Shortcuts in backward direction
auto source = cell.GetSourceNodes().begin();
auto shortcut_durations = cell.GetInDuration(node);
auto shortcut_distances = cell.GetInDistance(node);
for (auto shortcut_weight : cell.GetInWeight(node))
auto shortcut_durations = cell.GetInDuration(heapNode.node);
auto shortcut_distances = cell.GetInDistance(heapNode.node);
for (auto shortcut_weight : cell.GetInWeight(heapNode.node))
{
BOOST_ASSERT(source != cell.GetSourceNodes().end());
BOOST_ASSERT(!shortcut_durations.empty());
BOOST_ASSERT(!shortcut_distances.empty());
const NodeID to = *source;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
if (shortcut_weight != INVALID_EDGE_WEIGHT && heapNode.node != to)
{
const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front();
const auto to_distance = distance + shortcut_distances.front();
if (!query_heap.WasInserted(to))
const auto to_weight = heapNode.weight + shortcut_weight;
const auto to_duration = heapNode.data.duration + shortcut_durations.front();
const auto to_distance = heapNode.data.distance + shortcut_distances.front();
const auto toHeapNode = query_heap.GetHeapNodeIfWasInserted(to);
if (!toHeapNode)
{
query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
query_heap.Insert(
to, to_weight, {heapNode.node, true, to_duration, to_distance});
}
else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent))
else if (std::tie(to_weight, to_duration, to_distance, heapNode.node) <
std::tie(toHeapNode->weight,
toHeapNode->data.duration,
toHeapNode->data.distance,
toHeapNode->data.parent))
{
query_heap.GetData(to) = {node, true, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
toHeapNode->data = {heapNode.node, true, to_duration, to_distance};
toHeapNode->weight = to_weight;
query_heap.DecreaseKey(*toHeapNode);
}
}
++source;
@@ -193,7 +198,13 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
}
}
relaxBorderEdges<DIRECTION>(facade, node, weight, duration, distance, query_heap, level);
relaxBorderEdges<DIRECTION>(facade,
heapNode.node,
heapNode.weight,
heapNode.data.duration,
heapNode.data.distance,
query_heap,
level);
}
//
@@ -368,25 +379,17 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
while (!query_heap.Empty() && !target_nodes_index.empty())
{
// Extract node from the heap
const auto node = query_heap.DeleteMin();
const auto weight = query_heap.GetKey(node);
const auto duration = query_heap.GetData(node).duration;
const auto distance = query_heap.GetData(node).distance;
// Extract node from the heap. Take a copy (no ref) because otherwise can be modified later
// if toHeapNode is the same
const auto heapNode = query_heap.DeleteMinGetHeapNode();
// Update values
update_values(node, weight, duration, distance);
update_values(
heapNode.node, heapNode.weight, heapNode.data.duration, heapNode.data.distance);
// Relax outgoing edges
relaxOutgoingEdges<DIRECTION>(facade,
node,
weight,
duration,
distance,
query_heap,
phantom_nodes,
phantom_index,
phantom_indices);
relaxOutgoingEdges<DIRECTION>(
facade, heapNode, query_heap, phantom_nodes, phantom_index, phantom_indices);
}
return std::make_pair(durations, distances_table);
@@ -408,15 +411,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node)
{
const auto node = query_heap.DeleteMin();
const auto source_weight = query_heap.GetKey(node);
const auto source_duration = query_heap.GetData(node).duration;
const auto source_distance = query_heap.GetData(node).distance;
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same
const auto heapNode = query_heap.DeleteMinGetHeapNode();
// Check if each encountered node has an entry
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
search_space_with_buckets.end(),
node,
heapNode.node,
NodeBucket::Compare());
for (const auto &current_bucket : boost::make_iterator_range(bucket_list))
{
@@ -439,9 +441,9 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
auto &current_distance = distances_table.empty() ? nulldistance : distances_table[location];
// Check if new weight is better
auto new_weight = source_weight + target_weight;
auto new_duration = source_duration + target_duration;
auto new_distance = source_distance + target_distance;
auto new_weight = heapNode.weight + target_weight;
auto new_duration = heapNode.data.duration + target_duration;
auto new_distance = heapNode.data.distance + target_distance;
if (new_weight >= 0 && std::tie(new_weight, new_duration, new_distance) <
std::tie(current_weight, current_duration, current_distance))
@@ -449,12 +451,11 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
current_weight = new_weight;
current_duration = new_duration;
current_distance = new_distance;
middle_nodes_table[location] = node;
middle_nodes_table[location] = heapNode.node;
}
}
relaxOutgoingEdges<DIRECTION>(
facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node);
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, phantom_node);
}
template <bool DIRECTION>
@@ -464,28 +465,23 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<NodeBucket> &search_space_with_buckets,
const PhantomNode &phantom_node)
{
const auto node = query_heap.DeleteMin();
const auto target_weight = query_heap.GetKey(node);
const auto target_duration = query_heap.GetData(node).duration;
const auto target_distance = query_heap.GetData(node).distance;
const auto parent = query_heap.GetData(node).parent;
const auto from_clique_arc = query_heap.GetData(node).from_clique_arc;
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same
const auto heapNode = query_heap.DeleteMinGetHeapNode();
// Store settled nodes in search space bucket
search_space_with_buckets.emplace_back(
node, parent, from_clique_arc, column_idx, target_weight, target_duration, target_distance);
search_space_with_buckets.emplace_back(heapNode.node,
heapNode.data.parent,
heapNode.data.from_clique_arc,
column_idx,
heapNode.weight,
heapNode.data.duration,
heapNode.data.distance);
const auto &partition = facade.GetMultiLevelPartition();
const auto maximal_level = partition.GetNumberOfLevels() - 1;
relaxOutgoingEdges<!DIRECTION>(facade,
node,
target_weight,
target_duration,
target_distance,
query_heap,
phantom_node,
maximal_level);
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, phantom_node, maximal_level);
}
template <bool DIRECTION>