Unpack paths and return total distance in matrix plugin for CH (#4990)
This commit is contained in:
@@ -81,16 +81,21 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
}
|
||||
|
||||
auto snapped_phantoms = SnapPhantomNodes(phantom_nodes);
|
||||
auto result_table =
|
||||
algorithms.ManyToManySearch(snapped_phantoms, params.sources, params.destinations);
|
||||
|
||||
if (result_table.empty())
|
||||
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
||||
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||
|
||||
auto result_tables_pair = algorithms.ManyToManySearch(
|
||||
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration);
|
||||
|
||||
if ((request_duration & result_tables_pair.first.empty()) ||
|
||||
(request_distance && result_tables_pair.second.empty()))
|
||||
{
|
||||
return Error("NoTable", "No table found", result);
|
||||
}
|
||||
|
||||
api::TableAPI table_api{facade, params};
|
||||
table_api.MakeResponse(result_table, snapped_phantoms, result);
|
||||
table_api.MakeResponse(result_tables_pair, snapped_phantoms, result);
|
||||
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
@@ -475,7 +475,6 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
const auto forward_duration = forward_duration_range[edge.fwd_segment_position];
|
||||
const auto reverse_duration = reverse_duration_range[reverse_duration_range.size() -
|
||||
edge.fwd_segment_position - 1];
|
||||
|
||||
line_int_index.add(forward_duration);
|
||||
line_int_index.add(reverse_duration);
|
||||
}
|
||||
@@ -516,7 +515,6 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
const auto reverse_duration =
|
||||
reverse_duration_range[reverse_duration_range.size() -
|
||||
edge.fwd_segment_position - 1];
|
||||
|
||||
const auto forward_datasource_idx =
|
||||
forward_datasource_range(edge.fwd_segment_position);
|
||||
const auto reverse_datasource_idx = reverse_datasource_range(
|
||||
|
||||
+24
-19
@@ -131,7 +131,7 @@ void ManipulateTableForFSE(const std::size_t source_id,
|
||||
result_table.SetValue(destination_id, i, INVALID_EDGE_WEIGHT);
|
||||
}
|
||||
|
||||
// set destination->source to zero so rountrip treats source and
|
||||
// set destination->source to zero so roundtrip treats source and
|
||||
// destination as one location
|
||||
result_table.SetValue(destination_id, source_id, 0);
|
||||
|
||||
@@ -216,61 +216,66 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
|
||||
|
||||
// compute the duration table of all phantom nodes
|
||||
auto result_table = util::DistTableWrapper<EdgeWeight>(
|
||||
algorithms.ManyToManySearch(snapped_phantoms, {}, {}), number_of_locations);
|
||||
auto result_duration_table = util::DistTableWrapper<EdgeWeight>(
|
||||
algorithms
|
||||
.ManyToManySearch(
|
||||
snapped_phantoms, {}, {}, /*requestDistance*/ false, /*requestDuration*/ true)
|
||||
.first,
|
||||
number_of_locations);
|
||||
|
||||
if (result_table.size() == 0)
|
||||
if (result_duration_table.size() == 0)
|
||||
{
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const constexpr std::size_t BF_MAX_FEASABLE = 10;
|
||||
BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
|
||||
BOOST_ASSERT_MSG(result_duration_table.size() == number_of_locations * number_of_locations,
|
||||
"Distance Table has wrong size");
|
||||
|
||||
if (!IsStronglyConnectedComponent(result_table))
|
||||
if (!IsStronglyConnectedComponent(result_duration_table))
|
||||
{
|
||||
return Error("NoTrips", "No trip visiting all destinations possible.", json_result);
|
||||
}
|
||||
|
||||
if (fixed_start && fixed_end)
|
||||
{
|
||||
ManipulateTableForFSE(source_id, destination_id, result_table);
|
||||
ManipulateTableForFSE(source_id, destination_id, result_duration_table);
|
||||
}
|
||||
|
||||
std::vector<NodeID> trip;
|
||||
trip.reserve(number_of_locations);
|
||||
std::vector<NodeID> duration_trip;
|
||||
duration_trip.reserve(number_of_locations);
|
||||
// get an optimized order in which the destinations should be visited
|
||||
if (number_of_locations < BF_MAX_FEASABLE)
|
||||
{
|
||||
trip = trip::BruteForceTrip(number_of_locations, result_table);
|
||||
duration_trip = trip::BruteForceTrip(number_of_locations, result_duration_table);
|
||||
}
|
||||
else
|
||||
{
|
||||
trip = trip::FarthestInsertionTrip(number_of_locations, result_table);
|
||||
duration_trip = trip::FarthestInsertionTrip(number_of_locations, result_duration_table);
|
||||
}
|
||||
|
||||
// rotate result such that roundtrip starts at node with index 0
|
||||
// thist first if covers scenarios: !fixed_end || fixed_start || (fixed_start && fixed_end)
|
||||
if (!fixed_end || fixed_start)
|
||||
{
|
||||
auto desired_start_index = std::find(std::begin(trip), std::end(trip), 0);
|
||||
BOOST_ASSERT(desired_start_index != std::end(trip));
|
||||
std::rotate(std::begin(trip), desired_start_index, std::end(trip));
|
||||
auto desired_start_index = std::find(std::begin(duration_trip), std::end(duration_trip), 0);
|
||||
BOOST_ASSERT(desired_start_index != std::end(duration_trip));
|
||||
std::rotate(std::begin(duration_trip), desired_start_index, std::end(duration_trip));
|
||||
}
|
||||
else if (fixed_end && !fixed_start && parameters.roundtrip)
|
||||
{
|
||||
auto desired_start_index = std::find(std::begin(trip), std::end(trip), destination_id);
|
||||
BOOST_ASSERT(desired_start_index != std::end(trip));
|
||||
std::rotate(std::begin(trip), desired_start_index, std::end(trip));
|
||||
auto desired_start_index =
|
||||
std::find(std::begin(duration_trip), std::end(duration_trip), destination_id);
|
||||
BOOST_ASSERT(desired_start_index != std::end(duration_trip));
|
||||
std::rotate(std::begin(duration_trip), desired_start_index, std::end(duration_trip));
|
||||
}
|
||||
|
||||
// get the route when visiting all destinations in optimized order
|
||||
InternalRouteResult route =
|
||||
ComputeRoute(algorithms, snapped_phantoms, trip, parameters.roundtrip);
|
||||
ComputeRoute(algorithms, snapped_phantoms, duration_trip, parameters.roundtrip);
|
||||
|
||||
// get api response
|
||||
const std::vector<std::vector<NodeID>> trips = {trip};
|
||||
const std::vector<std::vector<NodeID>> trips = {duration_trip};
|
||||
const std::vector<InternalRouteResult> routes = {route};
|
||||
api::TripAPI trip_api{facade, parameters};
|
||||
trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "engine/routing_algorithms/direct_shortest_path.hpp"
|
||||
|
||||
#include "engine/routing_algorithms/routing_base.hpp"
|
||||
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||
#include "engine/routing_algorithms/routing_base_mld.hpp"
|
||||
|
||||
@@ -60,8 +60,8 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
|
||||
{
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
|
||||
const auto edge_weight = data.weight;
|
||||
|
||||
const auto edge_duration = data.duration;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
@@ -85,12 +85,13 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
|
||||
void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const unsigned row_idx,
|
||||
const unsigned number_of_targets,
|
||||
const std::size_t row_index,
|
||||
const std::size_t number_of_targets,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeWeight> &weights_table,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
std::vector<NodeID> &middle_nodes_table,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
const auto node = query_heap.DeleteMin();
|
||||
@@ -105,12 +106,12 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
for (const auto ¤t_bucket : boost::make_iterator_range(bucket_list))
|
||||
{
|
||||
// Get target id from bucket entry
|
||||
const auto column_idx = current_bucket.column_index;
|
||||
const auto column_index = current_bucket.column_index;
|
||||
const auto target_weight = current_bucket.weight;
|
||||
const auto target_duration = current_bucket.duration;
|
||||
|
||||
auto ¤t_weight = weights_table[row_idx * number_of_targets + column_idx];
|
||||
auto ¤t_duration = durations_table[row_idx * number_of_targets + column_idx];
|
||||
auto ¤t_weight = weights_table[row_index * number_of_targets + column_index];
|
||||
auto ¤t_duration = durations_table[row_index * number_of_targets + column_index];
|
||||
|
||||
// Check if new weight is better
|
||||
auto new_weight = source_weight + target_weight;
|
||||
@@ -122,12 +123,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
{
|
||||
current_weight = std::min(current_weight, new_weight);
|
||||
current_duration = std::min(current_duration, new_duration);
|
||||
middle_nodes_table[row_index * number_of_targets + column_index] = node;
|
||||
}
|
||||
}
|
||||
else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration))
|
||||
{
|
||||
current_weight = new_weight;
|
||||
current_duration = new_duration;
|
||||
middle_nodes_table[row_index * number_of_targets + column_index] = node;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +139,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
|
||||
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const unsigned column_idx,
|
||||
const unsigned column_index,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
std::vector<NodeBucket> &search_space_with_buckets,
|
||||
const PhantomNode &phantom_node)
|
||||
@@ -144,9 +147,11 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto node = query_heap.DeleteMin();
|
||||
const auto target_weight = query_heap.GetKey(node);
|
||||
const auto target_duration = query_heap.GetData(node).duration;
|
||||
const auto parent = query_heap.GetData(node).parent;
|
||||
|
||||
// Store settled nodes in search space bucket
|
||||
search_space_with_buckets.emplace_back(node, column_idx, target_weight, target_duration);
|
||||
search_space_with_buckets.emplace_back(
|
||||
node, parent, column_index, target_weight, target_duration);
|
||||
|
||||
relaxOutgoingEdges<REVERSE_DIRECTION>(
|
||||
facade, node, target_weight, target_duration, query_heap, phantom_node);
|
||||
@@ -154,26 +159,187 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
|
||||
} // namespace ch
|
||||
|
||||
template <>
|
||||
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices)
|
||||
void retrievePackedPathFromSearchSpace(const NodeID middle_node_id,
|
||||
const unsigned column_index,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<NodeID> &packed_leg)
|
||||
{
|
||||
auto bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||
search_space_with_buckets.end(),
|
||||
middle_node_id,
|
||||
NodeBucket::ColumnCompare(column_index));
|
||||
|
||||
NodeID current_node_id = middle_node_id;
|
||||
|
||||
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
|
||||
"The pointers are not pointing to the same element.");
|
||||
|
||||
while (bucket_list.first->parent_node != current_node_id &&
|
||||
bucket_list.first != search_space_with_buckets.end())
|
||||
{
|
||||
current_node_id = bucket_list.first->parent_node;
|
||||
|
||||
packed_leg.emplace_back(current_node_id);
|
||||
|
||||
bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||
search_space_with_buckets.end(),
|
||||
current_node_id,
|
||||
NodeBucket::ColumnCompare(column_index));
|
||||
}
|
||||
}
|
||||
|
||||
void calculateDistances(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const std::size_t row_index,
|
||||
const std::size_t source_index,
|
||||
const PhantomNode &source_phantom,
|
||||
const std::size_t number_of_targets,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeDistance> &distances_table,
|
||||
const std::vector<NodeID> &middle_nodes_table)
|
||||
{
|
||||
std::vector<NodeID> packed_leg;
|
||||
|
||||
for (auto column_index : util::irange<std::size_t>(0, number_of_targets))
|
||||
{
|
||||
const auto target_index = target_indices[column_index];
|
||||
const auto &target_phantom = phantom_nodes[target_index];
|
||||
|
||||
if (source_index == target_index)
|
||||
{
|
||||
distances_table[row_index * number_of_targets + column_index] = 0.0;
|
||||
continue;
|
||||
}
|
||||
|
||||
NodeID middle_node_id = middle_nodes_table[row_index * number_of_targets + column_index];
|
||||
|
||||
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||
{
|
||||
distances_table[row_index * number_of_targets + column_index] = INVALID_EDGE_DISTANCE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 1: Find path from source to middle node
|
||||
ch::retrievePackedPathFromSingleManyToManyHeap(query_heap, middle_node_id, packed_leg);
|
||||
std::reverse(packed_leg.begin(), packed_leg.end());
|
||||
|
||||
packed_leg.push_back(middle_node_id);
|
||||
|
||||
// Step 2: Find path from middle to target node
|
||||
retrievePackedPathFromSearchSpace(
|
||||
middle_node_id, column_index, search_space_with_buckets, packed_leg);
|
||||
|
||||
if (packed_leg.size() == 1 && (needsLoopForward(source_phantom, target_phantom) ||
|
||||
needsLoopBackwards(source_phantom, target_phantom)))
|
||||
{
|
||||
auto weight = ch::getLoopWeight<false>(facade, packed_leg.front());
|
||||
if (weight != INVALID_EDGE_WEIGHT)
|
||||
packed_leg.push_back(packed_leg.front());
|
||||
}
|
||||
if (!packed_leg.empty())
|
||||
{
|
||||
auto annotation =
|
||||
ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end());
|
||||
|
||||
distances_table[row_index * number_of_targets + column_index] = annotation;
|
||||
|
||||
// check the direction of travel to figure out how to calculate the offset to/from
|
||||
// the source/target
|
||||
if (source_phantom.forward_segment_id.id == packed_leg.front())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// -->s <-- subtract offset to start at source
|
||||
// ......... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
EdgeDistance offset = source_phantom.GetForwardDistance();
|
||||
distances_table[row_index * number_of_targets + column_index] -= offset;
|
||||
}
|
||||
else if (source_phantom.reverse_segment_id.id == packed_leg.front())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// s<------- <-- subtract offset to start at source
|
||||
// ... <-- want this distance
|
||||
// entry 0---1---2---3 <-- 3 is exit node
|
||||
EdgeDistance offset = source_phantom.GetReverseDistance();
|
||||
distances_table[row_index * number_of_targets + column_index] -= offset;
|
||||
}
|
||||
if (target_phantom.forward_segment_id.id == packed_leg.back())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// ++>t <-- add offset to get to target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
EdgeDistance offset = target_phantom.GetForwardDistance();
|
||||
distances_table[row_index * number_of_targets + column_index] += offset;
|
||||
}
|
||||
else if (target_phantom.reverse_segment_id.id == packed_leg.back())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// <++t <-- add offset to get from target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
EdgeDistance offset = target_phantom.GetReverseDistance();
|
||||
distances_table[row_index * number_of_targets + column_index] += offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// ->s -->t <-- offsets
|
||||
// --..........++++ <-- subtract source offset and add target offset
|
||||
// .............. <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
EdgeDistance offset =
|
||||
target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance();
|
||||
distances_table[row_index * number_of_targets + column_index] += offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// s<--------<--t <-- GetReverseDistance() returns this offset
|
||||
// ---.........++++ <-- subtract source offset and add target offset
|
||||
// ............. <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
EdgeDistance offset =
|
||||
target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance();
|
||||
distances_table[row_index * number_of_targets + column_index] += offset;
|
||||
}
|
||||
}
|
||||
packed_leg.clear();
|
||||
}
|
||||
}
|
||||
|
||||
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<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration)
|
||||
{
|
||||
(void)calculate_duration; // TODO: stub to use when computing durations become optional
|
||||
|
||||
const auto number_of_sources = source_indices.size();
|
||||
const auto number_of_targets = target_indices.size();
|
||||
const auto number_of_entries = number_of_sources * number_of_targets;
|
||||
|
||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table;
|
||||
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
|
||||
|
||||
std::vector<NodeBucket> search_space_with_buckets;
|
||||
|
||||
// Populate buckets with paths from all accessible nodes to destinations via backward searches
|
||||
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
|
||||
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
|
||||
{
|
||||
const auto index = target_indices[column_idx];
|
||||
const auto index = target_indices[column_index];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
@@ -184,7 +350,8 @@ std::vector<EdgeDuration> manyToManySearch(SearchEngineData<ch::Algorithm> &engi
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
backwardRoutingStep(facade, column_idx, query_heap, search_space_with_buckets, phantom);
|
||||
backwardRoutingStep(
|
||||
facade, column_index, query_heap, search_space_with_buckets, phantom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,32 +359,49 @@ std::vector<EdgeDuration> manyToManySearch(SearchEngineData<ch::Algorithm> &engi
|
||||
std::sort(search_space_with_buckets.begin(), search_space_with_buckets.end());
|
||||
|
||||
// Find shortest paths from sources to all accessible nodes
|
||||
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
|
||||
for (std::uint32_t row_index = 0; row_index < source_indices.size(); ++row_index)
|
||||
{
|
||||
const auto index = source_indices[row_idx];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
const auto source_index = source_indices[row_index];
|
||||
const auto &source_phantom = phantom_nodes[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, phantom);
|
||||
insertSourceInHeap(query_heap, source_phantom);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
forwardRoutingStep(facade,
|
||||
row_idx,
|
||||
row_index,
|
||||
number_of_targets,
|
||||
query_heap,
|
||||
search_space_with_buckets,
|
||||
weights_table,
|
||||
durations_table,
|
||||
phantom);
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
}
|
||||
|
||||
if (calculate_distance)
|
||||
{
|
||||
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
|
||||
calculateDistances(query_heap,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
target_indices,
|
||||
row_index,
|
||||
source_index,
|
||||
source_phantom,
|
||||
number_of_targets,
|
||||
search_space_with_buckets,
|
||||
distances_table,
|
||||
middle_nodes_table);
|
||||
}
|
||||
}
|
||||
|
||||
return durations_table;
|
||||
return std::make_pair(durations_table, distances_table);
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
|
||||
@@ -207,14 +207,16 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
// Unidirectional multi-layer Dijkstra search for 1-to-N and N-to-1 matrices
|
||||
//
|
||||
template <bool DIRECTION>
|
||||
std::vector<EdgeDuration> 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)
|
||||
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)
|
||||
{
|
||||
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances(phantom_indices.size(), INVALID_EDGE_DISTANCE);
|
||||
|
||||
// Collect destination (source) nodes into a map
|
||||
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>>
|
||||
@@ -364,7 +366,7 @@ std::vector<EdgeDuration> oneToManySearch(SearchEngineData<Algorithm> &engine_wo
|
||||
phantom_indices);
|
||||
}
|
||||
|
||||
return durations;
|
||||
return std::make_pair(durations, distances);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -432,9 +434,11 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto node = query_heap.DeleteMin();
|
||||
const auto target_weight = query_heap.GetKey(node);
|
||||
const auto target_duration = query_heap.GetData(node).duration;
|
||||
const auto parent = query_heap.GetData(node).parent;
|
||||
|
||||
// Store settled nodes in search space bucket
|
||||
search_space_with_buckets.emplace_back(node, column_idx, target_weight, target_duration);
|
||||
search_space_with_buckets.emplace_back(
|
||||
node, parent, column_idx, target_weight, target_duration);
|
||||
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
||||
@@ -444,11 +448,12 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices)
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices)
|
||||
{
|
||||
const auto number_of_sources = source_indices.size();
|
||||
const auto number_of_targets = target_indices.size();
|
||||
@@ -456,6 +461,7 @@ std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_w
|
||||
|
||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
|
||||
std::vector<NodeBucket> search_space_with_buckets;
|
||||
|
||||
@@ -516,7 +522,7 @@ std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_w
|
||||
}
|
||||
}
|
||||
|
||||
return durations_table;
|
||||
return std::make_pair(durations_table, distances_table);
|
||||
}
|
||||
|
||||
} // namespace mld
|
||||
@@ -534,12 +540,20 @@ std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_w
|
||||
// then search is performed on a reversed graph with phantom nodes with flipped roles and
|
||||
// returning a transposed matrix.
|
||||
template <>
|
||||
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices)
|
||||
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<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration)
|
||||
{
|
||||
(void)calculate_distance; // flag stub to use for calculating distances in matrix in mld in the
|
||||
// future
|
||||
(void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the
|
||||
// future
|
||||
|
||||
if (source_indices.size() == 1)
|
||||
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
||||
return mld::oneToManySearch<FORWARD_DIRECTION>(
|
||||
|
||||
@@ -59,6 +59,24 @@ void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHe
|
||||
}
|
||||
}
|
||||
|
||||
void retrievePackedPathFromSingleManyToManyHeap(
|
||||
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &search_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path)
|
||||
{
|
||||
NodeID current_node_id = middle_node_id;
|
||||
// all initial nodes will have itself as parent, or a node not in the heap
|
||||
// in case of a core search heap. We need a distinction between core entry nodes
|
||||
// and start nodes since otherwise start node specific code that assumes
|
||||
// node == node.parent (e.g. the loop code) might get actived.
|
||||
while (current_node_id != search_heap.GetData(current_node_id).parent &&
|
||||
search_heap.WasInserted(search_heap.GetData(current_node_id).parent))
|
||||
{
|
||||
current_node_id = search_heap.GetData(current_node_id).parent;
|
||||
packed_path.emplace_back(current_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
// ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
|
||||
// Offsets.
|
||||
|
||||
@@ -101,7 +101,6 @@ std::vector<TurnData> generateTurns(const datafacade &facade,
|
||||
// w
|
||||
// uv is the "approach"
|
||||
// vw is the "exit"
|
||||
|
||||
// Look at every node in the directed graph we created
|
||||
for (const auto &startnode : sorted_startnodes)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user