Support snapping to multiple ways at an input location (#5953)

This PR improves routing results by adding support for snapping to
multiple ways at input locations.

This means all edges at the snapped location can act as source/target
candidates for routing search, ensuring we always find the best route,
and not the one dependent on the edge selected.
This commit is contained in:
Michael Bell
2022-08-27 11:36:20 +01:00
committed by GitHub
parent bb18a2b428
commit d74e7b66bd
59 changed files with 2820 additions and 1964 deletions
@@ -190,8 +190,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
s_v_middle,
upper_bound_s_v_path_weight,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
{},
{});
}
// compute path <v,..,t> by reusing backward search from node t
NodeID v_t_middle = SPECIAL_NODEID;
@@ -205,8 +205,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
v_t_middle,
upper_bound_of_v_t_path_weight,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
{},
{});
}
*real_weight_of_via_path = upper_bound_s_v_path_weight + upper_bound_of_v_t_path_weight;
@@ -351,8 +351,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
*s_v_middle,
upper_bound_s_v_path_weight,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
{},
{});
}
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_weight)
@@ -372,8 +372,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
*v_t_middle,
upper_bound_of_v_t_path_weight,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
{},
{});
}
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_weight)
@@ -539,25 +539,13 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
{
if (!forward_heap3.Empty())
{
routingStep<FORWARD_DIRECTION>(facade,
forward_heap3,
reverse_heap3,
middle,
upper_bound,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
routingStep<FORWARD_DIRECTION>(
facade, forward_heap3, reverse_heap3, middle, upper_bound, min_edge_offset, {}, {});
}
if (!reverse_heap3.Empty())
{
routingStep<REVERSE_DIRECTION>(facade,
reverse_heap3,
forward_heap3,
middle,
upper_bound,
min_edge_offset,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
routingStep<REVERSE_DIRECTION>(
facade, reverse_heap3, forward_heap3, middle, upper_bound, min_edge_offset, {}, {});
}
}
return (upper_bound <= t_test_path_weight);
@@ -566,15 +554,12 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const PhantomNodes &phantom_node_pair,
const PhantomEndpointCandidates &endpoint_candidates,
unsigned /*number_of_alternatives*/)
{
InternalRouteResult primary_route;
InternalRouteResult secondary_route;
primary_route.segment_end_coordinates = {phantom_node_pair};
secondary_route.segment_end_coordinates = {phantom_node_pair};
std::vector<NodeID> alternative_path;
std::vector<NodeID> via_node_candidate_list;
std::vector<SearchSpaceEdge> forward_search_space;
@@ -592,15 +577,13 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
EdgeWeight upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT;
NodeID middle_node = SPECIAL_NODEID;
const EdgeWeight min_edge_offset =
std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled
? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset()
: 0,
phantom_node_pair.source_phantom.reverse_segment_id.enabled
? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset()
: 0);
insertNodesInHeaps(forward_heap1, reverse_heap1, phantom_node_pair);
insertNodesInHeaps(forward_heap1, reverse_heap1, endpoint_candidates);
// get offset to account for offsets on phantom nodes on compressed edges
EdgeWeight min_edge_offset = forward_heap1.Empty() ? 0 : std::min(0, forward_heap1.MinKey());
BOOST_ASSERT(min_edge_offset <= 0);
// we only every insert negative offsets for nodes in the forward heap
BOOST_ASSERT(reverse_heap1.Empty() || reverse_heap1.MinKey() >= 0);
// search from s and t till new_min/(1+epsilon) > weight_of_shortest_path
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
@@ -790,7 +773,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
&v_t_middle,
min_edge_offset))
{
// select first admissable
// select first admissible
selected_via_node = candidate.node;
break;
}
@@ -799,20 +782,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
// Unpack shortest path and alternative, if they exist
if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight)
{
auto phantom_endpoints = endpointsFromCandidates(endpoint_candidates, packed_shortest_path);
primary_route.leg_endpoints = {phantom_endpoints};
BOOST_ASSERT(!packed_shortest_path.empty());
primary_route.unpacked_path_segments.resize(1);
primary_route.source_traversed_in_reverse.push_back(
(packed_shortest_path.front() !=
phantom_node_pair.source_phantom.forward_segment_id.id));
phantom_endpoints.source_phantom.forward_segment_id.id));
primary_route.target_traversed_in_reverse.push_back((
packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
packed_shortest_path.back() != phantom_endpoints.target_phantom.forward_segment_id.id));
unpackPath(facade,
// -- packed input
packed_shortest_path.begin(),
packed_shortest_path.end(),
// -- start of route
phantom_node_pair,
phantom_endpoints,
// -- unpacked output
primary_route.unpacked_path_segments.front());
primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight;
@@ -830,19 +816,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
v_t_middle,
packed_alternate_path);
auto phantom_endpoints =
endpointsFromCandidates(endpoint_candidates, packed_alternate_path);
secondary_route.leg_endpoints = {phantom_endpoints};
secondary_route.unpacked_path_segments.resize(1);
secondary_route.source_traversed_in_reverse.push_back(
(packed_alternate_path.front() !=
phantom_node_pair.source_phantom.forward_segment_id.id));
phantom_endpoints.source_phantom.forward_segment_id.id));
secondary_route.target_traversed_in_reverse.push_back(
(packed_alternate_path.back() !=
phantom_node_pair.target_phantom.forward_segment_id.id));
phantom_endpoints.target_phantom.forward_segment_id.id));
// unpack the alternate path
unpackPath(facade,
packed_alternate_path.begin(),
packed_alternate_path.end(),
phantom_node_pair,
phantom_endpoints,
secondary_route.unpacked_path_segments.front());
secondary_route.shortest_path_weight = weight_of_via_path;
@@ -133,12 +133,13 @@ double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
return a + b / (duration - d) + c / std::pow(duration - d, 3);
}
Parameters parametersFromRequest(const PhantomNodes &phantom_node_pair)
Parameters parametersFromRequest(const PhantomEndpointCandidates &endpoint_candidates)
{
Parameters parameters;
const auto distance = util::coordinate_calculation::greatCircleDistance(
phantom_node_pair.source_phantom.location, phantom_node_pair.target_phantom.location);
candidatesSnappedLocation(endpoint_candidates.source_phantoms),
candidatesSnappedLocation(endpoint_candidates.target_phantoms));
// 10km
if (distance < 10000.)
@@ -547,7 +548,7 @@ void unpackPackedPaths(InputIt first,
OutIt out,
SearchEngineData<Algorithm> &search_engine_data,
const Facade &facade,
const PhantomNodes &phantom_node_pair)
const PhantomEndpointCandidates &endpoint_candidates)
{
util::static_assert_iter_category<InputIt, std::input_iterator_tag>();
util::static_assert_iter_category<OutIt, std::output_iterator_tag>();
@@ -600,7 +601,7 @@ void unpackPackedPaths(InputIt first,
}
else
{ // an overlay graph edge
LevelID level = getNodeQueryLevel(partition, source, phantom_node_pair); // XXX
LevelID level = getNodeQueryLevel(partition, source, endpoint_candidates); // XXX
CellID parent_cell_id = partition.GetCell(level, source);
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
@@ -624,8 +625,8 @@ void unpackPackedPaths(InputIt first,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
{},
{},
INVALID_EDGE_WEIGHT,
sublevel,
parent_cell_id);
@@ -656,13 +657,13 @@ void unpackPackedPaths(InputIt first,
inline std::vector<WeightedViaNode>
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
const Facade &facade,
const PhantomNodes &phantom_node_pair,
const PhantomEndpointCandidates &endpoint_candidates,
const Parameters &parameters)
{
Heap &forward_heap = *search_engine_data.forward_heap_1;
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
insertNodesInHeaps(forward_heap, reverse_heap, phantom_node_pair);
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
if (forward_heap.Empty() || reverse_heap.Empty())
{
return {};
@@ -712,9 +713,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
reverse_heap,
overlap_via,
overlap_weight,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
phantom_node_pair);
{},
{},
endpoint_candidates);
if (!forward_heap.Empty())
forward_heap_min = forward_heap.MinKey();
@@ -738,9 +739,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
forward_heap,
overlap_via,
overlap_weight,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
phantom_node_pair);
{},
{},
endpoint_candidates);
if (!reverse_heap.Empty())
reverse_heap_min = reverse_heap.MinKey();
@@ -776,10 +777,10 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
// https://github.com/Project-OSRM/osrm-backend/issues/3905
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
const Facade &facade,
const PhantomNodes &phantom_node_pair,
const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives)
{
Parameters parameters = parametersFromRequest(phantom_node_pair);
Parameters parameters = parametersFromRequest(endpoint_candidates);
const auto max_number_of_alternatives = number_of_alternatives;
const auto max_number_of_alternatives_to_unpack =
@@ -798,7 +799,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
// Do forward and backward search, save search space overlap as via candidates.
auto candidate_vias =
makeCandidateVias(search_engine_data, facade, phantom_node_pair, parameters);
makeCandidateVias(search_engine_data, facade, endpoint_candidates, parameters);
const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; };
auto shortest_path_via_it =
@@ -813,8 +814,6 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
if (!has_shortest_path)
{
InternalRouteResult invalid;
invalid.shortest_path_weight = INVALID_EDGE_WEIGHT;
invalid.segment_end_coordinates = {phantom_node_pair};
return invalid;
}
@@ -900,7 +899,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
std::back_inserter(unpacked_paths),
search_engine_data,
facade,
phantom_node_pair);
endpoint_candidates);
//
// Filter and rank a second time. This time instead of being fast and doing
@@ -927,7 +926,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
routes.reserve(number_of_unpacked_paths);
const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path) {
return extractRoute(facade, path.via.weight, phantom_node_pair, path.nodes, path.edges);
return extractRoute(facade, path.via.weight, endpoint_candidates, path.nodes, path.edges);
};
std::transform(unpacked_paths_first,
@@ -19,7 +19,7 @@ namespace routing_algorithms
template <>
InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade,
const PhantomNodes &phantom_nodes)
const PhantomEndpointCandidates &endpoint_candidates)
{
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
auto &forward_heap = *engine_working_data.forward_heap_1;
@@ -29,7 +29,7 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_leg;
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
search(engine_working_data,
facade,
@@ -37,9 +37,9 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
reverse_heap,
weight,
packed_leg,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
phantom_nodes);
{},
{},
endpoint_candidates);
std::vector<NodeID> unpacked_nodes;
std::vector<EdgeID> unpacked_edges;
@@ -60,19 +60,19 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
});
}
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges);
return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
}
template <>
InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &facade,
const PhantomNodes &phantom_nodes)
const PhantomEndpointCandidates &endpoint_candidates)
{
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
facade.GetMaxBorderNodeID() + 1);
auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1;
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
// TODO: when structured bindings will be allowed change to
// auto [weight, source_node, target_node, unpacked_edges] = ...
@@ -83,12 +83,12 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
{},
{},
INVALID_EDGE_WEIGHT,
phantom_nodes);
endpoint_candidates);
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges);
return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
}
} // namespace routing_algorithms
@@ -49,7 +49,7 @@ void relaxOutgoingEdges(
const DataFacade<Algorithm> &facade,
const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const PhantomNode &)
const PhantomNodeCandidates &)
{
if (stallAtNode<DIRECTION>(facade, heapNode, query_heap))
{
@@ -99,7 +99,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node)
const PhantomNodeCandidates &candidates)
{
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same
@@ -151,14 +151,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
}
}
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, phantom_node);
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, candidates);
}
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const unsigned column_index,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
std::vector<NodeBucket> &search_space_with_buckets,
const PhantomNode &phantom_node)
const PhantomNodeCandidates &candidates)
{
// Take a copy (no ref &) of the extracted node because otherwise could be modified later if
// toHeapNode is the same
@@ -172,7 +172,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
heapNode.data.duration,
heapNode.data.distance);
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, phantom_node);
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, candidates);
}
} // namespace ch
@@ -181,7 +181,7 @@ template <>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance)
@@ -202,18 +202,18 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
{
const auto index = target_indices[column_index];
const auto &phantom = phantom_nodes[index];
const auto &target_candidates = candidates_list[index];
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
facade.GetNumberOfNodes());
auto &query_heap = *(engine_working_data.many_to_many_heap);
insertTargetInHeap(query_heap, phantom);
insertTargetInHeap(query_heap, target_candidates);
// Explore search space
while (!query_heap.Empty())
{
backwardRoutingStep(
facade, column_index, query_heap, search_space_with_buckets, phantom);
facade, column_index, query_heap, search_space_with_buckets, target_candidates);
}
}
@@ -224,13 +224,13 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
for (std::uint32_t row_index = 0; row_index < source_indices.size(); ++row_index)
{
const auto source_index = source_indices[row_index];
const auto &source_phantom = phantom_nodes[source_index];
const auto &source_candidates = candidates_list[source_index];
// Clear heap and insert source nodes
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
facade.GetNumberOfNodes());
auto &query_heap = *(engine_working_data.many_to_many_heap);
insertSourceInHeap(query_heap, source_phantom);
insertSourceInHeap(query_heap, source_candidates);
// Explore search space
while (!query_heap.Empty())
@@ -244,7 +244,7 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
durations_table,
distances_table,
middle_nodes_table,
source_phantom);
source_candidates);
}
}
@@ -25,7 +25,7 @@ using PackedPath = std::vector<PackedEdge>;
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
const NodeID node,
const PhantomNode &phantom_node,
const PhantomNodeCandidates &phantom_node,
const LevelID maximal_level)
{
const auto node_level = getNodeQueryLevel(partition, node, phantom_node);
@@ -96,7 +96,7 @@ void relaxOutgoingEdges(
const DataFacade<mld::Algorithm> &facade,
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
Args... args)
const Args &... args)
{
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
@@ -214,59 +214,63 @@ template <bool DIRECTION>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
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<PhantomNodeCandidates> &candidates_list,
std::size_t source_index,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance)
{
std::vector<EdgeWeight> weights_table(phantom_indices.size(), INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations_table(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0,
std::vector<EdgeWeight> weights_table(target_indices.size(), INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations_table(target_indices.size(), MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table(calculate_distance ? target_indices.size() : 0,
MAXIMAL_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
std::vector<NodeID> middle_nodes_table(target_indices.size(), SPECIAL_NODEID);
// Collect destination (source) nodes into a map
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
target_nodes_index;
target_nodes_index.reserve(phantom_indices.size());
for (std::size_t index = 0; index < phantom_indices.size(); ++index)
target_nodes_index.reserve(target_indices.size());
for (std::size_t index = 0; index < target_indices.size(); ++index)
{
const auto &phantom_index = phantom_indices[index];
const auto &phantom_node = phantom_nodes[phantom_index];
const auto &target_candidates = candidates_list[target_indices[index]];
if (DIRECTION == FORWARD_DIRECTION)
for (const auto &phantom_node : target_candidates)
{
if (phantom_node.IsValidForwardTarget())
target_nodes_index.insert(
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseTarget())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance())});
}
else if (DIRECTION == REVERSE_DIRECTION)
{
if (phantom_node.IsValidForwardSource())
target_nodes_index.insert(
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseSource())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance())});
if (DIRECTION == FORWARD_DIRECTION)
{
if (phantom_node.IsValidForwardTarget())
target_nodes_index.insert(
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseTarget())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance())});
}
else if (DIRECTION == REVERSE_DIRECTION)
{
if (phantom_node.IsValidForwardSource())
target_nodes_index.insert(
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseSource())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance())});
}
}
}
@@ -337,42 +341,45 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
};
{ // Place source (destination) adjacent nodes into the heap
const auto &phantom_node = phantom_nodes[phantom_index];
const auto &source_candidates = candidates_list[source_index];
if (DIRECTION == FORWARD_DIRECTION)
for (const auto &phantom_node : source_candidates)
{
if (phantom_node.IsValidForwardSource())
if (DIRECTION == FORWARD_DIRECTION)
{
insert_node(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance());
}
if (phantom_node.IsValidForwardSource())
{
insert_node(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance());
}
if (phantom_node.IsValidReverseSource())
{
insert_node(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance());
if (phantom_node.IsValidReverseSource())
{
insert_node(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance());
}
}
}
else if (DIRECTION == REVERSE_DIRECTION)
{
if (phantom_node.IsValidForwardTarget())
else if (DIRECTION == REVERSE_DIRECTION)
{
insert_node(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance());
}
if (phantom_node.IsValidForwardTarget())
{
insert_node(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance());
}
if (phantom_node.IsValidReverseTarget())
{
insert_node(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance());
if (phantom_node.IsValidReverseTarget())
{
insert_node(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance());
}
}
}
}
@@ -389,7 +396,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
// Relax outgoing edges
relaxOutgoingEdges<DIRECTION>(
facade, heapNode, query_heap, phantom_nodes, phantom_index, phantom_indices);
facade, heapNode, query_heap, candidates_list, source_index, target_indices);
}
return std::make_pair(std::move(durations_table), std::move(distances_table));
@@ -409,7 +416,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node)
const PhantomNodeCandidates &candidates)
{
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same
@@ -455,7 +462,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
}
}
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, phantom_node);
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, candidates);
}
template <bool DIRECTION>
@@ -463,7 +470,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const unsigned column_idx,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
std::vector<NodeBucket> &search_space_with_buckets,
const PhantomNode &phantom_node)
const PhantomNodeCandidates &candidates)
{
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
// the same
@@ -481,7 +488,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto &partition = facade.GetMultiLevelPartition();
const auto maximal_level = partition.GetNumberOfLevels() - 1;
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, phantom_node, maximal_level);
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, candidates, maximal_level);
}
template <bool DIRECTION>
@@ -524,7 +531,7 @@ 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<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance)
@@ -545,22 +552,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 &target_phantom = phantom_nodes[index];
const auto &target_candidates = candidates_list[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, target_phantom);
insertTargetInHeap(query_heap, target_candidates);
else
insertSourceInHeap(query_heap, target_phantom);
insertSourceInHeap(query_heap, target_candidates);
// explore search space
while (!query_heap.Empty())
{
backwardRoutingStep<DIRECTION>(
facade, column_idx, query_heap, search_space_with_buckets, target_phantom);
facade, column_idx, query_heap, search_space_with_buckets, target_candidates);
}
}
@@ -571,7 +578,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
{
const auto source_index = source_indices[row_idx];
const auto &source_phantom = phantom_nodes[source_index];
const auto &source_candidates = candidates_list[source_index];
// Clear heap and insert source nodes
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
@@ -580,9 +587,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
auto &query_heap = *(engine_working_data.many_to_many_heap);
if (DIRECTION == FORWARD_DIRECTION)
insertSourceInHeap(query_heap, source_phantom);
insertSourceInHeap(query_heap, source_candidates);
else
insertTargetInHeap(query_heap, source_phantom);
insertTargetInHeap(query_heap, source_candidates);
// Explore search space
while (!query_heap.Empty())
@@ -597,7 +604,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
durations_table,
distances_table,
middle_nodes_table,
source_phantom);
source_candidates);
}
}
@@ -622,7 +629,7 @@ template <>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<PhantomNodeCandidates> &candidates_list,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance)
@@ -631,7 +638,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
facade,
phantom_nodes,
candidates_list,
source_indices.front(),
target_indices,
calculate_distance);
@@ -641,7 +648,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
{
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
facade,
phantom_nodes,
candidates_list,
target_indices.front(),
source_indices,
calculate_distance);
@@ -651,7 +658,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
{
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
facade,
phantom_nodes,
candidates_list,
target_indices,
source_indices,
calculate_distance);
@@ -659,7 +666,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
facade,
phantom_nodes,
candidates_list,
source_indices,
target_indices,
calculate_distance);
+88 -14
View File
@@ -7,30 +7,104 @@ namespace engine
namespace routing_algorithms
{
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom)
bool requiresForwardLoop(const PhantomNode &source, const PhantomNode &target)
{
return source_phantom.IsValidForwardSource() && target_phantom.IsValidForwardTarget() &&
source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id &&
source_phantom.GetForwardWeightPlusOffset() >
target_phantom.GetForwardWeightPlusOffset();
return source.IsValidForwardSource() && target.IsValidForwardTarget() &&
source.forward_segment_id.id == target.forward_segment_id.id &&
source.GetForwardWeightPlusOffset() > target.GetForwardWeightPlusOffset();
}
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom)
bool requiresBackwardLoop(const PhantomNode &source, const PhantomNode &target)
{
return source_phantom.IsValidReverseSource() && target_phantom.IsValidReverseTarget() &&
source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id &&
source_phantom.GetReverseWeightPlusOffset() >
target_phantom.GetReverseWeightPlusOffset();
return source.IsValidReverseSource() && target.IsValidReverseTarget() &&
source.reverse_segment_id.id == target.reverse_segment_id.id &&
source.GetReverseWeightPlusOffset() > target.GetReverseWeightPlusOffset();
}
bool needsLoopForward(const PhantomNodes &phantoms)
std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
{
return needsLoopForward(phantoms.source_phantom, phantoms.target_phantom);
std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
auto requires_loop =
std::any_of(endpoint_candidates.target_phantoms.begin(),
endpoint_candidates.target_phantoms.end(),
[&](const auto &target_phantom) {
return requiresForwardLoop(source_phantom, target_phantom);
});
if (requires_loop)
{
res.push_back(source_phantom.forward_segment_id.id);
}
}
return res;
}
bool needsLoopBackwards(const PhantomNodes &phantoms)
std::vector<NodeID> getForwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
{
return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom);
std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
if (requiresForwardLoop(source_phantom, endpoint_candidates.target_phantom))
{
res.push_back(source_phantom.forward_segment_id.id);
}
}
return res;
}
std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
{
std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
auto requires_loop =
std::any_of(endpoint_candidates.target_phantoms.begin(),
endpoint_candidates.target_phantoms.end(),
[&](const auto &target_phantom) {
return requiresBackwardLoop(source_phantom, target_phantom);
});
if (requires_loop)
{
res.push_back(source_phantom.reverse_segment_id.id);
}
}
return res;
}
std::vector<NodeID> getBackwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
{
std::vector<NodeID> res;
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
{
if (requiresBackwardLoop(source_phantom, endpoint_candidates.target_phantom))
{
res.push_back(source_phantom.reverse_segment_id.id);
}
}
return res;
}
PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candidates,
const std::vector<NodeID> &path)
{
auto source_it = std::find_if(candidates.source_phantoms.begin(),
candidates.source_phantoms.end(),
[&path](const auto &source_phantom) {
return path.front() == source_phantom.forward_segment_id.id ||
path.front() == source_phantom.reverse_segment_id.id;
});
BOOST_ASSERT(source_it != candidates.source_phantoms.end());
auto target_it = std::find_if(candidates.target_phantoms.begin(),
candidates.target_phantoms.end(),
[&path](const auto &target_phantom) {
return path.back() == target_phantom.forward_segment_id.id ||
path.back() == target_phantom.reverse_segment_id.id;
});
BOOST_ASSERT(target_it != candidates.target_phantoms.end());
return PhantomEndpoints{*source_it, *target_it};
}
} // namespace routing_algorithms
@@ -95,9 +95,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight,
std::vector<NodeID> &packed_leg,
const bool force_loop_forward,
const bool force_loop_reverse,
const PhantomNodes & /*phantom_nodes*/,
const std::vector<NodeID> &force_loop_forward_nodes,
const std::vector<NodeID> &force_loop_reverse_nodes,
const EdgeWeight weight_upper_bound)
{
if (forward_heap.Empty() || reverse_heap.Empty())
@@ -126,8 +125,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
middle,
weight,
min_edge_offset,
force_loop_forward,
force_loop_reverse);
force_loop_forward_nodes,
force_loop_reverse_nodes);
}
if (!reverse_heap.Empty())
{
@@ -137,8 +136,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
middle,
weight,
min_edge_offset,
force_loop_reverse,
force_loop_forward);
force_loop_reverse_nodes,
force_loop_forward_nodes);
}
}
@@ -179,7 +178,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
forward_heap.Clear();
reverse_heap.Clear();
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom});
PhantomEndpoints endpoints{source_phantom, target_phantom};
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_path;
@@ -189,9 +189,9 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
reverse_heap,
weight,
packed_path,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
{source_phantom, target_phantom},
{},
{},
endpoints,
weight_upper_bound);
if (weight == INVALID_EDGE_WEIGHT)
@@ -12,13 +12,13 @@ namespace routing_algorithms
template InternalRouteResult
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector,
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint);
template InternalRouteResult
shortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector,
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint);
} // namespace routing_algorithms