NearestNeighborsGNATNoThreadSafety.h
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011, Rice University
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Rice University nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 /* Author: Mark Moll, Bryant Gipson */
36 
37 #ifndef OMPL_DATASTRUCTURES_NEAREST_NEIGHBORS_GNAT_NO_THREAD_SAFETY_
38 #define OMPL_DATASTRUCTURES_NEAREST_NEIGHBORS_GNAT_NO_THREAD_SAFETY_
39 
40 #include "ompl/datastructures/NearestNeighbors.h"
41 #include "ompl/datastructures/GreedyKCenters.h"
42 #include "ompl/datastructures/Permutation.h"
43 #ifdef GNAT_SAMPLER
44 #include "ompl/datastructures/PDF.h"
45 #endif
46 #include "ompl/util/Exception.h"
47 #include <unordered_set>
48 #include <queue>
49 #include <algorithm>
50 
51 namespace ompl
52 {
53 
70  template<typename _T>
72  {
73  protected:
75  // internally, we use a priority queue for nearest neighbors, paired
76  // with their distance to the query point
77  typedef std::pair<const _T*, double> DataDist;
78  struct DataDistCompare
79  {
80  bool operator()(const DataDist& d0, const DataDist& d1)
81  {
82  return d0.second < d1.second;
83  }
84  };
85  typedef std::priority_queue<DataDist, std::vector<DataDist>, DataDistCompare> NearQueue;
87 
88  public:
89  NearestNeighborsGNATNoThreadSafety(unsigned int degree = 8, unsigned int minDegree = 4,
90  unsigned int maxDegree = 12, unsigned int maxNumPtsPerLeaf = 50,
91  unsigned int removedCacheSize = 500, bool rebalancing = false
92 #ifdef GNAT_SAMPLER
93  , double estimatedDimension = 6.0
94 #endif
95  )
96  : NearestNeighbors<_T>(), tree_(nullptr), degree_(degree),
97  minDegree_(std::min(degree,minDegree)), maxDegree_(std::max(maxDegree,degree)),
98  maxNumPtsPerLeaf_(maxNumPtsPerLeaf), size_(0),
99  rebuildSize_(rebalancing ? maxNumPtsPerLeaf*degree : std::numeric_limits<std::size_t>::max()),
100  removedCacheSize_(removedCacheSize),
102 #ifdef GNAT_SAMPLER
103  , estimatedDimension_(estimatedDimension)
104 #endif
105  {
106  }
107 
109  {
110  if (tree_)
111  delete tree_;
112  }
114  virtual void setDistanceFunction(const typename NearestNeighbors<_T>::DistanceFunction &distFun)
115  {
117  pivotSelector_.setDistanceFunction(distFun);
118  if (tree_)
120  }
121 
122  virtual void clear()
123  {
124  if (tree_)
125  {
126  delete tree_;
127  tree_ = nullptr;
128  }
129  size_ = 0;
130  removed_.clear();
131  if (rebuildSize_ != std::numeric_limits<std::size_t>::max())
133  }
134 
135  virtual bool reportsSortedResults() const
136  {
137  return true;
138  }
139 
140  virtual void add(const _T &data)
141  {
142  if (tree_)
143  {
144  if (isRemoved(data))
146  tree_->add(*this, data);
147  }
148  else
149  {
150  tree_ = new Node(degree_, maxNumPtsPerLeaf_, data);
151  size_ = 1;
152  }
153  }
154  virtual void add(const std::vector<_T> &data)
155  {
156  if (tree_)
158  else if (data.size()>0)
159  {
160  tree_ = new Node(degree_, maxNumPtsPerLeaf_, data[0]);
161 #ifdef GNAT_SAMPLER
162  tree_->subtreeSize_= data.size();
163 #endif
164  for (unsigned int i=1; i<data.size(); ++i)
165  tree_->data_.push_back(data[i]);
166  size_ += data.size();
167  if (tree_->needToSplit(*this))
168  tree_->split(*this);
169  }
170  }
173  {
174  std::vector<_T> lst;
175  list(lst);
176  clear();
177  add(lst);
178  }
184  virtual bool remove(const _T &data)
185  {
186  if (!size_) return false;
187  // find data in tree
188  bool isPivot = nearestKInternal(data, 1);
189  const _T *d = nearQueue_.top().first;
190  nearQueue_.pop();
191  if (*d != data)
192  return false;
193  removed_.insert(d);
194  size_--;
195  // if we removed a pivot or if the capacity of removed elements
196  // has been reached, we rebuild the entire GNAT
197  if (isPivot || removed_.size() >= removedCacheSize_)
199  return true;
200  }
201 
202  virtual _T nearest(const _T &data) const
203  {
204  if (size_)
205  {
206  nearestKInternal(data, 1);
207  if (nearQueue_.size())
208  {
209  _T result = *nearQueue_.top().first;
210  nearQueue_.pop();
211  return result;
212  }
213  }
214  throw Exception("No elements found in nearest neighbors data structure");
215  }
216 
218  virtual void nearestK(const _T &data, std::size_t k, std::vector<_T> &nbh) const
219  {
220  nbh.clear();
221  if (k == 0) return;
222  if (size_)
223  {
224  nearestKInternal(data, k);
225  postprocessNearest(nbh);
226  }
227  }
228 
230  virtual void nearestR(const _T &data, double radius, std::vector<_T> &nbh) const
231  {
232  nbh.clear();
233  if (size_)
234  {
235  nearestRInternal(data, radius);
236  postprocessNearest(nbh);
237  }
238  assert(nearQueue_.empty());
239  assert(nodeQueue_.empty());
240  }
241 
242  virtual std::size_t size() const
243  {
244  return size_;
245  }
246 
247 #ifdef GNAT_SAMPLER
248  const _T& sample(RNG &rng) const
250  {
251  if (!size())
252  throw Exception("Cannot sample from an empty tree");
253  else
254  return tree_->sample(*this, rng);
255  }
256 #endif
257 
258  virtual void list(std::vector<_T> &data) const
259  {
260  data.clear();
261  data.reserve(size());
262  if (tree_)
263  tree_->list(*this, data);
264  }
265 
267  friend std::ostream& operator<<(std::ostream &out, const NearestNeighborsGNATNoThreadSafety<_T> &gnat)
268  {
269  if (gnat.tree_)
270  {
271  out << *gnat.tree_;
272  if (!gnat.removed_.empty())
273  {
274  out << "Elements marked for removal:\n";
275  for (typename std::unordered_set<const _T*>::const_iterator it = gnat.removed_.begin();
276  it != gnat.removed_.end(); it++)
277  out << **it << '\t';
278  out << std::endl;
279  }
280  }
281  return out;
282  }
283 
284  // for debugging purposes
285  void integrityCheck()
286  {
287  std::vector<_T> lst;
288  std::unordered_set<const _T*> tmp;
289  // get all elements, including those marked for removal
290  removed_.swap(tmp);
291  list(lst);
292  // check if every element marked for removal is also in the tree
293  for (typename std::unordered_set<const _T*>::iterator it=tmp.begin(); it!=tmp.end(); it++)
294  {
295  unsigned int i;
296  for (i=0; i<lst.size(); ++i)
297  if (lst[i]==**it)
298  break;
299  if (i == lst.size())
300  {
301  // an element marked for removal is not actually in the tree
302  std::cout << "***** FAIL!! ******\n" << *this << '\n';
303  for (unsigned int j=0; j<lst.size(); ++j) std::cout<<lst[j]<<'\t';
304  std::cout<<std::endl;
305  }
306  assert(i != lst.size());
307  }
308  // restore
309  removed_.swap(tmp);
310  // get elements in the tree with elements marked for removal purged from the list
311  list(lst);
312  if (lst.size() != size_)
313  std::cout << "#########################################\n" << *this << std::endl;
314  assert(lst.size() == size_);
315  }
316  protected:
317  typedef NearestNeighborsGNATNoThreadSafety<_T> GNAT;
318 
320  bool isRemoved(const _T &data) const
321  {
322  return !removed_.empty() && removed_.find(&data) != removed_.end();
323  }
328  bool nearestKInternal(const _T &data, std::size_t k) const
329  {
330  bool isPivot;
331  double dist;
332  Node* node;
333 
335  isPivot = tree_->insertNeighborK(nearQueue_, k, tree_->pivot_, data, tree_->distToPivot_);
336  tree_->nearestK(*this, data, k, isPivot);
337  while (nodeQueue_.size() > 0)
338  {
339  dist = nearQueue_.top().second; // note the difference with nearestRInternal
340  node = nodeQueue_.top();
341  nodeQueue_.pop();
342  if (nearQueue_.size() == k &&
343  (node->distToPivot_ > node->maxRadius_ + dist ||
344  node->distToPivot_ < node->minRadius_ - dist))
345  continue;
346  node->nearestK(*this, data, k, isPivot);
347  }
348  return isPivot;
349  }
351  void nearestRInternal(const _T &data, double radius) const
352  {
353  double dist = radius; // note the difference with nearestKInternal
354  Node* node;
355 
356  tree_->insertNeighborR(nearQueue_, radius, tree_->pivot_,
358  tree_->nearestR(*this, data, radius);
359  while (nodeQueue_.size() > 0)
360  {
361  node = nodeQueue_.top();
362  nodeQueue_.pop();
363  if (node->distToPivot_ > node->maxRadius_ + dist ||
364  node->distToPivot_ < node->minRadius_ - dist)
365  continue;
366  node->nearestR(*this, data, radius);
367  }
368  }
371  void postprocessNearest(std::vector<_T> &nbh) const
372  {
373  typename std::vector<_T>::reverse_iterator it;
374  nbh.resize(nearQueue_.size());
375  for (it=nbh.rbegin(); it!=nbh.rend(); it++, nearQueue_.pop())
376  *it = *nearQueue_.top().first;
377  }
378 
380  class Node
381  {
382  public:
385  Node(int degree, int capacity, const _T &pivot)
386  : degree_(degree), pivot_(pivot),
387  minRadius_(std::numeric_limits<double>::infinity()),
389  maxRange_(degree, maxRadius_)
390 #ifdef GNAT_SAMPLER
391  , subtreeSize_(1), activity_(0)
392 #endif
393  {
394  // The "+1" is needed because we add an element before we check whether to split
395  data_.reserve(capacity+1);
396  }
397 
398  ~Node()
399  {
400  for (unsigned int i=0; i<children_.size(); ++i)
401  delete children_[i];
402  }
403 
406  void updateRadius(double dist)
407  {
408  if (minRadius_ > dist)
409  minRadius_ = dist;
410 #ifndef GNAT_SAMPLER
411  if (maxRadius_ < dist)
412  maxRadius_ = dist;
413 #else
414  if (maxRadius_ < dist)
415  {
416  maxRadius_ = dist;
417  activity_ = 0;
418  }
419  else
420  activity_ = std::max(-32, activity_ - 1);
421 #endif
422  }
426  void updateRange(unsigned int i, double dist)
427  {
428  if (minRange_[i] > dist)
429  minRange_[i] = dist;
430  if (maxRange_[i] < dist)
431  maxRange_[i] = dist;
432  }
434  void add(GNAT &gnat, const _T &data)
435  {
436 #ifdef GNAT_SAMPLER
437  subtreeSize_++;
438 #endif
439  if (children_.size()==0)
440  {
441  data_.push_back(data);
442  gnat.size_++;
443  if (needToSplit(gnat))
444  {
445  if (gnat.removed_.size() > 0)
446  gnat.rebuildDataStructure();
447  else if (gnat.size_ >= gnat.rebuildSize_)
448  {
449  gnat.rebuildSize_ <<= 1;
450  gnat.rebuildDataStructure();
451  }
452  else
453  split(gnat);
454  }
455  }
456  else
457  {
458  double minDist = children_[0]->distToPivot_ = gnat.distFun_(data, children_[0]->pivot_);
459  int minInd = 0;
460 
461  for (unsigned int i=1; i<children_.size(); ++i)
462  if ((children_[i]->distToPivot_ = gnat.distFun_(data, children_[i]->pivot_)) < minDist)
463  {
464  minDist = children_[i]->distToPivot_;
465  minInd = i;
466  }
467  for (unsigned int i=0; i<children_.size(); ++i)
468  children_[i]->updateRange(minInd, children_[i]->distToPivot_);
469  children_[minInd]->updateRadius(minDist);
470  children_[minInd]->add(gnat, data);
471  }
472  }
474  bool needToSplit(const GNAT &gnat) const
475  {
476  unsigned int sz = data_.size();
477  return sz > gnat.maxNumPtsPerLeaf_ && sz > degree_;
478  }
482  void split(GNAT &gnat)
483  {
484  typename GreedyKCenters<_T>::Matrix &dists = gnat.distances_;
485  std::vector<unsigned int>& pivots = gnat.pivots_;
486 
487  children_.reserve(degree_);
488  gnat.pivotSelector_.kcenters(data_, degree_, pivots, dists);
489  for(unsigned int i=0; i<pivots.size(); i++)
490  children_.push_back(new Node(degree_, gnat.maxNumPtsPerLeaf_, data_[pivots[i]]));
491  degree_ = pivots.size(); // in case fewer than degree_ pivots were found
492  for (unsigned int j=0; j<data_.size(); ++j)
493  {
494  unsigned int k = 0;
495  for (unsigned int i=1; i<degree_; ++i)
496  if (dists(j, i) < dists(j, k))
497  k = i;
498  Node *child = children_[k];
499  if (j != pivots[k])
500  {
501  child->data_.push_back(data_[j]);
502  child->updateRadius(dists(j, k));
503  }
504  for (unsigned int i=0; i<degree_; ++i)
505  children_[i]->updateRange(k, dists(j, i));
506  }
507 
508  for (unsigned int i=0; i<degree_; ++i)
509  {
510  // make sure degree lies between minDegree_ and maxDegree_
511  children_[i]->degree_ = std::min(std::max(
512  (unsigned int) ((degree_ * children_[i]->data_.size()) / data_.size()),
513  gnat.minDegree_), gnat.maxDegree_);
514  // singleton
515  if (children_[i]->minRadius_ >= std::numeric_limits<double>::infinity())
516  children_[i]->minRadius_ = children_[i]->maxRadius_ = 0.;
517 #ifdef GNAT_SAMPLER
518  // set subtree size
519  children_[i]->subtreeSize_ = children_[i]->data_.size() + 1;
520 #endif
521  }
522  // this does more than clear(); it also sets capacity to 0 and frees the memory
523  std::vector<_T> tmp;
524  data_.swap(tmp);
525  // check if new leaves need to be split
526  for (unsigned int i=0; i<degree_; ++i)
527  if (children_[i]->needToSplit(gnat))
528  children_[i]->split(gnat);
529  }
530 
532  bool insertNeighborK(NearQueue &nbh, std::size_t k, const _T &data, const _T &key, double dist) const
533  {
534  if (nbh.size() < k)
535  {
536  nbh.push(std::make_pair(&data, dist));
537  return true;
538  }
539  else if (dist < nbh.top().second ||
540  (dist < std::numeric_limits<double>::epsilon() && data==key))
541  {
542  nbh.pop();
543  nbh.push(std::make_pair(&data, dist));
544  return true;
545  }
546  return false;
547  }
548 
553  void nearestK(const GNAT& gnat, const _T &data, std::size_t k,
554  bool &isPivot) const
555  {
556  NearQueue& nbh = gnat.nearQueue_;
557  for (unsigned int i=0; i<data_.size(); ++i)
558  if (!gnat.isRemoved(data_[i]))
559  {
560  if (insertNeighborK(nbh, k, data_[i], data, gnat.distFun_(data, data_[i])))
561  isPivot = false;
562  }
563  if (children_.size() > 0)
564  {
565  double dist;
566  Node *child;
567  Permutation& permutation = gnat.permutation_;
568  permutation.permute(children_.size());
569 
570  for (unsigned int i=0; i<children_.size(); ++i)
571  if (permutation[i] >= 0)
572  {
573  child = children_[permutation[i]];
574  child->distToPivot_ = gnat.distFun_(data, child->pivot_);
575  if (insertNeighborK(nbh, k, child->pivot_, data, child->distToPivot_))
576  isPivot = true;
577  if (nbh.size()==k)
578  {
579  dist = nbh.top().second; // note difference with nearestR
580  for (unsigned int j=0; j<children_.size(); ++j)
581  if (permutation[j] >=0 && i != j &&
582  (child->distToPivot_ - dist > child->maxRange_[permutation[j]] ||
583  child->distToPivot_ + dist < child->minRange_[permutation[j]]))
584  permutation[j] = -1;
585  }
586  }
587 
588  dist = nbh.top().second;
589  for (unsigned int i=0; i<children_.size(); ++i)
590  if (permutation[i] >= 0)
591  {
592  child = children_[permutation[i]];
593  if (nbh.size()<k ||
594  (child->distToPivot_ - dist <= child->maxRadius_ &&
595  child->distToPivot_ + dist >= child->minRadius_))
596  gnat.nodeQueue_.push(child);
597  }
598  }
599  }
601  void insertNeighborR(NearQueue &nbh, double r, const _T &data, double dist) const
602  {
603  if (dist <= r)
604  nbh.push(std::make_pair(&data, dist));
605  }
607  void nearestR(const GNAT &gnat, const _T &data, double r) const
608  {
609  NearQueue& nbh = gnat.nearQueue_;
610  double dist = r; //note difference with nearestK
611 
612  for (unsigned int i=0; i<data_.size(); ++i)
613  if (!gnat.isRemoved(data_[i]))
614  insertNeighborR(nbh, r, data_[i], gnat.distFun_(data, data_[i]));
615  if (children_.size() > 0)
616  {
617  Node *child;
618  Permutation& permutation = gnat.permutation_;
619  permutation.permute(children_.size());
620 
621  for (unsigned int i=0; i<children_.size(); ++i)
622  if (permutation[i] >= 0)
623  {
624  child = children_[permutation[i]];
625  child->distToPivot_ = gnat.distFun_(data, child->pivot_);
626  insertNeighborR(nbh, r, child->pivot_, child->distToPivot_);
627  for (unsigned int j=0; j<children_.size(); ++j)
628  if (permutation[j] >=0 && i != j &&
629  (child->distToPivot_ - dist > child->maxRange_[permutation[j]] ||
630  child->distToPivot_ + dist < child->minRange_[permutation[j]]))
631  permutation[j] = -1;
632  }
633 
634  for (unsigned int i=0; i<children_.size(); ++i)
635  if (permutation[i] >= 0)
636  {
637  child = children_[permutation[i]];
638  if (child->distToPivot_ - dist <= child->maxRadius_ &&
639  child->distToPivot_ + dist >= child->minRadius_)
640  gnat.nodeQueue_.push(child);
641  }
642  }
643  }
644 
645 #ifdef GNAT_SAMPLER
646  double getSamplingWeight(const GNAT &gnat) const
647  {
648  double minR = std::numeric_limits<double>::max();
649  for(size_t i = 0; i<minRange_.size(); i++)
650  if(minRange_[i] < minR && minRange_[i] > 0.0)
651  minR = minRange_[i];
652  minR = std::max(minR, maxRadius_);
653  return std::pow(minR, gnat.estimatedDimension_) / (double) subtreeSize_;
654  }
655  const _T& sample(const GNAT &gnat, RNG &rng) const
656  {
657  if (children_.size() != 0)
658  {
659  if (rng.uniform01() < 1./(double) subtreeSize_)
660  return pivot_;
661  PDF<const Node*> distribution;
662  for(unsigned int i = 0; i < children_.size(); ++i)
663  distribution.add(children_[i], children_[i]->getSamplingWeight(gnat));
664  return distribution.sample(rng.uniform01())->sample(gnat, rng);
665  }
666  else
667  {
668  unsigned int i = rng.uniformInt(0, data_.size());
669  return (i==data_.size()) ? pivot_ : data_[i];
670  }
671  }
672 #endif
673 
674  void list(const GNAT &gnat, std::vector<_T> &data) const
675  {
676  if (!gnat.isRemoved(pivot_))
677  data.push_back(pivot_);
678  for (unsigned int i=0; i<data_.size(); ++i)
679  if(!gnat.isRemoved(data_[i]))
680  data.push_back(data_[i]);
681  for (unsigned int i=0; i<children_.size(); ++i)
682  children_[i]->list(gnat, data);
683  }
684 
685  friend std::ostream& operator<<(std::ostream &out, const Node &node)
686  {
687  out << "\ndegree:\t" << node.degree_;
688  out << "\nminRadius:\t" << node.minRadius_;
689  out << "\nmaxRadius:\t" << node.maxRadius_;
690  out << "\nminRange:\t";
691  for (unsigned int i=0; i<node.minRange_.size(); ++i)
692  out << node.minRange_[i] << '\t';
693  out << "\nmaxRange: ";
694  for (unsigned int i=0; i<node.maxRange_.size(); ++i)
695  out << node.maxRange_[i] << '\t';
696  out << "\npivot:\t" << node.pivot_;
697  out << "\ndata: ";
698  for (unsigned int i=0; i<node.data_.size(); ++i)
699  out << node.data_[i] << '\t';
700  out << "\nthis:\t" << &node;
701 #ifdef GNAT_SAMPLER
702  out << "\nsubtree size:\t" << node.subtreeSize_;
703  out << "\nactivity:\t" << node.activity_;
704 #endif
705  out << "\nchildren:\n";
706  for (unsigned int i=0; i<node.children_.size(); ++i)
707  out << node.children_[i] << '\t';
708  out << '\n';
709  for (unsigned int i=0; i<node.children_.size(); ++i)
710  out << *node.children_[i] << '\n';
711  return out;
712  }
713 
715  unsigned int degree_;
717  const _T pivot_;
719  double minRadius_;
721  double maxRadius_;
724  std::vector<double> minRange_;
727  std::vector<double> maxRange_;
730  std::vector<_T> data_;
733  std::vector<Node*> children_;
734 
736  mutable double distToPivot_;
737 
738 #ifdef GNAT_SAMPLER
739  unsigned int subtreeSize_;
745  int activity_;
746 #endif
747  };
748 
750  // another internal data structure is a priority queue of nodes to
751  // check next for possible nearest neighbors
752  struct NodeCompare
753  {
754  bool operator()(const Node *n0, const Node *n1) const
755  {
756  return (n0->distToPivot_ - n0->maxRadius_) > (n1->distToPivot_ - n1->maxRadius_);
757  }
758  };
759  typedef std::priority_queue<Node*, std::vector<Node*>, NodeCompare> NodeQueue;
761 
765  unsigned int degree_;
770  unsigned int minDegree_;
775  unsigned int maxDegree_;
778  unsigned int maxNumPtsPerLeaf_;
780  std::size_t size_;
783  std::size_t rebuildSize_;
787  std::size_t removedCacheSize_;
791  std::unordered_set<const _T*> removed_;
792 
796  mutable NearQueue nearQueue_;
798  mutable NodeQueue nodeQueue_;
802  mutable std::vector<unsigned int> pivots_;
806 
807 #ifdef GNAT_SAMPLER
808  double estimatedDimension_;
810 #endif
811  };
812 
813 }
814 
815 #endif
bool nearestKInternal(const _T &data, std::size_t k) const
Return in nearQueue_ the k nearest neighbors of data. For k=1, return true if the nearest neighbor is...
virtual std::size_t size() const
Get the number of elements in the datastructure.
void insertNeighborR(NearQueue &nbh, double r, const _T &data, double dist) const
Insert data in nbh if it is a near neighbor.
void permute(unsigned int n)
Create a permutation of the numbers 0, ..., n - 1.
Definition: Permutation.h:59
unsigned int minDegree_
After splitting a Node, each child Node has degree equal to the default degree times the fraction of ...
GreedyKCenters< _T > pivotSelector_
The data structure used to split data into subtrees.
void updateRange(unsigned int i, double dist)
Update minRange_[i] and maxRange_[i], given that an element was added to the i-th child of the parent...
An instance of this class can be used to greedily select a given number of representatives from a set...
void updateRadius(double dist)
Update minRadius_ and maxRadius_, given that an element was added with distance dist to the pivot...
void nearestK(const GNAT &gnat, const _T &data, std::size_t k, bool &isPivot) const
Compute the k nearest neighbors of data in the tree. For k=1, isPivot is true if the nearest neighbor...
virtual _T nearest(const _T &data) const
Get the nearest neighbor of a point.
void rebuildDataStructure()
Rebuild the internal data structure.
Permutation permutation_
Permutation of indices to process children of a node in random order.
NodeQueue nodeQueue_
Nodes yet to be processed for possible nearest neighbors.
std::size_t removedCacheSize_
Maximum number of removed elements that can be stored in the removed_ cache. If the cache is full...
virtual void setDistanceFunction(const typename NearestNeighbors< _T >::DistanceFunction &distFun)
Set the distance function to use.
unsigned int maxDegree_
After splitting a Node, each child Node has degree equal to the default degree times the fraction of ...
std::function< double(const _T &, const _T &)> DistanceFunction
The definition of a distance function.
std::vector< double > maxRange_
The i-th element in maxRange_ is the maximum distance between the pivot and any data_ element in the ...
A container that supports probabilistic sampling over weighted data.
Definition: PDF.h:48
void add(GNAT &gnat, const _T &data)
Add an element to the tree rooted at this node.
double uniform01()
Generate a random real between 0 and 1.
Definition: RandomNumbers.h:69
Node(int degree, int capacity, const _T &pivot)
Construct a node of given degree with at most capacity data elements and with given pivot...
void postprocessNearest(std::vector< _T > &nbh) const
Convert the internal data structure used for storing neighbors to the vector that NearestNeighbor API...
Random number generation. An instance of this class cannot be used by multiple threads at once (membe...
Definition: RandomNumbers.h:58
Geometric Near-neighbor Access Tree (GNAT), a data structure for nearest neighbor search...
Node * tree_
The data structure containing the elements stored in this structure.
std::vector< _T > data_
The data elements stored in this node (in addition to the pivot element). An internal node has no ele...
virtual void add(const _T &data)
Add an element to the datastructure.
bool isRemoved(const _T &data) const
Return true iff data has been marked for removal.
virtual void setDistanceFunction(const DistanceFunction &distFun)
Set the distance function to use.
std::vector< double > minRange_
The i-th element in minRange_ is the minimum distance between the pivot and any data_ element in the ...
DistanceFunction distFun_
The used distance function.
void split(GNAT &gnat)
The split operation finds pivot elements for the child nodes and moves each data element of this node...
GreedyKCenters< _T >::Matrix distances_
Matrix of distances to pivots.
bool needToSplit(const GNAT &gnat) const
Return true iff the node needs to be split into child nodes.
std::vector< Node * > children_
The child nodes of this node. By definition, only internal nodes have child nodes.
A permutation of indices into an array.
Definition: Permutation.h:50
std::unordered_set< const _T * > removed_
Cache of removed elements.
Abstract representation of a container that can perform nearest neighbors queries.
virtual bool reportsSortedResults() const
Return true if the solutions reported by this data structure are sorted, when calling nearestK / near...
The exception type for ompl.
Definition: Exception.h:47
double distToPivot_
Scratch space to store distance to pivot during nearest neighbor queries.
virtual void add(const _T &data)=0
Add an element to the datastructure.
Element * add(const _T &d, const double w)
Adds a piece of data with a given weight to the PDF. Returns a corresponding Element, which can be used to subsequently update or remove the data from the PDF.
Definition: PDF.h:97
virtual void nearestR(const _T &data, double radius, std::vector< _T > &nbh) const
Return the nearest neighbors within distance radius in sorted order.
std::size_t rebuildSize_
If size_ exceeds rebuildSize_, the tree will be rebuilt (and automatically rebalanced), and rebuildSize_ will be doubled.
virtual void nearestK(const _T &data, std::size_t k, std::vector< _T > &nbh) const
Return the k nearest neighbors in sorted order.
void nearestR(const GNAT &gnat, const _T &data, double r) const
Return all elements that are within distance r in nbh.
double maxRadius_
Maximum distance between the pivot element and the elements stored in data_.
The class used internally to define the GNAT.
std::size_t size_
Number of elements stored in the tree.
unsigned int maxNumPtsPerLeaf_
Maximum number of elements allowed to be stored in a Node before it needs to be split into several no...
boost::numeric::ublas::matrix< double > Matrix
A matrix type for storing distances between points and centers.
unsigned int degree_
The desired degree of each node.
void nearestRInternal(const _T &data, double radius) const
Return in nearQueue_ the elements that are within distance radius of data.
virtual void add(const std::vector< _T > &data)
Add a vector of points.
int uniformInt(int lower_bound, int upper_bound)
Generate a random integer within given bounds: [lower_bound, upper_bound].
Definition: RandomNumbers.h:82
virtual void list(std::vector< _T > &data) const
Get all the elements in the datastructure.
bool insertNeighborK(NearQueue &nbh, std::size_t k, const _T &data, const _T &key, double dist) const
Insert data in nbh if it is a near neighbor. Return true iff data was added to nbh.
std::vector< unsigned int > pivots_
Pivot indices within a vector of elements as selected by GreedyKCenters.
_T & sample(double r) const
Returns a piece of data from the PDF according to the input sampling value, which must be between 0 a...
Definition: PDF.h:132
double minRadius_
Minimum distance between the pivot element and the elements stored in data_.