inline bool StallAtNode(const DataFacadeT &facade, const NodeID node, const EdgeWeight weight, QueryHeap &query_heap) const { for (auto edge : facade.GetAdjacentEdgeRange(node)) { const auto &data = facade.GetEdgeData(edge); const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward); if (reverse_flag) { const NodeID to = facade.GetTarget(edge); const int edge_weight = data.weight; BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid"); if (query_heap.WasInserted(to)) { if (query_heap.GetKey(to) + edge_weight < weight) { return true; } } } } return false; }
inline void RelaxOutgoingEdges(const DataFacadeT &facade, const NodeID node, const EdgeWeight weight, QueryHeap &query_heap) const { for (auto edge : facade.GetAdjacentEdgeRange(node)) { const auto &data = facade.GetEdgeData(edge); const bool direction_flag = (forward_direction ? data.forward : data.backward); if (direction_flag) { const NodeID to = facade.GetTarget(edge); const int edge_weight = data.weight; BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid"); const int to_weight = weight + edge_weight; // New Node discovered -> Add to Heap + Node Info Storage if (!query_heap.WasInserted(to)) { query_heap.Insert(to, to_weight, node); } // Found a shorter Path -> Update weight else if (to_weight < query_heap.GetKey(to)) { // new parent query_heap.GetData(to).parent = node; query_heap.DecreaseKey(to, to_weight); } } } }
void BackwardRoutingStep(const unsigned target_id, QueryHeap &query_heap, SearchSpaceWithBuckets &search_space_with_buckets) const { const NodeID node = query_heap.DeleteMin(); const int target_distance = query_heap.GetKey(node); // store settled nodes in search space bucket search_space_with_buckets[node].emplace_back(target_id, target_distance); if (StallAtNode<false>(node, target_distance, query_heap)) { return; } RelaxOutgoingEdges<false>(node, target_distance, query_heap); }
void ForwardRoutingStep(const DataFacadeT &facade, const unsigned row_idx, const unsigned number_of_targets, QueryHeap &query_heap, const SearchSpaceWithBuckets &search_space_with_buckets, std::vector<EdgeWeight> &result_table) const { const NodeID node = query_heap.DeleteMin(); const int source_weight = query_heap.GetKey(node); // check if each encountered node has an entry const auto bucket_iterator = search_space_with_buckets.find(node); // iterate bucket if there exists one if (bucket_iterator != search_space_with_buckets.end()) { const std::vector<NodeBucket> &bucket_list = bucket_iterator->second; for (const NodeBucket ¤t_bucket : bucket_list) { // get target id from bucket entry const unsigned column_idx = current_bucket.target_id; const int target_weight = current_bucket.weight; auto ¤t_weight = result_table[row_idx * number_of_targets + column_idx]; // check if new weight is better const EdgeWeight new_weight = source_weight + target_weight; if (new_weight < 0) { const EdgeWeight loop_weight = super::GetLoopWeight(facade, node); const int new_weight_with_loop = new_weight + loop_weight; if (loop_weight != INVALID_EDGE_WEIGHT && new_weight_with_loop >= 0) { current_weight = std::min(current_weight, new_weight_with_loop); } } else if (new_weight < current_weight) { result_table[row_idx * number_of_targets + column_idx] = new_weight; } } } if (StallAtNode<true>(facade, node, source_weight, query_heap)) { return; } RelaxOutgoingEdges<true>(facade, node, source_weight, query_heap); }
void BackwardRoutingStep(const DataFacadeT &facade, const unsigned column_idx, QueryHeap &query_heap, SearchSpaceWithBuckets &search_space_with_buckets) const { const NodeID node = query_heap.DeleteMin(); const int target_weight = query_heap.GetKey(node); // store settled nodes in search space bucket search_space_with_buckets[node].emplace_back(column_idx, target_weight); if (StallAtNode<false>(facade, node, target_weight, query_heap)) { return; } RelaxOutgoingEdges<false>(facade, node, target_weight, query_heap); }
// allows a uturn at the target_phantom // searches source forward/reverse -> target forward/reverse void SearchWithUTurn(QueryHeap &forward_heap, QueryHeap &reverse_heap, const bool search_from_forward_node, const bool search_from_reverse_node, const bool search_to_forward_node, const bool search_to_reverse_node, const PhantomNode &source_phantom, const PhantomNode &target_phantom, const int total_distance_to_forward, const int total_distance_to_reverse, int &new_total_distance, std::vector<NodeID> &leg_packed_path) const { forward_heap.Clear(); reverse_heap.Clear(); if (search_from_forward_node) { forward_heap.Insert(source_phantom.forward_node_id, total_distance_to_forward - source_phantom.GetForwardWeightPlusOffset(), source_phantom.forward_node_id); } if (search_from_reverse_node) { forward_heap.Insert(source_phantom.reverse_node_id, total_distance_to_reverse - source_phantom.GetReverseWeightPlusOffset(), source_phantom.reverse_node_id); } if (search_to_forward_node) { reverse_heap.Insert(target_phantom.forward_node_id, target_phantom.GetForwardWeightPlusOffset(), target_phantom.forward_node_id); } if (search_to_reverse_node) { reverse_heap.Insert(target_phantom.reverse_node_id, target_phantom.GetReverseWeightPlusOffset(), target_phantom.reverse_node_id); } BOOST_ASSERT(forward_heap.Size() > 0); BOOST_ASSERT(reverse_heap.Size() > 0); super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path, forceLoop(FORWARD_DIRECTION, source_phantom, target_phantom), forceLoop(REVERSE_DIRECTION, source_phantom, target_phantom)); }
void ForwardRoutingStep(const unsigned source_id, const unsigned number_of_locations, QueryHeap &query_heap, const SearchSpaceWithBuckets &search_space_with_buckets, std::shared_ptr<std::vector<EdgeWeight>> result_table) const { const NodeID node = query_heap.DeleteMin(); const int source_distance = query_heap.GetKey(node); // check if each encountered node has an entry const auto bucket_iterator = search_space_with_buckets.find(node); // iterate bucket if there exists one if (bucket_iterator != search_space_with_buckets.end()) { const std::vector<NodeBucket> &bucket_list = bucket_iterator->second; for (const NodeBucket ¤t_bucket : bucket_list) { // get target id from bucket entry const unsigned target_id = current_bucket.target_id; const int target_distance = current_bucket.distance; const EdgeWeight current_distance = (*result_table)[source_id * number_of_locations + target_id]; // check if new distance is better const EdgeWeight new_distance = source_distance + target_distance; if (new_distance >= 0 && new_distance < current_distance) { (*result_table)[source_id * number_of_locations + target_id] = (source_distance + target_distance); } } } if (StallAtNode<true>(node, source_distance, query_heap)) { return; } RelaxOutgoingEdges<true>(node, source_distance, query_heap); }
// conduct T-Test bool ViaNodeCandidatePassesTTest(QueryHeap &existing_forward_heap, QueryHeap &existing_reverse_heap, QueryHeap &new_forward_heap, QueryHeap &new_reverse_heap, const RankedCandidateNode &candidate, const int length_of_shortest_path, int *length_of_via_path, NodeID *s_v_middle, NodeID *v_t_middle, const EdgeWeight min_edge_offset) const { new_forward_heap.Clear(); new_reverse_heap.Clear(); std::vector<NodeID> packed_s_v_path; std::vector<NodeID> packed_v_t_path; *s_v_middle = SPECIAL_NODEID; int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT; // compute path <s,..,v> by reusing forward search from s new_reverse_heap.Insert(candidate.node, 0, candidate.node); while (new_reverse_heap.Size() > 0) { super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle, &upper_bound_s_v_path_length, min_edge_offset, false); } if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length) { return false; } // compute path <v,..,t> by reusing backward search from t *v_t_middle = SPECIAL_NODEID; int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT; new_forward_heap.Insert(candidate.node, 0, candidate.node); while (new_forward_heap.Size() > 0) { super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle, &upper_bound_of_v_t_path_length, min_edge_offset, true); } if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length) { return false; } *length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length; // retrieve packed paths super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, *s_v_middle, packed_s_v_path); super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, *v_t_middle, packed_v_t_path); NodeID s_P = *s_v_middle, t_P = *v_t_middle; if (SPECIAL_NODEID == s_P) { return false; } if (SPECIAL_NODEID == t_P) { return false; } const int T_threshold = static_cast<int>(VIAPATH_EPSILON * length_of_shortest_path); int unpacked_until_distance = 0; std::stack<SearchSpaceEdge> unpack_stack; // Traverse path s-->v for (std::size_t i = packed_s_v_path.size() - 1; (i > 0) && unpack_stack.empty(); --i) { const EdgeID current_edge_id = facade->FindEdgeInEitherDirection(packed_s_v_path[i - 1], packed_s_v_path[i]); const int length_of_current_edge = facade->GetEdgeData(current_edge_id).distance; if ((length_of_current_edge + unpacked_until_distance) >= T_threshold) { unpack_stack.emplace(packed_s_v_path[i - 1], packed_s_v_path[i]); } else { unpacked_until_distance += length_of_current_edge; s_P = packed_s_v_path[i - 1]; } } while (!unpack_stack.empty()) { const SearchSpaceEdge via_path_edge = unpack_stack.top(); unpack_stack.pop(); EdgeID edge_in_via_path_id = facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second); if (SPECIAL_EDGEID == edge_in_via_path_id) { return false; } const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id); const bool current_edge_is_shortcut = current_edge_data.shortcut; if (current_edge_is_shortcut) { const NodeID via_path_middle_node_id = current_edge_data.id; const EdgeID second_segment_edge_id = facade->FindEdgeInEitherDirection( via_path_middle_node_id, via_path_edge.second); const int second_segment_length = facade->GetEdgeData(second_segment_edge_id).distance; // attention: !unpacking in reverse! // Check if second segment is the one to go over treshold? if yes add second segment // to stack, else push first segment to stack and add distance of second one. if (unpacked_until_distance + second_segment_length >= T_threshold) { unpack_stack.emplace(via_path_middle_node_id, via_path_edge.second); } else { unpacked_until_distance += second_segment_length; unpack_stack.emplace(via_path_edge.first, via_path_middle_node_id); } } else { // edge is not a shortcut, set the start node for T-Test to end of edge. unpacked_until_distance += current_edge_data.distance; s_P = via_path_edge.first; } } int t_test_path_length = unpacked_until_distance; unpacked_until_distance = 0; // Traverse path s-->v BOOST_ASSERT(!packed_v_t_path.empty()); for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1); (i < packed_path_length) && unpack_stack.empty(); ++i) { const EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_v_t_path[i], packed_v_t_path[i + 1]); int length_of_current_edge = facade->GetEdgeData(edgeID).distance; if (length_of_current_edge + unpacked_until_distance >= T_threshold) { unpack_stack.emplace(packed_v_t_path[i], packed_v_t_path[i + 1]); } else { unpacked_until_distance += length_of_current_edge; t_P = packed_v_t_path[i + 1]; } } while (!unpack_stack.empty()) { const SearchSpaceEdge via_path_edge = unpack_stack.top(); unpack_stack.pop(); EdgeID edge_in_via_path_id = facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second); if (SPECIAL_EDGEID == edge_in_via_path_id) { return false; } const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id); const bool IsViaEdgeShortCut = current_edge_data.shortcut; if (IsViaEdgeShortCut) { const NodeID middleOfViaPath = current_edge_data.id; EdgeID edgeIDOfFirstSegment = facade->FindEdgeInEitherDirection(via_path_edge.first, middleOfViaPath); int lengthOfFirstSegment = facade->GetEdgeData(edgeIDOfFirstSegment).distance; // Check if first segment is the one to go over treshold? if yes first segment to // stack, else push second segment to stack and add distance of first one. if (unpacked_until_distance + lengthOfFirstSegment >= T_threshold) { unpack_stack.emplace(via_path_edge.first, middleOfViaPath); } else { unpacked_until_distance += lengthOfFirstSegment; unpack_stack.emplace(middleOfViaPath, via_path_edge.second); } } else { // edge is not a shortcut, set the start node for T-Test to end of edge. unpacked_until_distance += current_edge_data.distance; t_P = via_path_edge.second; } } t_test_path_length += unpacked_until_distance; // Run actual T-Test query and compare if distances equal. engine_working_data.InitializeOrClearThirdThreadLocalStorage( super::facade->GetNumberOfNodes()); QueryHeap &forward_heap3 = *engine_working_data.forward_heap_3; QueryHeap &reverse_heap3 = *engine_working_data.reverse_heap_3; int upper_bound = INVALID_EDGE_WEIGHT; NodeID middle = SPECIAL_NODEID; forward_heap3.Insert(s_P, 0, s_P); reverse_heap3.Insert(t_P, 0, t_P); // exploration from s and t until deletemin/(1+epsilon) > _lengt_oO_sShortest_path while ((forward_heap3.Size() + reverse_heap3.Size()) > 0) { if (!forward_heap3.Empty()) { super::RoutingStep(forward_heap3, reverse_heap3, &middle, &upper_bound, min_edge_offset, true); } if (!reverse_heap3.Empty()) { super::RoutingStep(reverse_heap3, forward_heap3, &middle, &upper_bound, min_edge_offset, false); } } return (upper_bound <= t_test_path_length); }