75 static constexpr bool same_internal_data = std::is_same<Data_, AnnoyData_>::value;
76 typename std::conditional<!same_internal_data, std::vector<AnnoyData_>,
bool>::type my_buffer;
78 static constexpr bool same_internal_index = std::is_same<Index_, AnnoyIndex_>::value;
79 std::vector<AnnoyIndex_> my_indices;
81 static constexpr bool same_internal_distance = std::is_same<Distance_, AnnoyData_>::value;
82 typename std::conditional<!same_internal_distance, std::vector<AnnoyData_>,
bool>::type my_distances;
84 int get_search_k(
int k)
const {
85 if (my_parent.my_search_mult < 0) {
88 return my_parent.my_search_mult *
static_cast<double>(k) + 0.5;
97 if constexpr(!same_internal_data) {
98 my_buffer.resize(my_parent.my_dim);
106 std::pair<std::vector<AnnoyIndex_>*, std::vector<AnnoyData_>*> obtain_pointers(std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances, Index_ k) {
107 std::vector<AnnoyIndex_>* icopy_ptr = &my_indices;
108 if (output_indices) {
109 if constexpr(same_internal_index) {
110 icopy_ptr = output_indices;
114 icopy_ptr->reserve(k);
116 std::vector<AnnoyData_>* dcopy_ptr = NULL;
117 if (output_distances) {
118 if constexpr(same_internal_distance) {
119 dcopy_ptr = output_distances;
121 dcopy_ptr = &my_distances;
124 dcopy_ptr->reserve(k);
127 return std::make_pair(icopy_ptr, dcopy_ptr);
130 template<
typename Type_>
131 static void remove_self(std::vector<Type_>& vec,
size_t at) {
132 if (at < vec.size()) {
133 vec.erase(vec.begin() + at);
139 template<
typename Source_,
typename Dest_>
140 static void copy_skip_self(
const std::vector<Source_>& source, std::vector<Dest_>& dest,
size_t at) {
141 auto sIt = source.begin();
142 size_t end = source.size();
144 dest.reserve(end - 1);
147 dest.insert(dest.end(), sIt, sIt + at);
148 dest.insert(dest.end(), sIt + at + 1, source.end());
155 dest.insert(dest.end(), sIt, sIt + end - 1);
160 void search(Index_ i, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
162 auto ptrs = obtain_pointers(output_indices, output_distances, kp1);
163 auto icopy_ptr = ptrs.first;
164 auto dcopy_ptr = ptrs.second;
166 my_parent.my_index.get_nns_by_item(i, kp1, get_search_k(kp1), icopy_ptr, dcopy_ptr);
170 const auto& cur_i = *icopy_ptr;
172 AnnoyIndex_ icopy = i;
173 for (
size_t x = 0, end = cur_i.size(); x < end; ++x) {
174 if (cur_i[x] == icopy) {
181 if (output_indices) {
182 if constexpr(same_internal_index) {
183 remove_self(*output_indices, at);
185 copy_skip_self(my_indices, *output_indices, at);
189 if (output_distances) {
190 if constexpr(same_internal_distance) {
191 remove_self(*output_distances, at);
193 copy_skip_self(my_distances, *output_distances, at);
199 void search_raw(
const AnnoyData_* query, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
200 auto ptrs = obtain_pointers(output_indices, output_distances, k);
201 auto icopy_ptr = ptrs.first;
202 auto dcopy_ptr = ptrs.second;
204 my_parent.my_index.get_nns_by_vector(query, k, get_search_k(k), icopy_ptr, dcopy_ptr);
206 if (output_indices) {
207 if constexpr(!same_internal_index) {
208 output_indices->clear();
209 output_indices->insert(output_indices->end(), my_indices.begin(), my_indices.end());
213 if (output_distances) {
214 if constexpr(!same_internal_distance) {
215 output_distances->clear();
216 output_distances->insert(output_distances->end(), my_distances.begin(), my_distances.end());
222 void search(
const Data_* query, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
223 if constexpr(same_internal_data) {
224 search_raw(query, k, output_indices, output_distances);
226 std::copy_n(query, my_parent.my_dim, my_buffer.begin());
227 search_raw(my_buffer.data(), k, output_indices, output_distances);
263 template<
class Matrix_>
265 my_dim(data.num_dimensions()),
266 my_obs(data.num_observations()),
270 auto work = data.new_extractor();
271 if constexpr(std::is_same<Data_, AnnoyData_>::value) {
272 for (Index_ i = 0; i < my_obs; ++i) {
273 auto ptr = work->next();
274 my_index.add_item(i, ptr);
277 std::vector<AnnoyData_> incoming(my_dim);
278 for (Index_ i = 0; i < my_obs; ++i) {
279 auto ptr = work->next();
280 std::copy_n(ptr, my_dim, incoming.begin());
281 my_index.add_item(i, incoming.data());
295 double my_search_mult;
296 Annoy::AnnoyIndex<AnnoyIndex_, AnnoyData_, AnnoyDistance_, AnnoyRng_, AnnoyThreadPolicy_> my_index;
298 friend class AnnoySearcher<Index_, Data_, Distance_, AnnoyDistance_, AnnoyIndex_, AnnoyData_, AnnoyRng_, AnnoyThreadPolicy_>;
301 size_t num_dimensions()
const {
305 Index_ num_observations()
const {
312 std::unique_ptr<knncolle::Searcher<Index_, Data_, Distance_> >
initialize()
const {
313 return std::make_unique<AnnoySearcher<Index_, Data_, Distance_, AnnoyDistance_, AnnoyIndex_, AnnoyData_, AnnoyRng_, AnnoyThreadPolicy_> >(*this);