mlpack
rectangle_tree_impl.hpp
Go to the documentation of this file.
1 
12 #ifndef MLPACK_CORE_TREE_RECTANGLE_TREE_RECTANGLE_TREE_IMPL_HPP
13 #define MLPACK_CORE_TREE_RECTANGLE_TREE_RECTANGLE_TREE_IMPL_HPP
14 
15 // In case it wasn't included already for some reason.
16 #include "rectangle_tree.hpp"
17 
18 #include <mlpack/core/util/log.hpp>
19 
20 namespace mlpack {
21 namespace tree {
22 
23 // Build the statistics, bottom-up.
24 template<typename MetricType,
25  typename StatisticType,
26  typename MatType,
27  typename SplitType,
28  typename DescentType,
29  template<typename> class AuxiliaryInformationType>
30 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
31  AuxiliaryInformationType>::
32 BuildStatistics(RectangleTree* node)
33 {
34  // Recurse first.
35  for (size_t i = 0; i < node->NumChildren(); ++i)
36  BuildStatistics(&node->Child(i));
37 
38  // Now build the statistic.
39  node->Stat() = StatisticType(*node);
40 }
41 
42 template<typename MetricType,
43  typename StatisticType,
44  typename MatType,
45  typename SplitType,
46  typename DescentType,
47  template<typename> class AuxiliaryInformationType>
48 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
49  AuxiliaryInformationType>::
50 RectangleTree(const MatType& data,
51  const size_t maxLeafSize,
52  const size_t minLeafSize,
53  const size_t maxNumChildren,
54  const size_t minNumChildren,
55  const size_t firstDataIndex) :
56  maxNumChildren(maxNumChildren),
57  minNumChildren(minNumChildren),
58  numChildren(0),
59  children(maxNumChildren + 1), // Add one to make splitting the node simpler.
60  parent(NULL),
61  begin(0),
62  count(0),
63  numDescendants(0),
64  maxLeafSize(maxLeafSize),
65  minLeafSize(minLeafSize),
66  bound(data.n_rows),
67  parentDistance(0),
68  dataset(new MatType(data)),
69  ownsDataset(true),
70  points(maxLeafSize + 1), // Add one to make splitting the node simpler.
71  auxiliaryInfo(this)
72 {
73  // For now, just insert the points in order.
74  RectangleTree* root = this;
75 
76  for (size_t i = firstDataIndex; i < data.n_cols; ++i)
77  root->InsertPoint(i);
78 
79  // Initialize statistic recursively after tree construction is complete.
80  BuildStatistics(this);
81 }
82 
83 template<typename MetricType,
84  typename StatisticType,
85  typename MatType,
86  typename SplitType,
87  typename DescentType,
88  template<typename> class AuxiliaryInformationType>
89 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
90  AuxiliaryInformationType>::
91 RectangleTree(MatType&& data,
92  const size_t maxLeafSize,
93  const size_t minLeafSize,
94  const size_t maxNumChildren,
95  const size_t minNumChildren,
96  const size_t firstDataIndex) :
97  maxNumChildren(maxNumChildren),
98  minNumChildren(minNumChildren),
99  numChildren(0),
100  children(maxNumChildren + 1), // Add one to make splitting the node simpler.
101  parent(NULL),
102  begin(0),
103  count(0),
104  numDescendants(0),
105  maxLeafSize(maxLeafSize),
106  minLeafSize(minLeafSize),
107  bound(data.n_rows),
108  parentDistance(0),
109  dataset(new MatType(std::move(data))),
110  ownsDataset(true),
111  points(maxLeafSize + 1), // Add one to make splitting the node simpler.
112  auxiliaryInfo(this)
113 {
114  // For now, just insert the points in order.
115  RectangleTree* root = this;
116 
117  for (size_t i = firstDataIndex; i < dataset->n_cols; ++i)
118  root->InsertPoint(i);
119 
120  // Initialize statistic recursively after tree construction is complete.
121  BuildStatistics(this);
122 }
123 
124 template<typename MetricType,
125  typename StatisticType,
126  typename MatType,
127  typename SplitType,
128  typename DescentType,
129  template<typename> class AuxiliaryInformationType>
130 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
131  AuxiliaryInformationType>::
133  RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
134  AuxiliaryInformationType>*
135  parentNode, const size_t numMaxChildren) :
136  maxNumChildren(numMaxChildren > 0 ? numMaxChildren :
137  parentNode->MaxNumChildren()),
138  minNumChildren(parentNode->MinNumChildren()),
139  numChildren(0),
140  children(maxNumChildren + 1),
141  parent(parentNode),
142  begin(0),
143  count(0),
144  numDescendants(0),
145  maxLeafSize(parentNode->MaxLeafSize()),
146  minLeafSize(parentNode->MinLeafSize()),
147  bound(parentNode->Bound().Dim()),
148  parentDistance(0),
149  dataset(&parentNode->Dataset()),
150  ownsDataset(false),
151  points(maxLeafSize + 1), // Add one to make splitting the node simpler.
152  auxiliaryInfo(this)
153 {
154  // Initialize statistic.
155  BuildStatistics(this);
156 }
157 
162 template<typename MetricType,
163  typename StatisticType,
164  typename MatType,
165  typename SplitType,
166  typename DescentType,
167  template<typename> class AuxiliaryInformationType>
168 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
169  AuxiliaryInformationType>::
171  const RectangleTree& other,
172  const bool deepCopy,
173  RectangleTree* newParent) :
174  maxNumChildren(other.MaxNumChildren()),
175  minNumChildren(other.MinNumChildren()),
176  numChildren(other.NumChildren()),
177  children(maxNumChildren + 1, NULL),
178  parent(deepCopy ? newParent : other.Parent()),
179  begin(other.Begin()),
180  count(other.Count()),
181  numDescendants(other.numDescendants),
182  maxLeafSize(other.MaxLeafSize()),
183  minLeafSize(other.MinLeafSize()),
184  bound(other.bound),
185  stat(other.stat),
186  parentDistance(other.ParentDistance()),
187  dataset(deepCopy ?
188  (parent ? parent->dataset : new MatType(*other.dataset)) :
189  &other.Dataset()),
190  ownsDataset(deepCopy && (!parent)),
191  points(other.points),
192  auxiliaryInfo(other.auxiliaryInfo, this, deepCopy)
193 {
194  if (deepCopy)
195  {
196  if (numChildren > 0)
197  {
198  for (size_t i = 0; i < numChildren; ++i)
199  children[i] = new RectangleTree(other.Child(i), true, this);
200  }
201  }
202  else
203  children = other.children;
204 }
205 
209 template<typename MetricType,
210  typename StatisticType,
211  typename MatType,
212  typename SplitType,
213  typename DescentType,
214  template<typename> class AuxiliaryInformationType>
215 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
216  AuxiliaryInformationType>::
218  maxNumChildren(other.MaxNumChildren()),
219  minNumChildren(other.MinNumChildren()),
220  numChildren(other.NumChildren()),
221  children(std::move(other.children)),
222  parent(other.Parent()),
223  begin(other.Begin()),
224  count(other.Count()),
225  numDescendants(other.numDescendants),
226  maxLeafSize(other.MaxLeafSize()),
227  minLeafSize(other.MinLeafSize()),
228  bound(std::move(other.bound)),
229  stat(std::move(other.stat)),
230  parentDistance(other.ParentDistance()),
231  dataset(other.dataset),
232  ownsDataset(other.ownsDataset),
233  points(std::move(other.points)),
234  auxiliaryInfo(std::move(other.auxiliaryInfo))
235 {
236  if (parent)
237  {
238  size_t iChild = 0;
239  while (parent->children[iChild] != (&other))
240  iChild++;
241  assert(iChild < numChildren);
242  parent->children[iChild] = this;
243  }
244  if (!IsLeaf())
245  {
246  for (size_t i = 0; i < numChildren; ++i)
247  children[i]->parent = this;
248  }
249  // Now we are a clone of the other tree. But we must also clear the other
250  // tree's contents, so it doesn't delete anything when it is destructed.
251  other.maxNumChildren = 0;
252  other.minNumChildren = 0;
253  other.numChildren = 0;
254  other.parent = NULL;
255  other.begin = 0;
256  other.count = 0;
257  other.numDescendants = 0;
258  other.maxLeafSize = 0;
259  other.minLeafSize = 0;
260  other.parentDistance = 0;
261  other.dataset = NULL;
262  other.ownsDataset = false;
263 }
264 
268 template<typename MetricType,
269  typename StatisticType,
270  typename MatType,
271  typename SplitType,
272  typename DescentType,
273  template<typename> class AuxiliaryInformationType>
274 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
275  AuxiliaryInformationType>&
276 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
277  AuxiliaryInformationType>::
278 operator=(const RectangleTree& other)
279 {
280  // Return if it's the same tree.
281  if (this == &other)
282  return *this;
283 
284  // Freeing memory that will not be used anymore.
285  for (size_t i = 0; i < numChildren; ++i)
286  delete children[i];
287 
288  if (ownsDataset)
289  delete dataset;
290 
291  maxNumChildren = other.MaxNumChildren();
292  minNumChildren = other.MinNumChildren();
293  numChildren = other.NumChildren();
294  children.resize(maxNumChildren + 1, NULL);
295  parent = NULL;
296  begin = other.Begin();
297  count = other.Count();
298  numDescendants = other.numDescendants;
299  maxLeafSize = other.MaxLeafSize();
300  minLeafSize = other.MinLeafSize();
301  bound = other.bound;
302  stat = other.stat;
303  parentDistance = other.ParentDistance();
304  dataset = new MatType(*other.dataset);
305  ownsDataset = true;
306  points = other.points;
307  auxiliaryInfo = AuxiliaryInfoType(other.auxiliaryInfo, this, true);
308 
309  if (numChildren > 0)
310  {
311  for (size_t i = 0; i < numChildren; ++i)
312  children[i] = new RectangleTree(other.Child(i), true, this);
313  }
314 
315  return *this;
316 }
317 
321 template<typename MetricType,
322  typename StatisticType,
323  typename MatType,
324  typename SplitType,
325  typename DescentType,
326  template<typename> class AuxiliaryInformationType>
327 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
328  AuxiliaryInformationType>&
329 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
330  AuxiliaryInformationType>::
331 operator=(RectangleTree&& other)
332 {
333  // Return if it's the same tree.
334  if (this == &other)
335  return *this;
336 
337  // Freeing memory that will not be used anymore.
338  for (size_t i = 0; i < numChildren; ++i)
339  delete children[i];
340 
341  if (ownsDataset)
342  delete dataset;
343 
344  maxNumChildren = other.MaxNumChildren();
345  minNumChildren = other.MinNumChildren();
346  numChildren = other.NumChildren();
347  children = std::move(other.children);
348  parent = other.Parent();
349  begin = other.Begin();
350  count = other.Count();
351  numDescendants = other.numDescendants;
352  maxLeafSize = other.MaxLeafSize();
353  minLeafSize = other.MinLeafSize();
354  bound = std::move(other.bound);
355  stat = std::move(other.stat);
356  parentDistance = other.ParentDistance();
357  dataset = other.dataset;
358  ownsDataset = other.ownsDataset;
359  points = std::move(other.points);
360  auxiliaryInfo = std::move(other.auxiliaryInfo);
361 
362  // Now we are a clone of the other tree. But we must also clear the other
363  // tree's contents, so it doesn't delete anything when it is destructed.
364  other.maxNumChildren = 0;
365  other.minNumChildren = 0;
366  other.numChildren = 0;
367  other.parent = NULL;
368  other.begin = 0;
369  other.count = 0;
370  other.numDescendants = 0;
371  other.maxLeafSize = 0;
372  other.minLeafSize = 0;
373  other.parentDistance = 0;
374  other.dataset = NULL;
375  other.ownsDataset = false;
376 
377  return *this;
378 }
379 
383 template<typename MetricType,
384  typename StatisticType,
385  typename MatType,
386  typename SplitType,
387  typename DescentType,
388  template<typename> class AuxiliaryInformationType>
389 template<typename Archive>
390 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
391  AuxiliaryInformationType>::
393  Archive& ar,
394  const typename std::enable_if_t<cereal::is_loading<Archive>()>*) :
395  RectangleTree() // Use default constructor.
396 {
397  // Now serialize.
398  ar(CEREAL_NVP(*this));
399 }
400 
406 template<typename MetricType,
407  typename StatisticType,
408  typename MatType,
409  typename SplitType,
410  typename DescentType,
411  template<typename> class AuxiliaryInformationType>
412 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
413  AuxiliaryInformationType>::
415 {
416  for (size_t i = 0; i < numChildren; ++i)
417  delete children[i];
418 
419  if (ownsDataset)
420  delete dataset;
421 }
422 
427 template<typename MetricType,
428  typename StatisticType,
429  typename MatType,
430  typename SplitType,
431  typename DescentType,
432  template<typename> class AuxiliaryInformationType>
433 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
434  AuxiliaryInformationType>::
436 {
437  parent = NULL;
438 
439  for (size_t i = 0; i < children.size(); ++i)
440  children[i] = NULL;
441 
442  numChildren = 0;
443  delete this;
444 }
445 
449 template<typename MetricType,
450  typename StatisticType,
451  typename MatType,
452  typename SplitType,
453  typename DescentType,
454  template<typename> class AuxiliaryInformationType>
455 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
456  AuxiliaryInformationType>::
458 {
459  auxiliaryInfo.NullifyData();
460 }
461 
466 template<typename MetricType,
467  typename StatisticType,
468  typename MatType,
469  typename SplitType,
470  typename DescentType,
471  template<typename> class AuxiliaryInformationType>
472 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
473  AuxiliaryInformationType>::
474  InsertPoint(const size_t point)
475 {
476  // Expand the bound regardless of whether it is a leaf node.
477  bound |= dataset->col(point);
478 
479  numDescendants++;
480 
481  std::vector<bool> lvls(TreeDepth(), true);
482 
483  // If this is a leaf node, we stop here and add the point.
484  if (numChildren == 0)
485  {
486  if (!auxiliaryInfo.HandlePointInsertion(this, point))
487  points[count++] = point;
488 
489  SplitNode(lvls);
490  return;
491  }
492 
493  // If it is not a leaf node, we use the DescentHeuristic to choose a child
494  // to which we recurse.
495  auxiliaryInfo.HandlePointInsertion(this, point);
496  const size_t descentNode = DescentType::ChooseDescentNode(this, point);
497  children[descentNode]->InsertPoint(point, lvls);
498 }
499 
503 template<typename MetricType,
504  typename StatisticType,
505  typename MatType,
506  typename SplitType,
507  typename DescentType,
508  template<typename> class AuxiliaryInformationType>
509 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
510  AuxiliaryInformationType>::
511  InsertPoint(const size_t point, std::vector<bool>& relevels)
512 {
513  // Expand the bound regardless of whether it is a leaf node.
514  bound |= dataset->col(point);
515 
516  numDescendants++;
517 
518  // If this is a leaf node, we stop here and add the point.
519  if (numChildren == 0)
520  {
521  if (!auxiliaryInfo.HandlePointInsertion(this, point))
522  points[count++] = point;
523 
524  SplitNode(relevels);
525  return;
526  }
527 
528  // If it is not a leaf node, we use the DescentHeuristic to choose a child
529  // to which we recurse.
530  auxiliaryInfo.HandlePointInsertion(this, point);
531  const size_t descentNode = DescentType::ChooseDescentNode(this, point);
532  children[descentNode]->InsertPoint(point, relevels);
533 }
534 
543 template<typename MetricType,
544  typename StatisticType,
545  typename MatType,
546  typename SplitType,
547  typename DescentType,
548  template<typename> class AuxiliaryInformationType>
549 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
550  AuxiliaryInformationType>::
552  const size_t level,
553  std::vector<bool>& relevels)
554 {
555  // Expand the bound regardless of the level.
556  bound |= node->Bound();
557  numDescendants += node->numDescendants;
558  if (level == TreeDepth())
559  {
560  if (!auxiliaryInfo.HandleNodeInsertion(this, node, true))
561  {
562  children[numChildren++] = node;
563  node->Parent() = this;
564  }
565  SplitNode(relevels);
566  }
567  else
568  {
569  auxiliaryInfo.HandleNodeInsertion(this, node, false);
570  const size_t descentNode = DescentType::ChooseDescentNode(this, node);
571  children[descentNode]->InsertNode(node, level, relevels);
572  }
573 }
574 
579 template<typename MetricType,
580  typename StatisticType,
581  typename MatType,
582  typename SplitType,
583  typename DescentType,
584  template<typename> class AuxiliaryInformationType>
585 bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
586  AuxiliaryInformationType>::
587  DeletePoint(const size_t point)
588 {
589  // It is possible that this will cause a reinsertion, so we need to handle the
590  // levels properly.
591  RectangleTree* root = this;
592  while (root->Parent() != NULL)
593  root = root->Parent();
594 
595  std::vector<bool> lvls(root->TreeDepth(), true);
596 
597  if (numChildren == 0)
598  {
599  for (size_t i = 0; i < count; ++i)
600  {
601  if (points[i] == point)
602  {
603  if (!auxiliaryInfo.HandlePointDeletion(this, i))
604  points[i] = points[--count];
605 
606  RectangleTree* tree = this;
607  while (tree != NULL)
608  {
609  tree->numDescendants--;
610  tree = tree->Parent();
611  }
612  // This function wil ensure that minFill is satisfied.
613  CondenseTree(dataset->col(point), lvls, true);
614  return true;
615  }
616  }
617  }
618 
619  for (size_t i = 0; i < numChildren; ++i)
620  if (children[i]->Bound().Contains(dataset->col(point)))
621  if (children[i]->DeletePoint(point, lvls))
622  return true;
623 
624  return false;
625 }
626 
631 template<typename MetricType,
632  typename StatisticType,
633  typename MatType,
634  typename SplitType,
635  typename DescentType,
636  template<typename> class AuxiliaryInformationType>
637 bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
638  AuxiliaryInformationType>::
639  DeletePoint(const size_t point, std::vector<bool>& relevels)
640 {
641  if (numChildren == 0)
642  {
643  for (size_t i = 0; i < count; ++i)
644  {
645  if (points[i] == point)
646  {
647  if (!auxiliaryInfo.HandlePointDeletion(this, i))
648  points[i] = points[--count];
649 
650  RectangleTree* tree = this;
651  while (tree != NULL)
652  {
653  tree->numDescendants--;
654  tree = tree->Parent();
655  }
656  // This function will ensure that minFill is satisfied.
657  CondenseTree(dataset->col(point), relevels, true);
658  return true;
659  }
660  }
661  }
662 
663  for (size_t i = 0; i < numChildren; ++i)
664  if (children[i]->Bound().Contains(dataset->col(point)))
665  if (children[i]->DeletePoint(point, relevels))
666  return true;
667 
668  return false;
669 }
670 
671 
676 template<typename MetricType,
677  typename StatisticType,
678  typename MatType,
679  typename SplitType,
680  typename DescentType,
681  template<typename> class AuxiliaryInformationType>
682 bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
683  AuxiliaryInformationType>::
684  RemoveNode(const RectangleTree* node, std::vector<bool>& relevels)
685 {
686  for (size_t i = 0; i < numChildren; ++i)
687  {
688  if (children[i] == node)
689  {
690  if (!auxiliaryInfo.HandleNodeRemoval(this, i))
691  {
692  children[i] = children[--numChildren]; // Decrement numChildren.
693  }
694  RectangleTree* tree = this;
695  while (tree != NULL)
696  {
697  tree->numDescendants -= node->numDescendants;
698  tree = tree->Parent();
699  }
700  CondenseTree(arma::vec(), relevels, false);
701  return true;
702  }
703 
704  bool contains = true;
705  for (size_t j = 0; j < node->Bound().Dim(); ++j)
706  contains &= Child(i).Bound()[j].Contains(node->Bound()[j]);
707 
708  if (contains)
709  if (children[i]->RemoveNode(node, relevels))
710  return true;
711  }
712 
713  return false;
714 }
715 
716 template<typename MetricType,
717  typename StatisticType,
718  typename MatType,
719  typename SplitType,
720  typename DescentType,
721  template<typename> class AuxiliaryInformationType>
722 size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
723  DescentType, AuxiliaryInformationType>::TreeSize() const
724 {
725  int n = 0;
726  for (int i = 0; i < numChildren; ++i)
727  n += children[i]->TreeSize();
728 
729  return n + 1; // Add one for this node.
730 }
731 
732 template<typename MetricType,
733  typename StatisticType,
734  typename MatType,
735  typename SplitType,
736  typename DescentType,
737  template<typename> class AuxiliaryInformationType>
738 size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
739  DescentType, AuxiliaryInformationType>::TreeDepth() const
740 {
741  int n = 1;
742  RectangleTree* currentNode = const_cast<RectangleTree*> (this);
743 
744  while (!currentNode->IsLeaf())
745  {
746  currentNode = currentNode->children[0];
747  n++;
748  }
749 
750  return n;
751 }
752 
753 template<typename MetricType,
754  typename StatisticType,
755  typename MatType,
756  typename SplitType,
757  typename DescentType,
758  template<typename> class AuxiliaryInformationType>
759 inline bool RectangleTree<MetricType, StatisticType, MatType, SplitType,
760  DescentType, AuxiliaryInformationType>::IsLeaf() const
761 {
762  return (numChildren == 0);
763 }
764 
769 template<typename MetricType,
770  typename StatisticType,
771  typename MatType,
772  typename SplitType,
773  typename DescentType,
774  template<typename> class AuxiliaryInformationType>
775 template<typename VecType>
776 size_t RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
777  AuxiliaryInformationType>::GetNearestChild(
778  const VecType& point,
779  typename std::enable_if_t<IsVector<VecType>::value>*)
780 {
781  if (IsLeaf())
782  return 0;
783 
784  ElemType bestDistance = std::numeric_limits<ElemType>::max();
785  size_t bestIndex = 0;
786  for (size_t i = 0; i < NumChildren(); ++i)
787  {
788  ElemType distance = Child(i).MinDistance(point);
789  if (distance <= bestDistance)
790  {
791  bestDistance = distance;
792  bestIndex = i;
793  }
794  }
795  return bestIndex;
796 }
797 
802 template<typename MetricType,
803  typename StatisticType,
804  typename MatType,
805  typename SplitType,
806  typename DescentType,
807  template<typename> class AuxiliaryInformationType>
808 template<typename VecType>
809 size_t RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
810  AuxiliaryInformationType>::GetFurthestChild(
811  const VecType& point,
812  typename std::enable_if_t<IsVector<VecType>::value>*)
813 {
814  if (IsLeaf())
815  return 0;
816 
817  ElemType bestDistance = 0;
818  size_t bestIndex = 0;
819  for (size_t i = 0; i < NumChildren(); ++i)
820  {
821  ElemType distance = Child(i).MaxDistance(point);
822  if (distance >= bestDistance)
823  {
824  bestDistance = distance;
825  bestIndex = i;
826  }
827  }
828  return bestIndex;
829 }
830 
835 template<typename MetricType,
836  typename StatisticType,
837  typename MatType,
838  typename SplitType,
839  typename DescentType,
840  template<typename> class AuxiliaryInformationType>
841 size_t RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
842  AuxiliaryInformationType>::GetNearestChild(const RectangleTree& queryNode)
843 {
844  if (IsLeaf())
845  return 0;
846 
847  ElemType bestDistance = std::numeric_limits<ElemType>::max();
848  size_t bestIndex = 0;
849  for (size_t i = 0; i < NumChildren(); ++i)
850  {
851  ElemType distance = Child(i).MinDistance(queryNode);
852  if (distance <= bestDistance)
853  {
854  bestDistance = distance;
855  bestIndex = i;
856  }
857  }
858  return bestIndex;
859 }
860 
865 template<typename MetricType,
866  typename StatisticType,
867  typename MatType,
868  typename SplitType,
869  typename DescentType,
870  template<typename> class AuxiliaryInformationType>
871 size_t RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
872  AuxiliaryInformationType>::GetFurthestChild(const RectangleTree& queryNode)
873 {
874  if (IsLeaf())
875  return 0;
876 
877  ElemType bestDistance = 0;
878  size_t bestIndex = 0;
879  for (size_t i = 0; i < NumChildren(); ++i)
880  {
881  ElemType distance = Child(i).MaxDistance(queryNode);
882  if (distance >= bestDistance)
883  {
884  bestDistance = distance;
885  bestIndex = i;
886  }
887  }
888  return bestIndex;
889 }
890 
895 template<typename MetricType,
896  typename StatisticType,
897  typename MatType,
898  typename SplitType,
899  typename DescentType,
900  template<typename> class AuxiliaryInformationType>
901 inline
902 typename RectangleTree<MetricType, StatisticType, MatType, SplitType,
903  DescentType, AuxiliaryInformationType>::ElemType
904 RectangleTree<MetricType, StatisticType, MatType, SplitType,
905  DescentType, AuxiliaryInformationType>::FurthestPointDistance() const
906 {
907  if (!IsLeaf())
908  return 0.0;
909 
910  // Otherwise return the distance from the centroid to a corner of the bound.
911  return 0.5 * bound.Diameter();
912 }
913 
921 template<typename MetricType,
922  typename StatisticType,
923  typename MatType,
924  typename SplitType,
925  typename DescentType,
926  template<typename> class AuxiliaryInformationType>
927 inline
928 typename RectangleTree<MetricType, StatisticType, MatType, SplitType,
929  DescentType, AuxiliaryInformationType>::ElemType
930 RectangleTree<MetricType, StatisticType, MatType, SplitType,
931  DescentType, AuxiliaryInformationType>::FurthestDescendantDistance() const
932 {
933  // Return the distance from the centroid to a corner of the bound.
934  return 0.5 * bound.Diameter();
935 }
936 
941 template<typename MetricType,
942  typename StatisticType,
943  typename MatType,
944  typename SplitType,
945  typename DescentType,
946  template<typename> class AuxiliaryInformationType>
947 inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
948  DescentType, AuxiliaryInformationType>::NumPoints() const
949 {
950  if (numChildren != 0) // This is not a leaf node.
951  return 0;
952 
953  return count;
954 }
955 
959 template<typename MetricType,
960  typename StatisticType,
961  typename MatType,
962  typename SplitType,
963  typename DescentType,
964  template<typename> class AuxiliaryInformationType>
965 inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
966  DescentType, AuxiliaryInformationType>::NumDescendants() const
967 {
968  return numDescendants;
969 }
970 
974 template<typename MetricType,
975  typename StatisticType,
976  typename MatType,
977  typename SplitType,
978  typename DescentType,
979  template<typename> class AuxiliaryInformationType>
980 inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
981  DescentType, AuxiliaryInformationType>::Descendant(const size_t index) const
982 {
983  // I think this may be inefficient...
984  if (numChildren == 0)
985  {
986  return (points[index]);
987  }
988  else
989  {
990  size_t n = 0;
991  for (size_t i = 0; i < numChildren; ++i)
992  {
993  const size_t nd = children[i]->NumDescendants();
994  if (index - n < nd)
995  return children[i]->Descendant(index - n);
996  n += nd;
997  }
998 
999  // I don't think this is valid.
1000  return children[numChildren - 1]->Descendant(index - n);
1001  }
1002 }
1003 
1008 template<typename MetricType,
1009  typename StatisticType,
1010  typename MatType,
1011  typename SplitType,
1012  typename DescentType,
1013  template<typename> class AuxiliaryInformationType>
1014 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
1015  AuxiliaryInformationType>::
1016  SplitNode(std::vector<bool>& relevels)
1017 {
1018  if (numChildren == 0)
1019  {
1020  // We let the SplitType check if the node if overflowed
1021  // since an intermediate node of the R+ tree may be overflowed if the leaf
1022  // node contains only one point.
1023 
1024  // The SplitType takes care of this and of moving up the tree if necessary.
1025  SplitType::SplitLeafNode(this, relevels);
1026  }
1027  else
1028  {
1029  // Check to see if we are full.
1030  if (numChildren <= maxNumChildren)
1031  return; // We don't need to split.
1032 
1033  // If we are full, then we need to split (or at least try). The SplitType
1034  // takes care of this and of moving up the tree if necessary.
1035  SplitType::SplitNonLeafNode(this, relevels);
1036  }
1037 }
1038 
1040 template<typename MetricType,
1041  typename StatisticType,
1042  typename MatType,
1043  typename SplitType,
1044  typename DescentType,
1045  template<typename> class AuxiliaryInformationType>
1046 RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
1047  AuxiliaryInformationType>::
1049  maxNumChildren(0), // Try to give sensible defaults, but it shouldn't matter
1050  minNumChildren(0), // because this tree isn't valid anyway and is only used
1051  numChildren(0), // by cereal.
1052  parent(NULL),
1053  begin(0),
1054  count(0),
1055  numDescendants(0),
1056  maxLeafSize(0),
1057  minLeafSize(0),
1058  parentDistance(0.0),
1059  dataset(NULL),
1060  ownsDataset(false)
1061 {
1062  // Nothing to do.
1063 }
1064 
1069 template<typename MetricType,
1070  typename StatisticType,
1071  typename MatType,
1072  typename SplitType,
1073  typename DescentType,
1074  template<typename> class AuxiliaryInformationType>
1075 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
1076  AuxiliaryInformationType>::
1077  CondenseTree(const arma::vec& point,
1078  std::vector<bool>& relevels,
1079  const bool usePoint)
1080 {
1081  // First delete the node if we need to. There's no point in shrinking the
1082  // bound first.
1083  if (IsLeaf() && count < minLeafSize && parent != NULL)
1084  {
1085  // We can't delete the root node.
1086  for (size_t i = 0; i < parent->NumChildren(); ++i)
1087  {
1088  if (parent->children[i] == this)
1089  {
1090  // Decrement numChildren.
1091  if (!auxiliaryInfo.HandleNodeRemoval(parent, i))
1092  {
1093  parent->children[i] = parent->children[--parent->NumChildren()];
1094  }
1095 
1096  // We find the root and shrink bounds at the same time.
1097  bool stillShrinking = true;
1098  RectangleTree* root = parent;
1099  while (root->Parent() != NULL)
1100  {
1101  if (stillShrinking)
1102  stillShrinking = root->ShrinkBoundForBound(bound);
1103  root = root->Parent();
1104  }
1105  if (stillShrinking)
1106  root->ShrinkBoundForBound(bound);
1107 
1108  root = parent;
1109  while (root != NULL)
1110  {
1111  root->numDescendants -= numDescendants;
1112  root = root->Parent();
1113  }
1114 
1115  stillShrinking = true;
1116  root = parent;
1117  while (root->Parent() != NULL)
1118  {
1119  if (stillShrinking)
1120  stillShrinking = root->AuxiliaryInfo().UpdateAuxiliaryInfo(root);
1121  root = root->Parent();
1122  }
1123  if (stillShrinking)
1124  root->AuxiliaryInfo().UpdateAuxiliaryInfo(root);
1125 
1126  // Reinsert the points at the root node.
1127  for (size_t j = 0; j < count; ++j)
1128  root->InsertPoint(points[j], relevels);
1129 
1130  // This will check the minFill of the parent.
1131  parent->CondenseTree(point, relevels, usePoint);
1132  // Now it should be safe to delete this node.
1133  SoftDelete();
1134 
1135  return;
1136  }
1137  }
1138  // Control should never reach here.
1139  assert(false);
1140  }
1141  else if (!IsLeaf() && numChildren < minNumChildren)
1142  {
1143  if (parent != NULL)
1144  {
1145  // The normal case. We need to be careful with the root.
1146  for (size_t j = 0; j < parent->NumChildren(); ++j)
1147  {
1148  if (parent->children[j] == this)
1149  {
1150  // Decrement numChildren.
1151  if (!auxiliaryInfo.HandleNodeRemoval(parent, j))
1152  {
1153  parent->children[j] = parent->children[--parent->NumChildren()];
1154  }
1155  size_t level = TreeDepth();
1156 
1157  // We find the root and shrink bounds at the same time.
1158  bool stillShrinking = true;
1159  RectangleTree* root = parent;
1160  while (root->Parent() != NULL)
1161  {
1162  if (stillShrinking)
1163  stillShrinking = root->ShrinkBoundForBound(bound);
1164  root = root->Parent();
1165  }
1166  if (stillShrinking)
1167  root->ShrinkBoundForBound(bound);
1168 
1169  root = parent;
1170  while (root != NULL)
1171  {
1172  root->numDescendants -= numDescendants;
1173  root = root->Parent();
1174  }
1175 
1176  stillShrinking = true;
1177  root = parent;
1178  while (root->Parent() != NULL)
1179  {
1180  if (stillShrinking)
1181  stillShrinking = root->AuxiliaryInfo().UpdateAuxiliaryInfo(root);
1182  root = root->Parent();
1183  }
1184  if (stillShrinking)
1185  root->AuxiliaryInfo().UpdateAuxiliaryInfo(root);
1186 
1187  // Reinsert the nodes at the root node.
1188  for (size_t i = 0; i < numChildren; ++i)
1189  root->InsertNode(children[i], level, relevels);
1190 
1191  // This will check the minFill of the point.
1192  parent->CondenseTree(point, relevels, usePoint);
1193  // Now it should be safe to delete this node.
1194  SoftDelete();
1195 
1196  return;
1197  }
1198  }
1199  }
1200  else if (numChildren == 1)
1201  {
1202  // If there are multiple children, we can't do anything to the root.
1203  RectangleTree* child = children[0];
1204 
1205  // Required for the X tree.
1206  if (child->NumChildren() > maxNumChildren)
1207  {
1208  maxNumChildren = child->MaxNumChildren();
1209  children.resize(maxNumChildren + 1);
1210  }
1211 
1212  for (size_t i = 0; i < child->NumChildren(); ++i)
1213  {
1214  children[i] = child->children[i];
1215  children[i]->Parent() = this;
1216  child->children[i] = NULL;
1217  }
1218 
1219  numChildren = child->NumChildren();
1220  child->NumChildren() = 0;
1221 
1222  for (size_t i = 0; i < child->Count(); ++i)
1223  {
1224  // In case the tree has a height of two.
1225  points[i] = child->Point(i);
1226  }
1227 
1228  auxiliaryInfo = child->AuxiliaryInfo();
1229 
1230  count = child->Count();
1231  child->Count() = 0;
1232 
1233  delete child;
1234  return;
1235  }
1236  }
1237 
1238  // If we didn't delete it, shrink the bound if we need to.
1239  if (usePoint &&
1240  (ShrinkBoundForPoint(point) || auxiliaryInfo.UpdateAuxiliaryInfo(this)) &&
1241  parent != NULL)
1242  parent->CondenseTree(point, relevels, usePoint);
1243  else if (!usePoint &&
1244  (ShrinkBoundForBound(bound) ||
1245  auxiliaryInfo.UpdateAuxiliaryInfo(this)) &&
1246  parent != NULL)
1247  parent->CondenseTree(point, relevels, usePoint);
1248 }
1249 
1253 template<typename MetricType,
1254  typename StatisticType,
1255  typename MatType,
1256  typename SplitType,
1257  typename DescentType,
1258  template<typename> class AuxiliaryInformationType>
1259 bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
1260  AuxiliaryInformationType>::
1261  ShrinkBoundForPoint(const arma::vec& point)
1262 {
1263  bool shrunk = false;
1264  if (IsLeaf())
1265  {
1266  for (size_t i = 0; i < bound.Dim(); ++i)
1267  {
1268  if (bound[i].Lo() == point[i])
1269  {
1270  ElemType min = std::numeric_limits<ElemType>::max();
1271  for (size_t j = 0; j < count; ++j)
1272  {
1273  if (dataset->col(points[j])[i] < min)
1274  min = dataset->col(points[j])[i];
1275  }
1276 
1277  if (bound[i].Lo() < min)
1278  {
1279  shrunk = true;
1280  bound[i].Lo() = min;
1281  }
1282  else if (min < bound[i].Lo())
1283  {
1284  assert(false); // We have a problem.
1285  }
1286  }
1287  else if (bound[i].Hi() == point[i])
1288  {
1289  ElemType max = std::numeric_limits<ElemType>::lowest();
1290  for (size_t j = 0; j < count; ++j)
1291  {
1292  if (dataset->col(points[j])[i] > max)
1293  max = dataset->col(points[j])[i];
1294  }
1295 
1296  if (bound[i].Hi() > max)
1297  {
1298  shrunk = true;
1299  bound[i].Hi() = max;
1300  }
1301  else if (max > bound[i].Hi())
1302  {
1303  assert(false); // We have a problem.
1304  }
1305  }
1306  }
1307  }
1308  else
1309  {
1310  for (size_t i = 0; i < bound.Dim(); ++i)
1311  {
1312  if (bound[i].Lo() == point[i])
1313  {
1314  ElemType min = std::numeric_limits<ElemType>::max();
1315  for (size_t j = 0; j < numChildren; ++j)
1316  {
1317  if (children[j]->Bound()[i].Lo() < min)
1318  min = children[j]->Bound()[i].Lo();
1319  }
1320 
1321  if (bound[i].Lo() < min)
1322  {
1323  shrunk = true;
1324  bound[i].Lo() = min;
1325  }
1326  }
1327  else if (bound[i].Hi() == point[i])
1328  {
1329  ElemType max = std::numeric_limits<ElemType>::lowest();
1330  for (size_t j = 0; j < numChildren; ++j)
1331  {
1332  if (children[j]->Bound()[i].Hi() > max)
1333  max = children[j]->Bound()[i].Hi();
1334  }
1335 
1336  if (bound[i].Hi() > max)
1337  {
1338  shrunk = true;
1339  bound[i].Hi() = max;
1340  }
1341  }
1342  }
1343  }
1344 
1345  return shrunk;
1346 }
1347 
1351 template<typename MetricType,
1352  typename StatisticType,
1353  typename MatType,
1354  typename SplitType,
1355  typename DescentType,
1356  template<typename> class AuxiliaryInformationType>
1357 bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
1358  AuxiliaryInformationType>::
1360 {
1361  // Using the sum is safe since none of the dimensions can increase.
1362  ElemType sum = 0;
1363 
1364  // I think it may be faster to just recalculate the whole thing.
1365  for (size_t i = 0; i < bound.Dim(); ++i)
1366  {
1367  sum += bound[i].Width();
1368  bound[i].Lo() = std::numeric_limits<ElemType>::max();
1369  bound[i].Hi() = std::numeric_limits<ElemType>::lowest();
1370  }
1371 
1372  for (size_t i = 0; i < numChildren; ++i)
1373  {
1374  bound |= children[i]->Bound();
1375  }
1376 
1377  ElemType sum2 = 0;
1378  for (size_t i = 0; i < bound.Dim(); ++i)
1379  sum2 += bound[i].Width();
1380 
1381  return sum != sum2;
1382 }
1383 
1387 template<typename MetricType,
1388  typename StatisticType,
1389  typename MatType,
1390  typename SplitType,
1391  typename DescentType,
1392  template<typename> class AuxiliaryInformationType>
1393 template<typename Archive>
1394 void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
1395  AuxiliaryInformationType>::serialize(
1396  Archive& ar,
1397  const uint32_t /* version */)
1398 {
1399  // Clean up memory, if necessary.
1400  if (cereal::is_loading<Archive>())
1401  {
1402  for (size_t i = 0; i < numChildren; ++i)
1403  delete children[i];
1404  children.clear();
1405 
1406  if (ownsDataset && dataset)
1407  delete dataset;
1408 
1409  parent = NULL;
1410  }
1411 
1412  bool hasParent = (parent != NULL);
1413 
1414  ar(CEREAL_NVP(maxNumChildren));
1415  ar(CEREAL_NVP(minNumChildren));
1416  ar(CEREAL_NVP(numChildren));
1417  if (cereal::is_loading<Archive>())
1418  children.resize(maxNumChildren + 1);
1419 
1420  ar(CEREAL_NVP(begin));
1421  ar(CEREAL_NVP(count));
1422  ar(CEREAL_NVP(numDescendants));
1423  ar(CEREAL_NVP(maxLeafSize));
1424  ar(CEREAL_NVP(minLeafSize));
1425  ar(CEREAL_NVP(bound));
1426  ar(CEREAL_NVP(stat));
1427  ar(CEREAL_NVP(parentDistance));
1428  ar(CEREAL_NVP(hasParent));
1429 
1430  if (!hasParent)
1431  {
1432  MatType*& datasetTemp = const_cast<MatType*&>(dataset);
1433  ar(CEREAL_POINTER(datasetTemp));
1434  }
1435 
1436  ar(CEREAL_NVP(points));
1437  ar(CEREAL_NVP(auxiliaryInfo));
1438 
1439  // Since we may or may not be holding children, we need to serialize _only_
1440  // numChildren children.
1441  for (size_t i = 0; i < numChildren; ++i)
1442  {
1443  std::ostringstream oss;
1444  oss << "children" << i;
1445  ar(CEREAL_POINTER(children[i]));
1446 
1447  if (cereal::is_loading<Archive>())
1448  children[i]->parent = this;
1449  }
1450  for (size_t i = numChildren; i < maxNumChildren + 1; ++i)
1451  {
1452  children[i] = NULL;
1453  }
1454 
1455  // If we are the root, we need to restore the dataset pointer throughout
1456  if (!hasParent)
1457  {
1458  std::stack<RectangleTree*> stack;
1459  for (size_t i = 0; i < numChildren; ++i)
1460  {
1461  stack.push(children[i]);
1462  }
1463  while (!stack.empty())
1464  {
1465  RectangleTree* node = stack.top();
1466  stack.pop();
1467  node->dataset = dataset;
1468  for (size_t i = 0; i < node->numChildren; ++i)
1469  {
1470  stack.push(node->children[i]);
1471  }
1472  }
1473  }
1474 }
1475 
1476 } // namespace tree
1477 } // namespace mlpack
1478 
1479 #endif
size_t TreeSize() const
Obtains the number of nodes in the tree, starting with this.
Definition: rectangle_tree_impl.hpp:723
const MatType & Dataset() const
Get the dataset which the tree is built on.
Definition: rectangle_tree.hpp:360
ElemType FurthestDescendantDistance() const
Return the furthest possible descendant distance.
Definition: rectangle_tree_impl.hpp:931
size_t Point(const size_t index) const
Return the index (with reference to the dataset) of a particular point in this node.
Definition: rectangle_tree.hpp:480
void NullifyData()
Nullify the auxiliary information.
Definition: rectangle_tree_impl.hpp:457
void SoftDelete()
Delete this node of the tree, but leave the stuff contained in it intact.
Definition: rectangle_tree_impl.hpp:435
~RectangleTree()
Deletes this node, deallocating the memory for the children and calling their destructors in turn...
Definition: rectangle_tree_impl.hpp:414
Linear algebra utility functions, generally performed on matrices or vectors.
Definition: cv.hpp:1
size_t Begin() const
Return the index of the beginning point of this subset.
Definition: rectangle_tree.hpp:543
ElemType MinDistance(const RectangleTree &other) const
Return the minimum distance to another node.
Definition: rectangle_tree.hpp:487
ElemType FurthestPointDistance() const
Return the furthest distance to a point held in this node.
Definition: rectangle_tree_impl.hpp:905
const bound::HRectBound< MetricType > & Bound() const
Return the bound object for this node.
Definition: rectangle_tree.hpp:315
Definition: pointer_wrapper.hpp:23
bool DeletePoint(const size_t point)
Deletes a point from the treeand, updates the bounding rectangle.
Definition: rectangle_tree_impl.hpp:587
ElemType Diameter() const
Returns the diameter of the hyperrectangle (that is, the longest diagonal).
Definition: hrectbound_impl.hpp:669
size_t NumDescendants() const
Return the number of descendants of this node.
Definition: rectangle_tree_impl.hpp:966
size_t GetNearestChild(const VecType &point, typename std::enable_if_t< IsVector< VecType >::value > *=0)
Return the index of the nearest child node to the given query point.
Definition: rectangle_tree_impl.hpp:777
void serialize(Archive &ar, const uint32_t)
Serialize the tree.
Definition: rectangle_tree_impl.hpp:1395
ElemType MaxDistance(const RectangleTree &other) const
Return the maximum distance to another node.
Definition: rectangle_tree.hpp:493
const AuxiliaryInformationType< RectangleTree > & AuxiliaryInfo() const
Return the auxiliary information object of this node.
Definition: rectangle_tree.hpp:325
size_t NumPoints() const
Return the number of points in this node (returns 0 if this node is not a leaf).
Definition: rectangle_tree_impl.hpp:948
bool RemoveNode(const RectangleTree *node, std::vector< bool > &relevels)
Removes a node from the tree.
Definition: rectangle_tree_impl.hpp:684
bool Contains(const VecType &point) const
Determines if a point is within this bound.
Definition: hrectbound_impl.hpp:579
friend DescentType
Give friend access for DescentType.
Definition: rectangle_tree.hpp:580
size_t NumChildren() const
Return the number of child nodes. (One level beneath this one only.)
Definition: rectangle_tree.hpp:371
friend SplitType
Give friend access for SplitType.
Definition: rectangle_tree.hpp:583
MatType::elem_type ElemType
The element type held by the matrix type.
Definition: rectangle_tree.hpp:64
size_t MinNumChildren() const
Return the minimum number of children (in a non-leaf node).
Definition: rectangle_tree.hpp:350
void InsertPoint(const size_t point)
Inserts a point into the tree.
Definition: rectangle_tree_impl.hpp:474
size_t TreeDepth() const
Obtains the number of levels below this node in the tree, starting with this.
Definition: rectangle_tree_impl.hpp:739
bool ShrinkBoundForBound(const bound::HRectBound< MetricType > &changedBound)
Shrink the bound object of this node for the removal of a child node.
Definition: rectangle_tree_impl.hpp:1359
A rectangle type tree tree, such as an R-tree or X-tree.
Definition: rectangle_tree.hpp:54
size_t GetFurthestChild(const VecType &point, typename std::enable_if_t< IsVector< VecType >::value > *=0)
Return the index of the furthest child node to the given query point.
Definition: rectangle_tree_impl.hpp:810
size_t MaxLeafSize() const
Return the maximum leaf size.
Definition: rectangle_tree.hpp:335
void CondenseTree(const arma::vec &point, std::vector< bool > &relevels, const bool usePoint)
Condense the bounding rectangles for this node based on the removal of the point specified by the arm...
Definition: rectangle_tree_impl.hpp:1077
RectangleTree()
A default constructor.
Definition: rectangle_tree_impl.hpp:1048
void InsertNode(RectangleTree *node, const size_t level, std::vector< bool > &relevels)
Inserts a node into the tree, tracking which levels have been inserted into.
Definition: rectangle_tree_impl.hpp:551
#define CEREAL_POINTER(T)
Cereal does not support the serialization of raw pointer.
Definition: pointer_wrapper.hpp:96
size_t MaxNumChildren() const
Return the maximum number of children (in a non-leaf node).
Definition: rectangle_tree.hpp:345
size_t Dim() const
Gets the dimensionality.
Definition: hrectbound.hpp:96
bool IsLeaf() const
Return whether or not this node is a leaf (true if it has no children).
Definition: rectangle_tree_impl.hpp:760
RectangleTree & Child(const size_t child) const
Get the specified child.
Definition: rectangle_tree.hpp:437
ElemType ParentDistance() const
Return the distance from the center of this node to the center of the parent node.
Definition: rectangle_tree.hpp:427
size_t Descendant(const size_t index) const
Return the index (with reference to the dataset) of a particular descendant of this node...
Definition: rectangle_tree_impl.hpp:981
size_t MinLeafSize() const
Return the minimum leaf size.
Definition: rectangle_tree.hpp:340
bool ShrinkBoundForPoint(const arma::vec &point)
Shrink the bound object of this node for the removal of a point.
Definition: rectangle_tree_impl.hpp:1261
If value == true, then VecType is some sort of Armadillo vector or subview.
Definition: arma_traits.hpp:35
RectangleTree * Parent() const
Gets the parent of this node.
Definition: rectangle_tree.hpp:355
size_t Count() const
Return the number of points in this subset.
Definition: rectangle_tree.hpp:548