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
+2 -2
View File
@@ -239,10 +239,10 @@ makeWaypoint(const util::Coordinate &location, const double &distance, std::stri
util::json::Object makeWaypoint(const util::Coordinate &location,
const double &distance,
std::string name,
const Hint &hint)
const Hint &location_hints)
{
auto waypoint = makeWaypoint(location, distance, std::move(name));
waypoint.values["hint"] = hint.ToBase64();
waypoint.values["hint"] = location_hints.ToBase64();
return waypoint;
}
+76 -9
View File
@@ -3,10 +3,10 @@
#include "engine/datafacade/datafacade_base.hpp"
#include <boost/assert.hpp>
#include <boost/unordered_set.hpp>
#include <algorithm>
#include <iterator>
#include <ostream>
#include <tuple>
namespace osrm
@@ -14,8 +14,8 @@ namespace osrm
namespace engine
{
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
const datafacade::BaseDataFacade &facade) const
bool SegmentHint::IsValid(const util::Coordinate new_input_coordinates,
const datafacade::BaseDataFacade &facade) const
{
auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
new_input_coordinates.lat == phantom.input_location.lat;
@@ -25,7 +25,7 @@ bool Hint::IsValid(const util::Coordinate new_input_coordinates,
return is_same_input_coordinate && phantom.IsValid() && facade.GetCheckSum() == data_checksum;
}
std::string Hint::ToBase64() const
std::string SegmentHint::ToBase64() const
{
auto base64 = encodeBase64Bytewise(*this);
@@ -36,9 +36,9 @@ std::string Hint::ToBase64() const
return base64;
}
Hint Hint::FromBase64(const std::string &base64Hint)
SegmentHint SegmentHint::FromBase64(const std::string &base64Hint)
{
BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_HINT_SIZE, "Hint has invalid size");
BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_SEGMENT_HINT_SIZE, "Hint has invalid size");
// We need mutability but don't want to change the API
auto encoded = base64Hint;
@@ -47,15 +47,82 @@ Hint Hint::FromBase64(const std::string &base64Hint)
std::replace(begin(encoded), end(encoded), '-', '+');
std::replace(begin(encoded), end(encoded), '_', '/');
return decodeBase64Bytewise<Hint>(encoded);
return decodeBase64Bytewise<SegmentHint>(encoded);
}
bool operator==(const Hint &lhs, const Hint &rhs)
bool operator==(const SegmentHint &lhs, const SegmentHint &rhs)
{
return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum);
}
std::ostream &operator<<(std::ostream &out, const Hint &hint) { return out << hint.ToBase64(); }
bool operator!=(const SegmentHint &lhs, const SegmentHint &rhs) { return !(lhs == rhs); }
std::ostream &operator<<(std::ostream &out, const SegmentHint &hint)
{
return out << hint.ToBase64();
}
std::string Hint::ToBase64() const
{
std::string res;
for (const auto &hint : segment_hints)
{
res += hint.ToBase64();
}
return res;
}
Hint Hint::FromBase64(const std::string &base64Hint)
{
BOOST_ASSERT_MSG(base64Hint.size() % ENCODED_SEGMENT_HINT_SIZE == 0,
"SegmentHint has invalid size");
auto num_hints = base64Hint.size() / ENCODED_SEGMENT_HINT_SIZE;
std::vector<SegmentHint> res(num_hints);
for (const auto i : util::irange<std::size_t>(0UL, num_hints))
{
auto start_offset = i * ENCODED_SEGMENT_HINT_SIZE;
auto end_offset = start_offset + ENCODED_SEGMENT_HINT_SIZE;
res[i] = SegmentHint::FromBase64(
std::string(base64Hint.begin() + start_offset, base64Hint.begin() + end_offset));
}
return {std::move(res)};
}
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
const datafacade::BaseDataFacade &facade) const
{
const auto all_valid =
std::all_of(segment_hints.begin(), segment_hints.end(), [&](const auto &seg_hint) {
return seg_hint.IsValid(new_input_coordinates, facade);
});
if (!all_valid)
{
return false;
}
// Check hints do not contain duplicate segment pairs
// We can't allow duplicates as search heaps do not support it.
boost::unordered_set<NodeID> forward_segments;
boost::unordered_set<NodeID> reverse_segments;
for (const auto &seg_hint : segment_hints)
{
const auto forward_res = forward_segments.insert(seg_hint.phantom.forward_segment_id.id);
if (!forward_res.second)
{
return false;
}
const auto backward_res = reverse_segments.insert(seg_hint.phantom.reverse_segment_id.id);
if (!backward_res.second)
{
return false;
}
}
return true;
}
} // namespace engine
} // namespace osrm
+15 -14
View File
@@ -4,21 +4,16 @@
#include "engine/api/match_api.hpp"
#include "engine/api/match_parameters.hpp"
#include "engine/api/match_parameters_tidy.hpp"
#include "engine/map_matching/bayes_classifier.hpp"
#include "engine/map_matching/sub_matching.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/integer_range.hpp"
#include "util/json_util.hpp"
#include "util/string_util.hpp"
#include <cstdlib>
#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
#include <set>
#include <string>
#include <vector>
namespace osrm
@@ -28,7 +23,7 @@ namespace engine
namespace plugins
{
// Filters PhantomNodes to obtain a set of viable candiates
// Filters PhantomNodes to obtain a set of viable candidates
void filterCandidates(const std::vector<util::Coordinate> &coordinates,
MatchPlugin::CandidateLists &candidates_lists)
{
@@ -272,20 +267,26 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
// FIXME we only run this to obtain the geometry
// The clean way would be to get this directly from the map matching plugin
PhantomNodes current_phantom_node_pair;
for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i)
{
current_phantom_node_pair.source_phantom = sub_matchings[index].nodes[i];
current_phantom_node_pair.target_phantom = sub_matchings[index].nodes[i + 1];
BOOST_ASSERT(current_phantom_node_pair.source_phantom.IsValid());
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
PhantomEndpoints current_endpoints{sub_matchings[index].nodes[i],
sub_matchings[index].nodes[i + 1]};
BOOST_ASSERT(current_endpoints.source_phantom.IsValid());
BOOST_ASSERT(current_endpoints.target_phantom.IsValid());
sub_routes[index].leg_endpoints.push_back(current_endpoints);
}
std::vector<PhantomNodeCandidates> waypoint_candidates;
waypoint_candidates.reserve(sub_matchings[index].nodes.size());
std::transform(sub_matchings[index].nodes.begin(),
sub_matchings[index].nodes.end(),
std::back_inserter(waypoint_candidates),
[](const auto &phantom) { return PhantomNodeCandidates{phantom}; });
// force uturns to be on
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
// possible uturns
sub_routes[index] =
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
sub_routes[index] = algorithms.ShortestPathSearch(waypoint_candidates, {false});
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
if (collapse_legs)
{
-3
View File
@@ -1,10 +1,7 @@
#include "engine/plugins/nearest.hpp"
#include "engine/api/nearest_api.hpp"
#include "engine/api/nearest_parameters.hpp"
#include "engine/phantom_node.hpp"
#include "util/integer_range.hpp"
#include <cstddef>
#include <string>
#include <boost/assert.hpp>
+6 -10
View File
@@ -2,17 +2,11 @@
#include "engine/api/table_api.hpp"
#include "engine/api/table_parameters.hpp"
#include "engine/routing_algorithms/many_to_many.hpp"
#include "engine/search_engine_data.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/json_container.hpp"
#include "util/string_util.hpp"
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include <boost/assert.hpp>
@@ -47,7 +41,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("InvalidOptions", "Coordinates are invalid", result);
}
if (params.bearings.size() > 0 && params.coordinates.size() != params.bearings.size())
if (!params.bearings.empty() && params.coordinates.size() != params.bearings.size())
{
return Error(
"InvalidOptions", "Number of bearings does not match number of coordinates", result);
@@ -79,7 +73,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
"NoSegment", MissingPhantomErrorMessage(phantom_nodes, params.coordinates), result);
}
auto snapped_phantoms = SnapPhantomNodes(phantom_nodes);
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_nodes));
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
@@ -117,9 +111,11 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
params.fallback_coordinate_type ==
api::TableParameters::FallbackCoordinateType::Input
? util::coordinate_calculation::greatCircleDistance(
source.input_location, destination.input_location)
candidatesInputLocation(source),
candidatesInputLocation(destination))
: util::coordinate_calculation::greatCircleDistance(
source.location, destination.location);
candidatesSnappedLocation(source),
candidatesSnappedLocation(destination));
result_tables_pair.first[table_index] =
distance_estimate / (double)params.fallback_speed;
-1
View File
@@ -20,7 +20,6 @@
#include <algorithm>
#include <numeric>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
+17 -30
View File
@@ -4,18 +4,12 @@
#include "engine/api/trip_parameters.hpp"
#include "engine/trip/trip_brute_force.hpp"
#include "engine/trip/trip_farthest_insertion.hpp"
#include "engine/trip/trip_nearest_neighbour.hpp"
#include "util/dist_table_wrapper.hpp" // to access the dist table more easily
#include "util/json_container.hpp"
#include <boost/assert.hpp>
#include <algorithm>
#include <cstdlib>
#include <iterator>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -41,40 +35,33 @@ bool IsSupportedParameterCombination(const bool fixed_start,
// given the node order in which to visit, compute the actual route (with geometry, travel time and
// so on) and return the result
InternalRouteResult TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
const std::vector<PhantomNode> &snapped_phantoms,
const std::vector<NodeID> &trip,
const bool roundtrip) const
InternalRouteResult
TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
const std::vector<NodeID> &trip,
const bool roundtrip) const
{
InternalRouteResult min_route;
// given the final trip, compute total duration and return the route and location permutation
PhantomNodes viapoint;
// computes a roundtrip from the nodes in trip
for (auto node = trip.begin(); node < trip.end() - 1; ++node)
{
const auto from_node = *node;
const auto to_node = *std::next(node);
viapoint = PhantomNodes{snapped_phantoms[from_node], snapped_phantoms[to_node]};
min_route.segment_end_coordinates.emplace_back(viapoint);
}
// TODO make a more efficient solution that doesn't require copying all the waypoints vectors.
std::vector<PhantomNodeCandidates> trip_candidates;
std::transform(trip.begin(),
trip.end(),
std::back_inserter(trip_candidates),
[&](const auto &node) { return waypoint_candidates[node]; });
// return back to the first node if it is a round trip
if (roundtrip)
{
viapoint = PhantomNodes{snapped_phantoms[trip.back()], snapped_phantoms[trip.front()]};
min_route.segment_end_coordinates.emplace_back(viapoint);
trip_candidates.push_back(waypoint_candidates[trip.front()]);
// trip comes out to be something like 0 1 4 3 2 0
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
BOOST_ASSERT(trip_candidates.size() == trip.size() + 1);
}
else
{
// trip comes out to be something like 0 1 4 3 2, so the sizes don't match
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1);
// trip comes out to be something like 0 1 4 3 2
BOOST_ASSERT(trip_candidates.size() == trip.size());
}
min_route = algorithms.ShortestPathSearch(min_route.segment_end_coordinates, {false});
auto min_route = algorithms.ShortestPathSearch(trip_candidates, {false});
BOOST_ASSERT_MSG(min_route.shortest_path_weight < INVALID_EDGE_WEIGHT, "unroutable route");
return min_route;
}
@@ -226,7 +213,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("InvalidValue", "Invalid source or destination value.", result);
}
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
+28 -25
View File
@@ -5,12 +5,10 @@
#include "util/for_each_pair.hpp"
#include "util/integer_range.hpp"
#include "util/json_container.hpp"
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
@@ -95,19 +93,10 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
}
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
std::vector<PhantomNodes> start_end_nodes;
auto build_phantom_pairs = [&start_end_nodes](const PhantomNode &first_node,
const PhantomNode &second_node) {
start_end_nodes.push_back(PhantomNodes{first_node, second_node});
};
util::for_each_pair(snapped_phantoms, build_phantom_pairs);
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
api::RouteAPI route_api{facade, route_parameters};
InternalManyRoutesResult routes;
// TODO: in v6 we should remove the boolean and only keep the number parameter.
// For now just force them to be in sync. and keep backwards compatibility.
const auto wants_alternatives =
@@ -115,20 +104,23 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
(route_parameters.alternatives || route_parameters.number_of_alternatives > 0);
const auto number_of_alternatives = std::max(1u, route_parameters.number_of_alternatives);
InternalManyRoutesResult routes;
// Alternatives do not support vias, only direct s,t queries supported
// See the implementation notes and high-level outline.
// https://github.com/Project-OSRM/osrm-backend/issues/3905
if (1 == start_end_nodes.size() && algorithms.HasAlternativePathSearch() && wants_alternatives)
if (2 == snapped_phantoms.size() && algorithms.HasAlternativePathSearch() && wants_alternatives)
{
routes = algorithms.AlternativePathSearch(start_end_nodes.front(), number_of_alternatives);
routes = algorithms.AlternativePathSearch({snapped_phantoms[0], snapped_phantoms[1]},
number_of_alternatives);
}
else if (1 == start_end_nodes.size() && algorithms.HasDirectShortestPathSearch())
else if (2 == snapped_phantoms.size() && algorithms.HasDirectShortestPathSearch())
{
routes = algorithms.DirectShortestPathSearch(start_end_nodes.front());
routes = algorithms.DirectShortestPathSearch({snapped_phantoms[0], snapped_phantoms[1]});
}
else
{
routes = algorithms.ShortestPathSearch(start_end_nodes, route_parameters.continue_straight);
routes =
algorithms.ShortestPathSearch(snapped_phantoms, route_parameters.continue_straight);
}
// The post condition for all path searches is we have at least one route in our result.
@@ -160,18 +152,29 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
}
}
route_api.MakeResponse(routes, start_end_nodes, result);
route_api.MakeResponse(routes, snapped_phantoms, result);
}
else
{
auto first_component_id = snapped_phantoms.front().component.id;
auto not_in_same_component = std::any_of(snapped_phantoms.begin(),
snapped_phantoms.end(),
[first_component_id](const PhantomNode &node) {
return node.component.id != first_component_id;
});
const auto all_in_same_component =
[](const std::vector<PhantomNodeCandidates> &waypoint_candidates) {
return std::any_of(waypoint_candidates.front().begin(),
waypoint_candidates.front().end(),
// For each of the first possible phantoms, check if all other
// positions in the list have a phantom from the same component.
[&](const PhantomNode &phantom) {
const auto component_id = phantom.component.id;
return std::all_of(
std::next(waypoint_candidates.begin()),
std::end(waypoint_candidates),
[component_id](const PhantomNodeCandidates &candidates) {
return candidatesHaveComponent(candidates,
component_id);
});
});
};
if (not_in_same_component)
if (!all_in_same_component(snapped_phantoms))
{
return Error("NoRoute", "Impossible route between points", result);
}
@@ -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