Add support for annotations=distances in MLD
This commit brings feature parity with CH for the `table` pluging.
This commit is contained in:
committed by
Patrick Niklaus
parent
1a1293608d
commit
2a15e6dec8
@@ -85,14 +85,6 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
||||
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||
|
||||
if (request_distance && !algorithms.SupportsDistanceAnnotationType())
|
||||
{
|
||||
return Error("NotImplemented",
|
||||
"The distance annotations calculation is not implemented for the chosen "
|
||||
"search algorithm.",
|
||||
result);
|
||||
}
|
||||
|
||||
auto result_tables_pair = algorithms.ManyToManySearch(
|
||||
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration);
|
||||
|
||||
|
||||
@@ -74,6 +74,15 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||
|
||||
std::cout << "source_phantom.forward_segment_id.id: "
|
||||
<< phantom_nodes.source_phantom.forward_segment_id.id
|
||||
<< " source_phantom.reverse_segment_id.id: "
|
||||
<< phantom_nodes.source_phantom.reverse_segment_id.id << std::endl;
|
||||
std::cout << "target_phantom.forward_segment_id.id: "
|
||||
<< phantom_nodes.target_phantom.forward_segment_id.id
|
||||
<< " target_phantom.reverse_segment_id.id: "
|
||||
<< phantom_nodes.target_phantom.reverse_segment_id.id << std::endl;
|
||||
|
||||
// TODO: when structured bindings will be allowed change to
|
||||
// auto [weight, source_node, target_node, unpacked_edges] = ...
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
|
||||
@@ -148,10 +148,11 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto target_weight = query_heap.GetKey(node);
|
||||
const auto target_duration = query_heap.GetData(node).duration;
|
||||
const auto parent = query_heap.GetData(node).parent;
|
||||
const bool INVALID_CLIQUE_ARC_TYPE = false;
|
||||
|
||||
// Store settled nodes in search space bucket
|
||||
search_space_with_buckets.emplace_back(
|
||||
node, parent, column_index, target_weight, target_duration);
|
||||
node, parent, INVALID_CLIQUE_ARC_TYPE, column_index, target_weight, target_duration);
|
||||
|
||||
relaxOutgoingEdges<REVERSE_DIRECTION>(
|
||||
facade, node, target_weight, target_duration, query_heap, phantom_node);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
||||
#include "engine/routing_algorithms/routing_base.hpp"
|
||||
#include "engine/routing_algorithms/routing_base_mld.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
@@ -19,22 +19,8 @@ namespace routing_algorithms
|
||||
namespace mld
|
||||
{
|
||||
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
const NodeID node,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
||||
if (phantom_node.enabled)
|
||||
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
||||
return INVALID_LEVEL_ID;
|
||||
};
|
||||
|
||||
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
||||
highest_diffrent_level(phantom_node.reverse_segment_id));
|
||||
|
||||
return node_level;
|
||||
}
|
||||
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
||||
using PackedPath = std::vector<PackedEdge>;
|
||||
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
@@ -50,38 +36,6 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
return node_level;
|
||||
}
|
||||
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
NodeID node,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::size_t phantom_index,
|
||||
const std::vector<std::size_t> &phantom_indices)
|
||||
{
|
||||
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
||||
|
||||
const auto &forward_segment = phantom_node.forward_segment_id;
|
||||
const auto forward_level =
|
||||
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
||||
: INVALID_LEVEL_ID;
|
||||
|
||||
const auto &reverse_segment = phantom_node.reverse_segment_id;
|
||||
const auto reverse_level =
|
||||
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
|
||||
: INVALID_LEVEL_ID;
|
||||
|
||||
return std::min(forward_level, reverse_level);
|
||||
};
|
||||
|
||||
// Get minimum level over all phantoms of the highest different level with respect to node
|
||||
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
||||
auto result = min_level(phantom_nodes[phantom_index]);
|
||||
for (const auto &index : phantom_indices)
|
||||
{
|
||||
result = std::min(result, min_level(phantom_nodes[index]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <bool DIRECTION, typename... Args>
|
||||
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
const NodeID node,
|
||||
@@ -125,8 +79,10 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
{
|
||||
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration) <
|
||||
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
||||
else if (std::tie(to_weight, to_duration, node) <
|
||||
std::tie(query_heap.GetKey(to),
|
||||
query_heap.GetData(to).duration,
|
||||
query_heap.GetData(to).parent))
|
||||
{
|
||||
query_heap.GetData(to) = {node, true, to_duration};
|
||||
query_heap.DecreaseKey(to, to_weight);
|
||||
@@ -155,8 +111,10 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
{
|
||||
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration) <
|
||||
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
||||
else if (std::tie(to_weight, to_duration, node) <
|
||||
std::tie(query_heap.GetKey(to),
|
||||
query_heap.GetData(to).duration,
|
||||
query_heap.GetData(to).parent))
|
||||
{
|
||||
query_heap.GetData(to) = {node, true, to_duration};
|
||||
query_heap.DecreaseKey(to, to_weight);
|
||||
@@ -198,8 +156,10 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
query_heap.Insert(to, to_weight, {node, false, to_duration});
|
||||
}
|
||||
// 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))
|
||||
else if (std::tie(to_weight, to_duration, node) <
|
||||
std::tie(query_heap.GetKey(to),
|
||||
query_heap.GetData(to).duration,
|
||||
query_heap.GetData(to).parent))
|
||||
{
|
||||
query_heap.GetData(to) = {node, false, to_duration};
|
||||
query_heap.DecreaseKey(to, to_weight);
|
||||
@@ -217,11 +177,13 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
std::size_t phantom_index,
|
||||
const std::vector<std::size_t> &phantom_indices)
|
||||
const std::vector<std::size_t> &phantom_indices,
|
||||
const bool calculate_distance)
|
||||
{
|
||||
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances(phantom_indices.size(), INVALID_EDGE_DISTANCE);
|
||||
std::vector<EdgeDistance> distances_table;
|
||||
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
|
||||
|
||||
// Collect destination (source) nodes into a map
|
||||
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>>
|
||||
@@ -289,6 +251,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
{
|
||||
weights[index] = path_weight;
|
||||
durations[index] = path_duration;
|
||||
middle_nodes_table[index] = node;
|
||||
}
|
||||
|
||||
// Remove node from destinations list
|
||||
@@ -306,12 +269,15 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
// Update single node paths
|
||||
update_values(node, initial_weight, initial_duration);
|
||||
|
||||
query_heap.Insert(node, initial_weight, {node, initial_duration});
|
||||
|
||||
// Place adjacent nodes into heap
|
||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = facade.GetEdgeData(edge);
|
||||
if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge)
|
||||
: facade.IsBackwardEdge(edge))
|
||||
if ((DIRECTION == FORWARD_DIRECTION ? facade.IsForwardEdge(edge)
|
||||
: facade.IsBackwardEdge(edge)) &&
|
||||
!query_heap.WasInserted(facade.GetTarget(edge)))
|
||||
{
|
||||
const auto turn_id = data.turn_id;
|
||||
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
|
||||
@@ -330,28 +296,35 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration());
|
||||
}
|
||||
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration());
|
||||
}
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration());
|
||||
}
|
||||
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +349,127 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
phantom_indices);
|
||||
}
|
||||
|
||||
return std::make_pair(durations, distances);
|
||||
if (calculate_distance)
|
||||
{
|
||||
// Initialize unpacking heaps
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||
|
||||
distances_table.resize(phantom_indices.size(), INVALID_EDGE_DISTANCE);
|
||||
|
||||
for (unsigned location = 0; location < phantom_indices.size(); ++location)
|
||||
{
|
||||
// Get the "middle" node that is the last node of a path
|
||||
const NodeID middle_node_id = middle_nodes_table[location];
|
||||
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retrieve the packed path from the heap
|
||||
PackedPath packed_path = mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
|
||||
query_heap, middle_node_id);
|
||||
|
||||
// ... and reverse it to have packed edges in the correct order,
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
}
|
||||
|
||||
// ... unpack path
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
std::vector<EdgeID> unpacked_edges;
|
||||
|
||||
std::tie(weight, unpacked_nodes, unpacked_edges) =
|
||||
unpackPathAndCalculateDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
packed_path,
|
||||
middle_node_id,
|
||||
phantom_nodes,
|
||||
phantom_index,
|
||||
phantom_indices);
|
||||
|
||||
// Accumulate the path length without the last node
|
||||
auto annotation = 0.0;
|
||||
|
||||
BOOST_ASSERT(!unpacked_nodes.empty());
|
||||
for (auto node = unpacked_nodes.begin(), last_node = std::prev(unpacked_nodes.end());
|
||||
node != last_node;
|
||||
++node)
|
||||
{
|
||||
annotation += computeEdgeDistance(facade, *node);
|
||||
}
|
||||
|
||||
// ... and add negative source and positive target offsets
|
||||
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
|
||||
// Get source and target phantom nodes
|
||||
// * 1-to-N: source is a single index, target is the corresponding from the indices list
|
||||
// * N-to-1: source is the corresponding from the indices list, target is a single index
|
||||
auto source_phantom_index = phantom_index;
|
||||
auto target_phantom_index = phantom_indices[location];
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::swap(source_phantom_index, target_phantom_index);
|
||||
}
|
||||
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||
const NodeID source_node = unpacked_nodes.front();
|
||||
const NodeID target_node = unpacked_nodes.back();
|
||||
|
||||
EdgeDistance source_offset = 0., target_offset = 0.;
|
||||
if (source_phantom.IsValidForwardSource() &&
|
||||
source_phantom.forward_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// -->s <-- subtract offset to start at source
|
||||
// ......... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
source_offset = source_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (source_phantom.IsValidReverseSource() &&
|
||||
source_phantom.reverse_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// s<------- <-- subtract offset to start at source
|
||||
// ... <-- want this distance
|
||||
// entry 0---1---2---3 <-- 3 is exit node
|
||||
source_offset = source_phantom.GetReverseDistance();
|
||||
}
|
||||
if (target_phantom.IsValidForwardTarget() &&
|
||||
target_phantom.forward_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// ++>t <-- add offset to get to target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (target_phantom.IsValidReverseTarget() &&
|
||||
target_phantom.reverse_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// <++t <-- add offset to get from target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetReverseDistance();
|
||||
}
|
||||
|
||||
distances_table[location] = -source_offset + annotation + target_offset;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(durations, distances_table);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -391,6 +484,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeWeight> &weights_table,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
std::vector<NodeID> &middle_nodes_table,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
const auto node = query_heap.DeleteMin();
|
||||
@@ -427,6 +521,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
{
|
||||
current_weight = new_weight;
|
||||
current_duration = new_duration;
|
||||
middle_nodes_table[location] = node;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,10 +540,11 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto target_weight = query_heap.GetKey(node);
|
||||
const auto target_duration = query_heap.GetData(node).duration;
|
||||
const auto parent = query_heap.GetData(node).parent;
|
||||
const auto from_clique_arc = query_heap.GetData(node).from_clique_arc;
|
||||
|
||||
// Store settled nodes in search space bucket
|
||||
search_space_with_buckets.emplace_back(
|
||||
node, parent, column_idx, target_weight, target_duration);
|
||||
node, parent, from_clique_arc, column_idx, target_weight, target_duration);
|
||||
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
||||
@@ -457,13 +553,226 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
facade, node, target_weight, target_duration, query_heap, phantom_node, maximal_level);
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
void retrievePackedPathFromSearchSpace(NodeID middle_node_id,
|
||||
const unsigned column_idx,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
PackedPath &path)
|
||||
{
|
||||
auto bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||
search_space_with_buckets.end(),
|
||||
middle_node_id,
|
||||
NodeBucket::ColumnCompare(column_idx));
|
||||
|
||||
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
|
||||
"The pointers are not pointing to the same element.");
|
||||
|
||||
NodeID current_node_id = middle_node_id;
|
||||
|
||||
while (bucket_list.first->parent_node != current_node_id &&
|
||||
bucket_list.first != search_space_with_buckets.end())
|
||||
{
|
||||
const auto parent_node_id = bucket_list.first->parent_node;
|
||||
|
||||
const auto from = DIRECTION == FORWARD_DIRECTION ? current_node_id : parent_node_id;
|
||||
const auto to = DIRECTION == FORWARD_DIRECTION ? parent_node_id : current_node_id;
|
||||
path.emplace_back(std::make_tuple(from, to, bucket_list.first->from_clique_arc));
|
||||
|
||||
current_node_id = parent_node_id;
|
||||
bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||
search_space_with_buckets.end(),
|
||||
current_node_id,
|
||||
NodeBucket::ColumnCompare(column_idx));
|
||||
|
||||
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
|
||||
"The pointers are not pointing to the same element.");
|
||||
}
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
void calculateDistances(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const unsigned row_idx,
|
||||
const std::size_t source_index,
|
||||
const unsigned number_of_sources,
|
||||
const unsigned number_of_targets,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeDistance> &distances_table,
|
||||
const std::vector<NodeID> &middle_nodes_table,
|
||||
SearchEngineData<mld::Algorithm> &engine_working_data)
|
||||
{
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
|
||||
facade.GetMaxBorderNodeID() + 1);
|
||||
|
||||
for (unsigned column_idx = 0; column_idx < number_of_targets; ++column_idx)
|
||||
{
|
||||
// Step 1: Get source and target phantom nodes that were used in the bucketed search
|
||||
auto source_phantom_index = source_index;
|
||||
auto target_phantom_index = target_indices[column_idx];
|
||||
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||
|
||||
const auto location = DIRECTION == FORWARD_DIRECTION
|
||||
? row_idx * number_of_targets + column_idx
|
||||
: row_idx + column_idx * number_of_sources;
|
||||
|
||||
if (source_phantom_index == target_phantom_index)
|
||||
{
|
||||
distances_table[location] = 0.0;
|
||||
continue;
|
||||
}
|
||||
|
||||
NodeID middle_node_id = middle_nodes_table[location];
|
||||
|
||||
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||
{
|
||||
distances_table[location] = INVALID_EDGE_DISTANCE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 2: Find path from source to middle node
|
||||
PackedPath packed_path =
|
||||
mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(query_heap, middle_node_id);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
}
|
||||
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> unpacked_nodes_from_source;
|
||||
std::vector<EdgeID> unpacked_edges;
|
||||
std::tie(weight, unpacked_nodes_from_source, unpacked_edges) =
|
||||
unpackPathAndCalculateDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
packed_path,
|
||||
middle_node_id,
|
||||
source_phantom);
|
||||
|
||||
// Step 3: Find path from middle to target node
|
||||
packed_path.clear();
|
||||
retrievePackedPathFromSearchSpace<DIRECTION>(
|
||||
middle_node_id, column_idx, search_space_with_buckets, packed_path);
|
||||
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
}
|
||||
|
||||
std::vector<NodeID> unpacked_nodes_to_target;
|
||||
std::tie(weight, unpacked_nodes_to_target, unpacked_edges) =
|
||||
unpackPathAndCalculateDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
packed_path,
|
||||
middle_node_id,
|
||||
target_phantom);
|
||||
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::swap(unpacked_nodes_to_target, unpacked_nodes_from_source);
|
||||
}
|
||||
|
||||
// Step 4: Compute annotation value along the path nodes without the target node
|
||||
auto annotation = 0.0;
|
||||
|
||||
for (auto node = unpacked_nodes_from_source.begin(),
|
||||
last_node = std::prev(unpacked_nodes_from_source.end());
|
||||
node != last_node;
|
||||
++node)
|
||||
{
|
||||
annotation += computeEdgeDistance(facade, *node);
|
||||
}
|
||||
|
||||
for (auto node = unpacked_nodes_to_target.begin(),
|
||||
last_node = std::prev(unpacked_nodes_to_target.end());
|
||||
node != last_node;
|
||||
++node)
|
||||
{
|
||||
annotation += computeEdgeDistance(facade, *node);
|
||||
}
|
||||
|
||||
// Step 5: Get phantom node offsets and compute the annotation value
|
||||
EdgeDistance source_offset = 0., target_offset = 0.;
|
||||
{
|
||||
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::swap(source_phantom_index, target_phantom_index);
|
||||
}
|
||||
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||
|
||||
NodeID source_node = unpacked_nodes_from_source.front();
|
||||
NodeID target_node = unpacked_nodes_to_target.back();
|
||||
|
||||
if (source_phantom.IsValidForwardSource() &&
|
||||
source_phantom.forward_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// -->s <-- subtract offset to start at source
|
||||
// ......... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
source_offset = source_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (source_phantom.IsValidReverseSource() &&
|
||||
source_phantom.reverse_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// s<------- <-- subtract offset to start at source
|
||||
// ... <-- want this distance
|
||||
// entry 0---1---2---3 <-- 3 is exit node
|
||||
source_offset = source_phantom.GetReverseDistance();
|
||||
}
|
||||
|
||||
if (target_phantom.IsValidForwardTarget() &&
|
||||
target_phantom.forward_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// ++>t <-- add offset to get to target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (target_phantom.IsValidReverseTarget() &&
|
||||
target_phantom.reverse_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// <++t <-- add offset to get from target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetReverseDistance();
|
||||
}
|
||||
}
|
||||
|
||||
distances_table[location] = -source_offset + annotation + target_offset;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices)
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance)
|
||||
{
|
||||
const auto number_of_sources = source_indices.size();
|
||||
const auto number_of_targets = target_indices.size();
|
||||
@@ -471,7 +780,8 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table;
|
||||
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
|
||||
|
||||
std::vector<NodeBucket> search_space_with_buckets;
|
||||
|
||||
@@ -479,22 +789,22 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
|
||||
{
|
||||
const auto index = target_indices[column_idx];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
const auto &target_phantom = phantom_nodes[index];
|
||||
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
insertTargetInHeap(query_heap, phantom);
|
||||
insertTargetInHeap(query_heap, target_phantom);
|
||||
else
|
||||
insertSourceInHeap(query_heap, phantom);
|
||||
insertSourceInHeap(query_heap, target_phantom);
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
backwardRoutingStep<DIRECTION>(
|
||||
facade, column_idx, query_heap, search_space_with_buckets, phantom);
|
||||
facade, column_idx, query_heap, search_space_with_buckets, target_phantom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,18 +814,19 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
// Find shortest paths from sources to all accessible nodes
|
||||
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
|
||||
{
|
||||
const auto index = source_indices[row_idx];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
const auto source_index = source_indices[row_idx];
|
||||
const auto &source_phantom = phantom_nodes[source_index];
|
||||
|
||||
// Clear heap and insert source nodes
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
insertSourceInHeap(query_heap, phantom);
|
||||
insertSourceInHeap(query_heap, source_phantom);
|
||||
else
|
||||
insertTargetInHeap(query_heap, phantom);
|
||||
insertTargetInHeap(query_heap, source_phantom);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
@@ -528,7 +839,25 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
search_space_with_buckets,
|
||||
weights_table,
|
||||
durations_table,
|
||||
phantom);
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
}
|
||||
|
||||
if (calculate_distance)
|
||||
{
|
||||
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
|
||||
calculateDistances<DIRECTION>(query_heap,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
target_indices, // source_indices
|
||||
row_idx,
|
||||
source_index,
|
||||
number_of_sources,
|
||||
number_of_targets,
|
||||
search_space_with_buckets,
|
||||
distances_table,
|
||||
middle_nodes_table,
|
||||
engine_working_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,31 +888,45 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration)
|
||||
{
|
||||
(void)calculate_distance; // flag stub to use for calculating distances in matrix in mld in the
|
||||
// future
|
||||
(void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the
|
||||
// future
|
||||
|
||||
if (source_indices.size() == 1)
|
||||
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
||||
return mld::oneToManySearch<FORWARD_DIRECTION>(
|
||||
engine_working_data, facade, phantom_nodes, source_indices.front(), target_indices);
|
||||
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
source_indices.front(),
|
||||
target_indices,
|
||||
calculate_distance);
|
||||
}
|
||||
|
||||
if (target_indices.size() == 1)
|
||||
{
|
||||
return mld::oneToManySearch<REVERSE_DIRECTION>(
|
||||
engine_working_data, facade, phantom_nodes, target_indices.front(), source_indices);
|
||||
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
target_indices.front(),
|
||||
source_indices,
|
||||
calculate_distance);
|
||||
}
|
||||
|
||||
if (target_indices.size() < source_indices.size())
|
||||
{
|
||||
return mld::manyToManySearch<REVERSE_DIRECTION>(
|
||||
engine_working_data, facade, phantom_nodes, target_indices, source_indices);
|
||||
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
target_indices,
|
||||
source_indices,
|
||||
calculate_distance);
|
||||
}
|
||||
|
||||
return mld::manyToManySearch<FORWARD_DIRECTION>(
|
||||
engine_working_data, facade, phantom_nodes, source_indices, target_indices);
|
||||
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
source_indices,
|
||||
target_indices,
|
||||
calculate_distance);
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
|
||||
Reference in New Issue
Block a user