InternalRouteResult directShortestPathSearch( SearchEngineData<mld::Algorithm> &engine_working_data, const datafacade::ContiguousInternalMemoryDataFacade<mld::Algorithm> &facade, const PhantomNodes &phantom_nodes) { engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); 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); // TODO: when structured bindings will be allowed change to // auto [weight, source_node, target_node, unpacked_edges] = ... EdgeWeight weight = INVALID_EDGE_WEIGHT; std::vector<NodeID> unpacked_nodes; std::vector<EdgeID> unpacked_edges; std::tie(weight, unpacked_nodes, unpacked_edges) = mld::search(engine_working_data, facade, forward_heap, reverse_heap, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS, INVALID_EDGE_WEIGHT, phantom_nodes); return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges); }
InternalRouteResult directShortestPathSearch(SearchEngineData<Algorithm> &engine_working_data, const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade, const PhantomNodes &phantom_nodes) { engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); auto &forward_heap = *engine_working_data.forward_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1; forward_heap.Clear(); reverse_heap.Clear(); EdgeWeight weight = INVALID_EDGE_WEIGHT; std::vector<NodeID> packed_leg; insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); search(engine_working_data, facade, forward_heap, reverse_heap, weight, packed_leg, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS, phantom_nodes); std::vector<NodeID> unpacked_nodes; std::vector<EdgeID> unpacked_edges; if (!packed_leg.empty()) { unpacked_nodes.reserve(packed_leg.size()); unpacked_edges.reserve(packed_leg.size()); unpacked_nodes.push_back(packed_leg.front()); ch::unpackPath(facade, packed_leg.begin(), packed_leg.end(), [&unpacked_nodes, &unpacked_edges](std::pair<NodeID, NodeID> &edge, const auto &edge_id) { BOOST_ASSERT(edge.first == unpacked_nodes.back()); unpacked_nodes.push_back(edge.second); unpacked_edges.push_back(edge_id); }); } return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges); }
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data, const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade, const std::vector<PhantomNodes> &phantom_nodes_vector, const boost::optional<bool> continue_straight_at_waypoint) { InternalRouteResult raw_route_data; raw_route_data.segment_end_coordinates = phantom_nodes_vector; const bool allow_uturn_at_waypoint = !(continue_straight_at_waypoint ? *continue_straight_at_waypoint : facade.GetContinueStraightDefault()); engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); auto &forward_heap = *engine_working_data.forward_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1; int total_weight_to_forward = 0; int total_weight_to_reverse = 0; bool search_from_forward_node = phantom_nodes_vector.front().source_phantom.IsValidForwardSource(); bool search_from_reverse_node = phantom_nodes_vector.front().source_phantom.IsValidReverseSource(); std::vector<NodeID> prev_packed_leg_to_forward; std::vector<NodeID> prev_packed_leg_to_reverse; std::vector<NodeID> total_packed_path_to_forward; std::vector<std::size_t> packed_leg_to_forward_begin; std::vector<NodeID> total_packed_path_to_reverse; std::vector<std::size_t> packed_leg_to_reverse_begin; std::size_t current_leg = 0; // this implements a dynamic program that finds the shortest route through // a list of vias for (const auto &phantom_node_pair : phantom_nodes_vector) { int new_total_weight_to_forward = INVALID_EDGE_WEIGHT; int new_total_weight_to_reverse = INVALID_EDGE_WEIGHT; std::vector<NodeID> packed_leg_to_forward; std::vector<NodeID> packed_leg_to_reverse; const auto &source_phantom = phantom_node_pair.source_phantom; const auto &target_phantom = phantom_node_pair.target_phantom; bool search_to_forward_node = target_phantom.IsValidForwardTarget(); bool search_to_reverse_node = target_phantom.IsValidReverseTarget(); BOOST_ASSERT(!search_from_forward_node || source_phantom.IsValidForwardSource()); BOOST_ASSERT(!search_from_reverse_node || source_phantom.IsValidReverseSource()); if (search_to_reverse_node || search_to_forward_node) { if (allow_uturn_at_waypoint) { searchWithUTurn(engine_working_data, facade, forward_heap, reverse_heap, search_from_forward_node, search_from_reverse_node, search_to_forward_node, search_to_reverse_node, source_phantom, target_phantom, total_weight_to_forward, total_weight_to_reverse, new_total_weight_to_forward, packed_leg_to_forward); // if only the reverse node is valid (e.g. when using the match plugin) we // actually need to move if (!target_phantom.IsValidForwardTarget()) { BOOST_ASSERT(target_phantom.IsValidReverseTarget()); new_total_weight_to_reverse = new_total_weight_to_forward; packed_leg_to_reverse = std::move(packed_leg_to_forward); new_total_weight_to_forward = INVALID_EDGE_WEIGHT; // (*) // // Below we have to check if new_total_weight_to_forward is invalid. // This prevents use-after-move on packed_leg_to_forward. } else if (target_phantom.IsValidReverseTarget()) { new_total_weight_to_reverse = new_total_weight_to_forward; packed_leg_to_reverse = packed_leg_to_forward; } } else { search(engine_working_data, facade, forward_heap, reverse_heap, search_from_forward_node, search_from_reverse_node, search_to_forward_node, search_to_reverse_node, source_phantom, target_phantom, total_weight_to_forward, total_weight_to_reverse, new_total_weight_to_forward, new_total_weight_to_reverse, packed_leg_to_forward, packed_leg_to_reverse); } } // Note: To make sure we do not access the moved-from packed_leg_to_forward // we guard its access by a check for invalid edge weight. See (*) above. // No path found for both target nodes? if ((INVALID_EDGE_WEIGHT == new_total_weight_to_forward) && (INVALID_EDGE_WEIGHT == new_total_weight_to_reverse)) { return raw_route_data; } // we need to figure out how the new legs connect to the previous ones if (current_leg > 0) { bool forward_to_forward = (new_total_weight_to_forward != INVALID_EDGE_WEIGHT) && packed_leg_to_forward.front() == source_phantom.forward_segment_id.id; bool reverse_to_forward = (new_total_weight_to_forward != INVALID_EDGE_WEIGHT) && packed_leg_to_forward.front() == source_phantom.reverse_segment_id.id; bool forward_to_reverse = (new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) && packed_leg_to_reverse.front() == source_phantom.forward_segment_id.id; bool reverse_to_reverse = (new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) && packed_leg_to_reverse.front() == source_phantom.reverse_segment_id.id; BOOST_ASSERT(!forward_to_forward || !reverse_to_forward); BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse); // in this case we always need to copy if (forward_to_forward && forward_to_reverse) { // in this case we copy the path leading to the source forward node // and change the case total_packed_path_to_reverse = total_packed_path_to_forward; packed_leg_to_reverse_begin = packed_leg_to_forward_begin; forward_to_reverse = false; reverse_to_reverse = true; } else if (reverse_to_forward && reverse_to_reverse) { total_packed_path_to_forward = total_packed_path_to_reverse; packed_leg_to_forward_begin = packed_leg_to_reverse_begin; reverse_to_forward = false; forward_to_forward = true; } BOOST_ASSERT(!forward_to_forward || !forward_to_reverse); BOOST_ASSERT(!reverse_to_forward || !reverse_to_reverse); // in this case we just need to swap to regain the correct mapping if (reverse_to_forward || forward_to_reverse) { total_packed_path_to_forward.swap(total_packed_path_to_reverse); packed_leg_to_forward_begin.swap(packed_leg_to_reverse_begin); } } if (new_total_weight_to_forward != INVALID_EDGE_WEIGHT) { BOOST_ASSERT(target_phantom.IsValidForwardTarget()); packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size()); total_packed_path_to_forward.insert(total_packed_path_to_forward.end(), packed_leg_to_forward.begin(), packed_leg_to_forward.end()); search_from_forward_node = true; } else { total_packed_path_to_forward.clear(); packed_leg_to_forward_begin.clear(); search_from_forward_node = false; } if (new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) { BOOST_ASSERT(target_phantom.IsValidReverseTarget()); packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size()); total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(), packed_leg_to_reverse.begin(), packed_leg_to_reverse.end()); search_from_reverse_node = true; } else { total_packed_path_to_reverse.clear(); packed_leg_to_reverse_begin.clear(); search_from_reverse_node = false; } prev_packed_leg_to_forward = std::move(packed_leg_to_forward); prev_packed_leg_to_reverse = std::move(packed_leg_to_reverse); total_weight_to_forward = new_total_weight_to_forward; total_weight_to_reverse = new_total_weight_to_reverse; ++current_leg; } BOOST_ASSERT(total_weight_to_forward != INVALID_EDGE_WEIGHT || total_weight_to_reverse != INVALID_EDGE_WEIGHT); // We make sure the fastest route is always in packed_legs_to_forward if (total_weight_to_forward < total_weight_to_reverse || (total_weight_to_forward == total_weight_to_reverse && total_packed_path_to_forward.size() < total_packed_path_to_reverse.size())) { // insert sentinel packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size()); BOOST_ASSERT(packed_leg_to_forward_begin.size() == phantom_nodes_vector.size() + 1); unpackLegs(facade, phantom_nodes_vector, total_packed_path_to_forward, packed_leg_to_forward_begin, total_weight_to_forward, raw_route_data); } else { // insert sentinel packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size()); BOOST_ASSERT(packed_leg_to_reverse_begin.size() == phantom_nodes_vector.size() + 1); unpackLegs(facade, phantom_nodes_vector, total_packed_path_to_reverse, packed_leg_to_reverse_begin, total_weight_to_reverse, raw_route_data); } return raw_route_data; }
std::vector<EdgeWeight> manyToManySearch(SearchEngineData &engine_working_data, const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &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.empty() ? phantom_nodes.size() : source_indices.size(); const auto number_of_targets = target_indices.empty() ? phantom_nodes.size() : 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<EdgeWeight> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION); engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(facade.GetNumberOfNodes()); auto &query_heap = *(engine_working_data.many_to_many_heap); SearchSpaceWithBuckets search_space_with_buckets; unsigned column_idx = 0; const auto search_target_phantom = [&](const PhantomNode &phantom) { // clear heap and insert target nodes query_heap.Clear(); insertNodesInHeap<REVERSE_DIRECTION>(query_heap, phantom); // explore search space while (!query_heap.Empty()) { backwardRoutingStep(facade, column_idx, query_heap, search_space_with_buckets); } ++column_idx; }; // for each source do forward search unsigned row_idx = 0; const auto search_source_phantom = [&](const PhantomNode &phantom) { // clear heap and insert source nodes query_heap.Clear(); insertNodesInHeap<FORWARD_DIRECTION>(query_heap, phantom); // explore search space while (!query_heap.Empty()) { forwardRoutingStep(facade, row_idx, number_of_targets, query_heap, search_space_with_buckets, weights_table, durations_table); } ++row_idx; }; if (target_indices.empty()) { for (const auto &phantom : phantom_nodes) { search_target_phantom(phantom); } } else { for (const auto index : target_indices) { const auto &phantom = phantom_nodes[index]; search_target_phantom(phantom); } } if (source_indices.empty()) { for (const auto &phantom : phantom_nodes) { search_source_phantom(phantom); } } else { for (const auto index : source_indices) { const auto &phantom = phantom_nodes[index]; search_source_phantom(phantom); } } return durations_table; }