Candidate query for match is now only depending on gps_precision

This commit is contained in:
Patrick Niklaus 2015-08-29 15:53:33 +02:00
parent ee0c20ae44
commit 262b380280
6 changed files with 73 additions and 97 deletions

View File

@ -91,13 +91,23 @@ template <class CandidateLists> struct HiddenMarkovModel
: breakage(candidates_list.size()), candidates_list(candidates_list), : breakage(candidates_list.size()), candidates_list(candidates_list),
emission_log_probability(emission_log_probability) 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<std::size_t>(0u, candidates_list.size()))
{ {
viterbi.emplace_back(l.size()); const auto& num_candidates = candidates_list[i].size();
parents.emplace_back(l.size()); // add empty vectors
path_lengths.emplace_back(l.size()); if (num_candidates > 0)
suspicious.emplace_back(l.size()); {
pruned.emplace_back(l.size()); 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); clear(0);
@ -121,10 +131,11 @@ template <class CandidateLists> struct HiddenMarkovModel
std::size_t initialize(std::size_t initial_timestamp) std::size_t initialize(std::size_t initial_timestamp)
{ {
BOOST_ASSERT(initial_timestamp < candidates_list.size()); auto num_points = candidates_list.size();
do do
{ {
BOOST_ASSERT(initial_timestamp < num_points);
for (const auto s : osrm::irange<std::size_t>(0u, viterbi[initial_timestamp].size())) for (const auto s : osrm::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
{ {
viterbi[initial_timestamp][s] = viterbi[initial_timestamp][s] =
@ -139,9 +150,9 @@ template <class CandidateLists> struct HiddenMarkovModel
} }
++initial_timestamp; ++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; return osrm::matching::INVALID_STATE;
} }

View File

@ -783,32 +783,18 @@ class StaticRTree
// Returns elements within max_distance. // Returns elements within max_distance.
// If the minium of elements could not be found in the search radius, widen // If the minium of elements could not be found in the search radius, widen
// it until the minimum can be satisfied. // it until the minimum can be satisfied.
// At the number of returned nodes is capped at the given maximum.
bool IncrementalFindPhantomNodeForCoordinateWithDistance( bool IncrementalFindPhantomNodeForCoordinateWithDistance(
const FixedPointCoordinate &input_coordinate, const FixedPointCoordinate &input_coordinate,
std::vector<std::pair<PhantomNode, double>> &result_phantom_node_vector, std::vector<std::pair<PhantomNode, double>> &result_phantom_node_vector,
const double max_distance, 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) const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE)
{ {
unsigned inspected_elements = 0; 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<double, double> projected_coordinate = { std::pair<double, double> projected_coordinate = {
mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION), mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION),
input_coordinate.lon / COORDINATE_PRECISION}; input_coordinate.lon / COORDINATE_PRECISION};
// upper bound pruning technique
upper_bound<float> pruning_bound(max_number_of_phantom_nodes);
// initialize queue with root element // initialize queue with root element
std::priority_queue<IncrementalQueryCandidate> traversal_queue; std::priority_queue<IncrementalQueryCandidate> traversal_queue;
traversal_queue.emplace(0.f, m_search_tree[0]); traversal_queue.emplace(0.f, m_search_tree[0]);
@ -818,6 +804,11 @@ class StaticRTree
const IncrementalQueryCandidate current_query_node = traversal_queue.top(); const IncrementalQueryCandidate current_query_node = traversal_queue.top();
traversal_queue.pop(); traversal_queue.pop();
if (current_query_node.min_dist > max_distance || inspected_elements >= max_checked_elements)
{
break;
}
if (current_query_node.node.template is<TreeNode>()) if (current_query_node.node.template is<TreeNode>())
{ // current object is a tree node { // current object is a tree node
const TreeNode &current_tree_node = const TreeNode &current_tree_node =
@ -839,16 +830,9 @@ class StaticRTree
// distance must be non-negative // distance must be non-negative
BOOST_ASSERT(0.f <= current_perpendicular_distance); BOOST_ASSERT(0.f <= current_perpendicular_distance);
if (pruning_bound.get() >= current_perpendicular_distance || if (current_perpendicular_distance <= max_distance)
(!has_big_cc && !current_edge.is_in_tiny_cc()))
{ {
pruning_bound.insert(current_perpendicular_distance);
traversal_queue.emplace(current_perpendicular_distance, current_edge); traversal_queue.emplace(current_perpendicular_distance, current_edge);
has_big_cc = has_big_cc || !current_edge.is_in_tiny_cc();
}
else
{
++pruned_elements;
} }
} }
} }
@ -865,10 +849,13 @@ class StaticRTree
child_rectangle.GetMinDist(input_coordinate); child_rectangle.GetMinDist(input_coordinate);
BOOST_ASSERT(0.f <= lower_bound_to_element); BOOST_ASSERT(0.f <= lower_bound_to_element);
if (lower_bound_to_element <= max_distance)
{
traversal_queue.emplace(lower_bound_to_element, child_tree_node); traversal_queue.emplace(lower_bound_to_element, child_tree_node);
} }
} }
} }
}
else else
{ // current object is a leaf node { // current object is a leaf node
++inspected_elements; ++inspected_elements;
@ -876,14 +863,6 @@ class StaticRTree
const EdgeDataT &current_segment = const EdgeDataT &current_segment =
current_query_node.node.template get<EdgeDataT>(); current_query_node.node.template get<EdgeDataT>();
// 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 // check if it is smaller than what we had before
float current_ratio = 0.f; float current_ratio = 0.f;
FixedPointCoordinate foot_point_coordinate_on_segment; FixedPointCoordinate foot_point_coordinate_on_segment;
@ -894,9 +873,7 @@ class StaticRTree
m_coordinate_list->at(current_segment.v), input_coordinate, m_coordinate_list->at(current_segment.v), input_coordinate,
projected_coordinate, foot_point_coordinate_on_segment, current_ratio); projected_coordinate, foot_point_coordinate_on_segment, current_ratio);
if (number_of_elements_from_big_cc > 0 && if (current_perpendicular_distance >= max_distance)
result_phantom_node_vector.size() >= min_number_of_phantom_nodes &&
current_perpendicular_distance >= max_distance)
{ {
traversal_queue = std::priority_queue<IncrementalQueryCandidate>{}; traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
continue; continue;
@ -920,36 +897,14 @@ class StaticRTree
// set forward and reverse weights on the phantom node // set forward and reverse weights on the phantom node
SetForwardAndReverseWeightsOnPhantomNode(current_segment, SetForwardAndReverseWeightsOnPhantomNode(current_segment,
result_phantom_node_vector.back().first); 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 // stop the search by flushing the queue
if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes && if (inspected_elements >= max_checked_elements)
number_of_elements_from_big_cc > 0) ||
inspected_elements >= max_checked_elements)
{ {
traversal_queue = std::priority_queue<IncrementalQueryCandidate>{}; traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
} }
} }
// 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(); return !result_phantom_node_vector.empty();
} }

