knncolle
Collection of KNN methods in C++
Loading...
Searching...
No Matches
NeighborQueue.hpp
Go to the documentation of this file.
1#ifndef KNNCOLLE_NEIGHBOR_QUEUE_HPP
2#define KNNCOLLE_NEIGHBOR_QUEUE_HPP
3
4#include <queue>
5#include <vector>
6#include <algorithm>
7
13namespace knncolle {
14
29template<typename Index_, typename Distance_>
31public:
36 NeighborQueue() = default;
37
38public:
46 void reset(Index_ k) {
47 my_neighbors = k;
48 my_full = false;
49
50 // Popping any existing elements out, just in case. This shouldn't
51 // usually be necessary if report() was called as the queue should
52 // already be completely exhausted, but sometimes report() is a no-op
53 // or there might have been an intervening exception, etc.
54 while (!my_nearest.empty()) {
55 my_nearest.pop();
56 }
57 }
58
59public:
63 bool is_full() const {
64 return my_full;
65 }
66
71 Distance_ limit() const {
72 return my_nearest.top().first;
73 }
74
75public:
83 void add(Index_ i, Distance_ d) {
84 if (!my_full) {
85 my_nearest.emplace(d, i);
86 if (my_nearest.size() == my_neighbors) {
87 my_full = true;
88 }
89 } else {
90 my_nearest.emplace(d, i);
91 my_nearest.pop();
92 }
93 return;
94 }
95
96public:
109 void report(std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances, Index_ self) {
110 // We expect that nearest is non-empty, as a search should at least
111 // find 'self' (or duplicates thereof).
112 size_t num_expected = my_nearest.size() - 1;
113 if (output_indices) {
114 output_indices->clear();
115 output_indices->reserve(num_expected);
116 }
117 if (output_distances) {
118 output_distances->clear();
119 output_distances->reserve(num_expected);
120 }
121
122 bool found_self = false;
123 while (!my_nearest.empty()) {
124 const auto& top = my_nearest.top();
125 if (!found_self && top.second == self) {
126 found_self = true;
127 } else {
128 if (output_indices) {
129 output_indices->push_back(top.second);
130 }
131 if (output_distances) {
132 output_distances->push_back(top.first);
133 }
134 }
135 my_nearest.pop();
136 }
137
138 // We use push_back + reverse to give us sorting in increasing order;
139 // this is nicer than push_front() for std::vectors.
140 if (output_indices) {
141 std::reverse(output_indices->begin(), output_indices->end());
142 }
143 if (output_distances) {
144 std::reverse(output_distances->begin(), output_distances->end());
145 }
146
147 // Removing the most distance element if we couldn't find ourselves,
148 // e.g., because there are too many duplicates.
149 if (!found_self) {
150 if (output_indices) {
151 output_indices->pop_back();
152 }
153 if (output_distances) {
154 output_distances->pop_back();
155 }
156 }
157 }
158
159public:
170 void report(std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
171 size_t position = my_nearest.size();
172 if (output_indices) {
173 output_indices->resize(position);
174 }
175 if (output_distances) {
176 output_distances->resize(position);
177 }
178
179 while (!my_nearest.empty()) {
180 const auto& top = my_nearest.top();
181 --position;
182 if (output_indices) {
183 (*output_indices)[position] = top.second;
184 }
185 if (output_distances) {
186 (*output_distances)[position] = top.first;
187 }
188 my_nearest.pop();
189 }
190 }
191
192private:
193 size_t my_neighbors = 1;
194 bool my_full = false;
195 std::priority_queue<std::pair<Distance_, Index_> > my_nearest;
196};
197
198}
199
200#endif
Helper class to track nearest neighbors.
Definition NeighborQueue.hpp:30
void report(std::vector< Index_ > *output_indices, std::vector< Distance_ > *output_distances, Index_ self)
Definition NeighborQueue.hpp:109
void report(std::vector< Index_ > *output_indices, std::vector< Distance_ > *output_distances)
Definition NeighborQueue.hpp:170
void add(Index_ i, Distance_ d)
Definition NeighborQueue.hpp:83
Distance_ limit() const
Definition NeighborQueue.hpp:71
bool is_full() const
Definition NeighborQueue.hpp:63
void reset(Index_ k)
Definition NeighborQueue.hpp:46
Collection of KNN algorithms.
Definition Bruteforce.hpp:23