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
@@ -18,12 +18,12 @@ namespace routing_algorithms
InternalManyRoutesResult alternativePathSearch(SearchEngineData<ch::Algorithm> &search_engine_data,
const DataFacade<ch::Algorithm> &facade,
const PhantomNodes &phantom_node_pair,
const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives);
InternalManyRoutesResult alternativePathSearch(SearchEngineData<mld::Algorithm> &search_engine_data,
const DataFacade<mld::Algorithm> &facade,
const PhantomNodes &phantom_node_pair,
const PhantomEndpointCandidates &endpoint_candidates,
unsigned number_of_alternatives);
} // namespace routing_algorithms
@@ -24,7 +24,7 @@ namespace routing_algorithms
template <typename Algorithm>
InternalRouteResult directShortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const PhantomNodes &phantom_nodes);
const PhantomEndpointCandidates &endpoint_candidates);
} // namespace routing_algorithms
} // namespace engine
@@ -94,7 +94,7 @@ template <typename Algorithm>
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);
@@ -34,20 +34,12 @@ namespace engine
namespace routing_algorithms
{
static constexpr bool FORWARD_DIRECTION = true;
static constexpr bool REVERSE_DIRECTION = false;
static constexpr bool DO_NOT_FORCE_LOOPS = false;
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
bool needsLoopForward(const PhantomNodes &phantoms);
bool needsLoopBackwards(const PhantomNodes &phantoms);
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
namespace details
{
template <typename Heap>
void insertSourceInForwardHeap(Heap &forward_heap, const PhantomNode &source)
{
const auto &source = nodes.source_phantom;
if (source.IsValidForwardSource())
{
forward_heap.Insert(source.forward_segment_id.id,
@@ -61,8 +53,11 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
-source.GetReverseWeightPlusOffset(),
source.reverse_segment_id.id);
}
}
const auto &target = nodes.target_phantom;
template <typename Heap>
void insertTargetInReverseHeap(Heap &reverse_heap, const PhantomNode &target)
{
if (target.IsValidForwardTarget())
{
reverse_heap.Insert(target.forward_segment_id.id,
@@ -77,52 +72,104 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
target.reverse_segment_id.id);
}
}
} // namespace details
static constexpr bool FORWARD_DIRECTION = true;
static constexpr bool REVERSE_DIRECTION = false;
template <typename ManyToManyQueryHeap>
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
// Identify nodes in the forward(reverse) search direction that will require loop forcing
// e.g. if source and destination nodes are on the same segment.
std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &candidates);
std::vector<NodeID> getForwardLoopNodes(const PhantomCandidatesToTarget &candidates);
std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &candidates);
std::vector<NodeID> getBackwardLoopNodes(const PhantomCandidatesToTarget &candidates);
// Find the specific phantom node endpoints for a given path from a list of candidates.
PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candidates,
const std::vector<NodeID> &path);
template <typename HeapNodeT>
inline bool force_loop(const std::vector<NodeID> &force_nodes, const HeapNodeT &heap_node)
{
if (phantom_node.IsValidForwardSource())
// if loops are forced, they are so at the source
return !force_nodes.empty() &&
std::find(force_nodes.begin(), force_nodes.end(), heap_node.node) != force_nodes.end() &&
heap_node.data.parent == heap_node.node;
}
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomEndpoints &endpoints)
{
details::insertSourceInForwardHeap(forward_heap, endpoints.source_phantom);
details::insertTargetInReverseHeap(reverse_heap, endpoints.target_phantom);
}
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap,
Heap &reverse_heap,
const PhantomEndpointCandidates &endpoint_candidates)
{
for (const auto &source : endpoint_candidates.source_phantoms)
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id,
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance()});
details::insertSourceInForwardHeap(forward_heap, source);
}
if (phantom_node.IsValidReverseSource())
for (const auto &target : endpoint_candidates.target_phantoms)
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance()});
details::insertTargetInReverseHeap(reverse_heap, target);
}
}
template <typename ManyToManyQueryHeap>
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNodeCandidates &source_candidates)
{
if (phantom_node.IsValidForwardTarget())
for (const auto &phantom_node : source_candidates)
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id,
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance()});
if (phantom_node.IsValidForwardSource())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id,
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance()});
}
if (phantom_node.IsValidReverseSource())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance()});
}
}
if (phantom_node.IsValidReverseTarget())
}
template <typename ManyToManyQueryHeap>
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNodeCandidates &target_candidates)
{
for (const auto &phantom_node : target_candidates)
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id,
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance()});
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id,
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance()});
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id,
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance()});
}
}
}
template <typename FacadeT>
void annotatePath(const FacadeT &facade,
const PhantomNodes &phantom_node_pair,
const PhantomEndpoints &endpoints,
const std::vector<NodeID> &unpacked_nodes,
const std::vector<EdgeID> &unpacked_edges,
std::vector<PathData> &unpacked_path)
@@ -133,14 +180,14 @@ void annotatePath(const FacadeT &facade,
const auto source_node_id = unpacked_nodes.front();
const auto target_node_id = unpacked_nodes.back();
const bool start_traversed_in_reverse =
phantom_node_pair.source_phantom.forward_segment_id.id != source_node_id;
endpoints.source_phantom.forward_segment_id.id != source_node_id;
const bool target_traversed_in_reverse =
phantom_node_pair.target_phantom.forward_segment_id.id != target_node_id;
endpoints.target_phantom.forward_segment_id.id != target_node_id;
BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id == source_node_id ||
phantom_node_pair.source_phantom.reverse_segment_id.id == source_node_id);
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id == target_node_id ||
phantom_node_pair.target_phantom.reverse_segment_id.id == target_node_id);
BOOST_ASSERT(endpoints.source_phantom.forward_segment_id.id == source_node_id ||
endpoints.source_phantom.reverse_segment_id.id == source_node_id);
BOOST_ASSERT(endpoints.target_phantom.forward_segment_id.id == target_node_id ||
endpoints.target_phantom.reverse_segment_id.id == target_node_id);
// datastructures to hold extracted data from geometry
std::vector<NodeID> id_vector;
@@ -180,8 +227,8 @@ void annotatePath(const FacadeT &facade,
const auto geometry_index = facade.GetGeometryIndex(node_id);
get_segment_geometry(geometry_index);
BOOST_ASSERT(id_vector.size() > 0);
BOOST_ASSERT(datasource_vector.size() > 0);
BOOST_ASSERT(!id_vector.empty());
BOOST_ASSERT(!datasource_vector.empty());
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
@@ -190,11 +237,11 @@ void annotatePath(const FacadeT &facade,
std::size_t start_index = 0;
if (is_first_segment)
{
unsigned short segment_position = phantom_node_pair.source_phantom.fwd_segment_position;
unsigned short segment_position = endpoints.source_phantom.fwd_segment_position;
if (start_traversed_in_reverse)
{
segment_position = weight_vector.size() -
phantom_node_pair.source_phantom.fwd_segment_position - 1;
segment_position =
weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
}
BOOST_ASSERT(segment_position >= 0);
start_index = static_cast<std::size_t>(segment_position);
@@ -214,7 +261,7 @@ void annotatePath(const FacadeT &facade,
datasource_vector[segment_idx],
boost::none});
}
BOOST_ASSERT(unpacked_path.size() > 0);
BOOST_ASSERT(!unpacked_path.empty());
const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id);
@@ -237,19 +284,17 @@ void annotatePath(const FacadeT &facade,
{
if (is_local_path)
{
start_index =
weight_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position - 1;
start_index = weight_vector.size() - endpoints.source_phantom.fwd_segment_position - 1;
}
end_index =
weight_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position - 1;
end_index = weight_vector.size() - endpoints.target_phantom.fwd_segment_position - 1;
}
else
{
if (is_local_path)
{
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
start_index = endpoints.source_phantom.fwd_segment_position;
}
end_index = phantom_node_pair.target_phantom.fwd_segment_position;
end_index = endpoints.target_phantom.fwd_segment_position;
}
// Given the following compressed geometry:
@@ -277,11 +322,11 @@ void annotatePath(const FacadeT &facade,
if (!unpacked_path.empty())
{
const auto source_weight = start_traversed_in_reverse
? phantom_node_pair.source_phantom.reverse_weight
: phantom_node_pair.source_phantom.forward_weight;
? endpoints.source_phantom.reverse_weight
: endpoints.source_phantom.forward_weight;
const auto source_duration = start_traversed_in_reverse
? phantom_node_pair.source_phantom.reverse_duration
: phantom_node_pair.source_phantom.forward_duration;
? endpoints.source_phantom.reverse_duration
: endpoints.source_phantom.forward_duration;
// The above code will create segments for (v, w), (w,x), (x, y) and (y, Z).
// However the first segment duration needs to be adjusted to the fact that the source
// phantom is in the middle of the segment. We do this by subtracting v--s from the
@@ -358,12 +403,11 @@ double getPathDistance(const DataFacade<Algorithm> &facade,
template <typename AlgorithmT>
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
const EdgeWeight weight,
const PhantomNodes &phantom_nodes,
const PhantomEndpointCandidates &endpoint_candidates,
const std::vector<NodeID> &unpacked_nodes,
const std::vector<EdgeID> &unpacked_edges)
{
InternalRouteResult raw_route_data;
raw_route_data.segment_end_coordinates = {phantom_nodes};
// No path found for both target nodes?
if (INVALID_EDGE_WEIGHT == weight)
@@ -371,15 +415,18 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
return raw_route_data;
}
auto phantom_endpoints = endpointsFromCandidates(endpoint_candidates, unpacked_nodes);
raw_route_data.leg_endpoints = {phantom_endpoints};
raw_route_data.shortest_path_weight = weight;
raw_route_data.unpacked_path_segments.resize(1);
raw_route_data.source_traversed_in_reverse.push_back(
(unpacked_nodes.front() != phantom_nodes.source_phantom.forward_segment_id.id));
(unpacked_nodes.front() != phantom_endpoints.source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(
(unpacked_nodes.back() != phantom_nodes.target_phantom.forward_segment_id.id));
(unpacked_nodes.back() != phantom_endpoints.target_phantom.forward_segment_id.id));
annotatePath(facade,
phantom_nodes,
phantom_endpoints,
unpacked_nodes,
unpacked_edges,
raw_route_data.unpacked_path_segments.front());
@@ -120,8 +120,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
NodeID &middle_node_id,
EdgeWeight &upper_bound,
EdgeWeight min_edge_offset,
const bool force_loop_forward,
const bool force_loop_reverse)
const std::vector<NodeID> &force_loop_forward_nodes,
const std::vector<NodeID> &force_loop_reverse_nodes)
{
auto heapNode = forward_heap.DeleteMinGetHeapNode();
const auto reverseHeapNode = reverse_heap.GetHeapNodeIfWasInserted(heapNode.node);
@@ -131,9 +131,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight;
if (new_weight < upper_bound)
{
// if loops are forced, they are so at the source
if ((force_loop_forward && heapNode.data.parent == heapNode.node) ||
(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) ||
if (force_loop(force_loop_forward_nodes, heapNode) ||
force_loop(force_loop_reverse_nodes, heapNode) ||
// in this case we are looking at a bi-directional way where the source
// and target phantom are on the same edge based node
new_weight < 0)
@@ -398,7 +397,7 @@ template <typename RandomIter, typename FacadeT>
void unpackPath(const FacadeT &facade,
RandomIter packed_path_begin,
RandomIter packed_path_end,
const PhantomNodes &phantom_nodes,
const PhantomEndpoints &route_endpoints,
std::vector<PathData> &unpacked_path)
{
const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
@@ -422,7 +421,7 @@ void unpackPath(const FacadeT &facade,
});
}
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
annotatePath(facade, route_endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
}
/**
@@ -467,12 +466,35 @@ void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
std::int32_t &weight,
EdgeWeight &weight,
std::vector<NodeID> &packed_leg,
const bool force_loop_forward,
const bool force_loop_reverse,
const PhantomNodes &phantom_nodes,
const int duration_upper_bound = INVALID_EDGE_WEIGHT);
const std::vector<NodeID> &force_loop_forward_node,
const std::vector<NodeID> &force_loop_reverse_node,
const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT);
template <typename PhantomEndpointT>
void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight,
std::vector<NodeID> &packed_leg,
const std::vector<NodeID> &force_loop_forward_node,
const std::vector<NodeID> &force_loop_reverse_node,
const PhantomEndpointT & /*endpoints*/,
const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT)
{
// Avoid templating the CH search implementations.
return search(engine_working_data,
facade,
forward_heap,
reverse_heap,
weight,
packed_leg,
force_loop_forward_node,
force_loop_reverse_node,
duration_upper_bound);
}
// Requires the heaps for be empty
// If heaps should be adjusted to be initialized outside of this function,
@@ -33,24 +33,75 @@ namespace
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomNodes &phantom_nodes)
const PhantomNode &source,
const PhantomNode &target)
{
auto level = [&partition, node](const SegmentID &source, const SegmentID &target) {
if (source.enabled && target.enabled)
return partition.GetQueryLevel(source.id, target.id, node);
return INVALID_LEVEL_ID;
};
return std::min(std::min(level(phantom_nodes.source_phantom.forward_segment_id,
phantom_nodes.target_phantom.forward_segment_id),
level(phantom_nodes.source_phantom.forward_segment_id,
phantom_nodes.target_phantom.reverse_segment_id)),
std::min(level(phantom_nodes.source_phantom.reverse_segment_id,
phantom_nodes.target_phantom.forward_segment_id),
level(phantom_nodes.source_phantom.reverse_segment_id,
phantom_nodes.target_phantom.reverse_segment_id)));
return std::min(std::min(level(source.forward_segment_id, target.forward_segment_id),
level(source.forward_segment_id, target.reverse_segment_id)),
std::min(level(source.reverse_segment_id, target.forward_segment_id),
level(source.reverse_segment_id, target.reverse_segment_id)));
}
inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return true; }
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomEndpoints &endpoints)
{
return getNodeQueryLevel(partition, node, endpoints.source_phantom, endpoints.target_phantom);
}
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomCandidatesToTarget &endpoint_candidates)
{
auto min_level = std::accumulate(
endpoint_candidates.source_phantoms.begin(),
endpoint_candidates.source_phantoms.end(),
INVALID_LEVEL_ID,
[&](LevelID current_level, const PhantomNode &source) {
return std::min(
current_level,
getNodeQueryLevel(partition, node, source, endpoint_candidates.target_phantom));
});
return min_level;
}
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomEndpointCandidates &endpoint_candidates)
{
auto min_level = std::accumulate(
endpoint_candidates.source_phantoms.begin(),
endpoint_candidates.source_phantoms.end(),
INVALID_LEVEL_ID,
[&](LevelID level_1, const PhantomNode &source) {
return std::min(
level_1,
std::accumulate(endpoint_candidates.target_phantoms.begin(),
endpoint_candidates.target_phantoms.end(),
level_1,
[&](LevelID level_2, const PhantomNode &target) {
return std::min(
level_2,
getNodeQueryLevel(partition, node, source, target));
}));
});
return min_level;
}
template <typename PhantomCandidateT>
inline bool checkParentCellRestriction(CellID, const PhantomCandidateT &)
{
return true;
}
// Restricted search (Args is LevelID, CellID):
// * use the fixed level for queries
@@ -72,17 +123,23 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
const NodeID node,
const PhantomNode &phantom_node)
const PhantomNodeCandidates &candidates)
{
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;
auto highest_different_level = [&partition, node](const SegmentID &segment) {
return segment.enabled ? partition.GetHighestDifferentLevel(segment.id, node)
: 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));
auto node_level =
std::accumulate(candidates.begin(),
candidates.end(),
INVALID_LEVEL_ID,
[&](LevelID current_level, const PhantomNode &phantom_node) {
auto highest_level =
std::min(highest_different_level(phantom_node.forward_segment_id),
highest_different_level(phantom_node.reverse_segment_id));
return std::min(current_level, highest_level);
});
return node_level;
}
@@ -92,31 +149,17 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<PhantomNodeCandidates> &candidates_list,
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]));
}
auto init = getNodeQueryLevel(partition, node, candidates_list[phantom_index]);
auto result = std::accumulate(
phantom_indices.begin(), phantom_indices.end(), init, [&](LevelID level, size_t index) {
return std::min(level, getNodeQueryLevel(partition, node, candidates_list[index]));
});
return result;
}
} // namespace
@@ -229,7 +272,7 @@ template <bool DIRECTION, typename Algorithm, typename... Args>
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
const typename SearchEngineData<Algorithm>::QueryHeap::HeapNode &heapNode,
Args... args)
const Args &... args)
{
const auto &partition = facade.GetMultiLevelPartition();
const auto &cells = facade.GetCellStorage();
@@ -344,9 +387,9 @@ void routingStep(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
NodeID &middle_node,
EdgeWeight &path_upper_bound,
const bool force_loop_forward,
const bool force_loop_reverse,
Args... args)
const std::vector<NodeID> &force_loop_forward_nodes,
const std::vector<NodeID> &force_loop_reverse_nodes,
const Args &... args)
{
const auto heapNode = forward_heap.DeleteMinGetHeapNode();
const auto weight = heapNode.weight;
@@ -366,9 +409,9 @@ void routingStep(const DataFacade<Algorithm> &facade,
// MLD uses loops forcing only to prune single node paths in forward and/or
// backward direction (there is no need to force loops in MLD but in CH)
if (!(force_loop_forward && heapNode.data.parent == heapNode.node) &&
!(force_loop_reverse && reverseHeapNode->data.parent == heapNode.node) &&
(path_weight >= 0) && (path_weight < path_upper_bound))
if (!force_loop(force_loop_forward_nodes, heapNode) &&
!force_loop(force_loop_reverse_nodes, heapNode) && (path_weight >= 0) &&
(path_weight < path_upper_bound))
{
middle_node = heapNode.node;
path_upper_bound = path_weight;
@@ -393,10 +436,10 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool force_loop_forward,
const bool force_loop_reverse,
const std::vector<NodeID> &force_loop_forward_nodes,
const std::vector<NodeID> &force_loop_reverse_nodes,
EdgeWeight weight_upper_bound,
Args... args)
const Args &... args)
{
if (forward_heap.Empty() || reverse_heap.Empty())
{
@@ -423,8 +466,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
reverse_heap,
middle,
weight,
force_loop_forward,
force_loop_reverse,
force_loop_forward_nodes,
force_loop_reverse_nodes,
args...);
if (!forward_heap.Empty())
forward_heap_min = forward_heap.MinKey();
@@ -436,8 +479,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
forward_heap,
middle,
weight,
force_loop_reverse,
force_loop_forward,
force_loop_reverse_nodes,
force_loop_forward_nodes,
args...);
if (!reverse_heap.Empty())
reverse_heap_min = reverse_heap.MinKey();
@@ -494,15 +537,16 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
EdgeWeight subpath_weight;
std::vector<NodeID> subpath_nodes;
std::vector<EdgeID> subpath_edges;
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
facade,
forward_heap,
reverse_heap,
force_loop_forward,
force_loop_reverse,
INVALID_EDGE_WEIGHT,
sublevel,
parent_cell_id);
std::tie(subpath_weight, subpath_nodes, subpath_edges) =
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
force_loop_forward_nodes,
force_loop_reverse_nodes,
INVALID_EDGE_WEIGHT,
sublevel,
parent_cell_id);
BOOST_ASSERT(!subpath_edges.empty());
BOOST_ASSERT(subpath_nodes.size() > 1);
BOOST_ASSERT(subpath_nodes.front() == source);
@@ -517,16 +561,16 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
}
// Alias to be compatible with the CH-based search
template <typename Algorithm>
template <typename Algorithm, typename PhantomEndpointT>
inline void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight,
std::vector<NodeID> &unpacked_nodes,
const bool force_loop_forward,
const bool force_loop_reverse,
const PhantomNodes &phantom_nodes,
const std::vector<NodeID> &force_loop_forward_node,
const std::vector<NodeID> &force_loop_reverse_node,
const PhantomEndpointT &endpoints,
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
{
// TODO: change search calling interface to use unpacked_edges result
@@ -534,10 +578,10 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
facade,
forward_heap,
reverse_heap,
force_loop_forward,
force_loop_reverse,
force_loop_forward_node,
force_loop_reverse_node,
weight_upper_bound,
phantom_nodes);
endpoints);
}
// TODO: refactor CH-related stub to use unpacked_edges
@@ -545,7 +589,7 @@ template <typename RandomIter, typename FacadeT>
void unpackPath(const FacadeT &facade,
RandomIter packed_path_begin,
RandomIter packed_path_end,
const PhantomNodes &phantom_nodes,
const PhantomEndpoints &route_endpoints,
std::vector<PathData> &unpacked_path)
{
const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
@@ -568,7 +612,7 @@ void unpackPath(const FacadeT &facade,
});
}
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
annotatePath(facade, route_endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
}
template <typename Algorithm>
@@ -583,8 +627,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
forward_heap.Clear();
reverse_heap.Clear();
const PhantomNodes phantom_nodes{source_phantom, target_phantom};
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
const PhantomEndpoints endpoints{source_phantom, target_phantom};
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes;
@@ -593,10 +637,10 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
{},
{},
weight_upper_bound,
phantom_nodes);
endpoints);
if (weight == INVALID_EDGE_WEIGHT)
{
@@ -605,7 +649,7 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
std::vector<PathData> unpacked_path;
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
annotatePath(facade, endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
}
@@ -14,10 +14,11 @@ namespace routing_algorithms
{
template <typename Algorithm>
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector,
const boost::optional<bool> continue_straight_at_waypoint);
InternalRouteResult
shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const boost::optional<bool> continue_straight_at_waypoint);
} // namespace routing_algorithms
} // namespace engine
File diff suppressed because it is too large Load Diff