View File

@ -92,11 +92,13 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
} }
bool getCandiates(const std::vector<FixedPointCoordinate> &input_coords, bool getCandiates(const std::vector<FixedPointCoordinate> &input_coords,
const double gps_precision,
std::vector<double> &sub_trace_lengths, std::vector<double> &sub_trace_lengths,
osrm::matching::CandidateLists &candidates_lists) osrm::matching::CandidateLists &candidates_lists)
{ {
double last_distance = double query_radius = 10 * gps_precision;
coordinate_calculation::great_circle_distance(input_coords[0], input_coords[1]); double last_distance = coordinate_calculation::great_circle_distance(input_coords[0], input_coords[1]);
sub_trace_lengths.resize(input_coords.size()); sub_trace_lengths.resize(input_coords.size());
sub_trace_lengths[0] = 0; sub_trace_lengths[0] = 0;
for (const auto current_coordinate : osrm::irange<std::size_t>(0, input_coords.size())) for (const auto current_coordinate : osrm::irange<std::size_t>(0, input_coords.size()))
@ -104,8 +106,8 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
bool allow_uturn = false; bool allow_uturn = false;
if (0 < current_coordinate) if (0 < current_coordinate)
{ {
last_distance = coordinate_calculation::great_circle_distance( last_distance = coordinate_calculation::great_circle_distance(input_coords[current_coordinate - 1], input_coords[current_coordinate]);
input_coords[current_coordinate - 1], input_coords[current_coordinate]);
sub_trace_lengths[current_coordinate] += sub_trace_lengths[current_coordinate] +=
sub_trace_lengths[current_coordinate - 1] + last_distance; sub_trace_lengths[current_coordinate - 1] + last_distance;
} }
@ -124,18 +126,27 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
} }
std::vector<std::pair<PhantomNode, double>> candidates; std::vector<std::pair<PhantomNode, double>> candidates;
if (!facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance( facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
input_coords[current_coordinate], candidates, last_distance / 2.0, 5, input_coords[current_coordinate], candidates, query_radius);
max_number_of_candidates))
{
return false;
}
if (allow_uturn) // sort by foward id, then by reverse id and then by distance
{ std::sort(candidates.begin(), candidates.end(),
candidates_lists.push_back(candidates); [](const std::pair<PhantomNode, double>& lhs, const std::pair<PhantomNode, double>& rhs) {
} return lhs.first.forward_node_id < rhs.first.forward_node_id ||
else (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<PhantomNode, double>& lhs, const std::pair<PhantomNode, double>& 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(); const auto compact_size = candidates.size();
for (const auto i : osrm::irange<std::size_t>(0, compact_size)) for (const auto i : osrm::irange<std::size_t>(0, compact_size))
@ -151,8 +162,15 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
candidates[i].first.reverse_node_id = SPECIAL_NODEID; 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<PhantomNode, double>& lhs, const std::pair<PhantomNode, double>& rhs) {
return lhs.second < rhs.second;
});
candidates_lists.push_back(std::move(candidates));
} }
return true; return true;
@ -246,7 +264,7 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
} }
const bool found_candidates = 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) if (!found_candidates)
{ {
json_result.values["status"] = "No suitable matching candidates found."; json_result.values["status"] = "No suitable matching candidates found.";

View File

@ -107,9 +107,7 @@ template <class EdgeDataT> class BaseDataFacade
virtual bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( virtual bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
const FixedPointCoordinate &input_coordinate, const FixedPointCoordinate &input_coordinate,
std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector, std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector,
const double max_distance, const double max_distance) = 0;
const unsigned min_number_of_phantom_nodes,
const unsigned max_number_of_phantom_nodes) = 0;
virtual unsigned GetCheckSum() const = 0; virtual unsigned GetCheckSum() const = 0;

View File

@ -453,9 +453,7 @@ template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacad
bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
const FixedPointCoordinate &input_coordinate, const FixedPointCoordinate &input_coordinate,
std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector, std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector,
const double max_distance, const double max_distance) override final
const unsigned min_number_of_phantom_nodes,
const unsigned max_number_of_phantom_nodes) override final
{ {
if (!m_static_rtree.get()) if (!m_static_rtree.get())
{ {
@ -463,8 +461,7 @@ template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacad
} }
return m_static_rtree->IncrementalFindPhantomNodeForCoordinateWithDistance( return m_static_rtree->IncrementalFindPhantomNodeForCoordinateWithDistance(
input_coordinate, resulting_phantom_node_vector, max_distance, input_coordinate, resulting_phantom_node_vector, max_distance);
min_number_of_phantom_nodes, max_number_of_phantom_nodes);
} }
unsigned GetCheckSum() const override final { return m_check_sum; } unsigned GetCheckSum() const override final { return m_check_sum; }

View File

@ -424,9 +424,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
const FixedPointCoordinate &input_coordinate, const FixedPointCoordinate &input_coordinate,
std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector, std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector,
const double max_distance, const double max_distance) override final
const unsigned min_number_of_phantom_nodes,
const unsigned max_number_of_phantom_nodes) override final
{ {
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{ {
@ -434,8 +432,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
} }
return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinateWithDistance( return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinateWithDistance(
input_coordinate, resulting_phantom_node_vector, max_distance, input_coordinate, resulting_phantom_node_vector, max_distance);
min_number_of_phantom_nodes, max_number_of_phantom_nodes);
} }
unsigned GetCheckSum() const override final { return m_check_sum; } unsigned GetCheckSum() const override final { return m_check_sum; }