76 static constexpr bool same_internal_data = std::is_same<Data_, AnnoyData_>::value;
77 typename std::conditional<!same_internal_data, std::vector<AnnoyData_>,
bool>::type my_buffer;
79 static constexpr bool same_internal_index = std::is_same<Index_, AnnoyIndex_>::value;
80 std::vector<AnnoyIndex_> my_indices;
82 static constexpr bool same_internal_distance = std::is_same<Distance_, AnnoyData_>::value;
83 typename std::conditional<!same_internal_distance, std::vector<AnnoyData_>,
bool>::type my_distances;
85 int get_search_k(
int k)
const {
86 if (my_parent.my_search_mult < 1) {
89 return my_parent.my_search_mult *
static_cast<double>(k) + 0.5;
98 if constexpr(!same_internal_data) {
99 my_buffer.resize(my_parent.my_dim);
107 std::pair<std::vector<AnnoyIndex_>*, std::vector<AnnoyData_>*> obtain_pointers(std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances, Index_ k) {
108 std::vector<AnnoyIndex_>* icopy_ptr = &my_indices;
109 if (output_indices) {
110 if constexpr(same_internal_index) {
111 icopy_ptr = output_indices;
115 icopy_ptr->reserve(k);
117 std::vector<AnnoyData_>* dcopy_ptr = NULL;
118 if (output_distances) {
119 if constexpr(same_internal_distance) {
120 dcopy_ptr = output_distances;
122 dcopy_ptr = &my_distances;
125 dcopy_ptr->reserve(k);
128 return std::make_pair(icopy_ptr, dcopy_ptr);
131 template<
typename Type_>
132 static void remove_self(std::vector<Type_>& vec, std::size_t at) {
133 if (at < vec.size()) {
134 vec.erase(vec.begin() + at);
140 template<
typename Source_,
typename Dest_>
141 static void copy_skip_self(
const std::vector<Source_>& source, std::vector<Dest_>& dest, std::size_t at) {
142 auto sIt = source.begin();
143 auto end = source.size();
145 dest.reserve(end - 1);
148 dest.insert(dest.end(), sIt, sIt + at);
149 dest.insert(dest.end(), sIt + at + 1, source.end());
156 dest.insert(dest.end(), sIt, sIt + end - 1);
161 void search(Index_ i, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
163 auto ptrs = obtain_pointers(output_indices, output_distances, kp1);
164 auto icopy_ptr = ptrs.first;
165 auto dcopy_ptr = ptrs.second;
167 my_parent.my_index.get_nns_by_item(i, kp1, get_search_k(kp1), icopy_ptr, dcopy_ptr);
171 const auto& cur_i = *icopy_ptr;
173 AnnoyIndex_ icopy = i;
174 for (std::size_t x = 0, end = cur_i.size(); x < end; ++x) {
175 if (cur_i[x] == icopy) {
182 if (output_indices) {
183 if constexpr(same_internal_index) {
184 remove_self(*output_indices, at);
186 copy_skip_self(my_indices, *output_indices, at);
190 if (output_distances) {
191 if constexpr(same_internal_distance) {
192 remove_self(*output_distances, at);
194 copy_skip_self(my_distances, *output_distances, at);
200 void search_raw(
const AnnoyData_* query, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
201 auto ptrs = obtain_pointers(output_indices, output_distances, k);
202 auto icopy_ptr = ptrs.first;
203 auto dcopy_ptr = ptrs.second;
205 my_parent.my_index.get_nns_by_vector(query, k, get_search_k(k), icopy_ptr, dcopy_ptr);
207 if (output_indices) {
208 if constexpr(!same_internal_index) {
209 output_indices->clear();
210 output_indices->insert(output_indices->end(), my_indices.begin(), my_indices.end());
214 if (output_distances) {
215 if constexpr(!same_internal_distance) {
216 output_distances->clear();
217 output_distances->insert(output_distances->end(), my_distances.begin(), my_distances.end());
223 void search(
const Data_* query, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
224 if constexpr(same_internal_data) {
225 search_raw(query, k, output_indices, output_distances);
227 std::copy_n(query, my_parent.my_dim, my_buffer.begin());
228 search_raw(my_buffer.data(), k, output_indices, output_distances);
264 template<
class Matrix_>
266 my_dim(data.num_dimensions()),
267 my_obs(data.num_observations()),
271 auto work = data.new_extractor();
272 if constexpr(std::is_same<Data_, AnnoyData_>::value) {
273 for (Index_ i = 0; i < my_obs; ++i) {
274 auto ptr = work->next();
275 my_index.add_item(i, ptr);
278 std::vector<AnnoyData_> incoming(my_dim);
279 for (Index_ i = 0; i < my_obs; ++i) {
280 auto ptr = work->next();
281 std::copy_n(ptr, my_dim, incoming.begin());
282 my_index.add_item(i, incoming.data());
296 double my_search_mult;
297 Annoy::AnnoyIndex<AnnoyIndex_, AnnoyData_, AnnoyDistance_, AnnoyRng_, AnnoyThreadPolicy_> my_index;
299 friend class AnnoySearcher<Index_, Data_, Distance_, AnnoyDistance_, AnnoyIndex_, AnnoyData_, AnnoyRng_, AnnoyThreadPolicy_>;
302 std::size_t num_dimensions()
const {
306 Index_ num_observations()
const {
313 std::unique_ptr<knncolle::Searcher<Index_, Data_, Distance_> >
initialize()
const {
314 return std::make_unique<AnnoySearcher<Index_, Data_, Distance_, AnnoyDistance_, AnnoyIndex_, AnnoyData_, AnnoyRng_, AnnoyThreadPolicy_> >(*this);