| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifndef FLANN_RESULTSET_H |
| #define FLANN_RESULTSET_H |
|
|
| #include <algorithm> |
| #include <cstring> |
| #include <iostream> |
| #include <limits> |
| #include <set> |
| #include <vector> |
|
|
| namespace flann |
| { |
|
|
| |
| |
| |
| |
|
|
| template <typename T, typename DistanceType> |
| struct BranchStruct |
| { |
| T node; |
| DistanceType mindist; |
|
|
| BranchStruct() {} |
| BranchStruct(const T& aNode, DistanceType dist) : node(aNode), mindist(dist) {} |
|
|
| bool operator<(const BranchStruct<T, DistanceType>& rhs) const |
| { |
| return mindist<rhs.mindist; |
| } |
| }; |
|
|
|
|
| template <typename DistanceType> |
| struct DistanceIndex |
| { |
| DistanceIndex(DistanceType dist, size_t index) : |
| dist_(dist), index_(index) |
| { |
| } |
| bool operator<(const DistanceIndex& dist_index) const |
| { |
| return (dist_ < dist_index.dist_) || ((dist_ == dist_index.dist_) && index_ < dist_index.index_); |
| } |
| DistanceType dist_; |
| size_t index_; |
| }; |
|
|
|
|
| template <typename DistanceType> |
| class ResultSet |
| { |
| public: |
| virtual ~ResultSet() {} |
|
|
| virtual bool full() const = 0; |
|
|
| virtual void addPoint(DistanceType dist, size_t index) = 0; |
|
|
| virtual DistanceType worstDist() const = 0; |
|
|
| }; |
|
|
| |
| |
| |
| |
| |
| template <typename DistanceType> |
| class KNNSimpleResultSet : public ResultSet<DistanceType> |
| { |
| public: |
| typedef DistanceIndex<DistanceType> DistIndex; |
|
|
| KNNSimpleResultSet(size_t capacity_) : |
| capacity_(capacity_) |
| { |
| |
| dist_index_.resize(capacity_, DistIndex(std::numeric_limits<DistanceType>::max(),-1)); |
| clear(); |
| } |
|
|
| ~KNNSimpleResultSet() |
| { |
| } |
|
|
| |
| |
| |
| void clear() |
| { |
| worst_distance_ = std::numeric_limits<DistanceType>::max(); |
| dist_index_[capacity_-1].dist_ = worst_distance_; |
| count_ = 0; |
| } |
|
|
| |
| |
| |
| |
| size_t size() const |
| { |
| return count_; |
| } |
|
|
| |
| |
| |
| |
| bool full() const |
| { |
| return count_==capacity_; |
| } |
|
|
| |
| |
| |
| |
| |
| void addPoint(DistanceType dist, size_t index) |
| { |
| if (dist>=worst_distance_) return; |
|
|
| if (count_ < capacity_) ++count_; |
| size_t i; |
| for (i=count_-1; i>0; --i) { |
| #ifdef FLANN_FIRST_MATCH |
| if ( (dist_index_[i-1].dist_>dist) || ((dist==dist_index_[i-1].dist_)&&(dist_index_[i-1].index_>index)) ) |
| #else |
| if (dist_index_[i-1].dist_>dist) |
| #endif |
| { |
| dist_index_[i] = dist_index_[i-1]; |
| } |
| else break; |
| } |
| dist_index_[i].dist_ = dist; |
| dist_index_[i].index_ = index; |
| worst_distance_ = dist_index_[capacity_-1].dist_; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| void copy(size_t* indices, DistanceType* dists, size_t num_elements, bool sorted = true) |
| { |
| size_t n = std::min(count_, num_elements); |
| for (size_t i=0; i<n; ++i) { |
| *indices++ = dist_index_[i].index_; |
| *dists++ = dist_index_[i].dist_; |
| } |
| } |
|
|
| DistanceType worstDist() const |
| { |
| return worst_distance_; |
| } |
|
|
| private: |
| size_t capacity_; |
| size_t count_; |
| DistanceType worst_distance_; |
| std::vector<DistIndex> dist_index_; |
| }; |
|
|
| |
| |
| |
| template <typename DistanceType> |
| class KNNResultSet : public ResultSet<DistanceType> |
| { |
| public: |
| typedef DistanceIndex<DistanceType> DistIndex; |
|
|
| KNNResultSet(int capacity) : capacity_(capacity) |
| { |
| |
| dist_index_.resize(capacity_, DistIndex(std::numeric_limits<DistanceType>::max(),-1)); |
| clear(); |
| } |
|
|
| ~KNNResultSet() |
| { |
|
|
| } |
|
|
| |
| |
| |
| void clear() |
| { |
| worst_distance_ = std::numeric_limits<DistanceType>::max(); |
| dist_index_[capacity_-1].dist_ = worst_distance_; |
| count_ = 0; |
| } |
|
|
| size_t size() const |
| { |
| return count_; |
| } |
|
|
| bool full() const |
| { |
| return count_ == capacity_; |
| } |
|
|
|
|
| void addPoint(DistanceType dist, size_t index) |
| { |
| if (dist >= worst_distance_) return; |
| size_t i; |
| for (i = count_; i > 0; --i) { |
| #ifdef FLANN_FIRST_MATCH |
| if ( (dist_index_[i-1].dist_<=dist) && ((dist!=dist_index_[i-1].dist_)||(dist_index_[i-1].index_<=index)) ) |
| #else |
| if (dist_index_[i-1].dist_<=dist) |
| #endif |
| { |
| |
| for (size_t j = i - 1; dist_index_[j].dist_ == dist && j--;) { |
| if (dist_index_[j].index_ == index) { |
| return; |
| } |
| } |
| break; |
| } |
| } |
| if (count_ < capacity_) ++count_; |
| for (size_t j = count_-1; j > i; --j) { |
| dist_index_[j] = dist_index_[j-1]; |
| } |
| dist_index_[i].dist_ = dist; |
| dist_index_[i].index_ = index; |
| worst_distance_ = dist_index_[capacity_-1].dist_; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| void copy(size_t* indices, DistanceType* dists, size_t num_elements, bool sorted = true) |
| { |
| size_t n = std::min(count_, num_elements); |
| for (size_t i=0; i<n; ++i) { |
| *indices++ = dist_index_[i].index_; |
| *dists++ = dist_index_[i].dist_; |
| } |
| } |
|
|
| DistanceType worstDist() const |
| { |
| return worst_distance_; |
| } |
|
|
| private: |
| size_t capacity_; |
| size_t count_; |
| DistanceType worst_distance_; |
| std::vector<DistIndex> dist_index_; |
|
|
| }; |
|
|
|
|
|
|
| template <typename DistanceType> |
| class KNNResultSet2 : public ResultSet<DistanceType> |
| { |
| public: |
| typedef DistanceIndex<DistanceType> DistIndex; |
|
|
| KNNResultSet2(size_t capacity_) : |
| capacity_(capacity_) |
| { |
| |
| dist_index_.reserve(capacity_); |
| clear(); |
| } |
|
|
| ~KNNResultSet2() |
| { |
| } |
|
|
| |
| |
| |
| void clear() |
| { |
| dist_index_.clear(); |
| worst_dist_ = std::numeric_limits<DistanceType>::max(); |
| is_full_ = false; |
| } |
|
|
| |
| |
| |
| |
| size_t size() const |
| { |
| return dist_index_.size(); |
| } |
|
|
| |
| |
| |
| |
| bool full() const |
| { |
| return is_full_; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| void addPoint(DistanceType dist, size_t index) |
| { |
| if (dist>=worst_dist_) return; |
|
|
| if (dist_index_.size()==capacity_) { |
| |
| std::pop_heap(dist_index_.begin(), dist_index_.end()); |
| dist_index_.pop_back(); |
| } |
|
|
| |
| dist_index_.push_back(DistIndex(dist,index)); |
| if (is_full_) { |
| std::push_heap(dist_index_.begin(), dist_index_.end()); |
| } |
|
|
| if (dist_index_.size()==capacity_) { |
| if (!is_full_) { |
| std::make_heap(dist_index_.begin(), dist_index_.end()); |
| is_full_ = true; |
| } |
| |
| worst_dist_ = dist_index_[0].dist_; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| void copy(size_t* indices, DistanceType* dists, size_t num_elements, bool sorted = true) |
| { |
| if (sorted) { |
| |
| |
| std::sort(dist_index_.begin(), dist_index_.end()); |
| } |
| else { |
| if (num_elements<size()) { |
| std::nth_element(dist_index_.begin(), dist_index_.begin()+num_elements, dist_index_.end()); |
| } |
| } |
|
|
| size_t n = std::min(dist_index_.size(), num_elements); |
| for (size_t i=0; i<n; ++i) { |
| *indices++ = dist_index_[i].index_; |
| *dists++ = dist_index_[i].dist_; |
| } |
| } |
|
|
| DistanceType worstDist() const |
| { |
| return worst_dist_; |
| } |
|
|
| private: |
| size_t capacity_; |
| DistanceType worst_dist_; |
| std::vector<DistIndex> dist_index_; |
| bool is_full_; |
| }; |
|
|
|
|
| |
| |
| |
| |
| template <typename DistanceType> |
| class RadiusResultSet : public ResultSet<DistanceType> |
| { |
| public: |
| typedef DistanceIndex<DistanceType> DistIndex; |
|
|
| RadiusResultSet(DistanceType radius_) : |
| radius_(radius_) |
| { |
| |
| dist_index_.reserve(1024); |
| clear(); |
| } |
|
|
| ~RadiusResultSet() |
| { |
| } |
|
|
| |
| |
| |
| void clear() |
| { |
| dist_index_.clear(); |
| } |
|
|
| |
| |
| |
| |
| size_t size() const |
| { |
| return dist_index_.size(); |
| } |
|
|
| |
| |
| |
| |
| bool full() const |
| { |
| return true; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| void addPoint(DistanceType dist, size_t index) |
| { |
| if (dist<radius_) { |
| |
| dist_index_.push_back(DistIndex(dist,index)); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| void copy(size_t* indices, DistanceType* dists, size_t num_elements, bool sorted = true) |
| { |
| if (sorted) { |
| |
| |
| std::sort(dist_index_.begin(), dist_index_.end()); |
| } |
| else { |
| if (num_elements<size()) { |
| std::nth_element(dist_index_.begin(), dist_index_.begin()+num_elements, dist_index_.end()); |
| } |
| } |
|
|
| size_t n = std::min(dist_index_.size(), num_elements); |
| for (size_t i=0; i<n; ++i) { |
| *indices++ = dist_index_[i].index_; |
| *dists++ = dist_index_[i].dist_; |
| } |
| } |
|
|
| DistanceType worstDist() const |
| { |
| return radius_; |
| } |
|
|
| private: |
| DistanceType radius_; |
| std::vector<DistIndex> dist_index_; |
| }; |
|
|
|
|
|
|
| |
| |
| |
| |
| template <typename DistanceType> |
| class KNNRadiusResultSet : public ResultSet<DistanceType> |
| { |
| public: |
| typedef DistanceIndex<DistanceType> DistIndex; |
|
|
| KNNRadiusResultSet(DistanceType radius_, size_t capacity_) : |
| radius_(radius_), capacity_(capacity_) |
| { |
| |
| dist_index_.reserve(capacity_); |
| clear(); |
| } |
|
|
| ~KNNRadiusResultSet() |
| { |
| } |
|
|
| |
| |
| |
| void clear() |
| { |
| dist_index_.clear(); |
| worst_dist_ = radius_; |
| is_heap_ = false; |
| } |
|
|
| |
| |
| |
| |
| size_t size() const |
| { |
| return dist_index_.size(); |
| } |
|
|
| |
| |
| |
| |
| bool full() const |
| { |
| return true; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| void addPoint(DistanceType dist, size_t index) |
| { |
| if (dist>=worst_dist_) return; |
|
|
| if (dist_index_.size()==capacity_) { |
| |
| std::pop_heap(dist_index_.begin(), dist_index_.end()); |
| dist_index_.pop_back(); |
| } |
|
|
| |
| dist_index_.push_back(DistIndex(dist,index)); |
| if (is_heap_) { |
| std::push_heap(dist_index_.begin(), dist_index_.end()); |
| } |
|
|
| if (dist_index_.size()==capacity_) { |
| |
| if (!is_heap_) { |
| std::make_heap(dist_index_.begin(), dist_index_.end()); |
| is_heap_ = true; |
| } |
| |
| worst_dist_ = dist_index_[0].dist_; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| void copy(size_t* indices, DistanceType* dists, size_t num_elements, bool sorted = true) |
| { |
| if (sorted) { |
| |
| |
| std::sort(dist_index_.begin(), dist_index_.end()); |
| } |
| else { |
| if (num_elements<size()) { |
| std::nth_element(dist_index_.begin(), dist_index_.begin()+num_elements, dist_index_.end()); |
| } |
| } |
|
|
| size_t n = std::min(dist_index_.size(), num_elements); |
| for (size_t i=0; i<n; ++i) { |
| *indices++ = dist_index_[i].index_; |
| *dists++ = dist_index_[i].dist_; |
| } |
| } |
|
|
| DistanceType worstDist() const |
| { |
| return worst_dist_; |
| } |
|
|
| private: |
| bool is_heap_; |
| DistanceType radius_; |
| size_t capacity_; |
| DistanceType worst_dist_; |
| std::vector<DistIndex> dist_index_; |
| }; |
|
|
|
|
| |
| |
| |
| |
|
|
| template <typename DistanceType> |
| class CountRadiusResultSet : public ResultSet<DistanceType> |
| { |
| DistanceType radius; |
| size_t count; |
|
|
| public: |
| CountRadiusResultSet(DistanceType radius_ ) : |
| radius(radius_) |
| { |
| clear(); |
| } |
|
|
| ~CountRadiusResultSet() |
| { |
| } |
|
|
| void clear() |
| { |
| count = 0; |
| } |
|
|
| size_t size() const |
| { |
| return count; |
| } |
|
|
| bool full() const |
| { |
| return true; |
| } |
|
|
| void addPoint(DistanceType dist, size_t index) |
| { |
| if (dist<radius) { |
| count++; |
| } |
| } |
|
|
| DistanceType worstDist() const |
| { |
| return radius; |
| } |
|
|
| }; |
|
|
|
|
|
|
| |
|
|
| |
| |
| template<typename DistanceType> |
| class UniqueResultSet : public ResultSet<DistanceType> |
| { |
| public: |
| struct DistIndex |
| { |
| DistIndex(DistanceType dist, unsigned int index) : |
| dist_(dist), index_(index) |
| { |
| } |
| bool operator<(const DistIndex dist_index) const |
| { |
| return (dist_ < dist_index.dist_) || ((dist_ == dist_index.dist_) && index_ < dist_index.index_); |
| } |
| DistanceType dist_; |
| unsigned int index_; |
| }; |
|
|
| |
| UniqueResultSet() : |
| worst_distance_(std::numeric_limits<DistanceType>::max()) |
| { |
| } |
|
|
| |
| |
| |
| inline bool full() const |
| { |
| return is_full_; |
| } |
|
|
| |
| |
| |
| |
| |
| void copy(size_t* indices, DistanceType* dist, int n_neighbors, bool sorted = true) |
| { |
| if (n_neighbors<0) n_neighbors = dist_indices_.size(); |
| int i = 0; |
| typedef typename std::set<DistIndex>::const_iterator Iterator; |
| for (Iterator dist_index = dist_indices_.begin(), dist_index_end = |
| dist_indices_.end(); (dist_index != dist_index_end) && (i < n_neighbors); ++dist_index, ++indices, ++dist, ++i) { |
| *indices = dist_index->index_; |
| *dist = dist_index->dist_; |
| } |
| } |
|
|
| |
| |
| |
| size_t size() const |
| { |
| return dist_indices_.size(); |
| } |
|
|
| |
| |
| |
| |
| inline DistanceType worstDist() const |
| { |
| return worst_distance_; |
| } |
| protected: |
| |
| bool is_full_; |
|
|
| |
| DistanceType worst_distance_; |
|
|
| |
| std::set<DistIndex> dist_indices_; |
| }; |
|
|
| |
|
|
| |
| |
| |
| template<typename DistanceType> |
| class KNNUniqueResultSet : public UniqueResultSet<DistanceType> |
| { |
| public: |
| |
| |
| |
| KNNUniqueResultSet(unsigned int capacity) : capacity_(capacity) |
| { |
| this->is_full_ = false; |
| this->clear(); |
| } |
|
|
| |
| |
| |
| |
| inline void addPoint(DistanceType dist, size_t index) |
| { |
| |
| if (dist >= worst_distance_) return; |
| dist_indices_.insert(DistIndex(dist, index)); |
|
|
| if (is_full_) { |
| if (dist_indices_.size() > capacity_) { |
| dist_indices_.erase(*dist_indices_.rbegin()); |
| worst_distance_ = dist_indices_.rbegin()->dist_; |
| } |
| } |
| else if (dist_indices_.size() == capacity_) { |
| is_full_ = true; |
| worst_distance_ = dist_indices_.rbegin()->dist_; |
| } |
| } |
|
|
| |
| |
| void clear() |
| { |
| dist_indices_.clear(); |
| worst_distance_ = std::numeric_limits<DistanceType>::max(); |
| is_full_ = false; |
| } |
|
|
| protected: |
| typedef typename UniqueResultSet<DistanceType>::DistIndex DistIndex; |
| using UniqueResultSet<DistanceType>::is_full_; |
| using UniqueResultSet<DistanceType>::worst_distance_; |
| using UniqueResultSet<DistanceType>::dist_indices_; |
|
|
| |
| unsigned int capacity_; |
| }; |
|
|
| |
|
|
| |
| |
| |
| template<typename DistanceType> |
| class RadiusUniqueResultSet : public UniqueResultSet<DistanceType> |
| { |
| public: |
| |
| |
| |
| RadiusUniqueResultSet(DistanceType radius) : |
| radius_(radius) |
| { |
| is_full_ = true; |
| } |
|
|
| |
| |
| |
| |
| void addPoint(DistanceType dist, size_t index) |
| { |
| if (dist < radius_) dist_indices_.insert(DistIndex(dist, index)); |
| } |
|
|
| |
| |
| inline void clear() |
| { |
| dist_indices_.clear(); |
| } |
|
|
|
|
| |
| |
| |
| inline bool full() const |
| { |
| return true; |
| } |
|
|
| |
| |
| |
| |
| inline DistanceType worstDist() const |
| { |
| return radius_; |
| } |
| private: |
| typedef typename UniqueResultSet<DistanceType>::DistIndex DistIndex; |
| using UniqueResultSet<DistanceType>::dist_indices_; |
| using UniqueResultSet<DistanceType>::is_full_; |
|
|
| |
| DistanceType radius_; |
| }; |
|
|
| |
|
|
| |
| |
| template<typename DistanceType> |
| class KNNRadiusUniqueResultSet : public KNNUniqueResultSet<DistanceType> |
| { |
| public: |
| |
| |
| |
| KNNRadiusUniqueResultSet(DistanceType radius, size_t capacity) : KNNUniqueResultSet<DistanceType>(capacity) |
| { |
| this->radius_ = radius; |
| this->clear(); |
| } |
|
|
| |
| |
| void clear() |
| { |
| dist_indices_.clear(); |
| worst_distance_ = radius_; |
| is_full_ = true; |
| } |
| private: |
| using KNNUniqueResultSet<DistanceType>::dist_indices_; |
| using KNNUniqueResultSet<DistanceType>::is_full_; |
| using KNNUniqueResultSet<DistanceType>::worst_distance_; |
|
|
| |
| DistanceType radius_; |
| }; |
| } |
|
|
| #endif |
|
|
|
|