From 48176c64e6fc9ec533eb39f550a9887568439ec2 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 29 Sep 2011 11:48:13 +0000 Subject: [PATCH] k-nearest query optimized by use of heap instead of sorting. [SVN r74608] --- .../index/rtree/visitors/nearest.hpp | 37 +++++++++++------- tests/rtree_function.hpp | 39 ++++++++++++++++++- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp b/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp index d696780e0..dd17994f6 100644 --- a/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp +++ b/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp @@ -73,22 +73,30 @@ public: inline explicit nearest_k(size_t k) : m_count(k) { - // TEMP? - m_neighbors.reserve(m_count + 1); + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_count, "Number of neighbors should be greater than 0"); + + m_neighbors.reserve(m_count); } inline void store(Value const& val, distance_type const& curr_comp_dist) { - m_neighbors.push_back(std::make_pair(curr_comp_dist, val)); - std::sort(m_neighbors.begin(), m_neighbors.end(), neighbors_less); + if ( m_neighbors.size() < m_count ) + { + m_neighbors.push_back(std::make_pair(curr_comp_dist, val)); - if ( m_count < m_neighbors.size() ) - m_neighbors.pop_back(); - - // TODO: awulkiew - test other methods: - // heap, manual inserting - // don't sort if size < k ? - // check the furthest distance at the first place, before push_back() + if ( m_neighbors.size() == m_count ) + std::make_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less); + } + else + { + if ( curr_comp_dist < m_neighbors.front().first ) + { + std::pop_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less); + m_neighbors.back().first = curr_comp_dist; + m_neighbors.back().second = val; + std::push_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less); + } + } } inline bool is_comparable_distance_valid() const @@ -98,9 +106,9 @@ public: inline distance_type comparable_distance() const { - return m_neighbors.size() < m_count ? - std::numeric_limits::max() : - m_neighbors.back().first; + return m_neighbors.size() < 0 + ? std::numeric_limits::max() + : m_neighbors.front().first; } template @@ -123,6 +131,7 @@ private: size_t m_count; std::vector< std::pair > m_neighbors; + distance_type m_biggest_comp_dist; }; // TODO: awulkiew - add additional pruning before adding nodes to the ABL diff --git a/tests/rtree_function.hpp b/tests/rtree_function.hpp index 86db25daa..2243f8399 100644 --- a/tests/rtree_function.hpp +++ b/tests/rtree_function.hpp @@ -148,6 +148,43 @@ namespace helpers return true; } + template + bool nearest_results_compare(Point const& p, Cont const& c1, Cont const& c2, Translator const& tr) + { + namespace bg = boost::geometry; + namespace bgi = boost::geometry::index; + + typedef typename Translator::indexable_type indexable_type; + typedef bg::default_distance_result::type distance_type; + + if ( c1.size() != c2.size() ) + return false; + + if ( c1.size() == 0 && c2.size() == 0 ) + return true; + + distance_type biggest_distance1 = 0; + + for ( typename Cont::const_iterator it = c1.begin() ; it != c1.end() ; ++it ) + { + distance_type curr_distance = bgi::comparable_distance_near(p, tr(*it)); + + if ( biggest_distance1 < curr_distance ) + biggest_distance1 = curr_distance; + } + + distance_type biggest_distance2 = 0; + for ( typename Cont::const_iterator it = c2.begin() ; it != c2.end() ; ++it ) + { + distance_type curr_distance = bgi::comparable_distance_near(p, tr(*it)); + + if ( biggest_distance2 < curr_distance ) + biggest_distance2 = curr_distance; + } + + return biggest_distance1 == biggest_distance2; + } + template void random_query_check(Rtree const& t, Cont const& c, size_t n, Randomizer r) { @@ -233,7 +270,7 @@ namespace helpers std::stringstream ss; ss << "\nPredicate: " << typeid(Predicate).name() << "\nres1: " << res1.size() << ", res2: " << res2.size() << '\n'; - BOOST_CHECK_MESSAGE( helpers::results_compare(res1, res2, t.get_translator()), ss.str()); + BOOST_CHECK_MESSAGE(helpers::nearest_results_compare(pt, res1, res2, t.get_translator()), ss.str()); } } }