85#include <unordered_map>
89#define NANOFLANN_VERSION_STRING "1.10.1"
91#define NANOFLANN_VERSION 0x010A01
94#if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64))
107#if defined(__GNUC__) || defined(__clang__)
108#define NANOFLANN_RESTRICT __restrict__
109#elif defined(_MSC_VER)
110#define NANOFLANN_RESTRICT __restrict
112#define NANOFLANN_RESTRICT
116#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
117#define NANOFLANN_NODISCARD [[nodiscard]]
119#define NANOFLANN_NODISCARD
123#if defined(__has_cpp_attribute) && __has_cpp_attribute(fallthrough)
124#define NANOFLANN_FALLTHROUGH [[fallthrough]]
126#define NANOFLANN_FALLTHROUGH
130#ifndef NANOFLANN_NODE_ALIGNMENT
131#define NANOFLANN_NODE_ALIGNMENT 16
143 return static_cast<T
>(3.14159265358979323846);
150template <
typename T,
typename =
int>
160template <
typename T,
typename =
int>
173template <
typename Container>
174inline typename std::enable_if<has_resize<Container>::value,
void>::type
resize(
175 Container& c,
const size_t nElements)
184template <
typename Container>
185inline typename std::enable_if<!has_resize<Container>::value,
void>::type
resize(
186 Container& c,
const size_t nElements)
188 if (nElements != c.size())
throw std::logic_error(
"Attempt to resize a fixed size container.");
194template <
typename Container,
typename T>
195inline typename std::enable_if<has_assign<Container>::value,
void>::type
assign(
196 Container& c,
const size_t nElements,
const T& value)
198 c.assign(nElements, value);
204template <
typename Container,
typename T>
205inline typename std::enable_if<!has_assign<Container>::value,
void>::type
assign(
206 Container& c,
const size_t nElements,
const T& value)
208 for (
size_t i = 0; i < nElements; i++) c[i] = value;
215 template <
typename PairType>
216 bool operator()(
const PairType& p1,
const PairType& p2)
const
218 return p1.second < p2.second;
230template <
typename IndexType =
size_t,
typename DistanceType =
double>
233 ResultItem() =
default;
234 ResultItem(
const IndexType index,
const DistanceType distance) :
first(index),
second(distance)
248template <
typename DistanceType,
typename IndexType,
typename CountType>
249bool addPointToSortedResultSet(
250 DistanceType* dists, IndexType* indices, CountType& count, CountType capacity,
251 DistanceType dist, IndexType index)
254 for (i = count; i > 0; --i)
256#ifdef NANOFLANN_FIRST_MATCH
257 if ((dists[i - 1] > dist) || ((dist == dists[i - 1]) && (indices[i - 1] > index)))
260 if (dists[i - 1] > dist)
265 dists[i] = dists[i - 1];
266 indices[i] = indices[i - 1];
277 if (count < capacity) count++;
286template <
typename _DistanceType,
typename _IndexType =
size_t,
typename _CountType =
size_t>
290 using DistanceType = _DistanceType;
291 using IndexType = _IndexType;
292 using CountType = _CountType;
301 explicit KNNResultSet(CountType capacity_)
302 : indices(
nullptr), dists(
nullptr), capacity(capacity_), count(0)
306 void init(IndexType* indices_, DistanceType* dists_)
313 NANOFLANN_NODISCARD CountType size()
const noexcept {
return count; }
314 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return count == 0; }
315 NANOFLANN_NODISCARD
bool full()
const noexcept {
return count == capacity; }
324 return detail::addPointToSortedResultSet(dists, indices, count, capacity, dist, index);
329 NANOFLANN_NODISCARD DistanceType
worstDist() const noexcept
331 return (count < capacity || !count) ? std::numeric_limits<DistanceType>::max()
342template <
typename _DistanceType,
typename _IndexType =
size_t,
typename _CountType =
size_t>
346 using DistanceType = _DistanceType;
347 using IndexType = _IndexType;
348 using CountType = _CountType;
355 DistanceType maximumSearchDistanceSquared;
358 explicit RKNNResultSet(CountType capacity_, DistanceType maximumSearchDistanceSquared_)
363 maximumSearchDistanceSquared(maximumSearchDistanceSquared_)
367 void init(IndexType* indices_, DistanceType* dists_)
372 if (capacity) dists[capacity - 1] = maximumSearchDistanceSquared;
375 NANOFLANN_NODISCARD CountType size()
const noexcept {
return count; }
376 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return count == 0; }
377 NANOFLANN_NODISCARD
bool full()
const noexcept {
return count == capacity; }
386 return detail::addPointToSortedResultSet(dists, indices, count, capacity, dist, index);
391 NANOFLANN_NODISCARD DistanceType
worstDist() const noexcept
393 return (count < capacity || !count) ? maximumSearchDistanceSquared : dists[count - 1];
405template <
typename _DistanceType,
typename _IndexType =
size_t>
409 using DistanceType = _DistanceType;
410 using IndexType = _IndexType;
413 const DistanceType radius;
415 std::vector<ResultItem<IndexType, DistanceType>>& m_indices_dists;
417 explicit RadiusResultSet(
419 : radius(radius_), m_indices_dists(indices_dists)
424 void init() { clear(); }
425 void clear() { m_indices_dists.clear(); }
427 NANOFLANN_NODISCARD
size_t size()
const noexcept {
return m_indices_dists.size(); }
428 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return m_indices_dists.empty(); }
429 NANOFLANN_NODISCARD
bool full()
const noexcept {
return true; }
438 if (dist < radius) m_indices_dists.emplace_back(index, dist);
442 NANOFLANN_NODISCARD DistanceType worstDist() const noexcept {
return radius; }
450 if (m_indices_dists.empty())
451 throw std::runtime_error(
452 "Cannot invoke RadiusResultSet::worst_item() on "
453 "an empty list of results.");
455 std::max_element(m_indices_dists.begin(), m_indices_dists.end(),
IndexDist_Sorter());
459 void sort() { std::sort(m_indices_dists.begin(), m_indices_dists.end(),
IndexDist_Sorter()); }
467template <
typename _IndexType =
size_t>
471 using IndexType = _IndexType;
473 std::vector<IndexType>& m_indices;
475 explicit BoxResultSet(std::vector<IndexType>& indices) : m_indices(indices)
480 NANOFLANN_NODISCARD
size_t size()
const noexcept {
return m_indices.size(); }
481 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return m_indices.empty(); }
482 NANOFLANN_NODISCARD
bool full()
const noexcept {
return true; }
486 template <
typename DistanceType>
489 m_indices.push_back(index);
493 void sort() { std::sort(m_indices.begin(), m_indices.end()); }
501void save_value(std::ostream& stream,
const T& value)
503 stream.write(
reinterpret_cast<const char*
>(&value),
sizeof(T));
507void save_value(std::ostream& stream,
const std::vector<T>& value)
509 size_t size = value.size();
510 stream.write(
reinterpret_cast<const char*
>(&size),
sizeof(
size_t));
511 stream.write(
reinterpret_cast<const char*
>(value.data()),
sizeof(T) * size);
515void load_value(std::istream& stream, T& value)
517 stream.read(
reinterpret_cast<char*
>(&value),
sizeof(T));
521void load_value(std::istream& stream, std::vector<T>& value)
524 stream.read(
reinterpret_cast<char*
>(&size),
sizeof(
size_t));
526 stream.read(
reinterpret_cast<char*
>(value.data()),
sizeof(T) * size);
547template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
550 using ElementType = T;
551 using DistanceType = _DistanceType;
553 const DataSource& data_source;
555 L1_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
557 inline DistanceType evalMetric(
558 const T* NANOFLANN_RESTRICT a,
const IndexType b_idx,
size_t size)
const
560 DistanceType result = DistanceType();
561 const size_t multof4 = (size >> 2) << 2;
564 for (d = 0; d < multof4; d += 4)
566 const DistanceType diff0 = std::abs(a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0));
567 const DistanceType diff1 = std::abs(a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1));
568 const DistanceType diff2 = std::abs(a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2));
569 const DistanceType diff3 = std::abs(a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3));
571 result += (diff0 + diff1) + (diff2 + diff3);
575 switch (size - multof4)
578 result += std::abs(a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2));
579 NANOFLANN_FALLTHROUGH;
581 result += std::abs(a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1));
582 NANOFLANN_FALLTHROUGH;
584 result += std::abs(a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0));
585 NANOFLANN_FALLTHROUGH;
592 template <
typename U,
typename V>
593 inline DistanceType accum_dist(
const U a,
const V b,
const size_t)
const
595 return std::abs(a - b);
609template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
612 using ElementType = T;
613 using DistanceType = _DistanceType;
615 const DataSource& data_source;
617 L2_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
619 inline DistanceType evalMetric(
620 const T* NANOFLANN_RESTRICT a,
const IndexType b_idx,
size_t size)
const
622 DistanceType result = DistanceType();
623 const size_t multof4 = (size >> 2) << 2;
626 for (d = 0; d < multof4; d += 4)
628 const DistanceType diff0 = a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0);
629 const DistanceType diff1 = a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1);
630 const DistanceType diff2 = a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2);
631 const DistanceType diff3 = a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3);
633 result += (diff0 * diff0 + diff1 * diff1) + (diff2 * diff2 + diff3 * diff3);
638 switch (size - multof4)
641 diff = a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2);
642 result += diff * diff;
643 NANOFLANN_FALLTHROUGH;
645 diff = a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1);
646 result += diff * diff;
647 NANOFLANN_FALLTHROUGH;
649 diff = a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0);
650 result += diff * diff;
651 NANOFLANN_FALLTHROUGH;
658 template <
typename U,
typename V>
659 inline DistanceType accum_dist(
const U a,
const V b,
const size_t)
const
676template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
677struct L2_Simple_Adaptor
679 using ElementType = T;
680 using DistanceType = _DistanceType;
682 const DataSource& data_source;
684 L2_Simple_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
686 inline DistanceType evalMetric(
const T* a,
const IndexType b_idx,
size_t size)
const
688 DistanceType result = DistanceType();
689 for (
size_t i = 0; i < size; ++i)
691 const DistanceType diff = a[i] - data_source.kdtree_get_pt(b_idx, i);
692 result += diff * diff;
697 template <
typename U,
typename V>
698 inline DistanceType accum_dist(
const U a,
const V b,
const size_t)
const
715template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
718 using ElementType = T;
719 using DistanceType = _DistanceType;
721 const DataSource& data_source;
723 SO2_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
725 inline DistanceType evalMetric(
const T* a,
const IndexType b_idx,
size_t size)
const
727 return accum_dist(a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1), size - 1);
735 template <
typename U,
typename V>
736 inline DistanceType
accum_dist(
const U a,
const V b,
const size_t)
const
738 DistanceType diff =
static_cast<DistanceType
>(b) -
static_cast<DistanceType
>(a);
744 return diff < DistanceType(0) ? -diff : diff;
758template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
761 using ElementType = T;
762 using DistanceType = _DistanceType;
766 SO3_Adaptor(
const DataSource& _data_source) : distance_L2_Simple(_data_source) {}
768 inline DistanceType evalMetric(
const T* a,
const IndexType b_idx,
size_t size)
const
770 return distance_L2_Simple.evalMetric(a, b_idx, size);
773 template <
typename U,
typename V>
774 inline DistanceType accum_dist(
const U a,
const V b,
const size_t idx)
const
776 return distance_L2_Simple.accum_dist(a, b, idx);
783 template <
class T,
class DataSource,
typename IndexType =
size_t>
793 template <
class T,
class DataSource,
typename IndexType =
size_t>
803 template <
class T,
class DataSource,
typename IndexType =
size_t>
812 template <
class T,
class DataSource,
typename IndexType =
size_t>
821 template <
class T,
class DataSource,
typename IndexType =
size_t>
833enum class KDTreeSingleIndexAdaptorFlags
836 SkipInitialBuildIndex = 1
839inline std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type operator&(
840 KDTreeSingleIndexAdaptorFlags lhs, KDTreeSingleIndexAdaptorFlags rhs)
842 using underlying =
typename std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type;
843 return static_cast<underlying
>(lhs) &
static_cast<underlying
>(rhs);
848inline bool has_flag(KDTreeSingleIndexAdaptorFlags f, KDTreeSingleIndexAdaptorFlags flag)
850 return (f & flag) != 0;
854struct KDTreeSingleIndexAdaptorParams
856 KDTreeSingleIndexAdaptorParams(
857 size_t _leaf_max_size = 10,
858 KDTreeSingleIndexAdaptorFlags _flags = KDTreeSingleIndexAdaptorFlags::None,
859 unsigned int _n_thread_build = 1)
860 : leaf_max_size(_leaf_max_size), flags(_flags), n_thread_build(_n_thread_build)
864 size_t leaf_max_size;
865 KDTreeSingleIndexAdaptorFlags flags;
866 unsigned int n_thread_build;
870struct SearchParameters
872 SearchParameters(
float eps_ = 0,
bool sorted_ =
true) :
eps(eps_),
sorted(sorted_) {}
899 static constexpr size_t WORDSIZE = 16;
900 static constexpr size_t BLOCKSIZE = 8192;
911 void* base_ =
nullptr;
912 void* loc_ =
nullptr;
924 Size wastedMemory = 0;
939 while (base_ !=
nullptr)
942 void* prev = *(
static_cast<void**
>(base_));
959 const Size size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
964 if (size > remaining_)
966 wastedMemory += remaining_;
969 const Size blocksize = size > BLOCKSIZE ? size + WORDSIZE : BLOCKSIZE + WORDSIZE;
972 void* m = ::malloc(blocksize);
975 throw std::bad_alloc();
979 static_cast<void**
>(m)[0] = base_;
982 remaining_ = blocksize - WORDSIZE;
983 loc_ =
static_cast<char*
>(m) + WORDSIZE;
986 loc_ =
static_cast<char*
>(loc_) + size;
1001 template <
typename T>
1004 T* mem =
static_cast<T*
>(this->
allocateBytes(
sizeof(T) * count));
1016template <
int32_t DIM,
typename T>
1019 using type = std::array<T, DIM>;
1022template <
typename T>
1025 using type = std::vector<T>;
1045 class Derived,
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
1046 typename index_t = uint32_t>
1054 obj.pool_.free_all();
1055 obj.root_node_ =
nullptr;
1056 obj.size_at_index_build_ = 0;
1059 using ElementType =
typename Distance::ElementType;
1060 using DistanceType =
typename Distance::DistanceType;
1061 using IndexType = index_t;
1068 using Offset =
typename decltype(
vAcc_)::size_type;
1069 using Size =
typename decltype(
vAcc_)::size_type;
1070 using Dimension = int32_t;
1084 struct alignas(NANOFLANN_NODE_ALIGNMENT)
Node
1098 DistanceType divlow, divhigh;
1106 using NodePtr =
Node*;
1107 using NodeConstPtr =
const Node*;
1111 ElementType low, high;
1114 NodePtr root_node_ =
nullptr;
1116 Size leaf_max_size_ = 0;
1147 NANOFLANN_NODISCARD Size
size(
const Derived& obj)
const noexcept {
return obj.size_; }
1153 NANOFLANN_NODISCARD Size
veclen(
const Derived& obj)
const noexcept
1155#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
1156 if constexpr (DIM > 0)
1165 return DIM > 0 ? DIM : obj.dim_;
1170 ElementType
dataset_get(
const Derived& obj, IndexType element, Dimension component)
const
1172 return obj.dataset_.kdtree_get_pt(element, component);
1181 return obj.pool_.usedMemory + obj.pool_.wastedMemory +
1182 obj.dataset_.kdtree_get_point_count() *
1190 const Derived& obj, Offset ind, Size count, Dimension element, ElementType& min_elem,
1191 ElementType& max_elem)
const
1194 max_elem = min_elem;
1195 for (Offset i = 1; i < count; ++i)
1198 if (val < min_elem) min_elem = val;
1199 if (val > max_elem) max_elem = val;
1206 NANOFLANN_NODISCARD
bool isActive(IndexType )
const {
return true; }
1213 Derived& obj =
static_cast<Derived&
>(*this);
1214 const Dimension dims =
static_cast<Dimension
>(
veclen(obj));
1216 if (obj.dataset_.kdtree_get_bbox(bbox))
return;
1218 throw std::runtime_error(
1219 "[nanoflann] computeBoundingBox() called but "
1220 "no data points found.");
1221 for (Dimension i = 0; i < dims; ++i)
1223 for (Offset k = 1; k <
size_; ++k)
1224 for (Dimension i = 0; i < dims; ++i)
1227 if (val < bbox[i].low) bbox[i].low = val;
1228 if (val > bbox[i].high) bbox[i].high = val;
1240 template <
class RESULTSET>
1242 RESULTSET& result_set,
const ElementType* vec,
const NodePtr node, DistanceType mindist,
1245 const Derived& obj =
static_cast<const Derived&
>(*this);
1252 const Size dim =
veclen(obj);
1253 for (Offset i = node->
node_type.lr.left; i < node->node_type.lr.right; ++i)
1255 const IndexType accessor =
vAcc_[i];
1256 if (!obj.isActive(accessor))
continue;
1257 DistanceType dist = obj.distance_.evalMetric(vec, accessor, dim);
1258 if (dist < result_set.worstDist())
1260 if (!result_set.addPoint(
1261 static_cast<typename RESULTSET::DistanceType
>(dist),
1262 static_cast<typename RESULTSET::IndexType
>(accessor)))
1270 Dimension idx = node->
node_type.sub.divfeat;
1271 ElementType val = vec[idx];
1272 DistanceType diff1 = val - node->
node_type.sub.divlow;
1273 DistanceType diff2 = val - node->
node_type.sub.divhigh;
1277 DistanceType cut_dist;
1278 if ((diff1 + diff2) < 0)
1280 bestChild = node->
child1;
1281 otherChild = node->child2;
1282 cut_dist = obj.distance_.accum_dist(val, node->
node_type.sub.divhigh, idx);
1286 bestChild = node->child2;
1287 otherChild = node->
child1;
1288 cut_dist = obj.distance_.accum_dist(val, node->
node_type.sub.divlow, idx);
1292 if (!
searchLevel(result_set, vec, bestChild, mindist, dists, epsError))
return false;
1294 DistanceType dst = dists[idx];
1295 mindist = mindist + cut_dist - dst;
1296 dists[idx] = cut_dist;
1297 if (mindist * epsError <= result_set.worstDist())
1299 if (!
searchLevel(result_set, vec, otherChild, mindist, dists, epsError))
return false;
1325 Derived& obj, NodePtr node,
const Offset left,
const Offset right,
BoundingBox& bbox,
1326 Offset& idx, Dimension& cutfeat, DistanceType& cutval)
1328 const Dimension dims =
static_cast<Dimension
>(
veclen(obj));
1331 if ((right - left) <=
static_cast<Offset
>(obj.leaf_max_size_))
1333 node->
child1 = node->child2 =
nullptr;
1338 for (Dimension i = 0; i < dims; ++i)
1340 bbox[i].low =
dataset_get(obj, obj.vAcc_[left], i);
1341 bbox[i].high =
dataset_get(obj, obj.vAcc_[left], i);
1343 for (Offset k = left + 1; k < right; ++k)
1345 for (Dimension i = 0; i < dims; ++i)
1347 const auto val =
dataset_get(obj, obj.vAcc_[k], i);
1348 if (bbox[i].low > val) bbox[i].low = val;
1349 if (bbox[i].high < val) bbox[i].high = val;
1356 middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox);
1367 Derived& obj, NodePtr node,
const Dimension cutfeat,
const BoundingBox& left_bbox,
1370 node->
node_type.sub.divlow = left_bbox[cutfeat].high;
1371 node->
node_type.sub.divhigh = right_bbox[cutfeat].low;
1373 const Dimension dims =
static_cast<Dimension
>(
veclen(obj));
1374 for (Dimension i = 0; i < dims; ++i)
1376 bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
1377 bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
1381 NodePtr divideTree(Derived& obj,
const Offset left,
const Offset right, BoundingBox& bbox)
1383 assert(
static_cast<Size
>(obj.vAcc_.at(left)) < obj.dataset_.kdtree_get_point_count());
1385 NodePtr node = obj.pool_.template allocate<Node>();
1388 DistanceType cutval;
1389 if (makeNode(obj, node, left, right, bbox, idx, cutfeat, cutval))
return node;
1392 BoundingBox left_bbox(bbox);
1393 left_bbox[cutfeat].high = cutval;
1394 node->child1 = this->divideTree(obj, left, left + idx, left_bbox);
1397 BoundingBox right_bbox(bbox);
1398 right_bbox[cutfeat].low = cutval;
1399 node->child2 = this->divideTree(obj, left + idx, right, right_bbox);
1401 finalizeSplitNode(obj, node, cutfeat, left_bbox, right_bbox, bbox);
1419 Derived& obj,
const Offset left,
const Offset right,
BoundingBox& bbox,
1420 std::atomic<unsigned int>& thread_count, std::mutex& mutex)
1422 std::unique_lock<std::mutex> lock(mutex);
1423 NodePtr node = obj.pool_.template allocate<Node>();
1428 DistanceType cutval;
1429 if (
makeNode(obj, node, left, right, bbox, idx, cutfeat, cutval))
return node;
1431 std::future<NodePtr> right_future;
1436 right_bbox[cutfeat].low = cutval;
1441 right_future = std::async(
1443 left + idx, right, std::ref(right_bbox), std::ref(thread_count), std::ref(mutex));
1453 left_bbox[cutfeat].high = cutval;
1457 if (right_future.valid())
1461 node->child2 = right_future.get();
1478 const Derived& obj,
const Offset ind,
const Size count, Offset& index, Dimension& cutfeat,
1479 DistanceType& cutval,
const BoundingBox& bbox)
1481 const Dimension dims =
static_cast<Dimension
>(veclen(obj));
1482 const auto EPS =
static_cast<DistanceType
>(0.00001);
1485 ElementType max_span = bbox[0].high - bbox[0].low;
1486 for (Dimension i = 1; i < dims; ++i)
1488 ElementType span = bbox[i].high - bbox[i].low;
1489 if (span > max_span) max_span = span;
1495 ElementType max_spread = -1;
1496 ElementType min_elem = 0, max_elem = 0;
1497 const ElementType threshold = (1 - EPS) * max_span;
1499 for (Dimension dim = 0; dim < dims; ++dim)
1501 if (bbox[dim].high - bbox[dim].low < threshold)
continue;
1503 ElementType local_min = dataset_get(obj, vAcc_[ind], dim);
1504 ElementType local_max = local_min;
1507 constexpr size_t UNROLL = 4;
1509 for (; k + UNROLL <= count; k += UNROLL)
1511 ElementType v0 = dataset_get(obj, vAcc_[ind + k], dim);
1512 ElementType v1 = dataset_get(obj, vAcc_[ind + k + 1], dim);
1513 ElementType v2 = dataset_get(obj, vAcc_[ind + k + 2], dim);
1514 ElementType v3 = dataset_get(obj, vAcc_[ind + k + 3], dim);
1516 local_min = std::min({local_min, v0, v1, v2, v3});
1517 local_max = std::max({local_max, v0, v1, v2, v3});
1521 for (; k < count; ++k)
1523 ElementType val = dataset_get(obj, vAcc_[ind + k], dim);
1524 local_min = std::min(local_min, val);
1525 local_max = std::max(local_max, val);
1528 ElementType spread = local_max - local_min;
1529 if (spread > max_spread)
1532 max_spread = spread;
1533 min_elem = local_min;
1534 max_elem = local_max;
1539 DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2;
1540 if (split_val < min_elem) split_val = min_elem;
1541 if (split_val > max_elem) split_val = max_elem;
1547 planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2);
1549 index = (lim1 > count / 2) ? lim1 : (lim2 < count / 2) ? lim2 : count / 2;
1562 const Derived& obj,
const Offset ind,
const Size count,
const Dimension cutfeat,
1563 const DistanceType& cutval, Offset& lim1, Offset& lim2)
1568 Offset right = count - 1;
1570 while (mid <= right)
1576 std::swap(
vAcc_[ind + left],
vAcc_[ind + mid]);
1580 else if (val > cutval)
1582 std::swap(
vAcc_[ind + mid],
vAcc_[ind + right]);
1595 DistanceType computeInitialDistances(
1596 const Derived& obj,
const ElementType* vec, distance_vector_t& dists)
const
1599 DistanceType dist = DistanceType();
1601 const Dimension dims =
static_cast<Dimension
>(veclen(obj));
1602 for (Dimension i = 0; i < dims; ++i)
1604 if (vec[i] < obj.root_bbox_[i].low)
1606 dists[i] = obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].low, i);
1609 else if (vec[i] > obj.root_bbox_[i].high)
1611 dists[i] = obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].high, i);
1618 static void save_tree(
const Derived& obj, std::ostream& stream,
const NodeConstPtr tree)
1620 save_value(stream, *tree);
1621 if (tree->child1 !=
nullptr)
1623 save_tree(obj, stream, tree->child1);
1625 if (tree->child2 !=
nullptr)
1627 save_tree(obj, stream, tree->child2);
1631 static void load_tree(Derived& obj, std::istream& stream, NodePtr& tree)
1633 tree = obj.pool_.template allocate<Node>();
1634 load_value(stream, *tree);
1635 if (tree->child1 !=
nullptr)
1637 load_tree(obj, stream, tree->child1);
1639 if (tree->child2 !=
nullptr)
1641 load_tree(obj, stream, tree->child2);
1667 void saveIndex(
const Derived& obj, std::ostream& stream)
const
1675 const uint32_t hdr_version =
static_cast<uint32_t
>(NANOFLANN_VERSION);
1676 const uint8_t hdr_sz_st =
static_cast<uint8_t
>(
sizeof(size_t));
1677 const uint8_t hdr_sz_idx =
static_cast<uint8_t
>(
sizeof(IndexType));
1678 const uint8_t hdr_sz_elem =
static_cast<uint8_t
>(
sizeof(ElementType));
1679 const uint8_t hdr_sz_dist =
static_cast<uint8_t
>(
sizeof(DistanceType));
1680 save_value(stream, hdr_magic);
1681 save_value(stream, hdr_version);
1682 save_value(stream, hdr_sz_st);
1683 save_value(stream, hdr_sz_idx);
1684 save_value(stream, hdr_sz_elem);
1685 save_value(stream, hdr_sz_dist);
1687 save_value(stream, obj.size_);
1688 save_value(stream, obj.dim_);
1689 save_value(stream, obj.root_bbox_);
1690 save_value(stream, obj.leaf_max_size_);
1691 save_value(stream, obj.vAcc_);
1694 save_tree(obj, stream, obj.root_node_);
1717 load_value(stream, magic);
1720 throw std::runtime_error(
1721 "nanoflann loadIndex: invalid file (wrong magic number). "
1722 "The stream was not written by nanoflann saveIndex().");
1725 uint32_t file_version = 0;
1726 load_value(stream, file_version);
1727 if (file_version !=
static_cast<uint32_t
>(NANOFLANN_VERSION))
1732 "nanoflann loadIndex: version mismatch "
1733 "(file=0x%03X, library=0x%03X). Rebuild the index.",
1734 file_version,
static_cast<unsigned>(NANOFLANN_VERSION));
1735 throw std::runtime_error(msg);
1738 uint8_t sz_size_t = 0;
1740 uint8_t sz_elem = 0;
1741 uint8_t sz_dist = 0;
1742 load_value(stream, sz_size_t);
1743 load_value(stream, sz_idx);
1744 load_value(stream, sz_elem);
1745 load_value(stream, sz_dist);
1746 if (sz_size_t !=
static_cast<uint8_t
>(
sizeof(
size_t)) ||
1747 sz_idx !=
static_cast<uint8_t
>(
sizeof(IndexType)) ||
1748 sz_elem !=
static_cast<uint8_t
>(
sizeof(ElementType)) ||
1749 sz_dist !=
static_cast<uint8_t
>(
sizeof(DistanceType)))
1751 throw std::runtime_error(
1752 "nanoflann loadIndex: type-size mismatch between saved index and "
1753 "current template instantiation (sizeof size_t / IndexType / "
1754 "ElementType / DistanceType differ). Rebuild the index.");
1757 load_value(stream, obj.size_);
1758 load_value(stream, obj.dim_);
1759 load_value(stream, obj.root_bbox_);
1760 load_value(stream, obj.leaf_max_size_);
1761 load_value(stream, obj.vAcc_);
1765 load_tree(obj, stream, obj.root_node_);
1770 throw std::runtime_error(
1771 "nanoflann loadIndex: unexpected end of stream or read error.");
1829template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename index_t = uint32_t>
1832 KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, index_t>, Distance,
1833 DatasetAdaptor, DIM, index_t>
1849 DatasetAdaptor, DIM, index_t>;
1851 using Offset =
typename Base::Offset;
1852 using Size =
typename Base::Size;
1853 using Dimension =
typename Base::Dimension;
1855 using ElementType =
typename Base::ElementType;
1856 using DistanceType =
typename Base::DistanceType;
1857 using IndexType =
typename Base::IndexType;
1859 using Node =
typename Base::Node;
1860 using NodePtr = Node*;
1862 using Interval =
typename Base::Interval;
1892 template <
class... Args>
1894 const Dimension dimensionality,
const DatasetAdaptor& inputData,
1897 indexParams(params),
1898 distance_(inputData, std::forward<Args>(args)...)
1900 init(dimensionality, params);
1904 const Dimension dimensionality,
const DatasetAdaptor& inputData,
1906 : dataset_(inputData), indexParams(params), distance_(inputData)
1908 init(dimensionality, params);
1912 void init(
const Dimension dimensionality,
const KDTreeSingleIndexAdaptorParams& params)
1914 Base::size_ = dataset_.kdtree_get_point_count();
1915 Base::size_at_index_build_ = Base::size_;
1916 Base::dim_ = dimensionality;
1917 if (DIM > 0) Base::dim_ = DIM;
1918 Base::leaf_max_size_ = params.leaf_max_size;
1919 if (params.n_thread_build > 0)
1921 Base::n_thread_build_ = params.n_thread_build;
1925 Base::n_thread_build_ = std::max(std::thread::hardware_concurrency(), 1u);
1928 if (!
has_flag(params.flags, KDTreeSingleIndexAdaptorFlags::SkipInitialBuildIndex))
1941 Base::size_ =
dataset_.kdtree_get_point_count();
1942 Base::size_at_index_build_ = Base::size_;
1945 Base::size_at_index_build_ = Base::size_;
1946 if (Base::size_ == 0)
return;
1949 if (Base::n_thread_build_ == 1)
1951 Base::root_node_ = this->divideTree(*
this, 0, Base::size_, Base::root_bbox_);
1955#ifndef NANOFLANN_NO_THREADS
1956 std::atomic<unsigned int> thread_count(0u);
1959 *
this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
1961 throw std::runtime_error(
"Multithreading is disabled");
1985 template <
typename RESULTSET>
1987 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
1990 if (this->size(*
this) == 0)
return false;
1991 if (!Base::root_node_)
1992 throw std::runtime_error(
1993 "[nanoflann] findNeighbors() called before building the "
1995 DistanceType epsError = 1 +
static_cast<DistanceType
>(searchParams.eps);
1998 distance_vector_t dists;
2000 auto zero =
static_cast<typename RESULTSET::DistanceType
>(0);
2001 assign(dists, this->veclen(*
this), zero);
2002 DistanceType dist = this->computeInitialDistances(*
this, vec, dists);
2003 this->searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
2005 if (searchParams.sorted) result.sort();
2007 return result.full();
2025 template <
typename RESULTSET>
2028 if (this->size(*
this) == 0)
return 0;
2029 if (!Base::root_node_)
2030 throw std::runtime_error(
2031 "[nanoflann] findWithinBox() called before building the "
2034 std::stack<NodePtr> stack;
2035 stack.push(Base::root_node_);
2037 while (!stack.empty())
2039 const NodePtr node = stack.top();
2045 for (Offset i = node->node_type.lr.left; i < node->node_type.lr.right; ++i)
2047 if (contains(bbox, Base::vAcc_[i]))
2049 if (!result.addPoint(0, Base::vAcc_[i]))
2053 return result.size();
2060 const Dimension idx = node->node_type.sub.divfeat;
2061 const auto low_bound = node->node_type.sub.divlow;
2062 const auto high_bound = node->node_type.sub.divhigh;
2064 if (bbox[idx].low <= low_bound) stack.push(node->child1);
2065 if (bbox[idx].high >= high_bound) stack.push(node->child2);
2069 return result.size();
2088 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
2089 DistanceType* out_distances)
const
2092 resultSet.init(out_indices, out_distances);
2094 return resultSet.size();
2117 const ElementType* query_point,
const DistanceType& radius,
2122 const Size nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);
2131 template <
class SEARCH_CALLBACK>
2133 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
2136 findNeighbors(resultSet, query_point, searchParams);
2137 return resultSet.size();
2156 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
2157 DistanceType* out_distances,
const DistanceType& radius)
const
2160 resultSet.init(out_indices, out_distances);
2162 return resultSet.size();
2173 Base::size_ =
dataset_.kdtree_get_point_count();
2174 if (Base::vAcc_.
size() != Base::size_) Base::vAcc_.resize(Base::size_);
2175 for (IndexType i = 0; i < static_cast<IndexType>(Base::size_); i++) Base::vAcc_[i] = i;
2178 bool contains(
const BoundingBox& bbox, IndexType idx)
const
2180 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
2181 for (Dimension i = 0; i < dims; ++i)
2183 const auto point = this->dataset_.kdtree_get_pt(idx, i);
2184 if (point < bbox[i].low || point > bbox[i].high)
return false;
2195 void saveIndex(std::ostream& stream)
const { Base::saveIndex(*
this, stream); }
2202 void loadIndex(std::istream& stream) { Base::loadIndex(*
this, stream); }
2243template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
2246 KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>, Distance,
2247 DatasetAdaptor, DIM, IndexType>
2257 std::vector<int>& treeIndex_;
2263 Distance, DatasetAdaptor, DIM, IndexType>;
2265 using ElementType =
typename Base::ElementType;
2266 using DistanceType =
typename Base::DistanceType;
2268 using Offset =
typename Base::Offset;
2269 using Size =
typename Base::Size;
2270 using Dimension =
typename Base::Dimension;
2272 using Node =
typename Base::Node;
2273 using NodePtr = Node*;
2275 using Interval =
typename Base::Interval;
2285 NANOFLANN_NODISCARD
bool isActive(IndexType idx)
const {
return treeIndex_[idx] != -1; }
2303 const Dimension dimensionality,
const DatasetAdaptor& inputData,
2304 std::vector<int>& treeIndex,
2306 :
dataset_(inputData), index_params_(params), treeIndex_(treeIndex), distance_(inputData)
2309 Base::size_at_index_build_ = 0;
2310 for (
auto& v : Base::root_bbox_) v = {};
2311 Base::dim_ = dimensionality;
2312 if (DIM > 0) Base::dim_ = DIM;
2313 Base::leaf_max_size_ = params.leaf_max_size;
2314 if (params.n_thread_build > 0)
2316 Base::n_thread_build_ = params.n_thread_build;
2320 Base::n_thread_build_ = std::max(std::thread::hardware_concurrency(), 1u);
2330 if (
this == &rhs)
return *
this;
2332 std::swap(Base::vAcc_, tmp.Base::vAcc_);
2333 std::swap(Base::leaf_max_size_, tmp.Base::leaf_max_size_);
2334 std::swap(index_params_, tmp.index_params_);
2336 std::swap(Base::size_, tmp.Base::size_);
2337 std::swap(Base::size_at_index_build_, tmp.Base::size_at_index_build_);
2338 std::swap(Base::root_node_, tmp.Base::root_node_);
2339 std::swap(Base::root_bbox_, tmp.Base::root_bbox_);
2340 std::swap(Base::pool_, tmp.Base::pool_);
2349 Base::size_ = Base::vAcc_.size();
2351 Base::size_at_index_build_ = Base::size_;
2352 if (Base::size_ == 0)
return;
2355 if (Base::n_thread_build_ == 1)
2357 Base::root_node_ = this->divideTree(*
this, 0, Base::size_, Base::root_bbox_);
2361#ifndef NANOFLANN_NO_THREADS
2362 std::atomic<unsigned int> thread_count(0u);
2365 *
this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
2367 throw std::runtime_error(
"Multithreading is disabled");
2395 template <
typename RESULTSET>
2397 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
2400 if (this->size(*
this) == 0)
return false;
2401 if (!Base::root_node_)
return false;
2402 DistanceType epsError = 1 +
static_cast<DistanceType
>(searchParams.eps);
2405 distance_vector_t dists;
2407 assign(dists, this->veclen(*
this),
static_cast<typename distance_vector_t::value_type
>(0));
2408 DistanceType dist = this->computeInitialDistances(*
this, vec, dists);
2409 this->searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
2411 if (searchParams.sorted) result.sort();
2413 return result.full();
2431 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
2432 DistanceType* out_distances,
const SearchParameters& searchParams = {})
const
2435 resultSet.init(out_indices, out_distances);
2436 findNeighbors(resultSet, query_point, searchParams);
2437 return resultSet.size();
2460 const ElementType* query_point,
const DistanceType& radius,
2465 const Size nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);
2474 template <
class SEARCH_CALLBACK>
2476 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
2479 findNeighbors(resultSet, query_point, searchParams);
2480 return resultSet.size();
2492 void saveIndex(std::ostream& stream) { Base::saveIndex(*
this, stream); }
2499 void loadIndex(std::istream& stream) { Base::loadIndex(*
this, stream); }
2516template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
2520 using ElementType =
typename Distance::ElementType;
2521 using DistanceType =
typename Distance::DistanceType;
2523 using Offset =
typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Offset;
2524 using Size =
typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Size;
2526 typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Dimension;
2529 Size leaf_max_size_;
2550 using index_container_t =
2552 std::vector<index_container_t> index_;
2561 int First0Bit(Size num)
2575 using my_kd_tree_t =
2576 KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>;
2577 std::vector<my_kd_tree_t> index(
2578 treeCount_, my_kd_tree_t(dim_ , dataset_, treeIndex_, index_params_));
2601 const int dimensionality,
const DatasetAdaptor& inputData,
2603 const size_t maximumPointCount = 1000000000U)
2604 :
dataset_(inputData), index_params_(params), distance_(inputData)
2606 treeCount_ =
static_cast<size_t>(std::log2(maximumPointCount)) + 1;
2608 dim_ = dimensionality;
2610 if (DIM > 0)
dim_ = DIM;
2611 leaf_max_size_ = params.leaf_max_size;
2613 const size_t num_initial_points =
dataset_.kdtree_get_point_count();
2614 if (num_initial_points > 0)
2616 addPoints(0,
static_cast<IndexType
>(num_initial_points - 1));
2628 for (IndexType idx = start; idx <= end; idx++)
2643 const int pos = First0Bit(pointCount_);
2644 maxIndex = std::max(pos, maxIndex);
2645 if (
treeIndex_.size() <=
static_cast<size_t>(pointCount_))
2646 treeIndex_.resize(
static_cast<size_t>(pointCount_) + 1);
2649 for (
int i = 0; i < pos; i++)
2651 for (
size_t j = 0; j < index_[i].vAcc_.size(); j++)
2653 const IndexType e = index_[i].
vAcc_[j];
2654 index_[pos].vAcc_.push_back(e);
2660 index_[i].vAcc_.clear();
2662 index_[pos].vAcc_.push_back(idx);
2666 for (
int i = 0; i <= maxIndex; ++i)
2668 index_[i].freeIndex(index_[i]);
2669 if (!index_[i].vAcc_.empty()) index_[i].buildIndex();
2676 if (idx >= pointCount_)
return;
2700 template <
typename RESULTSET>
2702 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
2704 for (
size_t i = 0; i < treeCount_; i++)
2706 index_[i].findNeighbors(result, &vec[0], searchParams);
2708 return result.full();
2724struct KDTreeIncrementalIndexParams
2726 KDTreeIncrementalIndexParams(
float alpha_balance_ = 0.75f,
float alpha_deleted_ = 0.5f)
2727 : alpha_balance(alpha_balance_), alpha_deleted(alpha_deleted_)
2731 float alpha_balance;
2732 float alpha_deleted;
2769template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
2772 KDTreeSingleIndexIncrementalAdaptor<Distance, DatasetAdaptor, DIM, IndexType>, Distance,
2773 DatasetAdaptor, DIM, IndexType>
2778 DatasetAdaptor, DIM, IndexType>;
2780 using ElementType =
typename Base::ElementType;
2781 using DistanceType =
typename Base::DistanceType;
2783 using Offset =
typename Base::Offset;
2784 using Size =
typename Base::Size;
2785 using Dimension =
typename Base::Dimension;
2787 using Interval =
typename Base::Interval;
2788 using BoundingBox =
typename Base::BoundingBox;
2789 using distance_vector_t =
typename Base::distance_vector_t;
2814 typename array_or_vector<DIM, ElementType>::type pcoord;
2821#if defined(NANOFLANN_INCREMENTAL_NO_COORD_CACHE)
2828 INode* iroot_ =
nullptr;
2829 INode* freeList_ =
nullptr;
2831 Size liveCount_ = 0;
2832 Size totalCount_ = 0;
2834 float alphaBal_ = 0.75f;
2835 float alphaDel_ = 0.5f;
2837 static constexpr Size kMinBalanceRebuild = 4;
2840 static constexpr double kBulkInsertFraction = 0.5;
2843 INode* pendingRebuild_ =
nullptr;
2849 bool inlineRebuild_ =
true;
2852 std::vector<INode*> nodeOfPoint_;
2855 std::vector<IndexType> buildBuf_;
2858 bool collectRemoved_ =
false;
2859 std::vector<IndexType> removedSink_;
2871 const Dimension dimensionality,
const DatasetAdaptor& inputData,
2873 : dataset_(inputData), distance_(inputData)
2875 Base::dim_ = dimensionality;
2876 if (DIM > 0) Base::dim_ = DIM;
2877 alphaBal_ = params.alpha_balance;
2878 alphaDel_ = params.alpha_deleted;
2879 resize(Base::root_bbox_,
static_cast<Dimension
>(this->veclen(*
this)));
2910 if (end < start)
return;
2912 const Size batch =
static_cast<Size
>(end - start) + 1;
2914 static_cast<double>(batch) >= kBulkInsertFraction *
static_cast<double>(liveCount_))
2917 if (iroot_) collectLiveAndFree(iroot_, buildBuf_);
2918 for (IndexType idx = start; idx <= end; ++idx) buildBuf_.push_back(idx);
2919 iroot_ = buildBalanced(buildBuf_, 0, buildBuf_.size(), 0,
nullptr);
2920 liveCount_ = buildBuf_.size();
2921 totalCount_ = liveCount_;
2925 for (IndexType idx = start; idx <= end; ++idx) insertOne(idx);
2933 if (idx >= nodeOfPoint_.size())
return;
2934 INode* n = nodeOfPoint_[idx];
2935 if (!n || n->deleted)
return;
2938 for (INode* p = n->parent; p; p = p->parent)
2939 if (p->treeDeleted)
return;
2942 for (INode* p = n; p; p = p->parent) ++p->invalid_count;
2944 maybeRebuildForDeletion();
2951 if (iroot_) removeBoxRec(iroot_, box);
2952 maybeRebuildForDeletion();
2960 if (iroot_) removeOutsideBoxRec(iroot_, keep);
2961 maybeRebuildForDeletion();
2969 collectRemoved_ = enable;
2970 if (!enable) std::vector<IndexType>().swap(removedSink_);
2977 std::vector<IndexType> out;
2978 out.swap(removedSink_);
3000 return idx < nodeOfPoint_.size() && nodeOfPoint_[idx] !=
nullptr;
3010 collectLiveAndFree(iroot_, buildBuf_);
3013 IndexType maxIdx = 0;
3014 for (IndexType v : idxs) maxIdx = std::max(maxIdx, v);
3015 if (!idxs.empty()) ensureNodeMap(maxIdx);
3016 buildBuf_.assign(idxs.begin(), idxs.end());
3017 iroot_ = buildBalanced(buildBuf_, 0, buildBuf_.size(), 0,
nullptr);
3018 liveCount_ = buildBuf_.size();
3019 totalCount_ = liveCount_;
3029 NANOFLANN_NODISCARD Size
size() const noexcept {
return liveCount_; }
3030 NANOFLANN_NODISCARD
bool empty() const noexcept {
return liveCount_ == 0; }
3033 NANOFLANN_NODISCARD Size
physicalSize() const noexcept {
return totalCount_; }
3038 return Base::pool_.usedMemory + Base::pool_.wastedMemory +
3039 nodeOfPoint_.capacity() *
sizeof(INode*);
3045 NANOFLANN_NODISCARD BoundingBox
boundingBox()
const {
return Base::root_bbox_; }
3051 nodeOfPoint_.reserve(n);
3052 buildBuf_.reserve(n);
3061 template <
typename RESULTSET>
3063 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
3066 if (!iroot_ || liveCount_ == 0)
return false;
3067 const DistanceType epsError = 1 +
static_cast<DistanceType
>(searchParams.eps);
3069 distance_vector_t dists;
3070 assign(dists, this->veclen(*
this),
static_cast<typename distance_vector_t::value_type
>(0));
3071 const DistanceType dist = this->computeInitialDistances(*
this, vec, dists);
3072 searchLevelInc(result, vec, iroot_, dist, dists, epsError, this->veclen(*
this));
3073 if (searchParams.sorted) result.sort();
3074 return result.full();
3079 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
3080 DistanceType* out_distances,
const SearchParameters& searchParams = {})
const
3083 resultSet.init(out_indices, out_distances);
3084 findNeighbors(resultSet, query_point, searchParams);
3085 return resultSet.size();
3090 const ElementType* query_point,
const DistanceType& radius,
3095 findNeighbors(resultSet, query_point, searchParams);
3096 return resultSet.size();
3100 template <
class SEARCH_CALLBACK>
3102 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
3105 findNeighbors(resultSet, query_point, searchParams);
3106 return resultSet.size();
3111 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
3112 DistanceType* out_distances,
const DistanceType& radius)
const
3115 resultSet.init(out_indices, out_distances);
3117 return resultSet.size();
3121 template <
typename RESULTSET>
3122 NANOFLANN_NODISCARD Size
findWithinBox(RESULTSET& result,
const BoundingBox& bbox)
const
3124 if (iroot_) findWithinBoxRec(result, iroot_, bbox);
3125 return result.size();
3138 INode* n = freeList_;
3139 freeList_ = n->child1;
3142 INode* n = Base::pool_.template allocate<INode>();
3144 ::new (
static_cast<void*
>(n)) INode();
3145 resize(n->box,
static_cast<Dimension
>(this->veclen(*
this)));
3146 if (kCacheCoords) resize(n->pcoord,
static_cast<Dimension
>(this->veclen(*
this)));
3151 void cacheCoords(INode* n)
3153 if (!kCacheCoords)
return;
3154 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3155 for (Dimension i = 0; i < dims; ++i) n->pcoord[i] = pt(n->ptIdx, i);
3159 ElementType nodeCoord(
const INode* n, Dimension d)
const
3161 return kCacheCoords ? n->pcoord[d] : pt(n->ptIdx, d);
3165 bool nodeInBox(
const INode* n,
const BoundingBox& b)
const
3167 if (!kCacheCoords)
return pointInBox(n->ptIdx, b);
3168 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3169 for (Dimension i = 0; i < dims; ++i)
3170 if (n->pcoord[i] < b[i].low || n->pcoord[i] > b[i].high)
return false;
3174 void recycleNode(INode* n)
3176 n->child1 = freeList_;
3182 void destroyNodeObjects()
3184 if (std::is_trivially_destructible<INode>::value)
return;
3185 destroySubtree(iroot_);
3189 INode* n = freeList_;
3190 freeList_ = n->child1;
3195 void destroySubtree(INode* n)
3198 destroySubtree(n->child1);
3199 destroySubtree(n->child2);
3206 ElementType pt(IndexType idx, Dimension d)
const {
return dataset_.kdtree_get_pt(idx, d); }
3208 void ensureNodeMap(IndexType idx)
3210 if (idx >= nodeOfPoint_.size()) nodeOfPoint_.resize(
static_cast<size_t>(idx) + 1,
nullptr);
3215 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3217 for (Dimension i = 0; i < dims; ++i) Base::root_bbox_[i] = iroot_->box[i];
3219 for (Dimension i = 0; i < dims; ++i) Base::root_bbox_[i] = Interval{0, 0};
3222 void initBoxToPoint(INode* n)
3224 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3225 for (Dimension i = 0; i < dims; ++i)
3227 const ElementType v = pt(n->ptIdx, i);
3228 n->box[i].low = n->box[i].high = v;
3232 void expandBoxToPoint(INode* n, IndexType idx)
3234 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3235 for (Dimension i = 0; i < dims; ++i)
3237 const ElementType v = pt(idx, i);
3238 if (v < n->box[i].low) n->box[i].low = v;
3239 if (v > n->box[i].high) n->box[i].high = v;
3243 void unionBox(INode* n,
const INode* c)
3246 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3247 for (Dimension i = 0; i < dims; ++i)
3249 if (c->box[i].low < n->box[i].low) n->box[i].low = c->box[i].low;
3250 if (c->box[i].high > n->box[i].high) n->box[i].high = c->box[i].high;
3254 bool pointInBox(IndexType idx,
const BoundingBox& b)
const
3256 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3257 for (Dimension i = 0; i < dims; ++i)
3259 const ElementType v = pt(idx, i);
3260 if (v < b[i].low || v > b[i].high)
return false;
3265 bool boxFullyInside(
const BoundingBox& inner,
const BoundingBox& outer)
const
3267 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3268 for (Dimension i = 0; i < dims; ++i)
3269 if (inner[i].low < outer[i].low || inner[i].high > outer[i].high)
return false;
3273 bool boxDisjoint(
const BoundingBox& a,
const BoundingBox& b)
const
3275 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3276 for (Dimension i = 0; i < dims; ++i)
3277 if (a[i].high < b[i].low || a[i].low > b[i].high)
return true;
3284 INode* makeLeaf(IndexType idx, Dimension depth, INode* parent)
3286 INode* n = allocNode();
3287 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3289 n->divfeat =
static_cast<Dimension
>(depth % dims);
3291 n->treeDeleted =
false;
3292 n->child1 = n->child2 =
nullptr;
3294 n->subtree_size = 1;
3295 n->invalid_count = 0;
3298 nodeOfPoint_[idx] = n;
3304 void insertOne(IndexType idx)
3306 pendingRebuild_ =
nullptr;
3307 iroot_ = insertRec(iroot_, idx, 0,
nullptr);
3310 if (pendingRebuild_ && inlineRebuild_) rebuildAt(pendingRebuild_);
3313 INode* insertRec(INode* node, IndexType idx, Dimension depth, INode* parent)
3315 if (!node)
return makeLeaf(idx, depth, parent);
3316 if (node->treeDeleted) pushDownDelete(node);
3318 ++node->subtree_size;
3319 expandBoxToPoint(node, idx);
3321 const Dimension axis = node->divfeat;
3322 if (pt(idx, axis) < nodeCoord(node, axis))
3323 node->child1 = insertRec(node->child1, idx,
static_cast<Dimension
>(depth + 1), node);
3325 node->child2 = insertRec(node->child2, idx,
static_cast<Dimension
>(depth + 1), node);
3330 if (isBalanceScapegoat(node)) pendingRebuild_ = node;
3336 void pushDownDelete(INode* node)
3338 node->deleted =
true;
3341 node->child1->treeDeleted =
true;
3342 node->child1->invalid_count = node->child1->subtree_size;
3346 node->child2->treeDeleted =
true;
3347 node->child2->invalid_count = node->child2->subtree_size;
3349 node->treeDeleted =
false;
3352 Size maxChildSize(
const INode* node)
const
3354 const Size l = node->child1 ? node->child1->subtree_size : 0;
3355 const Size r = node->child2 ? node->child2->subtree_size : 0;
3356 return l > r ? l : r;
3359 bool isBalanceScapegoat(
const INode* node)
const
3361 if (node->subtree_size < kMinBalanceRebuild)
return false;
3362 return static_cast<float>(maxChildSize(node)) >
3363 alphaBal_ *
static_cast<float>(node->subtree_size);
3370 void killSubtree(INode* node)
3372 node->treeDeleted =
true;
3373 node->invalid_count = node->subtree_size;
3377 Size removeOutsideBoxRec(INode* node,
const BoundingBox& keep)
3379 if (!node)
return 0;
3380 if (node->invalid_count == node->subtree_size)
return 0;
3381 if (boxFullyInside(node->box, keep))
return 0;
3382 if (boxDisjoint(node->box, keep))
3384 const Size newly = node->subtree_size - node->invalid_count;
3386 liveCount_ -= newly;
3390 if (!node->deleted && !nodeInBox(node, keep))
3392 node->deleted =
true;
3396 newly += removeOutsideBoxRec(node->child1, keep);
3397 newly += removeOutsideBoxRec(node->child2, keep);
3398 node->invalid_count += newly;
3403 Size removeBoxRec(INode* node,
const BoundingBox& box)
3405 if (!node)
return 0;
3406 if (node->invalid_count == node->subtree_size)
return 0;
3407 if (boxDisjoint(node->box, box))
return 0;
3408 if (boxFullyInside(node->box, box))
3410 const Size newly = node->subtree_size - node->invalid_count;
3412 liveCount_ -= newly;
3416 if (!node->deleted && nodeInBox(node, box))
3418 node->deleted =
true;
3422 newly += removeBoxRec(node->child1, box);
3423 newly += removeBoxRec(node->child2, box);
3424 node->invalid_count += newly;
3428 bool isDeletionScapegoat(
const INode* node)
const
3430 if (node->subtree_size == 0)
return false;
3431 return static_cast<float>(node->invalid_count) >
3432 alphaDel_ *
static_cast<float>(node->subtree_size);
3435 INode* findDeletionScapegoat(INode* node)
const
3437 if (!node)
return nullptr;
3438 if (isDeletionScapegoat(node))
return node;
3439 if (INode* l = findDeletionScapegoat(node->child1))
return l;
3440 return findDeletionScapegoat(node->child2);
3443 void maybeRebuildForDeletion()
3445 if (!iroot_ || !inlineRebuild_)
return;
3446 if (INode* sg = findDeletionScapegoat(iroot_)) rebuildAt(sg);
3452 void rebuildAt(INode* node)
3454 INode* par = node->parent;
3455 INode** link = par ? (par->child1 == node ? &par->child1 : &par->child2) : &iroot_;
3457 const Size oldSize = node->subtree_size;
3458 const Size oldInvalid = node->invalid_count;
3461 collectLiveAndFree(node, buildBuf_);
3463 INode* nb = buildBalanced(buildBuf_, 0, buildBuf_.size(), 0, par);
3466 const Size newSize = nb ? nb->subtree_size : 0;
3468 for (INode* p = par; p; p = p->parent)
3470 p->subtree_size = p->subtree_size - oldSize + newSize;
3471 p->invalid_count = p->invalid_count - oldInvalid;
3473 totalCount_ = totalCount_ - oldSize + newSize;
3479 void collectLiveAndFree(INode* node, std::vector<IndexType>& out)
3482 if (node->treeDeleted)
3484 freeDeadSubtree(node);
3488 out.push_back(node->ptIdx);
3490 dropDeadPoint(node->ptIdx);
3491 collectLiveAndFree(node->child1, out);
3492 collectLiveAndFree(node->child2, out);
3496 void freeDeadSubtree(INode* node)
3499 dropDeadPoint(node->ptIdx);
3500 freeDeadSubtree(node->child1);
3501 freeDeadSubtree(node->child2);
3505 void dropDeadPoint(IndexType idx)
3507 if (idx < nodeOfPoint_.size()) nodeOfPoint_[idx] =
nullptr;
3508 if (collectRemoved_) removedSink_.push_back(idx);
3512 void snapshotRec(
const INode* node, std::vector<IndexType>& out)
const
3515 if (node->invalid_count == node->subtree_size)
return;
3516 if (!node->deleted) out.push_back(node->ptIdx);
3517 snapshotRec(node->child1, out);
3518 snapshotRec(node->child2, out);
3522 void collectAllRec(
const INode* node, std::vector<IndexType>& out)
const
3525 out.push_back(node->ptIdx);
3526 collectAllRec(node->child1, out);
3527 collectAllRec(node->child2, out);
3531 INode* buildBalanced(
3532 std::vector<IndexType>& buf,
size_t lo,
size_t hi, Dimension depth, INode* parent)
3534 if (lo >= hi)
return nullptr;
3535 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3538 Dimension axis =
static_cast<Dimension
>(depth % dims);
3539 ElementType bestSpan = -1;
3540 for (Dimension d = 0; d < dims; ++d)
3542 ElementType mn = pt(buf[lo], d), mx = mn;
3543 for (
size_t k = lo + 1; k < hi; ++k)
3545 const ElementType v = pt(buf[k], d);
3549 const ElementType span = mx - mn;
3550 if (span > bestSpan)
3557 const size_t mid = lo + (hi - lo) / 2;
3559 buf.begin() + lo, buf.begin() + mid, buf.begin() + hi,
3560 [
this, axis](IndexType a, IndexType b) { return pt(a, axis) < pt(b, axis); });
3562 INode* node = allocNode();
3563 node->ptIdx = buf[mid];
3564 node->divfeat = axis;
3565 node->deleted =
false;
3566 node->treeDeleted =
false;
3567 node->parent = parent;
3569 nodeOfPoint_[buf[mid]] = node;
3571 node->child1 = buildBalanced(buf, lo, mid,
static_cast<Dimension
>(depth + 1), node);
3572 node->child2 = buildBalanced(buf, mid + 1, hi,
static_cast<Dimension
>(depth + 1), node);
3574 node->subtree_size = hi - lo;
3575 node->invalid_count = 0;
3576 initBoxToPoint(node);
3577 unionBox(node, node->child1);
3578 unionBox(node, node->child2);
3585 template <
class RESULTSET>
3586 void searchLevelInc(
3587 RESULTSET& rs,
const ElementType* vec,
const INode* node, DistanceType mindist,
3588 distance_vector_t& dists,
const DistanceType epsError,
const Size dim)
const
3591 if (node->invalid_count == node->subtree_size)
return;
3595#if defined(NANOFLANN_INCREMENTAL_INNODE_DISTANCE)
3601 DistanceType d = DistanceType();
3603 for (Size i = 0; i < dim; ++i)
3604 d += distance_.accum_dist(
3605 vec[i], node->pcoord[
static_cast<Dimension
>(i)],
static_cast<Dimension
>(i));
3607 d = distance_.evalMetric(vec, node->ptIdx, dim);
3609 const DistanceType d = distance_.evalMetric(vec, node->ptIdx, dim);
3611 if (d < rs.worstDist())
3613 static_cast<typename RESULTSET::DistanceType
>(d),
3614 static_cast<typename RESULTSET::IndexType
>(node->ptIdx));
3617 const Dimension axis = node->divfeat;
3618 const ElementType splitval = nodeCoord(node, axis);
3619 const ElementType val = vec[axis];
3620 const DistanceType cut = distance_.accum_dist(val, splitval, axis);
3622 const INode* nearChild;
3623 const INode* farChild;
3626 nearChild = node->child1;
3627 farChild = node->child2;
3631 nearChild = node->child2;
3632 farChild = node->child1;
3635 searchLevelInc(rs, vec, nearChild, mindist, dists, epsError, dim);
3637 const DistanceType dst = dists[axis];
3638 const DistanceType newmin = mindist + cut - dst;
3640 if (newmin * epsError <= rs.worstDist())
3641 searchLevelInc(rs, vec, farChild, newmin, dists, epsError, dim);
3645 template <
typename RESULTSET>
3646 void findWithinBoxRec(RESULTSET& result,
const INode* node,
const BoundingBox& bbox)
const
3649 if (node->invalid_count == node->subtree_size)
return;
3650 if (boxDisjoint(node->box, bbox))
return;
3651 if (!node->deleted && nodeInBox(node, bbox)) result.addPoint(0, node->ptIdx);
3652 findWithinBoxRec(result, node->child1, bbox);
3653 findWithinBoxRec(result, node->child2, bbox);
3657#ifndef NANOFLANN_NO_THREADS
3686template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
3691 using ElementType =
typename Inner::ElementType;
3692 using DistanceType =
typename Inner::DistanceType;
3693 using Size =
typename Inner::Size;
3694 using Dimension =
typename Inner::Dimension;
3695 using BoundingBox =
typename Inner::BoundingBox;
3703 const Dimension dimensionality,
const DatasetAdaptor& inputData,
3705 Size min_rebuild_size = 10000)
3706 : dataset_(inputData),
3707 dim_(dimensionality),
3709 rebuildGrowth_(rebuild_growth),
3710 minRebuildSize_(min_rebuild_size)
3712 active_.reset(
new Inner(dimensionality, inputData, params));
3713 active_->setInlineRebuild(
false);
3716 KDTreeSingleIndexIncrementalAdaptorMT(
const KDTreeSingleIndexIncrementalAdaptorMT&) =
delete;
3717 KDTreeSingleIndexIncrementalAdaptorMT& operator=(
const KDTreeSingleIndexIncrementalAdaptorMT&) =
3720 ~KDTreeSingleIndexIncrementalAdaptorMT()
3722 if (fut_.valid()) fut_.wait();
3726 void addPoints(IndexType start, IndexType end)
3729 active_->addPoints(start, end);
3730 if (building_) log_.push_back({OpKind::Add, start, end, {}});
3731 maybeTriggerRebuild();
3733 void addPoint(IndexType idx) { addPoints(idx, idx); }
3735 void removePoint(IndexType idx)
3738 active_->removePoint(idx);
3739 if (building_) log_.push_back({OpKind::Remove, idx, idx, {}});
3740 maybeTriggerRebuild();
3742 void removeBox(
const BoundingBox& box)
3745 active_->removeBox(box);
3746 if (building_) log_.push_back({OpKind::RemoveBox, 0, 0, box});
3747 maybeTriggerRebuild();
3749 void removeOutsideBox(
const BoundingBox& keep)
3752 active_->removeOutsideBox(keep);
3753 if (building_) log_.push_back({OpKind::RemoveOutsideBox, 0, 0, keep});
3754 maybeTriggerRebuild();
3759 template <
typename RESULTSET>
3761 RESULTSET& result,
const ElementType* vec,
const SearchParameters& sp = {})
const
3763 return active_->findNeighbors(result, vec, sp);
3766 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
3767 DistanceType* out_distances,
const SearchParameters& sp = {})
const
3769 return active_->knnSearch(query_point, num_closest, out_indices, out_distances, sp);
3772 const ElementType* query_point,
const DistanceType& radius,
3773 std::vector<ResultItem<IndexType, DistanceType>>& IndicesDists,
3774 const SearchParameters& sp = {})
const
3776 return active_->radiusSearch(query_point, radius, IndicesDists, sp);
3779 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
3780 DistanceType* out_distances,
const DistanceType& radius)
const
3782 return active_->rknnSearch(query_point, num_closest, out_indices, out_distances, radius);
3784 template <
typename RESULTSET>
3785 Size findWithinBox(RESULTSET& result,
const BoundingBox& bbox)
const
3787 return active_->findWithinBox(result, bbox);
3792 Size size() const noexcept {
return active_->size(); }
3793 bool empty() const noexcept {
return active_->empty(); }
3794 Size physicalSize() const noexcept {
return active_->physicalSize(); }
3795 bool isRebuilding() const noexcept {
return building_; }
3798 NANOFLANN_NODISCARD BoundingBox
boundingBox()
const {
return active_->boundingBox(); }
3803 active_->snapshotLiveIndices(out);
3812 if (building_ && fut_.valid()) fut_.wait();
3836 collectRemoved_ = enable;
3837 if (!enable) std::vector<IndexType>().swap(removedSink_);
3845 std::vector<IndexType> out;
3846 out.swap(removedSink_);
3866 void maybeTriggerRebuild()
3868 if (building_)
return;
3869 const Size phys = active_->physicalSize();
3870 if (phys < minRebuildSize_)
return;
3871 const Size base = lastBuildLive_ ? lastBuildLive_ : Size(1);
3872 if (
static_cast<double>(phys) < rebuildGrowth_ *
static_cast<double>(base))
return;
3876 auto snapshot = std::make_shared<std::vector<IndexType>>();
3877 active_->snapshotLiveIndices(*snapshot);
3879 const DatasetAdaptor& ds = dataset_;
3880 const Dimension d = dim_;
3881 KDTreeIncrementalIndexParams p = params_;
3882 std::function<void(Inner&)> cb = rebuildCallback_;
3885 [snapshot, &ds, d, p, cb]() -> std::unique_ptr<Inner>
3887 std::unique_ptr<Inner> t(
new Inner(d, ds, p));
3888 t->setInlineRebuild(
false);
3889 t->buildFromIndices(*snapshot);
3897 void integrateIfReady()
3899 if (!building_ || !fut_.valid())
return;
3900 if (fut_.wait_for(std::chrono::seconds(0)) != std::future_status::ready)
return;
3902 std::unique_ptr<Inner> fresh = fut_.get();
3903 fresh->setInlineRebuild(
false);
3905 for (
const auto& op : log_)
3910 fresh->addPoints(op.a, op.b);
3912 case OpKind::Remove:
3913 fresh->removePoint(op.a);
3915 case OpKind::RemoveBox:
3916 fresh->removeBox(op.box);
3918 case OpKind::RemoveOutsideBox:
3919 fresh->removeOutsideBox(op.box);
3926 if (collectRemoved_)
3928 std::vector<IndexType> oldPhysical;
3929 active_->collectPhysicalIndices(oldPhysical);
3930 for (IndexType idx : oldPhysical)
3931 if (!fresh->referencesIndex(idx)) removedSink_.push_back(idx);
3933 active_ = std::move(fresh);
3934 lastBuildLive_ = active_->size();
3938 const DatasetAdaptor& dataset_;
3940 KDTreeIncrementalIndexParams params_;
3941 double rebuildGrowth_;
3942 Size minRebuildSize_;
3944 std::unique_ptr<Inner> active_;
3945 std::future<std::unique_ptr<Inner>> fut_;
3946 bool building_ =
false;
3947 Size lastBuildLive_ = 0;
3948 std::vector<LoggedOp> log_;
3950 bool collectRemoved_ =
false;
3951 std::vector<IndexType> removedSink_;
3952 std::function<void(Inner&)> rebuildCallback_;
3982 class MatrixType, int32_t DIM = -1,
class Distance = nanoflann::metric_L2,
3983 bool row_major =
true>
3987 using num_t =
typename MatrixType::Scalar;
3988 using IndexType =
typename MatrixType::Index;
3989 using metric_t =
typename Distance::template traits<num_t, self_t, IndexType>::distance_t;
3992 metric_t, self_t, row_major ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime,
3999 using Size =
typename index_t::Size;
4000 using Dimension =
typename index_t::Dimension;
4004 const Dimension dimensionality,
const std::reference_wrapper<const MatrixType>& mat,
4005 const int leaf_max_size = 10,
const unsigned int n_thread_build = 1)
4006 : m_data_matrix(mat)
4008 const auto dims = row_major ? mat.get().cols() : mat.get().rows();
4009 if (
static_cast<Dimension
>(dims) != dimensionality)
4010 throw std::runtime_error(
4011 "Error: 'dimensionality' must match column count in data "
4013 if (DIM > 0 &&
static_cast<int32_t
>(dims) != DIM)
4014 throw std::runtime_error(
4015 "Data set dimensionality does not match the 'DIM' template "
4017 index_ =
new index_t(
4018 static_cast<Dimension
>(dims), *
this ,
4020 leaf_max_size, nanoflann::KDTreeSingleIndexAdaptorFlags::None, n_thread_build));
4026 self_t& operator=(
const self_t&) =
delete;
4033 self_t& operator=(self_t&&) =
delete;
4037 const std::reference_wrapper<const MatrixType> m_data_matrix;
4048 const num_t* query_point,
const Size num_closest, IndexType* out_indices,
4049 num_t* out_distances)
const
4052 resultSet.init(out_indices, out_distances);
4053 index_->findNeighbors(resultSet, query_point);
4059 inline const self_t& derived() const noexcept {
return *
this; }
4060 inline self_t& derived() noexcept {
return *
this; }
4063 inline Size kdtree_get_point_count()
const
4066 return m_data_matrix.get().rows();
4068 return m_data_matrix.get().cols();
4072 inline num_t kdtree_get_pt(
const IndexType idx,
size_t dim)
const
4075 return m_data_matrix.get().coeff(idx, IndexType(dim));
4077 return m_data_matrix.get().coeff(IndexType(dim), idx);
4085 template <
class BBOX>
4086 inline bool kdtree_get_bbox(BBOX& )
const
4099#undef NANOFLANN_RESTRICT
bool addPoint(DistanceType, IndexType index)
Definition nanoflann.hpp:487
Definition nanoflann.hpp:1048
NANOFLANN_NODISCARD bool isActive(IndexType) const
Definition nanoflann.hpp:1206
void freeIndex(Derived &obj)
Definition nanoflann.hpp:1052
NANOFLANN_NODISCARD Size veclen(const Derived &obj) const noexcept
Definition nanoflann.hpp:1153
void computeMinMax(const Derived &obj, Offset ind, Size count, Dimension element, ElementType &min_elem, ElementType &max_elem) const
Definition nanoflann.hpp:1189
BoundingBox root_bbox_
Definition nanoflann.hpp:1135
void saveIndex(const Derived &obj, std::ostream &stream) const
Definition nanoflann.hpp:1667
void computeBoundingBox(BoundingBox &bbox)
Definition nanoflann.hpp:1211
NANOFLANN_NODISCARD Size usedMemory(const Derived &obj) const
Definition nanoflann.hpp:1179
Dimension dim_
Dimensionality of each data point.
Definition nanoflann.hpp:1124
typename array_or_vector< DIM, DistanceType >::type distance_vector_t
Definition nanoflann.hpp:1132
void planeSplit(const Derived &obj, const Offset ind, const Size count, const Dimension cutfeat, const DistanceType &cutval, Offset &lim1, Offset &lim2)
Definition nanoflann.hpp:1561
Size n_thread_build_
Number of thread for concurrent tree build.
Definition nanoflann.hpp:1119
NANOFLANN_NODISCARD Size size(const Derived &obj) const noexcept
Definition nanoflann.hpp:1147
std::vector< IndexType > vAcc_
Definition nanoflann.hpp:1066
bool makeNode(Derived &obj, NodePtr node, const Offset left, const Offset right, BoundingBox &bbox, Offset &idx, Dimension &cutfeat, DistanceType &cutval)
Definition nanoflann.hpp:1324
bool searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindist, distance_vector_t &dists, const DistanceType epsError) const
Definition nanoflann.hpp:1241
Size size_at_index_build_
Number of points in the dataset when the index was built.
Definition nanoflann.hpp:1123
NodePtr divideTreeConcurrent(Derived &obj, const Offset left, const Offset right, BoundingBox &bbox, std::atomic< unsigned int > &thread_count, std::mutex &mutex)
Definition nanoflann.hpp:1418
Size size_
Number of current points in the dataset.
Definition nanoflann.hpp:1121
void finalizeSplitNode(Derived &obj, NodePtr node, const Dimension cutfeat, const BoundingBox &left_bbox, const BoundingBox &right_bbox, BoundingBox &bbox)
Definition nanoflann.hpp:1366
void loadIndex(Derived &obj, std::istream &stream)
Definition nanoflann.hpp:1713
PooledAllocator pool_
Definition nanoflann.hpp:1144
ElementType dataset_get(const Derived &obj, IndexType element, Dimension component) const
Helper accessor to the dataset points:
Definition nanoflann.hpp:1170
typename array_or_vector< DIM, Interval >::type BoundingBox
Definition nanoflann.hpp:1128
static constexpr uint32_t SAVE_MAGIC
Definition nanoflann.hpp:1647
Definition nanoflann.hpp:1834
void saveIndex(std::ostream &stream) const
Definition nanoflann.hpp:2195
NANOFLANN_NODISCARD Size findWithinBox(RESULTSET &result, const BoundingBox &bbox) const
Definition nanoflann.hpp:2026
void init_vind()
Definition nanoflann.hpp:2170
void buildIndex()
Definition nanoflann.hpp:1939
NANOFLANN_NODISCARD Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2116
NANOFLANN_NODISCARD Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2132
NANOFLANN_NODISCARD Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances) const
Definition nanoflann.hpp:2087
const self_t & dataset_
Definition nanoflann.hpp:1841
KDTreeSingleIndexAdaptor(const KDTreeSingleIndexAdaptor< Distance, DatasetAdaptor, DIM, index_t > &)=delete
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:1986
NANOFLANN_NODISCARD Size rknnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const DistanceType &radius) const
Definition nanoflann.hpp:2155
typename Base::distance_vector_t distance_vector_t
Definition nanoflann.hpp:1870
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:2202
typename Base::BoundingBox BoundingBox
Definition nanoflann.hpp:1866
KDTreeSingleIndexAdaptor(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams ¶ms, Args &&... args)
Definition nanoflann.hpp:1893
Definition nanoflann.hpp:2248
KDTreeSingleIndexDynamicAdaptor_(const Dimension dimensionality, const DatasetAdaptor &inputData, std::vector< int > &treeIndex, const KDTreeSingleIndexAdaptorParams ¶ms=KDTreeSingleIndexAdaptorParams())
Definition nanoflann.hpp:2302
typename Base::BoundingBox BoundingBox
Definition nanoflann.hpp:2278
const DatasetAdaptor & dataset_
Definition nanoflann.hpp:2253
NANOFLANN_NODISCARD Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2430
KDTreeSingleIndexDynamicAdaptor_(const KDTreeSingleIndexDynamicAdaptor_ &rhs)=default
void buildIndex()
Definition nanoflann.hpp:2347
void saveIndex(std::ostream &stream)
Definition nanoflann.hpp:2492
NANOFLANN_NODISCARD bool isActive(IndexType idx) const
Definition nanoflann.hpp:2285
NANOFLANN_NODISCARD Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2475
typename Base::distance_vector_t distance_vector_t
Definition nanoflann.hpp:2282
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:2499
KDTreeSingleIndexDynamicAdaptor_ & operator=(const KDTreeSingleIndexDynamicAdaptor_ &rhs)
Definition nanoflann.hpp:2328
NANOFLANN_NODISCARD Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2459
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2396
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2701
const DatasetAdaptor & dataset_
The source of our data.
Definition nanoflann.hpp:2536
void removePoint(size_t idx)
Definition nanoflann.hpp:2674
std::unordered_map< IndexType, int > removedPoints_
Definition nanoflann.hpp:2544
void addPoints(IndexType start, IndexType end)
Definition nanoflann.hpp:2625
KDTreeSingleIndexDynamicAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams ¶ms=KDTreeSingleIndexAdaptorParams(), const size_t maximumPointCount=1000000000U)
Definition nanoflann.hpp:2600
std::vector< int > treeIndex_
Definition nanoflann.hpp:2540
const std::vector< index_container_t > & getAllIndices() const
Definition nanoflann.hpp:2557
Dimension dim_
Dimensionality of each data point.
Definition nanoflann.hpp:2548
KDTreeSingleIndexDynamicAdaptor(const KDTreeSingleIndexDynamicAdaptor< Distance, DatasetAdaptor, DIM, IndexType > &)=delete
void snapshotLiveIndices(std::vector< IndexType > &out) const
Definition nanoflann.hpp:3801
KDTreeSingleIndexIncrementalAdaptorMT(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeIncrementalIndexParams ¶ms={}, double rebuild_growth=1.3, Size min_rebuild_size=10000)
Definition nanoflann.hpp:3702
void setCollectRemovedPoints(bool enable)
Definition nanoflann.hpp:3834
void sync()
Definition nanoflann.hpp:3810
const Inner & activeIndex() const
Definition nanoflann.hpp:3817
void reserve(Size n)
Definition nanoflann.hpp:3807
std::vector< IndexType > acquireRemovedPoints()
Definition nanoflann.hpp:3843
void setRebuildCallback(std::function< void(Inner &)> cb)
Definition nanoflann.hpp:3827
NANOFLANN_NODISCARD BoundingBox boundingBox() const
Definition nanoflann.hpp:3798
Definition nanoflann.hpp:2774
NANOFLANN_NODISCARD Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3089
NANOFLANN_NODISCARD Size rknnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const DistanceType &radius) const
Definition nanoflann.hpp:3110
void removeBox(const BoundingBox &box)
Definition nanoflann.hpp:2949
void setCollectRemovedPoints(bool enable)
Definition nanoflann.hpp:2967
NANOFLANN_NODISCARD Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3101
void addPoint(IndexType idx)
Definition nanoflann.hpp:2893
NANOFLANN_NODISCARD BoundingBox boundingBox() const
Definition nanoflann.hpp:3045
void setInlineRebuild(bool enable)
Definition nanoflann.hpp:2985
KDTreeSingleIndexIncrementalAdaptor(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeIncrementalIndexParams ¶ms={})
Definition nanoflann.hpp:2870
void snapshotLiveIndices(std::vector< IndexType > &out) const
Definition nanoflann.hpp:2989
NANOFLANN_NODISCARD Size usedMemory() const
Definition nanoflann.hpp:3036
void removePoint(IndexType idx)
Definition nanoflann.hpp:2931
NANOFLANN_NODISCARD Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3078
const DatasetAdaptor & dataset_
Definition nanoflann.hpp:2792
void reserve(Size n)
Definition nanoflann.hpp:3049
NANOFLANN_NODISCARD Size size() const noexcept
Definition nanoflann.hpp:3029
NANOFLANN_NODISCARD Size physicalSize() const noexcept
Definition nanoflann.hpp:3033
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3062
void collectPhysicalIndices(std::vector< IndexType > &out) const
Definition nanoflann.hpp:2994
KDTreeSingleIndexIncrementalAdaptor(const KDTreeSingleIndexIncrementalAdaptor &)=delete
static constexpr bool kCacheCoords
Definition nanoflann.hpp:2824
void removeOutsideBox(const BoundingBox &keep)
Definition nanoflann.hpp:2958
NANOFLANN_NODISCARD Size findWithinBox(RESULTSET &result, const BoundingBox &bbox) const
Definition nanoflann.hpp:3122
void addPoints(IndexType start, IndexType end)
Definition nanoflann.hpp:2908
void buildFromIndices(const std::vector< IndexType > &idxs)
Definition nanoflann.hpp:3005
NANOFLANN_NODISCARD bool referencesIndex(IndexType idx) const
Definition nanoflann.hpp:2998
std::vector< IndexType > acquireRemovedPoints()
Definition nanoflann.hpp:2975
Definition nanoflann.hpp:288
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:322
NANOFLANN_NODISCARD DistanceType worstDist() const noexcept
Returns the worst distance among found solutions if the search result is full, or the maximum possibl...
Definition nanoflann.hpp:329
Definition nanoflann.hpp:898
~PooledAllocator()
Definition nanoflann.hpp:934
void free_all()
Definition nanoflann.hpp:937
void * allocateBytes(const size_t req_size)
Definition nanoflann.hpp:953
T * allocate(const size_t count=1)
Definition nanoflann.hpp:1002
PooledAllocator()
Definition nanoflann.hpp:929
Definition nanoflann.hpp:344
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:384
NANOFLANN_NODISCARD DistanceType worstDist() const noexcept
Returns the worst distance among found solutions if the search result is full, or the maximum possibl...
Definition nanoflann.hpp:391
Definition nanoflann.hpp:407
ResultItem< IndexType, DistanceType > worst_item() const
Definition nanoflann.hpp:448
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:436
std::enable_if< has_assign< Container >::value, void >::type assign(Container &c, const size_t nElements, const T &value)
Definition nanoflann.hpp:195
std::enable_if< has_resize< Container >::value, void >::type resize(Container &c, const size_t nElements)
Definition nanoflann.hpp:174
constexpr T pi_const()
Definition nanoflann.hpp:141
bool has_flag(KDTreeSingleIndexAdaptorFlags f, KDTreeSingleIndexAdaptorFlags flag)
Definition nanoflann.hpp:848
Definition nanoflann.hpp:213
bool operator()(const PairType &p1, const PairType &p2) const
Definition nanoflann.hpp:216
Definition nanoflann.hpp:1110
Definition nanoflann.hpp:1085
Offset right
Indices of points in leaf node.
Definition nanoflann.hpp:1092
Dimension divfeat
Dimension used for subdivision. The values used for subdivision.
Definition nanoflann.hpp:1096
Node * child1
Definition nanoflann.hpp:1103
union nanoflann::KDTreeBaseClass::Node::@327270127162340211203002370327206303122355110302 node_type
void query(const num_t *query_point, const Size num_closest, IndexType *out_indices, num_t *out_distances) const
Definition nanoflann.hpp:4047
KDTreeEigenMatrixAdaptor(const self_t &)=delete
KDTreeEigenMatrixAdaptor(self_t &&)=delete
typename index_t::Offset Offset
Definition nanoflann.hpp:3998
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.
Definition nanoflann.hpp:4003
Definition nanoflann.hpp:2725
Definition nanoflann.hpp:855
Definition nanoflann.hpp:2799
Size invalid_count
number of tombstoned nodes in subtree
Definition nanoflann.hpp:2808
Dimension divfeat
splitting axis at this node
Definition nanoflann.hpp:2801
bool treeDeleted
whole subtree lazily tombstoned
Definition nanoflann.hpp:2803
IndexType ptIdx
index of the stored data point
Definition nanoflann.hpp:2800
INode * parent
parent (nullptr at the root)
Definition nanoflann.hpp:2806
Size subtree_size
number of nodes in this subtree
Definition nanoflann.hpp:2807
INode * child1
"< split" child (also free-list link)
Definition nanoflann.hpp:2804
INode * child2
">= split" child
Definition nanoflann.hpp:2805
BoundingBox box
AABB of all points (live+dead) in this subtree Cache of this node's own point coordinates,...
Definition nanoflann.hpp:2809
bool deleted
this node's point is tombstoned
Definition nanoflann.hpp:2802
Definition nanoflann.hpp:549
Definition nanoflann.hpp:611
Definition nanoflann.hpp:678
Definition nanoflann.hpp:534
Definition nanoflann.hpp:232
DistanceType second
Distance from sample to query point.
Definition nanoflann.hpp:239
IndexType first
Index of the sample in the dataset.
Definition nanoflann.hpp:238
Definition nanoflann.hpp:717
DistanceType accum_dist(const U a, const V b, const size_t) const
Definition nanoflann.hpp:736
Definition nanoflann.hpp:760
Definition nanoflann.hpp:871
bool sorted
only for radius search, require neighbors sorted by distance (default: true)
Definition nanoflann.hpp:875
float eps
search for eps-approximate neighbors (default: 0)
Definition nanoflann.hpp:874
Definition nanoflann.hpp:1018
Definition nanoflann.hpp:162
Definition nanoflann.hpp:152
Definition nanoflann.hpp:785
Definition nanoflann.hpp:782
Definition nanoflann.hpp:795
Definition nanoflann.hpp:805
Definition nanoflann.hpp:802
Definition nanoflann.hpp:792
Definition nanoflann.hpp:814
Definition nanoflann.hpp:811
Definition nanoflann.hpp:823
Definition nanoflann.hpp:820