CoastalME (Coastal Modelling Environment)
Simulates the long-term behaviour of complex coastlines
Loading...
Searching...
No Matches
nanoflann.hpp
Go to the documentation of this file.
1/***********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
5 * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
6 * Copyright 2011-2025 Jose Luis Blanco (joseluisblancoc@gmail.com).
7 * All rights reserved.
8 *
9 * THE BSD LICENSE
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *************************************************************************/
32
44
45#pragma once
46
47#include <algorithm>
48#include <array>
49#include <atomic>
50#include <cassert>
51#include <cmath> // for abs()
52#include <cstdint>
53#include <cstdlib> // for abs()
54#include <functional> // std::reference_wrapper
55#include <future>
56#include <istream>
57#include <limits> // std::numeric_limits
58#include <ostream>
59#include <stdexcept>
60#include <unordered_set>
61#include <vector>
62
64#define NANOFLANN_VERSION 0x171
65
66// Avoid conflicting declaration of min/max macros in Windows headers
67#if !defined(NOMINMAX) && \
68 (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64))
69#define NOMINMAX
70#ifdef max
71#undef max
72#undef min
73#endif
74#endif
75// Avoid conflicts with X11 headers
76#ifdef None
77#undef None
78#endif
79
80namespace nanoflann
81{
84
86template <typename T>
88{
89 return static_cast<T>(3.14159265358979323846);
90}
91
96template <typename T, typename = int>
97struct has_resize : std::false_type
98{
99};
100
101template <typename T>
102struct has_resize<T, decltype((void)std::declval<T>().resize(1), 0)>
103 : std::true_type
104{
105};
106
107template <typename T, typename = int>
108struct has_assign : std::false_type
109{
110};
111
112template <typename T>
113struct has_assign<T, decltype((void)std::declval<T>().assign(1, 0), 0)>
114 : std::true_type
115{
116};
117
121template <typename Container>
122inline typename std::enable_if<has_resize<Container>::value, void>::type resize(
123 Container& c, const size_t nElements)
124{
125 c.resize(nElements);
126}
127
132template <typename Container>
133inline typename std::enable_if<!has_resize<Container>::value, void>::type
134 resize(Container& c, const size_t nElements)
135{
136 if (nElements != c.size())
137 throw std::logic_error("Try to change the size of a std::array.");
138}
139
143template <typename Container, typename T>
144inline typename std::enable_if<has_assign<Container>::value, void>::type assign(
145 Container& c, const size_t nElements, const T& value)
146{
147 c.assign(nElements, value);
148}
149
153template <typename Container, typename T>
154inline typename std::enable_if<!has_assign<Container>::value, void>::type
155 assign(Container& c, const size_t nElements, const T& value)
156{
157 for (size_t i = 0; i < nElements; i++) c[i] = value;
158}
159
162{
164 template <typename PairType>
165 bool operator()(const PairType& p1, const PairType& p2) const
166 {
167 return p1.second < p2.second;
168 }
169};
170
179template <typename IndexType = size_t, typename DistanceType = double>
181{
182 ResultItem() = default;
183 ResultItem(const IndexType index, const DistanceType distance)
184 : first(index), second(distance)
185 {
186 }
187
188 IndexType first;
189 DistanceType second;
190};
191
194
196template <
197 typename _DistanceType, typename _IndexType = size_t,
198 typename _CountType = size_t>
200{
201 public:
202 using DistanceType = _DistanceType;
203 using IndexType = _IndexType;
204 using CountType = _CountType;
205
206 private:
211
212 public:
213 explicit KNNResultSet(CountType capacity_)
214 : indices(nullptr), dists(nullptr), capacity(capacity_), count(0)
215 {
216 }
217
218 void init(IndexType* indices_, DistanceType* dists_)
219 {
220 indices = indices_;
221 dists = dists_;
222 count = 0;
223 }
224
225 CountType size() const { return count; }
226 bool empty() const { return count == 0; }
227 bool full() const { return count == capacity; }
228
235 {
236 CountType i;
237 for (i = count; i > 0; --i)
238 {
241#ifdef NANOFLANN_FIRST_MATCH
242 if ((dists[i - 1] > dist) ||
243 ((dist == dists[i - 1]) && (indices[i - 1] > index)))
244 {
245#else
246 if (dists[i - 1] > dist)
247 {
248#endif
249 if (i < capacity)
250 {
251 dists[i] = dists[i - 1];
252 indices[i] = indices[i - 1];
253 }
254 }
255 else
256 break;
257 }
258 if (i < capacity)
259 {
260 dists[i] = dist;
261 indices[i] = index;
262 }
263 if (count < capacity) count++;
264
265 // tell caller that the search shall continue
266 return true;
267 }
268
272 {
273 return (count < capacity || !count)
274 ? std::numeric_limits<DistanceType>::max()
275 : dists[count - 1];
276 }
277
278 void sort()
279 {
280 // already sorted
281 }
282};
283
285template <
286 typename _DistanceType, typename _IndexType = size_t,
287 typename _CountType = size_t>
289{
290 public:
291 using DistanceType = _DistanceType;
292 using IndexType = _IndexType;
293 using CountType = _CountType;
294
295 private:
301
302 public:
304 CountType capacity_, DistanceType maximumSearchDistanceSquared_)
305 : indices(nullptr),
306 dists(nullptr),
307 capacity(capacity_),
308 count(0),
309 maximumSearchDistanceSquared(maximumSearchDistanceSquared_)
310 {
311 }
312
313 void init(IndexType* indices_, DistanceType* dists_)
314 {
315 indices = indices_;
316 dists = dists_;
317 count = 0;
319 }
320
321 CountType size() const { return count; }
322 bool empty() const { return count == 0; }
323 bool full() const { return count == capacity; }
324
331 {
332 CountType i;
333 for (i = count; i > 0; --i)
334 {
337#ifdef NANOFLANN_FIRST_MATCH
338 if ((dists[i - 1] > dist) ||
339 ((dist == dists[i - 1]) && (indices[i - 1] > index)))
340 {
341#else
342 if (dists[i - 1] > dist)
343 {
344#endif
345 if (i < capacity)
346 {
347 dists[i] = dists[i - 1];
348 indices[i] = indices[i - 1];
349 }
350 }
351 else
352 break;
353 }
354 if (i < capacity)
355 {
356 dists[i] = dist;
357 indices[i] = index;
358 }
359 if (count < capacity) count++;
360
361 // tell caller that the search shall continue
362 return true;
363 }
364
368 {
370 : dists[count - 1];
371 }
372
373 void sort()
374 {
375 // already sorted
376 }
377};
378
382template <typename _DistanceType, typename _IndexType = size_t>
384{
385 public:
386 using DistanceType = _DistanceType;
387 using IndexType = _IndexType;
388
389 public:
391
392 std::vector<ResultItem<IndexType, DistanceType>>& m_indices_dists;
393
395 DistanceType radius_,
396 std::vector<ResultItem<IndexType, DistanceType>>& indices_dists)
397 : radius(radius_), m_indices_dists(indices_dists)
398 {
399 init();
400 }
401
402 void init() { clear(); }
403 void clear() { m_indices_dists.clear(); }
404
405 size_t size() const { return m_indices_dists.size(); }
406 size_t empty() const { return m_indices_dists.empty(); }
407
408 bool full() const { return true; }
409
416 {
417 if (dist < radius) m_indices_dists.emplace_back(index, dist);
418 return true;
419 }
420
421 DistanceType worstDist() const { return radius; }
422
428 {
429 if (m_indices_dists.empty())
430 throw std::runtime_error(
431 "Cannot invoke RadiusResultSet::worst_item() on "
432 "an empty list of results.");
433 auto it = std::max_element(
435 return *it;
436 }
437
438 void sort()
439 {
440 std::sort(
442 }
443};
444
446
449template <typename T>
450void save_value(std::ostream& stream, const T& value)
451{
452 stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
453}
454
455template <typename T>
456void save_value(std::ostream& stream, const std::vector<T>& value)
457{
458 size_t size = value.size();
459 stream.write(reinterpret_cast<const char*>(&size), sizeof(size_t));
460 stream.write(reinterpret_cast<const char*>(value.data()), sizeof(T) * size);
461}
462
463template <typename T>
464void load_value(std::istream& stream, T& value)
465{
466 stream.read(reinterpret_cast<char*>(&value), sizeof(T));
467}
468
469template <typename T>
470void load_value(std::istream& stream, std::vector<T>& value)
471{
472 size_t size;
473 stream.read(reinterpret_cast<char*>(&size), sizeof(size_t));
474 value.resize(size);
475 stream.read(reinterpret_cast<char*>(value.data()), sizeof(T) * size);
476}
477
478
481
482struct Metric
483{
484};
485
496template <
497 class T, class DataSource, typename _DistanceType = T,
498 typename IndexType = size_t>
500{
501 using ElementType = T;
502 using DistanceType = _DistanceType;
503
504 const DataSource& data_source;
505
506 L1_Adaptor(const DataSource& _data_source) : data_source(_data_source) {}
507
509 const T* a, const IndexType b_idx, size_t size,
510 DistanceType worst_dist = -1) const
511 {
512 DistanceType result = DistanceType();
513 const T* last = a + size;
514 const T* lastgroup = last - 3;
515 size_t d = 0;
516
517 /* Process 4 items with each loop for efficiency. */
518 while (a < lastgroup)
519 {
520 const DistanceType diff0 =
521 std::abs(a[0] - data_source.kdtree_get_pt(b_idx, d++));
522 const DistanceType diff1 =
523 std::abs(a[1] - data_source.kdtree_get_pt(b_idx, d++));
524 const DistanceType diff2 =
525 std::abs(a[2] - data_source.kdtree_get_pt(b_idx, d++));
526 const DistanceType diff3 =
527 std::abs(a[3] - data_source.kdtree_get_pt(b_idx, d++));
528 result += diff0 + diff1 + diff2 + diff3;
529 a += 4;
530 if ((worst_dist > 0) && (result > worst_dist)) { return result; }
531 }
532 /* Process last 0-3 components. Not needed for standard vector lengths.
533 */
534 while (a < last)
535 {
536 result += std::abs(*a++ - data_source.kdtree_get_pt(b_idx, d++));
537 }
538 return result;
539 }
540
541 template <typename U, typename V>
542 DistanceType accum_dist(const U a, const V b, const size_t) const
543 {
544 return std::abs(a - b);
545 }
546};
547
558template <
559 class T, class DataSource, typename _DistanceType = T,
560 typename IndexType = size_t>
562{
563 using ElementType = T;
564 using DistanceType = _DistanceType;
565
566 const DataSource& data_source;
567
568 L2_Adaptor(const DataSource& _data_source) : data_source(_data_source) {}
569
571 const T* a, const IndexType b_idx, size_t size,
572 DistanceType worst_dist = -1) const
573 {
574 DistanceType result = DistanceType();
575 const T* last = a + size;
576 const T* lastgroup = last - 3;
577 size_t d = 0;
578
579 /* Process 4 items with each loop for efficiency. */
580 while (a < lastgroup)
581 {
582 const DistanceType diff0 =
583 a[0] - data_source.kdtree_get_pt(b_idx, d++);
584 const DistanceType diff1 =
585 a[1] - data_source.kdtree_get_pt(b_idx, d++);
586 const DistanceType diff2 =
587 a[2] - data_source.kdtree_get_pt(b_idx, d++);
588 const DistanceType diff3 =
589 a[3] - data_source.kdtree_get_pt(b_idx, d++);
590 result +=
591 diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
592 a += 4;
593 if ((worst_dist > 0) && (result > worst_dist)) { return result; }
594 }
595 /* Process last 0-3 components. Not needed for standard vector lengths.
596 */
597 while (a < last)
598 {
599 const DistanceType diff0 =
600 *a++ - data_source.kdtree_get_pt(b_idx, d++);
601 result += diff0 * diff0;
602 }
603 return result;
604 }
605
606 template <typename U, typename V>
607 DistanceType accum_dist(const U a, const V b, const size_t) const
608 {
609 return (a - b) * (a - b);
610 }
611};
612
623template <
624 class T, class DataSource, typename _DistanceType = T,
625 typename IndexType = size_t>
627{
628 using ElementType = T;
629 using DistanceType = _DistanceType;
630
631 const DataSource& data_source;
632
633 L2_Simple_Adaptor(const DataSource& _data_source)
634 : data_source(_data_source)
635 {
636 }
637
639 const T* a, const IndexType b_idx, size_t size) const
640 {
641 DistanceType result = DistanceType();
642 for (size_t i = 0; i < size; ++i)
643 {
644 const DistanceType diff =
645 a[i] - data_source.kdtree_get_pt(b_idx, i);
646 result += diff * diff;
647 }
648 return result;
649 }
650
651 template <typename U, typename V>
652 DistanceType accum_dist(const U a, const V b, const size_t) const
653 {
654 return (a - b) * (a - b);
655 }
656};
657
668template <
669 class T, class DataSource, typename _DistanceType = T,
670 typename IndexType = size_t>
672{
673 using ElementType = T;
674 using DistanceType = _DistanceType;
675
676 const DataSource& data_source;
677
678 SO2_Adaptor(const DataSource& _data_source) : data_source(_data_source) {}
679
681 const T* a, const IndexType b_idx, size_t size) const
682 {
683 return accum_dist(
684 a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1), size - 1);
685 }
686
689 template <typename U, typename V>
690 DistanceType accum_dist(const U a, const V b, const size_t) const
691 {
692 DistanceType result = DistanceType();
694 result = b - a;
695 if (result > PI)
696 result -= 2 * PI;
697 else if (result < -PI)
698 result += 2 * PI;
699 return result;
700 }
701};
702
713template <
714 class T, class DataSource, typename _DistanceType = T,
715 typename IndexType = size_t>
717{
718 using ElementType = T;
719 using DistanceType = _DistanceType;
720
723
724 SO3_Adaptor(const DataSource& _data_source)
725 : distance_L2_Simple(_data_source)
726 {
727 }
728
730 const T* a, const IndexType b_idx, size_t size) const
731 {
732 return distance_L2_Simple.evalMetric(a, b_idx, size);
733 }
734
735 template <typename U, typename V>
736 DistanceType accum_dist(const U a, const V b, const size_t idx) const
737 {
738 return distance_L2_Simple.accum_dist(a, b, idx);
739 }
740};
741
743struct metric_L1 : public Metric
744{
745 template <class T, class DataSource, typename IndexType = size_t>
750};
751
753struct metric_L2 : public Metric
754{
755 template <class T, class DataSource, typename IndexType = size_t>
760};
761
764{
765 template <class T, class DataSource, typename IndexType = size_t>
770};
771
772struct metric_SO2 : public Metric
773{
774 template <class T, class DataSource, typename IndexType = size_t>
779};
780
781struct metric_SO3 : public Metric
782{
783 template <class T, class DataSource, typename IndexType = size_t>
788};
789
791
794
800
801inline std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type operator&(
803{
804 using underlying =
805 typename std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type;
806 return static_cast<underlying>(lhs) & static_cast<underlying>(rhs);
807}
808
811{
813 size_t _leaf_max_size = 10,
816 unsigned int _n_thread_build = 1)
817 : leaf_max_size(_leaf_max_size),
818 flags(_flags),
819 n_thread_build(_n_thread_build)
820 {
821 }
822
825 unsigned int n_thread_build;
826};
827
830{
831 SearchParameters(float eps_ = 0, bool sorted_ = true)
832 : eps(eps_), sorted(sorted_)
833 {
834 }
835
836 float eps;
837 bool sorted;
839};
840
841
844
860{
861 static constexpr size_t WORDSIZE = 16; // WORDSIZE must >= 8
862 static constexpr size_t BLOCKSIZE = 8192;
863
864 /* We maintain memory alignment to word boundaries by requiring that all
865 allocations be in multiples of the machine wordsize. */
866 /* Size of machine word in bytes. Must be power of 2. */
867 /* Minimum number of bytes requested at a time from the system. Must be
868 * multiple of WORDSIZE. */
869
870 using Size = size_t;
871
873 void* base_ = nullptr;
874 void* loc_ = nullptr;
875
877 {
878 remaining_ = 0;
879 base_ = nullptr;
880 usedMemory = 0;
881 wastedMemory = 0;
882 }
883
884 public:
887
892
897
899 void free_all()
900 {
901 while (base_ != nullptr)
902 {
903 // Get pointer to prev block
904 void* prev = *(static_cast<void**>(base_));
905 ::free(base_);
906 base_ = prev;
907 }
909 }
910
915 void* malloc(const size_t req_size)
916 {
917 /* Round size up to a multiple of wordsize. The following expression
918 only works for WORDSIZE that is a power of 2, by masking last bits
919 of incremented size to zero.
920 */
921 const Size size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
922
923 /* Check whether a new block must be allocated. Note that the first
924 word of a block is reserved for a pointer to the previous block.
925 */
926 if (size > remaining_)
927 {
929
930 /* Allocate new storage. */
931 const Size blocksize =
932 size > BLOCKSIZE ? size + WORDSIZE : BLOCKSIZE + WORDSIZE;
933
934 // use the standard C malloc to allocate memory
935 void* m = ::malloc(blocksize);
936 if (!m)
937 {
938 throw std::bad_alloc();
939 }
940
941 /* Fill first word of new block with pointer to previous block. */
942 static_cast<void**>(m)[0] = base_;
943 base_ = m;
944
945 remaining_ = blocksize - WORDSIZE;
946 loc_ = static_cast<char*>(m) + WORDSIZE;
947 }
948 void* rloc = loc_;
949 loc_ = static_cast<char*>(loc_) + size;
950 remaining_ -= size;
951
952 usedMemory += size;
953
954 return rloc;
955 }
956
964 template <typename T>
965 T* allocate(const size_t count = 1)
966 {
967 T* mem = static_cast<T*>(this->malloc(sizeof(T) * count));
968 return mem;
969 }
970};
971
972
975
979template <int32_t DIM, typename T>
981{
982 using type = std::array<T, DIM>;
983};
984
985template <typename T>
986struct array_or_vector<-1, T>
987{
988 using type = std::vector<T>;
989};
990
992
1007template <
1008 class Derived, typename Distance, class DatasetAdaptor, int32_t DIM = -1,
1009 typename index_t = uint32_t>
1011{
1012 public:
1015 void freeIndex(Derived& obj)
1016 {
1017 obj.pool_.free_all();
1018 obj.root_node_ = nullptr;
1019 obj.size_at_index_build_ = 0;
1020 }
1021
1022 using ElementType = typename Distance::ElementType;
1023 using DistanceType = typename Distance::DistanceType;
1024 using IndexType = index_t;
1025
1029 std::vector<IndexType> vAcc_;
1030
1031 using Offset = typename decltype(vAcc_)::size_type;
1032 using Size = typename decltype(vAcc_)::size_type;
1034
1035 /*---------------------------
1036 * Internal Data Structures
1037 * --------------------------*/
1038 struct Node
1039 {
1042 union
1043 {
1044 struct leaf
1045 {
1047 } lr;
1048 struct nonleaf
1049 {
1053 } sub;
1054 } node_type;
1055
1057 Node *child1 = nullptr, *child2 = nullptr;
1058 };
1059
1060 using NodePtr = Node*;
1061 using NodeConstPtr = const Node*;
1062
1064 {
1066 };
1067
1069
1071
1079
1083
1087
1090
1099
1101 Size size(const Derived& obj) const { return obj.size_; }
1102
1104 Size veclen(const Derived& obj) const { return DIM > 0 ? DIM : obj.dim_; }
1105
1108 const Derived& obj, IndexType element, Dimension component) const
1109 {
1110 return obj.dataset_.kdtree_get_pt(element, component);
1111 }
1112
1117 Size usedMemory(const Derived& obj) const
1118 {
1119 return obj.pool_.usedMemory + obj.pool_.wastedMemory +
1120 obj.dataset_.kdtree_get_point_count() *
1121 sizeof(IndexType); // pool memory and vind array memory
1122 }
1123
1128 const Derived& obj, Offset ind, Size count, Dimension element,
1129 ElementType& min_elem, ElementType& max_elem) const
1130 {
1131 min_elem = dataset_get(obj, vAcc_[ind], element);
1132 max_elem = min_elem;
1133 for (Offset i = 1; i < count; ++i)
1134 {
1135 ElementType val = dataset_get(obj, vAcc_[ind + i], element);
1136 if (val < min_elem) min_elem = val;
1137 if (val > max_elem) max_elem = val;
1138 }
1139 }
1140
1150 Derived& obj, const Offset left, const Offset right, BoundingBox& bbox)
1151 {
1152 assert(left < obj.dataset_.kdtree_get_point_count());
1153
1154 NodePtr node = obj.pool_.template allocate<Node>(); // allocate memory
1155 const auto dims = (DIM > 0 ? DIM : obj.dim_);
1156
1157 /* If too few exemplars remain, then make this a leaf node. */
1158 if ((right - left) <= static_cast<Offset>(obj.leaf_max_size_))
1159 {
1160 node->child1 = node->child2 = nullptr; /* Mark as leaf node. */
1161 node->node_type.lr.left = left;
1162 node->node_type.lr.right = right;
1163
1164 // compute bounding-box of leaf points
1165 for (Dimension i = 0; i < dims; ++i)
1166 {
1167 bbox[i].low = dataset_get(obj, obj.vAcc_[left], i);
1168 bbox[i].high = dataset_get(obj, obj.vAcc_[left], i);
1169 }
1170 for (Offset k = left + 1; k < right; ++k)
1171 {
1172 for (Dimension i = 0; i < dims; ++i)
1173 {
1174 const auto val = dataset_get(obj, obj.vAcc_[k], i);
1175 if (bbox[i].low > val) bbox[i].low = val;
1176 if (bbox[i].high < val) bbox[i].high = val;
1177 }
1178 }
1179 }
1180 else
1181 {
1182 /* Determine the index, dimension and value for split plane */
1183 Offset idx;
1184 Dimension cutfeat;
1185 DistanceType cutval;
1186 middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox);
1187
1188 node->node_type.sub.divfeat = cutfeat;
1189
1190 /* Recurse on left */
1191 BoundingBox left_bbox(bbox);
1192 left_bbox[cutfeat].high = cutval;
1193 node->child1 = this->divideTree(obj, left, left + idx, left_bbox);
1194
1195 /* Recurse on right */
1196 BoundingBox right_bbox(bbox);
1197 right_bbox[cutfeat].low = cutval;
1198 node->child2 = this->divideTree(obj, left + idx, right, right_bbox);
1199
1200 node->node_type.sub.divlow = left_bbox[cutfeat].high;
1201 node->node_type.sub.divhigh = right_bbox[cutfeat].low;
1202
1203 for (Dimension i = 0; i < dims; ++i)
1204 {
1205 bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
1206 bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
1207 }
1208 }
1209
1210 return node;
1211 }
1212
1225 Derived& obj, const Offset left, const Offset right, BoundingBox& bbox,
1226 std::atomic<unsigned int>& thread_count, std::mutex& mutex)
1227 {
1228 std::unique_lock<std::mutex> lock(mutex);
1229 NodePtr node = obj.pool_.template allocate<Node>(); // allocate memory
1230 lock.unlock();
1231
1232 const auto dims = (DIM > 0 ? DIM : obj.dim_);
1233
1234 /* If too few exemplars remain, then make this a leaf node. */
1235 if ((right - left) <= static_cast<Offset>(obj.leaf_max_size_))
1236 {
1237 node->child1 = node->child2 = nullptr; /* Mark as leaf node. */
1238 node->node_type.lr.left = left;
1239 node->node_type.lr.right = right;
1240
1241 // compute bounding-box of leaf points
1242 for (Dimension i = 0; i < dims; ++i)
1243 {
1244 bbox[i].low = dataset_get(obj, obj.vAcc_[left], i);
1245 bbox[i].high = dataset_get(obj, obj.vAcc_[left], i);
1246 }
1247 for (Offset k = left + 1; k < right; ++k)
1248 {
1249 for (Dimension i = 0; i < dims; ++i)
1250 {
1251 const auto val = dataset_get(obj, obj.vAcc_[k], i);
1252 if (bbox[i].low > val) bbox[i].low = val;
1253 if (bbox[i].high < val) bbox[i].high = val;
1254 }
1255 }
1256 }
1257 else
1258 {
1259 /* Determine the index, dimension and value for split plane */
1260 Offset idx;
1261 Dimension cutfeat;
1262 DistanceType cutval;
1263 middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox);
1264
1265 node->node_type.sub.divfeat = cutfeat;
1266
1267 std::future<NodePtr> right_future;
1268
1269 /* Recurse on right concurrently, if possible */
1270
1271 BoundingBox right_bbox(bbox);
1272 right_bbox[cutfeat].low = cutval;
1273 if (++thread_count < n_thread_build_)
1274 {
1275 /* Concurrent thread for right recursion */
1276
1277 right_future = std::async(
1278 std::launch::async, &KDTreeBaseClass::divideTreeConcurrent,
1279 this, std::ref(obj), left + idx, right,
1280 std::ref(right_bbox), std::ref(thread_count),
1281 std::ref(mutex));
1282 }
1283 else { --thread_count; }
1284
1285 /* Recurse on left in this thread */
1286
1287 BoundingBox left_bbox(bbox);
1288 left_bbox[cutfeat].high = cutval;
1289 node->child1 = this->divideTreeConcurrent(
1290 obj, left, left + idx, left_bbox, thread_count, mutex);
1291
1292 if (right_future.valid())
1293 {
1294 /* Block and wait for concurrent right from above */
1295
1296 node->child2 = right_future.get();
1297 --thread_count;
1298 }
1299 else
1300 {
1301 /* Otherwise, recurse on right in this thread */
1302
1303 node->child2 = this->divideTreeConcurrent(
1304 obj, left + idx, right, right_bbox, thread_count, mutex);
1305 }
1306
1307 node->node_type.sub.divlow = left_bbox[cutfeat].high;
1308 node->node_type.sub.divhigh = right_bbox[cutfeat].low;
1309
1310 for (Dimension i = 0; i < dims; ++i)
1311 {
1312 bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
1313 bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
1314 }
1315 }
1316
1317 return node;
1318 }
1319
1321 const Derived& obj, const Offset ind, const Size count, Offset& index,
1322 Dimension& cutfeat, DistanceType& cutval, const BoundingBox& bbox)
1323 {
1324 const auto dims = (DIM > 0 ? DIM : obj.dim_);
1325 const auto EPS = static_cast<DistanceType>(0.00001);
1326 ElementType max_span = bbox[0].high - bbox[0].low;
1327 for (Dimension i = 1; i < dims; ++i)
1328 {
1329 ElementType span = bbox[i].high - bbox[i].low;
1330 if (span > max_span) { max_span = span; }
1331 }
1332 ElementType max_spread = -1;
1333 cutfeat = 0;
1334 ElementType min_elem = 0, max_elem = 0;
1335 for (Dimension i = 0; i < dims; ++i)
1336 {
1337 ElementType span = bbox[i].high - bbox[i].low;
1338 if (span >= (1 - EPS) * max_span)
1339 {
1340 ElementType min_elem_, max_elem_;
1341 computeMinMax(obj, ind, count, i, min_elem_, max_elem_);
1342 ElementType spread = max_elem_ - min_elem_;
1343 if (spread > max_spread)
1344 {
1345 cutfeat = i;
1346 max_spread = spread;
1347 min_elem = min_elem_;
1348 max_elem = max_elem_;
1349 }
1350 }
1351 }
1352 // split in the middle
1353 DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2;
1354
1355 if (split_val < min_elem)
1356 cutval = min_elem;
1357 else if (split_val > max_elem)
1358 cutval = max_elem;
1359 else
1360 cutval = split_val;
1361
1362 Offset lim1, lim2;
1363 planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2);
1364
1365 if (lim1 > count / 2)
1366 index = lim1;
1367 else if (lim2 < count / 2)
1368 index = lim2;
1369 else
1370 index = count / 2;
1371 }
1372
1383 const Derived& obj, const Offset ind, const Size count,
1384 const Dimension cutfeat, const DistanceType& cutval, Offset& lim1,
1385 Offset& lim2)
1386 {
1387 /* First pass.
1388 * Determine lim1 with all values less than cutval to the left.
1389 */
1390 Offset left = 0;
1391 Offset right = count - 1;
1392 for (;;)
1393 {
1394 while (left <= right &&
1395 dataset_get(obj, vAcc_[ind + left], cutfeat) < cutval)
1396 ++left;
1397 while (right && left <= right &&
1398 dataset_get(obj, vAcc_[ind + right], cutfeat) >= cutval)
1399 --right;
1400 if (left > right || !right)
1401 break; // "!right" was added to support unsigned Index types
1402 std::swap(vAcc_[ind + left], vAcc_[ind + right]);
1403 ++left;
1404 --right;
1405 }
1406 /* Second pass
1407 * Determine lim2 with all values greater than cutval to the right
1408 * The middle is used for balancing the tree
1409 */
1410 lim1 = left;
1411 right = count - 1;
1412 for (;;)
1413 {
1414 while (left <= right &&
1415 dataset_get(obj, vAcc_[ind + left], cutfeat) <= cutval)
1416 ++left;
1417 while (right && left <= right &&
1418 dataset_get(obj, vAcc_[ind + right], cutfeat) > cutval)
1419 --right;
1420 if (left > right || !right)
1421 break; // "!right" was added to support unsigned Index types
1422 std::swap(vAcc_[ind + left], vAcc_[ind + right]);
1423 ++left;
1424 --right;
1425 }
1426 lim2 = left;
1427 }
1428
1430 const Derived& obj, const ElementType* vec,
1431 distance_vector_t& dists) const
1432 {
1433 assert(vec);
1434 DistanceType dist = DistanceType();
1435
1436 for (Dimension i = 0; i < (DIM > 0 ? DIM : obj.dim_); ++i)
1437 {
1438 if (vec[i] < obj.root_bbox_[i].low)
1439 {
1440 dists[i] =
1441 obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].low, i);
1442 dist += dists[i];
1443 }
1444 if (vec[i] > obj.root_bbox_[i].high)
1445 {
1446 dists[i] =
1447 obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].high, i);
1448 dist += dists[i];
1449 }
1450 }
1451 return dist;
1452 }
1453
1454 static void save_tree(
1455 const Derived& obj, std::ostream& stream, const NodeConstPtr tree)
1456 {
1457 save_value(stream, *tree);
1458 if (tree->child1 != nullptr) { save_tree(obj, stream, tree->child1); }
1459 if (tree->child2 != nullptr) { save_tree(obj, stream, tree->child2); }
1460 }
1461
1462 static void load_tree(Derived& obj, std::istream& stream, NodePtr& tree)
1463 {
1464 tree = obj.pool_.template allocate<Node>();
1465 load_value(stream, *tree);
1466 if (tree->child1 != nullptr) { load_tree(obj, stream, tree->child1); }
1467 if (tree->child2 != nullptr) { load_tree(obj, stream, tree->child2); }
1468 }
1469
1475 void saveIndex(const Derived& obj, std::ostream& stream) const
1476 {
1477 save_value(stream, obj.size_);
1478 save_value(stream, obj.dim_);
1479 save_value(stream, obj.root_bbox_);
1480 save_value(stream, obj.leaf_max_size_);
1481 save_value(stream, obj.vAcc_);
1482 if (obj.root_node_) save_tree(obj, stream, obj.root_node_);
1483 }
1484
1490 void loadIndex(Derived& obj, std::istream& stream)
1491 {
1492 load_value(stream, obj.size_);
1493 load_value(stream, obj.dim_);
1494 load_value(stream, obj.root_bbox_);
1495 load_value(stream, obj.leaf_max_size_);
1496 load_value(stream, obj.vAcc_);
1497 load_tree(obj, stream, obj.root_node_);
1498 }
1499};
1500
1503
1542template <
1543 typename Distance, class DatasetAdaptor, int32_t DIM = -1,
1544 typename index_t = uint32_t>
1546 : public KDTreeBaseClass<
1547 KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, index_t>,
1548 Distance, DatasetAdaptor, DIM, index_t>
1549{
1550 public:
1554 Distance, DatasetAdaptor, DIM, index_t>&) = delete;
1555
1557 const DatasetAdaptor& dataset_;
1558
1560
1561 Distance distance_;
1562
1565 Distance, DatasetAdaptor, DIM, index_t>,
1566 Distance, DatasetAdaptor, DIM, index_t>;
1567
1568 using Offset = typename Base::Offset;
1569 using Size = typename Base::Size;
1570 using Dimension = typename Base::Dimension;
1571
1572 using ElementType = typename Base::ElementType;
1573 using DistanceType = typename Base::DistanceType;
1574 using IndexType = typename Base::IndexType;
1575
1576 using Node = typename Base::Node;
1577 using NodePtr = Node*;
1578
1579 using Interval = typename Base::Interval;
1580
1583 using BoundingBox = typename Base::BoundingBox;
1584
1587 using distance_vector_t = typename Base::distance_vector_t;
1588
1609 template <class... Args>
1611 const Dimension dimensionality, const DatasetAdaptor& inputData,
1612 const KDTreeSingleIndexAdaptorParams& params, Args&&... args)
1613 : dataset_(inputData),
1614 indexParams(params),
1615 distance_(inputData, std::forward<Args>(args)...)
1616 {
1617 init(dimensionality, params);
1618 }
1619
1621 const Dimension dimensionality, const DatasetAdaptor& inputData,
1622 const KDTreeSingleIndexAdaptorParams& params = {})
1623 : dataset_(inputData), indexParams(params), distance_(inputData)
1624 {
1625 init(dimensionality, params);
1626 }
1627
1628 private:
1629 void init(
1630 const Dimension dimensionality,
1631 const KDTreeSingleIndexAdaptorParams& params)
1632 {
1633 Base::size_ = dataset_.kdtree_get_point_count();
1634 Base::size_at_index_build_ = Base::size_;
1635 Base::dim_ = dimensionality;
1636 if (DIM > 0) Base::dim_ = DIM;
1637 Base::leaf_max_size_ = params.leaf_max_size;
1638 if (params.n_thread_build > 0)
1639 {
1640 Base::n_thread_build_ = params.n_thread_build;
1641 }
1642 else
1643 {
1644 Base::n_thread_build_ =
1645 std::max(std::thread::hardware_concurrency(), 1u);
1646 }
1647
1648 if (!(params.flags &
1650 {
1651 // Build KD-tree:
1652 buildIndex();
1653 }
1654 }
1655
1656 public:
1661 {
1662 Base::size_ = dataset_.kdtree_get_point_count();
1663 Base::size_at_index_build_ = Base::size_;
1664 init_vind();
1665 this->freeIndex(*this);
1666 Base::size_at_index_build_ = Base::size_;
1667 if (Base::size_ == 0) return;
1668 computeBoundingBox(Base::root_bbox_);
1669 // construct the tree
1670 if (Base::n_thread_build_ == 1)
1671 {
1672 Base::root_node_ =
1673 this->divideTree(*this, 0, Base::size_, Base::root_bbox_);
1674 }
1675 else
1676 {
1677#ifndef NANOFLANN_NO_THREADS
1678 std::atomic<unsigned int> thread_count(0u);
1679 std::mutex mutex;
1680 Base::root_node_ = this->divideTreeConcurrent(
1681 *this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
1682#else /* NANOFLANN_NO_THREADS */
1683 throw std::runtime_error("Multithreading is disabled");
1684#endif /* NANOFLANN_NO_THREADS */
1685 }
1686 }
1687
1690
1707 template <typename RESULTSET>
1709 RESULTSET& result, const ElementType* vec,
1710 const SearchParameters& searchParams = {}) const
1711 {
1712 assert(vec);
1713 if (this->size(*this) == 0) return false;
1714 if (!Base::root_node_)
1715 throw std::runtime_error(
1716 "[nanoflann] findNeighbors() called before building the "
1717 "index.");
1718 float epsError = 1 + searchParams.eps;
1719
1720 // fixed or variable-sized container (depending on DIM)
1721 distance_vector_t dists;
1722 // Fill it with zeros.
1723 auto zero = static_cast<typename RESULTSET::DistanceType>(0);
1724 assign(dists, (DIM > 0 ? DIM : Base::dim_), zero);
1725 DistanceType dist = this->computeInitialDistances(*this, vec, dists);
1726 searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
1727
1728 if (searchParams.sorted) result.sort();
1729
1730 return result.full();
1731 }
1732
1749 const ElementType* query_point, const Size num_closest,
1750 IndexType* out_indices, DistanceType* out_distances) const
1751 {
1753 resultSet.init(out_indices, out_distances);
1754 findNeighbors(resultSet, query_point);
1755 return resultSet.size();
1756 }
1757
1778 const ElementType* query_point, const DistanceType& radius,
1779 std::vector<ResultItem<IndexType, DistanceType>>& IndicesDists,
1780 const SearchParameters& searchParams = {}) const
1781 {
1783 radius, IndicesDists);
1784 const Size nFound =
1785 radiusSearchCustomCallback(query_point, resultSet, searchParams);
1786 return nFound;
1787 }
1788
1794 template <class SEARCH_CALLBACK>
1796 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
1797 const SearchParameters& searchParams = {}) const
1798 {
1799 findNeighbors(resultSet, query_point, searchParams);
1800 return resultSet.size();
1801 }
1802
1820 const ElementType* query_point, const Size num_closest,
1821 IndexType* out_indices, DistanceType* out_distances,
1822 const DistanceType& radius) const
1823 {
1825 num_closest, radius);
1826 resultSet.init(out_indices, out_distances);
1827 findNeighbors(resultSet, query_point);
1828 return resultSet.size();
1829 }
1830
1832
1833 public:
1837 {
1838 // Create a permutable array of indices to the input vectors.
1839 Base::size_ = dataset_.kdtree_get_point_count();
1840 if (Base::vAcc_.size() != Base::size_) Base::vAcc_.resize(Base::size_);
1841 for (IndexType i = 0; i < static_cast<IndexType>(Base::size_); i++)
1842 Base::vAcc_[i] = i;
1843 }
1844
1846 {
1847 const auto dims = (DIM > 0 ? DIM : Base::dim_);
1848 resize(bbox, dims);
1849 if (dataset_.kdtree_get_bbox(bbox))
1850 {
1851 // Done! It was implemented in derived class
1852 }
1853 else
1854 {
1855 const Size N = dataset_.kdtree_get_point_count();
1856 if (!N)
1857 throw std::runtime_error(
1858 "[nanoflann] computeBoundingBox() called but "
1859 "no data points found.");
1860 for (Dimension i = 0; i < dims; ++i)
1861 {
1862 bbox[i].low = bbox[i].high =
1863 this->dataset_get(*this, Base::vAcc_[0], i);
1864 }
1865 for (Offset k = 1; k < N; ++k)
1866 {
1867 for (Dimension i = 0; i < dims; ++i)
1868 {
1869 const auto val =
1870 this->dataset_get(*this, Base::vAcc_[k], i);
1871 if (val < bbox[i].low) bbox[i].low = val;
1872 if (val > bbox[i].high) bbox[i].high = val;
1873 }
1874 }
1875 }
1876 }
1877
1884 template <class RESULTSET>
1886 RESULTSET& result_set, const ElementType* vec, const NodePtr node,
1887 DistanceType mindist, distance_vector_t& dists,
1888 const float epsError) const
1889 {
1890 /* If this is a leaf node, then do check and return. */
1891 if ((node->child1 == nullptr) && (node->child2 == nullptr))
1892 {
1893 DistanceType worst_dist = result_set.worstDist();
1894 for (Offset i = node->node_type.lr.left;
1895 i < node->node_type.lr.right; ++i)
1896 {
1897 const IndexType accessor = Base::vAcc_[i]; // reorder... : i;
1898 DistanceType dist = distance_.evalMetric(
1899 vec, accessor, (DIM > 0 ? DIM : Base::dim_));
1900 if (dist < worst_dist)
1901 {
1902 if (!result_set.addPoint(dist, Base::vAcc_[i]))
1903 {
1904 // the resultset doesn't want to receive any more
1905 // points, we're done searching!
1906 return false;
1907 }
1908 }
1909 }
1910 return true;
1911 }
1912
1913 /* Which child branch should be taken first? */
1914 Dimension idx = node->node_type.sub.divfeat;
1915 ElementType val = vec[idx];
1916 DistanceType diff1 = val - node->node_type.sub.divlow;
1917 DistanceType diff2 = val - node->node_type.sub.divhigh;
1918
1919 NodePtr bestChild;
1920 NodePtr otherChild;
1921 DistanceType cut_dist;
1922 if ((diff1 + diff2) < 0)
1923 {
1924 bestChild = node->child1;
1925 otherChild = node->child2;
1926 cut_dist =
1927 distance_.accum_dist(val, node->node_type.sub.divhigh, idx);
1928 }
1929 else
1930 {
1931 bestChild = node->child2;
1932 otherChild = node->child1;
1933 cut_dist =
1934 distance_.accum_dist(val, node->node_type.sub.divlow, idx);
1935 }
1936
1937 /* Call recursively to search next level down. */
1938 if (!searchLevel(result_set, vec, bestChild, mindist, dists, epsError))
1939 {
1940 // the resultset doesn't want to receive any more points, we're done
1941 // searching!
1942 return false;
1943 }
1944
1945 DistanceType dst = dists[idx];
1946 mindist = mindist + cut_dist - dst;
1947 dists[idx] = cut_dist;
1948 if (mindist * epsError <= result_set.worstDist())
1949 {
1950 if (!searchLevel(
1951 result_set, vec, otherChild, mindist, dists, epsError))
1952 {
1953 // the resultset doesn't want to receive any more points, we're
1954 // done searching!
1955 return false;
1956 }
1957 }
1958 dists[idx] = dst;
1959 return true;
1960 }
1961
1962 public:
1968 void saveIndex(std::ostream& stream) const
1969 {
1970 Base::saveIndex(*this, stream);
1971 }
1972
1978 void loadIndex(std::istream& stream) { Base::loadIndex(*this, stream); }
1979
1980}; // class KDTree
1981
2019template <
2020 typename Distance, class DatasetAdaptor, int32_t DIM = -1,
2021 typename IndexType = uint32_t>
2023 : public KDTreeBaseClass<
2024 KDTreeSingleIndexDynamicAdaptor_<
2025 Distance, DatasetAdaptor, DIM, IndexType>,
2026 Distance, DatasetAdaptor, DIM, IndexType>
2027{
2028 public:
2032 const DatasetAdaptor& dataset_;
2033
2035
2036 std::vector<int>& treeIndex_;
2037
2038 Distance distance_;
2039
2042 Distance, DatasetAdaptor, DIM, IndexType>,
2043 Distance, DatasetAdaptor, DIM, IndexType>;
2044
2045 using ElementType = typename Base::ElementType;
2046 using DistanceType = typename Base::DistanceType;
2047
2048 using Offset = typename Base::Offset;
2049 using Size = typename Base::Size;
2050 using Dimension = typename Base::Dimension;
2051
2052 using Node = typename Base::Node;
2053 using NodePtr = Node*;
2054
2055 using Interval = typename Base::Interval;
2058 using BoundingBox = typename Base::BoundingBox;
2059
2062 using distance_vector_t = typename Base::distance_vector_t;
2063
2080 const Dimension dimensionality, const DatasetAdaptor& inputData,
2081 std::vector<int>& treeIndex,
2082 const KDTreeSingleIndexAdaptorParams& params =
2084 : dataset_(inputData),
2085 index_params_(params),
2086 treeIndex_(treeIndex),
2087 distance_(inputData)
2088 {
2089 Base::size_ = 0;
2090 Base::size_at_index_build_ = 0;
2091 for (auto& v : Base::root_bbox_) v = {};
2092 Base::dim_ = dimensionality;
2093 if (DIM > 0) Base::dim_ = DIM;
2094 Base::leaf_max_size_ = params.leaf_max_size;
2095 if (params.n_thread_build > 0)
2096 {
2097 Base::n_thread_build_ = params.n_thread_build;
2098 }
2099 else
2100 {
2101 Base::n_thread_build_ =
2102 std::max(std::thread::hardware_concurrency(), 1u);
2103 }
2104 }
2105
2108 const KDTreeSingleIndexDynamicAdaptor_& rhs) = default;
2109
2113 {
2115 std::swap(Base::vAcc_, tmp.Base::vAcc_);
2116 std::swap(Base::leaf_max_size_, tmp.Base::leaf_max_size_);
2117 std::swap(index_params_, tmp.index_params_);
2118 std::swap(treeIndex_, tmp.treeIndex_);
2119 std::swap(Base::size_, tmp.Base::size_);
2120 std::swap(Base::size_at_index_build_, tmp.Base::size_at_index_build_);
2121 std::swap(Base::root_node_, tmp.Base::root_node_);
2122 std::swap(Base::root_bbox_, tmp.Base::root_bbox_);
2123 std::swap(Base::pool_, tmp.Base::pool_);
2124 return *this;
2125 }
2126
2131 {
2132 Base::size_ = Base::vAcc_.size();
2133 this->freeIndex(*this);
2134 Base::size_at_index_build_ = Base::size_;
2135 if (Base::size_ == 0) return;
2136 computeBoundingBox(Base::root_bbox_);
2137 // construct the tree
2138 if (Base::n_thread_build_ == 1)
2139 {
2140 Base::root_node_ =
2141 this->divideTree(*this, 0, Base::size_, Base::root_bbox_);
2142 }
2143 else
2144 {
2145#ifndef NANOFLANN_NO_THREADS
2146 std::atomic<unsigned int> thread_count(0u);
2147 std::mutex mutex;
2148 Base::root_node_ = this->divideTreeConcurrent(
2149 *this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
2150#else /* NANOFLANN_NO_THREADS */
2151 throw std::runtime_error("Multithreading is disabled");
2152#endif /* NANOFLANN_NO_THREADS */
2153 }
2154 }
2155
2158
2179 template <typename RESULTSET>
2181 RESULTSET& result, const ElementType* vec,
2182 const SearchParameters& searchParams = {}) const
2183 {
2184 assert(vec);
2185 if (this->size(*this) == 0) return false;
2186 if (!Base::root_node_) return false;
2187 float epsError = 1 + searchParams.eps;
2188
2189 // fixed or variable-sized container (depending on DIM)
2190 distance_vector_t dists;
2191 // Fill it with zeros.
2192 assign(
2193 dists, (DIM > 0 ? DIM : Base::dim_),
2194 static_cast<typename distance_vector_t::value_type>(0));
2195 DistanceType dist = this->computeInitialDistances(*this, vec, dists);
2196 searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
2197 return result.full();
2198 }
2199
2215 const ElementType* query_point, const Size num_closest,
2216 IndexType* out_indices, DistanceType* out_distances,
2217 const SearchParameters& searchParams = {}) const
2218 {
2220 resultSet.init(out_indices, out_distances);
2221 findNeighbors(resultSet, query_point, searchParams);
2222 return resultSet.size();
2223 }
2224
2245 const ElementType* query_point, const DistanceType& radius,
2246 std::vector<ResultItem<IndexType, DistanceType>>& IndicesDists,
2247 const SearchParameters& searchParams = {}) const
2248 {
2250 radius, IndicesDists);
2251 const size_t nFound =
2252 radiusSearchCustomCallback(query_point, resultSet, searchParams);
2253 return nFound;
2254 }
2255
2261 template <class SEARCH_CALLBACK>
2263 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
2264 const SearchParameters& searchParams = {}) const
2265 {
2266 findNeighbors(resultSet, query_point, searchParams);
2267 return resultSet.size();
2268 }
2269
2271
2272 public:
2274 {
2275 const auto dims = (DIM > 0 ? DIM : Base::dim_);
2276 resize(bbox, dims);
2277
2278 if (dataset_.kdtree_get_bbox(bbox))
2279 {
2280 // Done! It was implemented in derived class
2281 }
2282 else
2283 {
2284 const Size N = Base::size_;
2285 if (!N)
2286 throw std::runtime_error(
2287 "[nanoflann] computeBoundingBox() called but "
2288 "no data points found.");
2289 for (Dimension i = 0; i < dims; ++i)
2290 {
2291 bbox[i].low = bbox[i].high =
2292 this->dataset_get(*this, Base::vAcc_[0], i);
2293 }
2294 for (Offset k = 1; k < N; ++k)
2295 {
2296 for (Dimension i = 0; i < dims; ++i)
2297 {
2298 const auto val =
2299 this->dataset_get(*this, Base::vAcc_[k], i);
2300 if (val < bbox[i].low) bbox[i].low = val;
2301 if (val > bbox[i].high) bbox[i].high = val;
2302 }
2303 }
2304 }
2305 }
2306
2311 template <class RESULTSET>
2313 RESULTSET& result_set, const ElementType* vec, const NodePtr node,
2314 DistanceType mindist, distance_vector_t& dists,
2315 const float epsError) const
2316 {
2317 /* If this is a leaf node, then do check and return. */
2318 if ((node->child1 == nullptr) && (node->child2 == nullptr))
2319 {
2320 DistanceType worst_dist = result_set.worstDist();
2321 for (Offset i = node->node_type.lr.left;
2322 i < node->node_type.lr.right; ++i)
2323 {
2324 const IndexType index = Base::vAcc_[i]; // reorder... : i;
2325 if (treeIndex_[index] == -1) continue;
2326 DistanceType dist = distance_.evalMetric(
2327 vec, index, (DIM > 0 ? DIM : Base::dim_));
2328 if (dist < worst_dist)
2329 {
2330 if (!result_set.addPoint(
2331 static_cast<typename RESULTSET::DistanceType>(dist),
2332 static_cast<typename RESULTSET::IndexType>(
2333 Base::vAcc_[i])))
2334 {
2335 // the resultset doesn't want to receive any more
2336 // points, we're done searching!
2337 return; // false;
2338 }
2339 }
2340 }
2341 return;
2342 }
2343
2344 /* Which child branch should be taken first? */
2345 Dimension idx = node->node_type.sub.divfeat;
2346 ElementType val = vec[idx];
2347 DistanceType diff1 = val - node->node_type.sub.divlow;
2348 DistanceType diff2 = val - node->node_type.sub.divhigh;
2349
2350 NodePtr bestChild;
2351 NodePtr otherChild;
2352 DistanceType cut_dist;
2353 if ((diff1 + diff2) < 0)
2354 {
2355 bestChild = node->child1;
2356 otherChild = node->child2;
2357 cut_dist =
2358 distance_.accum_dist(val, node->node_type.sub.divhigh, idx);
2359 }
2360 else
2361 {
2362 bestChild = node->child2;
2363 otherChild = node->child1;
2364 cut_dist =
2365 distance_.accum_dist(val, node->node_type.sub.divlow, idx);
2366 }
2367
2368 /* Call recursively to search next level down. */
2369 searchLevel(result_set, vec, bestChild, mindist, dists, epsError);
2370
2371 DistanceType dst = dists[idx];
2372 mindist = mindist + cut_dist - dst;
2373 dists[idx] = cut_dist;
2374 if (mindist * epsError <= result_set.worstDist())
2375 {
2376 searchLevel(result_set, vec, otherChild, mindist, dists, epsError);
2377 }
2378 dists[idx] = dst;
2379 }
2380
2381 public:
2387 void saveIndex(std::ostream& stream) { saveIndex(*this, stream); }
2388
2394 void loadIndex(std::istream& stream) { loadIndex(*this, stream); }
2395};
2396
2411template <
2412 typename Distance, class DatasetAdaptor, int32_t DIM = -1,
2413 typename IndexType = uint32_t>
2415{
2416 public:
2417 using ElementType = typename Distance::ElementType;
2418 using DistanceType = typename Distance::DistanceType;
2419
2421 Distance, DatasetAdaptor, DIM>::Offset;
2423 Distance, DatasetAdaptor, DIM>::Size;
2425 Distance, DatasetAdaptor, DIM>::Dimension;
2426
2427 protected:
2431
2435 const DatasetAdaptor& dataset_;
2436
2439 std::vector<int> treeIndex_;
2440 std::unordered_set<int> removedPoints_;
2441
2443
2445
2447 Distance, DatasetAdaptor, DIM, IndexType>;
2448 std::vector<index_container_t> index_;
2449
2450 public:
2453 const std::vector<index_container_t>& getAllIndices() const
2454 {
2455 return index_;
2456 }
2457
2458 private:
2460 int First0Bit(IndexType num)
2461 {
2462 int pos = 0;
2463 while (num & 1)
2464 {
2465 num = num >> 1;
2466 pos++;
2467 }
2468 return pos;
2469 }
2470
2472 void init()
2473 {
2474 using my_kd_tree_t = KDTreeSingleIndexDynamicAdaptor_<
2475 Distance, DatasetAdaptor, DIM, IndexType>;
2476 std::vector<my_kd_tree_t> index(
2477 treeCount_,
2478 my_kd_tree_t(dim_ /*dim*/, dataset_, treeIndex_, index_params_));
2479 index_ = index;
2480 }
2481
2482 public:
2483 Distance distance_;
2484
2501 const int dimensionality, const DatasetAdaptor& inputData,
2502 const KDTreeSingleIndexAdaptorParams& params =
2504 const size_t maximumPointCount = 1000000000U)
2505 : dataset_(inputData), index_params_(params), distance_(inputData)
2506 {
2507 treeCount_ = static_cast<size_t>(std::log2(maximumPointCount)) + 1;
2508 pointCount_ = 0U;
2509 dim_ = dimensionality;
2510 treeIndex_.clear();
2511 if (DIM > 0) dim_ = DIM;
2512 leaf_max_size_ = params.leaf_max_size;
2513 init();
2514 const size_t num_initial_points = dataset_.kdtree_get_point_count();
2515 if (num_initial_points > 0) { addPoints(0, num_initial_points - 1); }
2516 }
2517
2521 Distance, DatasetAdaptor, DIM, IndexType>&) = delete;
2522
2524 void addPoints(IndexType start, IndexType end)
2525 {
2526 const Size count = end - start + 1;
2527 int maxIndex = 0;
2528 treeIndex_.resize(treeIndex_.size() + count);
2529 for (IndexType idx = start; idx <= end; idx++)
2530 {
2531 const int pos = First0Bit(pointCount_);
2532 maxIndex = std::max(pos, maxIndex);
2533 treeIndex_[pointCount_] = pos;
2534
2535 const auto it = removedPoints_.find(idx);
2536 if (it != removedPoints_.end())
2537 {
2538 removedPoints_.erase(it);
2539 treeIndex_[idx] = pos;
2540 }
2541
2542 for (int i = 0; i < pos; i++)
2543 {
2544 for (int j = 0; j < static_cast<int>(index_[i].vAcc_.size());
2545 j++)
2546 {
2547 index_[pos].vAcc_.push_back(index_[i].vAcc_[j]);
2548 if (treeIndex_[index_[i].vAcc_[j]] != -1)
2549 treeIndex_[index_[i].vAcc_[j]] = pos;
2550 }
2551 index_[i].vAcc_.clear();
2552 }
2553 index_[pos].vAcc_.push_back(idx);
2554 pointCount_++;
2555 }
2556
2557 for (int i = 0; i <= maxIndex; ++i)
2558 {
2559 index_[i].freeIndex(index_[i]);
2560 if (!index_[i].vAcc_.empty()) index_[i].buildIndex();
2561 }
2562 }
2563
2565 void removePoint(size_t idx)
2566 {
2567 if (idx >= pointCount_) return;
2568 removedPoints_.insert(idx);
2569 treeIndex_[idx] = -1;
2570 }
2571
2588 template <typename RESULTSET>
2590 RESULTSET& result, const ElementType* vec,
2591 const SearchParameters& searchParams = {}) const
2592 {
2593 for (size_t i = 0; i < treeCount_; i++)
2594 {
2595 index_[i].findNeighbors(result, &vec[0], searchParams);
2596 }
2597 return result.full();
2598 }
2599};
2600
2626template <
2627 class MatrixType, int32_t DIM = -1, class Distance = nanoflann::metric_L2,
2628 bool row_major = true>
2630{
2631 using self_t =
2633 using num_t = typename MatrixType::Scalar;
2634 using IndexType = typename MatrixType::Index;
2635 using metric_t = typename Distance::template traits<
2636 num_t, self_t, IndexType>::distance_t;
2637
2640 row_major ? MatrixType::ColsAtCompileTime
2641 : MatrixType::RowsAtCompileTime,
2642 IndexType>;
2643
2646
2647 using Offset = typename index_t::Offset;
2648 using Size = typename index_t::Size;
2650
2653 const Dimension dimensionality,
2654 const std::reference_wrapper<const MatrixType>& mat,
2655 const int leaf_max_size = 10, const unsigned int n_thread_build = 1)
2656 : m_data_matrix(mat)
2657 {
2658 const auto dims = row_major ? mat.get().cols() : mat.get().rows();
2659 if (static_cast<Dimension>(dims) != dimensionality)
2660 throw std::runtime_error(
2661 "Error: 'dimensionality' must match column count in data "
2662 "matrix");
2663 if (DIM > 0 && static_cast<int32_t>(dims) != DIM)
2664 throw std::runtime_error(
2665 "Data set dimensionality does not match the 'DIM' template "
2666 "argument");
2667 index_ = new index_t(
2668 dims, *this /* adaptor */,
2671 n_thread_build));
2672 }
2673
2674 public:
2677
2679
2680 const std::reference_wrapper<const MatrixType> m_data_matrix;
2681
2690 void query(
2691 const num_t* query_point, const Size num_closest,
2692 IndexType* out_indices, num_t* out_distances) const
2693 {
2694 nanoflann::KNNResultSet<num_t, IndexType> resultSet(num_closest);
2695 resultSet.init(out_indices, out_distances);
2696 index_->findNeighbors(resultSet, query_point);
2697 }
2698
2701
2702 const self_t& derived() const { return *this; }
2703 self_t& derived() { return *this; }
2704
2705 // Must return the number of data points
2707 {
2708 if (row_major)
2709 return m_data_matrix.get().rows();
2710 else
2711 return m_data_matrix.get().cols();
2712 }
2713
2714 // Returns the dim'th component of the idx'th point in the class:
2715 num_t kdtree_get_pt(const IndexType idx, size_t dim) const
2716 {
2717 if (row_major)
2718 return m_data_matrix.get().coeff(idx, IndexType(dim));
2719 else
2720 return m_data_matrix.get().coeff(IndexType(dim), idx);
2721 }
2722
2723 // Optional bounding-box computation: return false to default to a standard
2724 // bbox computation loop.
2725 // Return true if the BBOX was already computed by the class and returned
2726 // in "bb" so it can be avoided to redo it again. Look at bb.size() to
2727 // find out the expected dimensionality (e.g. 2 or 3 for point clouds)
2728 template <class BBOX>
2729 bool kdtree_get_bbox(BBOX& /*bb*/) const
2730 {
2731 return false;
2732 }
2733
2735
2736}; // end of KDTreeEigenMatrixAdaptor
2737
2738 // end of grouping
2740} // namespace nanoflann
void freeIndex(Derived &obj)
void middleSplit_(const Derived &obj, const Offset ind, const Size count, Offset &index, Dimension &cutfeat, DistanceType &cutval, const BoundingBox &bbox)
Size veclen(const Derived &obj) const
DistanceType computeInitialDistances(const Derived &obj, const ElementType *vec, distance_vector_t &dists) const
void computeMinMax(const Derived &obj, Offset ind, Size count, Dimension element, ElementType &min_elem, ElementType &max_elem) const
void saveIndex(const Derived &obj, std::ostream &stream) const
typename decltype(vAcc_)::size_type Size
Dimension dim_
Dimensionality of each data point.
typename Distance::ElementType ElementType
typename array_or_vector< DIM, DistanceType >::type distance_vector_t
void planeSplit(const Derived &obj, const Offset ind, const Size count, const Dimension cutfeat, const DistanceType &cutval, Offset &lim1, Offset &lim2)
Size n_thread_build_
Number of thread for concurrent tree build.
static void load_tree(Derived &obj, std::istream &stream, NodePtr &tree)
NodePtr divideTree(Derived &obj, const Offset left, const Offset right, BoundingBox &bbox)
static void save_tree(const Derived &obj, std::ostream &stream, const NodeConstPtr tree)
std::vector< IndexType > vAcc_
Size size(const Derived &obj) const
Size size_at_index_build_
Number of points in the dataset when the index was built.
NodePtr divideTreeConcurrent(Derived &obj, const Offset left, const Offset right, BoundingBox &bbox, std::atomic< unsigned int > &thread_count, std::mutex &mutex)
typename Distance::DistanceType DistanceType
Size size_
Number of current points in the dataset.
typename decltype(vAcc_)::size_type Offset
Size usedMemory(const Derived &obj) const
void loadIndex(Derived &obj, std::istream &stream)
ElementType dataset_get(const Derived &obj, IndexType element, Dimension component) const
Helper accessor to the dataset points:
typename array_or_vector< DIM, Interval >::type BoundingBox
typename Base::DistanceType DistanceType
bool searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindist, distance_vector_t &dists, const float epsError) const
typename Base::IndexType IndexType
typename Base::ElementType ElementType
void saveIndex(std::ostream &stream) const
Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
typename Base::Dimension Dimension
typename nanoflann::KDTreeBaseClass< nanoflann::KDTreeSingleIndexAdaptor< Distance, DatasetAdaptor, DIM, index_t >, Distance, DatasetAdaptor, DIM, index_t > Base
KDTreeSingleIndexAdaptor(const KDTreeSingleIndexAdaptor< Distance, DatasetAdaptor, DIM, index_t > &)=delete
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Size rknnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const DistanceType &radius) const
typename Base::Interval Interval
Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
typename Base::distance_vector_t distance_vector_t
void loadIndex(std::istream &stream)
KDTreeSingleIndexAdaptor(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params={})
typename Base::BoundingBox BoundingBox
KDTreeSingleIndexAdaptor(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params, Args &&... args)
Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances) const
Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
KDTreeSingleIndexDynamicAdaptor_(const Dimension dimensionality, const DatasetAdaptor &inputData, std::vector< int > &treeIndex, const KDTreeSingleIndexAdaptorParams &params=KDTreeSingleIndexAdaptorParams())
Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
typename Base::DistanceType DistanceType
typename nanoflann::KDTreeBaseClass< nanoflann::KDTreeSingleIndexDynamicAdaptor_< Distance, DatasetAdaptor, DIM, IndexType >, Distance, DatasetAdaptor, DIM, IndexType > Base
KDTreeSingleIndexDynamicAdaptor_(const KDTreeSingleIndexDynamicAdaptor_ &rhs)=default
typename Base::distance_vector_t distance_vector_t
Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const SearchParameters &searchParams={}) const
void searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindist, distance_vector_t &dists, const float epsError) const
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
KDTreeSingleIndexDynamicAdaptor_ operator=(const KDTreeSingleIndexDynamicAdaptor_ &rhs)
typename Distance::ElementType ElementType
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
typename Distance::DistanceType DistanceType
const DatasetAdaptor & dataset_
The source of our data.
std::unordered_set< int > removedPoints_
typename KDTreeSingleIndexDynamicAdaptor_< Distance, DatasetAdaptor, DIM >::Offset Offset
KDTreeSingleIndexDynamicAdaptor_< Distance, DatasetAdaptor, DIM, IndexType > index_container_t
void addPoints(IndexType start, IndexType end)
std::vector< index_container_t > index_
KDTreeSingleIndexDynamicAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params=KDTreeSingleIndexAdaptorParams(), const size_t maximumPointCount=1000000000U)
typename KDTreeSingleIndexDynamicAdaptor_< Distance, DatasetAdaptor, DIM >::Dimension Dimension
const std::vector< index_container_t > & getAllIndices() const
typename KDTreeSingleIndexDynamicAdaptor_< Distance, DatasetAdaptor, DIM >::Size Size
KDTreeSingleIndexAdaptorParams index_params_
Dimension dim_
Dimensionality of each data point.
KDTreeSingleIndexDynamicAdaptor(const KDTreeSingleIndexDynamicAdaptor< Distance, DatasetAdaptor, DIM, IndexType > &)=delete
void init(IndexType *indices_, DistanceType *dists_)
_DistanceType DistanceType
bool addPoint(DistanceType dist, IndexType index)
CountType size() const
KNNResultSet(CountType capacity_)
DistanceType worstDist() const
static constexpr size_t BLOCKSIZE
void * malloc(const size_t req_size)
Size remaining_
Number of bytes left in current block of storage.
static constexpr size_t WORDSIZE
T * allocate(const size_t count=1)
void * loc_
Current location in block to next allocate.
void * base_
Pointer to base of current block of storage.
CountType size() const
bool addPoint(DistanceType dist, IndexType index)
void init(IndexType *indices_, DistanceType *dists_)
RKNNResultSet(CountType capacity_, DistanceType maximumSearchDistanceSquared_)
DistanceType maximumSearchDistanceSquared
_DistanceType DistanceType
DistanceType worstDist() const
const DistanceType radius
RadiusResultSet(DistanceType radius_, std::vector< ResultItem< IndexType, DistanceType > > &indices_dists)
DistanceType worstDist() const
ResultItem< IndexType, DistanceType > worst_item() const
std::vector< ResultItem< IndexType, DistanceType > > & m_indices_dists
bool addPoint(DistanceType dist, IndexType index)
double const PI
Definition cme.h:707
void load_value(std::istream &stream, T &value)
void save_value(std::ostream &stream, const T &value)
std::enable_if< has_assign< Container >::value, void >::type assign(Container &c, const size_t nElements, const T &value)
std::enable_if< has_resize< Container >::value, void >::type resize(Container &c, const size_t nElements)
std::underlying_type< KDTreeSingleIndexAdaptorFlags >::type operator&(KDTreeSingleIndexAdaptorFlags lhs, KDTreeSingleIndexAdaptorFlags rhs)
KDTreeSingleIndexAdaptorFlags
bool operator()(const PairType &p1, const PairType &p2) const
DistanceType divlow
The values used for subdivision.
Offset right
Indices of points in leaf node.
struct nanoflann::KDTreeBaseClass::Node::@364321301303311376260063053066165110326243214105::leaf lr
struct nanoflann::KDTreeBaseClass::Node::@364321301303311376260063053066165110326243214105::nonleaf sub
union nanoflann::KDTreeBaseClass::Node::@364321301303311376260063053066165110326243214105 node_type
typename Distance::template traits< num_t, self_t, IndexType >::distance_t metric_t
void query(const num_t *query_point, const Size num_closest, IndexType *out_indices, num_t *out_distances) const
KDTreeEigenMatrixAdaptor< MatrixType, DIM, Distance, row_major > self_t
num_t kdtree_get_pt(const IndexType idx, size_t dim) const
KDTreeSingleIndexAdaptor< metric_t, self_t, row_major ? MatrixType::ColsAtCompileTime :MatrixType::RowsAtCompileTime, IndexType > index_t
const std::reference_wrapper< const MatrixType > m_data_matrix
KDTreeEigenMatrixAdaptor(const self_t &)=delete
KDTreeEigenMatrixAdaptor(const Dimension dimensionality, const std::reference_wrapper< const MatrixType > &mat, const int leaf_max_size=10, const unsigned int n_thread_build=1)
Constructor: takes a const ref to the matrix object with the data points.
KDTreeSingleIndexAdaptorParams(size_t _leaf_max_size=10, KDTreeSingleIndexAdaptorFlags _flags=KDTreeSingleIndexAdaptorFlags::None, unsigned int _n_thread_build=1)
KDTreeSingleIndexAdaptorFlags flags
DistanceType evalMetric(const T *a, const IndexType b_idx, size_t size, DistanceType worst_dist=-1) const
DistanceType accum_dist(const U a, const V b, const size_t) const
_DistanceType DistanceType
L1_Adaptor(const DataSource &_data_source)
_DistanceType DistanceType
DistanceType accum_dist(const U a, const V b, const size_t) const
DistanceType evalMetric(const T *a, const IndexType b_idx, size_t size, DistanceType worst_dist=-1) const
L2_Adaptor(const DataSource &_data_source)
DistanceType evalMetric(const T *a, const IndexType b_idx, size_t size) const
DistanceType accum_dist(const U a, const V b, const size_t) const
L2_Simple_Adaptor(const DataSource &_data_source)
DistanceType second
Distance from sample to query point.
ResultItem(const IndexType index, const DistanceType distance)
IndexType first
Index of the sample in the dataset.
_DistanceType DistanceType
DistanceType evalMetric(const T *a, const IndexType b_idx, size_t size) const
SO2_Adaptor(const DataSource &_data_source)
DistanceType accum_dist(const U a, const V b, const size_t) const
_DistanceType DistanceType
L2_Simple_Adaptor< T, DataSource, DistanceType, IndexType > distance_L2_Simple
DistanceType evalMetric(const T *a, const IndexType b_idx, size_t size) const
SO3_Adaptor(const DataSource &_data_source)
DistanceType accum_dist(const U a, const V b, const size_t idx) const
SearchParameters(float eps_=0, bool sorted_=true)
bool sorted
distance (default: true)
float eps
search for eps-approximate neighbours (default: 0)
std::array< T, DIM > type
L1_Adaptor< T, DataSource, T, IndexType > distance_t
L2_Adaptor< T, DataSource, T, IndexType > distance_t
L2_Simple_Adaptor< T, DataSource, T, IndexType > distance_t
SO2_Adaptor< T, DataSource, T, IndexType > distance_t
SO3_Adaptor< T, DataSource, T, IndexType > distance_t