Skip to content

Commit 8bfad6c

Browse files
committed
Incremental Distance Calculation technique for faster queries.
1 parent 19bc257 commit 8bfad6c

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,5 @@ $ pip install ./pico_tree --install-option="-GMinGW Makefiles"
9191
* [Computational Geometry - Algorithms and Applications.](https://www.springer.com/gp/book/9783540779735) Mark de Berg, Otfried Cheong, Marc van Kreveld, and Mark Overmars, Springer-Verlag, third edition, 2008.
9292
* S. Maneewongvatana and D. M. Mount. [It's okay to be skinny, if your friends are fat.](http://www.cs.umd.edu/~mount/Papers/cgc99-smpack.pdf) 4th Annual CGC Workshop on Computational Geometry, 1999.
9393
* S. Arya and H. Y. Fu. [Expected-case complexity of approximate nearest neighbor searching.](https://www.cse.ust.hk/faculty/arya/pub/exp.pdf) InProceedings of the 11th ACM-SIAM Symposium on Discrete Algorithms, 2000.
94+
* S. Arya and D. M. Mount. [Algorithms for fast vector quantization](https://www.cs.umd.edu/~mount/Papers/DCC.pdf). In IEEE Data Compression Conference, pages 381–390, March 1993.
9495
* https://en.wikipedia.org/wiki/K-d_tree

src/pico_tree/pico_tree/kd_tree.hpp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,9 @@ class KdTree {
385385
//! \see internal::SearchAknn
386386
template <typename P, typename V>
387387
inline void SearchNearest(P const& x, V* visitor) const {
388-
SearchNearest(root_, x, visitor);
388+
Sequence node_box_offset;
389+
node_box_offset.Fill(Traits::SpaceSdim(points_), Scalar(0.0));
390+
SearchNearest(root_, x, Scalar(0.0), &node_box_offset, visitor);
389391
}
390392

391393
//! \brief Searches for the nearest neighbor of point \p x.
@@ -394,7 +396,7 @@ class KdTree {
394396
template <typename P>
395397
inline void SearchNn(P const& x, NeighborType* nn) const {
396398
internal::SearchNn<NeighborType> v(nn);
397-
SearchNearest(root_, x, &v);
399+
SearchNearest(x, &v);
398400
}
399401

400402
//! \brief Searches for the k nearest neighbors of point \p x, where k equals
@@ -414,7 +416,7 @@ class KdTree {
414416
"SEARCH_ITERATOR_VALUE_TYPE_DOES_NOT_EQUAL_NEIGHBOR_INDEX_SCALAR");
415417

416418
internal::SearchKnn<RandomAccessIterator> v(begin, end);
417-
SearchNearest(root_, x, &v);
419+
SearchNearest(x, &v);
418420
}
419421

420422
//! \brief Searches for the \p k nearest neighbors of point \p x and stores
@@ -455,7 +457,7 @@ class KdTree {
455457
std::vector<NeighborType>* n,
456458
bool const sort = false) const {
457459
internal::SearchRadius<NeighborType> v(radius, n);
458-
SearchNearest(root_, x, &v);
460+
SearchNearest(x, &v);
459461

460462
if (sort) {
461463
v.Sort();
@@ -508,7 +510,7 @@ class KdTree {
508510
"SEARCH_ITERATOR_VALUE_TYPE_DOES_NOT_EQUAL_NEIGHBOR_INDEX_SCALAR");
509511

510512
internal::SearchAknn<RandomAccessIterator> v(e, begin, end);
511-
SearchNearest(root_, x, &v);
513+
SearchNearest(x, &v);
512514
}
513515

514516
//! \brief Searches for the \p k approximate nearest neighbors of point \p x
@@ -643,7 +645,11 @@ class KdTree {
643645
//! on their selection by visitor \p visitor for node \p node .
644646
template <typename P, typename V>
645647
inline void SearchNearest(
646-
Node const* const node, P const& x, V* visitor) const {
648+
Node const* const node,
649+
P const& x,
650+
Scalar node_box_distance,
651+
Sequence* node_box_offset,
652+
V* visitor) const {
647653
if (node->IsLeaf()) {
648654
for (Index i = node->data.leaf.begin_idx; i < node->data.leaf.end_idx;
649655
++i) {
@@ -671,9 +677,29 @@ class KdTree {
671677
node_2nd = node->left;
672678
}
673679

674-
SearchNearest(node_1st, x, visitor);
675-
if (visitor->max() >= metric_(node->data.branch.split_val, v)) {
676-
SearchNearest(node_2nd, x, visitor);
680+
// S. Arya and D. M. Mount. Algorithms for fast vector quantization. In
681+
// IEEE Data Compression Conference, pages 381–390, March 1993
682+
// https://www.cs.umd.edu/~mount/Papers/DCC.pdf
683+
// This paper describes the "Incremental Distance Calculation" technique
684+
// to speed up nearest neighbor queries.
685+
686+
// The distance and offset for node_1st is the same as that of its parent.
687+
SearchNearest(node_1st, x, node_box_distance, node_box_offset, visitor);
688+
689+
// Calculate the distance to node_2nd.
690+
// NOTE: This method only works with Lp norms to which the exponent is not
691+
// applied.
692+
Scalar old_offset = (*node_box_offset)[node->data.branch.split_dim];
693+
Scalar new_offset = metric_(node->data.branch.split_val, v);
694+
node_box_distance = node_box_distance - old_offset + new_offset;
695+
696+
// The value visitor->max() contains the current nearest neighbor distance
697+
// or otherwise current maximum search distance. When testing against the
698+
// split value we determine if we should go into the neighboring node.
699+
if (visitor->max() >= node_box_distance) {
700+
(*node_box_offset)[node->data.branch.split_dim] = new_offset;
701+
SearchNearest(node_2nd, x, node_box_distance, node_box_offset, visitor);
702+
(*node_box_offset)[node->data.branch.split_dim] = old_offset;
677703
}
678704
}
679705
}

0 commit comments

Comments
 (0)