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:
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()),
388  maxRadius_(-minRadius_), minRange_(degree, minRadius_),
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.
STL namespace.
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...
Main namespace. Contains everything in this library.
Definition: Cost.h:42
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.
friend std::ostream & operator<<(std::ostream &out, const NearestNeighborsGNATNoThreadSafety< _T > &gnat)
Print a GNAT structure (mostly useful for debugging purposes).
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_.