From 262b3802804e53370b4cadee3f8f1f5d7f0333cb Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Sat, 29 Aug 2015 15:53:33 +0200 Subject: [PATCH] Candidate query for match is now only depending on gps_precision --- data_structures/hidden_markov_model.hpp | 31 ++++++--- data_structures/static_rtree.hpp | 69 ++++--------------- plugins/match.hpp | 52 +++++++++----- server/data_structures/datafacade_base.hpp | 4 +- .../data_structures/internal_datafacade.hpp | 7 +- server/data_structures/shared_datafacade.hpp | 7 +- 6 files changed, 73 insertions(+), 97 deletions(-) diff --git a/data_structures/hidden_markov_model.hpp b/data_structures/hidden_markov_model.hpp index cccaf7b5d..60738a561 100644 --- a/data_structures/hidden_markov_model.hpp +++ b/data_structures/hidden_markov_model.hpp @@ -91,13 +91,23 @@ template struct HiddenMarkovModel : breakage(candidates_list.size()), candidates_list(candidates_list), emission_log_probability(emission_log_probability) { - for (const auto &l : candidates_list) + viterbi.resize(candidates_list.size()); + parents.resize(candidates_list.size()); + path_lengths.resize(candidates_list.size()); + suspicious.resize(candidates_list.size()); + pruned.resize(candidates_list.size()); + for (const auto i : osrm::irange(0u, candidates_list.size())) { - viterbi.emplace_back(l.size()); - parents.emplace_back(l.size()); - path_lengths.emplace_back(l.size()); - suspicious.emplace_back(l.size()); - pruned.emplace_back(l.size()); + const auto& num_candidates = candidates_list[i].size(); + // add empty vectors + if (num_candidates > 0) + { + viterbi[i].resize(num_candidates); + parents[i].resize(num_candidates); + path_lengths[i].resize(num_candidates); + suspicious[i].resize(num_candidates); + pruned[i].resize(num_candidates); + } } clear(0); @@ -121,10 +131,11 @@ template struct HiddenMarkovModel std::size_t initialize(std::size_t initial_timestamp) { - BOOST_ASSERT(initial_timestamp < candidates_list.size()); - + auto num_points = candidates_list.size(); do { + BOOST_ASSERT(initial_timestamp < num_points); + for (const auto s : osrm::irange(0u, viterbi[initial_timestamp].size())) { viterbi[initial_timestamp][s] = @@ -139,9 +150,9 @@ template struct HiddenMarkovModel } ++initial_timestamp; - } while (breakage[initial_timestamp - 1]); + } while (initial_timestamp < num_points && breakage[initial_timestamp - 1]); - if (initial_timestamp >= viterbi.size()) + if (initial_timestamp >= num_points) { return osrm::matching::INVALID_STATE; } diff --git a/data_structures/static_rtree.hpp b/data_structures/static_rtree.hpp index e5b7be92c..bd88226ab 100644 --- a/data_structures/static_rtree.hpp +++ b/data_structures/static_rtree.hpp @@ -783,32 +783,18 @@ class StaticRTree // Returns elements within max_distance. // If the minium of elements could not be found in the search radius, widen // it until the minimum can be satisfied. - // At the number of returned nodes is capped at the given maximum. bool IncrementalFindPhantomNodeForCoordinateWithDistance( const FixedPointCoordinate &input_coordinate, std::vector> &result_phantom_node_vector, const double max_distance, - const unsigned min_number_of_phantom_nodes, - const unsigned max_number_of_phantom_nodes, const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE) { unsigned inspected_elements = 0; - unsigned number_of_elements_from_big_cc = 0; - unsigned number_of_elements_from_tiny_cc = 0; - - // is true if a big cc was added to the queue to we also have a lower bound - // for them. it actives pruning for big components - bool has_big_cc = false; - - unsigned pruned_elements = 0; std::pair projected_coordinate = { mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION), input_coordinate.lon / COORDINATE_PRECISION}; - // upper bound pruning technique - upper_bound pruning_bound(max_number_of_phantom_nodes); - // initialize queue with root element std::priority_queue traversal_queue; traversal_queue.emplace(0.f, m_search_tree[0]); @@ -818,6 +804,11 @@ class StaticRTree const IncrementalQueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop(); + if (current_query_node.min_dist > max_distance || inspected_elements >= max_checked_elements) + { + break; + } + if (current_query_node.node.template is()) { // current object is a tree node const TreeNode ¤t_tree_node = @@ -839,16 +830,9 @@ class StaticRTree // distance must be non-negative BOOST_ASSERT(0.f <= current_perpendicular_distance); - if (pruning_bound.get() >= current_perpendicular_distance || - (!has_big_cc && !current_edge.is_in_tiny_cc())) + if (current_perpendicular_distance <= max_distance) { - pruning_bound.insert(current_perpendicular_distance); traversal_queue.emplace(current_perpendicular_distance, current_edge); - has_big_cc = has_big_cc || !current_edge.is_in_tiny_cc(); - } - else - { - ++pruned_elements; } } } @@ -865,7 +849,10 @@ class StaticRTree child_rectangle.GetMinDist(input_coordinate); BOOST_ASSERT(0.f <= lower_bound_to_element); - traversal_queue.emplace(lower_bound_to_element, child_tree_node); + if (lower_bound_to_element <= max_distance) + { + traversal_queue.emplace(lower_bound_to_element, child_tree_node); + } } } } @@ -876,14 +863,6 @@ class StaticRTree const EdgeDataT ¤t_segment = current_query_node.node.template get(); - // continue searching for the first segment from a big component - if (number_of_elements_from_big_cc == 0 && - number_of_elements_from_tiny_cc >= max_number_of_phantom_nodes - 1 && - current_segment.is_in_tiny_cc()) - { - continue; - } - // check if it is smaller than what we had before float current_ratio = 0.f; FixedPointCoordinate foot_point_coordinate_on_segment; @@ -894,9 +873,7 @@ class StaticRTree m_coordinate_list->at(current_segment.v), input_coordinate, projected_coordinate, foot_point_coordinate_on_segment, current_ratio); - if (number_of_elements_from_big_cc > 0 && - result_phantom_node_vector.size() >= min_number_of_phantom_nodes && - current_perpendicular_distance >= max_distance) + if (current_perpendicular_distance >= max_distance) { traversal_queue = std::priority_queue{}; continue; @@ -920,36 +897,14 @@ class StaticRTree // set forward and reverse weights on the phantom node SetForwardAndReverseWeightsOnPhantomNode(current_segment, result_phantom_node_vector.back().first); - - // update counts on what we found from which result class - if (current_segment.is_in_tiny_cc()) - { // found an element in tiny component - ++number_of_elements_from_tiny_cc; - } - else - { // found an element in a big component - ++number_of_elements_from_big_cc; - } } // stop the search by flushing the queue - if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes && - number_of_elements_from_big_cc > 0) || - inspected_elements >= max_checked_elements) + if (inspected_elements >= max_checked_elements) { traversal_queue = std::priority_queue{}; } } - // SimpleLogger().Write() << "result_phantom_node_vector.size(): " << - // result_phantom_node_vector.size(); - // SimpleLogger().Write() << "max_number_of_phantom_nodes: " << max_number_of_phantom_nodes; - // SimpleLogger().Write() << "number_of_elements_from_big_cc: " << - // number_of_elements_from_big_cc; - // SimpleLogger().Write() << "number_of_elements_from_tiny_cc: " << - // number_of_elements_from_tiny_cc; - // SimpleLogger().Write() << "inspected_elements: " << inspected_elements; - // SimpleLogger().Write() << "max_checked_elements: " << max_checked_elements; - // SimpleLogger().Write() << "pruned_elements: " << pruned_elements; return !result_phantom_node_vector.empty(); } diff --git a/plugins/match.hpp b/plugins/match.hpp index a76ab634f..3da7e14af 100644 --- a/plugins/match.hpp +++ b/plugins/match.hpp @@ -92,11 +92,13 @@ template class MapMatchingPlugin : public BasePlugin } bool getCandiates(const std::vector &input_coords, + const double gps_precision, std::vector &sub_trace_lengths, osrm::matching::CandidateLists &candidates_lists) { - double last_distance = - coordinate_calculation::great_circle_distance(input_coords[0], input_coords[1]); + double query_radius = 10 * gps_precision; + double last_distance = coordinate_calculation::great_circle_distance(input_coords[0], input_coords[1]); + sub_trace_lengths.resize(input_coords.size()); sub_trace_lengths[0] = 0; for (const auto current_coordinate : osrm::irange(0, input_coords.size())) @@ -104,8 +106,8 @@ template class MapMatchingPlugin : public BasePlugin bool allow_uturn = false; if (0 < current_coordinate) { - last_distance = coordinate_calculation::great_circle_distance( - input_coords[current_coordinate - 1], input_coords[current_coordinate]); + last_distance = coordinate_calculation::great_circle_distance(input_coords[current_coordinate - 1], input_coords[current_coordinate]); + sub_trace_lengths[current_coordinate] += sub_trace_lengths[current_coordinate - 1] + last_distance; } @@ -124,18 +126,27 @@ template class MapMatchingPlugin : public BasePlugin } std::vector> candidates; - if (!facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance( - input_coords[current_coordinate], candidates, last_distance / 2.0, 5, - max_number_of_candidates)) - { - return false; - } + facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance( + input_coords[current_coordinate], candidates, query_radius); - if (allow_uturn) - { - candidates_lists.push_back(candidates); - } - else + // sort by foward id, then by reverse id and then by distance + std::sort(candidates.begin(), candidates.end(), + [](const std::pair& lhs, const std::pair& rhs) { + return lhs.first.forward_node_id < rhs.first.forward_node_id || + (lhs.first.forward_node_id == rhs.first.forward_node_id && + (lhs.first.reverse_node_id < rhs.first.reverse_node_id || + (lhs.first.reverse_node_id == rhs.first.reverse_node_id && + lhs.second < rhs.second))); + }); + + auto new_end = std::unique(candidates.begin(), candidates.end(), + [](const std::pair& lhs, const std::pair& rhs) { + return lhs.first.forward_node_id == rhs.first.forward_node_id && + lhs.first.reverse_node_id == rhs.first.reverse_node_id; + }); + candidates.resize(new_end - candidates.begin()); + + if (!allow_uturn) { const auto compact_size = candidates.size(); for (const auto i : osrm::irange(0, compact_size)) @@ -151,8 +162,15 @@ template class MapMatchingPlugin : public BasePlugin candidates[i].first.reverse_node_id = SPECIAL_NODEID; } } - candidates_lists.push_back(candidates); } + + // sort by distance to make pruning effective + std::sort(candidates.begin(), candidates.end(), + [](const std::pair& lhs, const std::pair& rhs) { + return lhs.second < rhs.second; + }); + + candidates_lists.push_back(std::move(candidates)); } return true; @@ -246,7 +264,7 @@ template class MapMatchingPlugin : public BasePlugin } const bool found_candidates = - getCandiates(input_coords, sub_trace_lengths, candidates_lists); + getCandiates(input_coords, route_parameters.gps_precision, sub_trace_lengths, candidates_lists); if (!found_candidates) { json_result.values["status"] = "No suitable matching candidates found."; diff --git a/server/data_structures/datafacade_base.hpp b/server/data_structures/datafacade_base.hpp index fc4519da2..baea2bf0e 100644 --- a/server/data_structures/datafacade_base.hpp +++ b/server/data_structures/datafacade_base.hpp @@ -107,9 +107,7 @@ template class BaseDataFacade virtual bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( const FixedPointCoordinate &input_coordinate, std::vector> &resulting_phantom_node_vector, - const double max_distance, - const unsigned min_number_of_phantom_nodes, - const unsigned max_number_of_phantom_nodes) = 0; + const double max_distance) = 0; virtual unsigned GetCheckSum() const = 0; diff --git a/server/data_structures/internal_datafacade.hpp b/server/data_structures/internal_datafacade.hpp index 0678b0937..357ee2532 100644 --- a/server/data_structures/internal_datafacade.hpp +++ b/server/data_structures/internal_datafacade.hpp @@ -453,9 +453,7 @@ template class InternalDataFacade final : public BaseDataFacad bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( const FixedPointCoordinate &input_coordinate, std::vector> &resulting_phantom_node_vector, - const double max_distance, - const unsigned min_number_of_phantom_nodes, - const unsigned max_number_of_phantom_nodes) override final + const double max_distance) override final { if (!m_static_rtree.get()) { @@ -463,8 +461,7 @@ template class InternalDataFacade final : public BaseDataFacad } return m_static_rtree->IncrementalFindPhantomNodeForCoordinateWithDistance( - input_coordinate, resulting_phantom_node_vector, max_distance, - min_number_of_phantom_nodes, max_number_of_phantom_nodes); + input_coordinate, resulting_phantom_node_vector, max_distance); } unsigned GetCheckSum() const override final { return m_check_sum; } diff --git a/server/data_structures/shared_datafacade.hpp b/server/data_structures/shared_datafacade.hpp index d9d907a0a..928a12540 100644 --- a/server/data_structures/shared_datafacade.hpp +++ b/server/data_structures/shared_datafacade.hpp @@ -424,9 +424,7 @@ template class SharedDataFacade final : public BaseDataFacade< bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( const FixedPointCoordinate &input_coordinate, std::vector> &resulting_phantom_node_vector, - const double max_distance, - const unsigned min_number_of_phantom_nodes, - const unsigned max_number_of_phantom_nodes) override final + const double max_distance) override final { if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) { @@ -434,8 +432,7 @@ template class SharedDataFacade final : public BaseDataFacade< } return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinateWithDistance( - input_coordinate, resulting_phantom_node_vector, max_distance, - min_number_of_phantom_nodes, max_number_of_phantom_nodes); + input_coordinate, resulting_phantom_node_vector, max_distance); } unsigned GetCheckSum() const override final { return m_check_sum; }