[mlpack] 01/37: Pull rectangle tree because it isn't done yet.
Barak A. Pearlmutter
barak+git at pearlmutter.net
Mon Feb 15 19:35:46 UTC 2016
This is an automated email from the git hooks/post-receive script.
bap pushed a commit to tag mlpack-1.0.10
in repository mlpack.
commit 5def8e7d29fb7536241b30729cf98669aec286e6
Author: Ryan Curtin <ryan at ratml.org>
Date: Sat Jul 26 15:23:22 2014 +0000
Pull rectangle tree because it isn't done yet.
---
src/mlpack/core/tree/CMakeLists.txt | 13 -
.../tree/rectangle_tree/dual_tree_traverser.hpp | 90 ---
.../rectangle_tree/dual_tree_traverser_impl.hpp | 49 --
.../tree/rectangle_tree/hilbert_r_tree_split.hpp | 1 -
.../rectangle_tree/hilbert_r_tree_split_impl.hpp | 1 -
.../r_star_tree_descent_heuristic.hpp | 44 --
.../r_star_tree_descent_heuristic_impl.hpp | 149 -----
.../core/tree/rectangle_tree/r_star_tree_split.hpp | 73 ---
.../tree/rectangle_tree/r_star_tree_split_impl.hpp | 479 --------------
.../rectangle_tree/r_tree_descent_heuristic.hpp | 44 --
.../r_tree_descent_heuristic_impl.hpp | 103 ---
.../core/tree/rectangle_tree/r_tree_split.hpp | 90 ---
.../core/tree/rectangle_tree/r_tree_split_impl.hpp | 526 ----------------
.../core/tree/rectangle_tree/rectangle_tree.hpp | 526 ----------------
.../tree/rectangle_tree/rectangle_tree_impl.hpp | 689 ---------------------
.../tree/rectangle_tree/single_tree_traverser.hpp | 74 ---
.../rectangle_tree/single_tree_traverser_impl.hpp | 77 ---
src/mlpack/core/tree/rectangle_tree/traits.hpp | 52 --
.../core/tree/rectangle_tree/x_tree_split.hpp | 1 -
.../core/tree/rectangle_tree/x_tree_split_impl.hpp | 1 -
src/mlpack/methods/neighbor_search/allknn_main.cpp | 206 ++----
.../methods/neighbor_search/neighbor_search.hpp | 1 -
src/mlpack/tests/CMakeLists.txt | 1 -
src/mlpack/tests/rectangle_tree_test.cpp | 654 -------------------
src/mlpack/tests/tree_test.cpp | 1 -
src/mlpack/tests/tree_traits_test.cpp | 1 -
26 files changed, 64 insertions(+), 3882 deletions(-)
diff --git a/src/mlpack/core/tree/CMakeLists.txt b/src/mlpack/core/tree/CMakeLists.txt
index a4bd182..b77a345 100644
--- a/src/mlpack/core/tree/CMakeLists.txt
+++ b/src/mlpack/core/tree/CMakeLists.txt
@@ -29,19 +29,6 @@ set(SOURCES
mrkd_statistic.hpp
mrkd_statistic_impl.hpp
mrkd_statistic.cpp
- rectangle_tree.hpp
- rectangle_tree/rectangle_tree.hpp
- rectangle_tree/rectangle_tree_impl.hpp
- rectangle_tree/single_tree_traverser.hpp
- rectangle_tree/single_tree_traverser_impl.hpp
- rectangle_tree/dual_tree_traverser.hpp
- rectangle_tree/dual_tree_traverser_impl.hpp
- rectangle_tree/r_tree_split.hpp
- rectangle_tree/r_tree_split_impl.hpp
- rectangle_tree/r_tree_descent_heuristic.hpp
- rectangle_tree/r_tree_descent_heuristic_impl.hpp
- rectangle_tree/r_star_tree_descent_heuristic.hpp
- rectangle_tree/r_star_tree_descent_heuristic_impl.hpp
statistic.hpp
traversal_info.hpp
tree_traits.hpp
diff --git a/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser.hpp b/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser.hpp
deleted file mode 100644
index 1091224..0000000
--- a/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * @file dual_tree_traverser.hpp
- * @author Andrew Wells
- *
- * A nested class of Rectangle Tree for traversing rectangle type trees
- * with a given set of rules which indicate the branches to prune and the
- * order in which to recurse. This is just here to make it compile.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_DUAL_TREE_TRAVERSER_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_DUAL_TREE_TRAVERSER_HPP
-
-#include <mlpack/core.hpp>
-
-#include "rectangle_tree.hpp"
-
-namespace mlpack {
-namespace tree {
-
-template<typename SplitType,
- typename DescentType,
- typename StatisticType,
- typename MatType>
-template<typename RuleType>
-class RectangleTree<SplitType, DescentType, StatisticType, MatType>::
- DualTreeTraverser
-{
- public:
- /**
- * Instantiate the dual-tree traverser with the given rule set.
- */
- DualTreeTraverser(RuleType& rule);
-
- /**
- * Traverse the two trees. This does not reset the number of prunes.
- *
- * @param queryNode The query node to be traversed.
- * @param referenceNode The reference node to be traversed.
- * @param score The score of the current node combination.
- */
- void Traverse(RectangleTree<SplitType, DescentType, StatisticType, MatType>& queryNode,
- RectangleTree<SplitType, DescentType, StatisticType, MatType>& referenceNode);
-
- //! Get the number of prunes.
- size_t NumPrunes() const { return numPrunes; }
- //! Modify the number of prunes.
- size_t& NumPrunes() { return numPrunes; }
-
- //! Get the number of visited combinations.
- size_t NumVisited() const { return numVisited; }
- //! Modify the number of visited combinations.
- size_t& NumVisited() { return numVisited; }
-
- //! Get the number of times a node combination was scored.
- size_t NumScores() const { return numScores; }
- //! Modify the number of times a node combination was scored.
- size_t& NumScores() { return numScores; }
-
- //! Get the number of times a base case was calculated.
- size_t NumBaseCases() const { return numBaseCases; }
- //! Modify the number of times a base case was calculated.
- size_t& NumBaseCases() { return numBaseCases; }
-
- private:
- //! Reference to the rules with which the trees will be traversed.
- RuleType& rule;
-
- //! The number of prunes.
- size_t numPrunes;
-
- //! The number of node combinations that have been visited during traversal.
- size_t numVisited;
-
- //! The number of times a node combination was scored.
- size_t numScores;
-
- //! The number of times a base case was calculated.
- size_t numBaseCases;
-
- //! Traversal information, held in the class so that it isn't continually
- //! being reallocated.
- typename RuleType::TraversalInfoType traversalInfo;
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-// Include implementation.
-#include "dual_tree_traverser_impl.hpp"
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser_impl.hpp b/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser_impl.hpp
deleted file mode 100644
index 8af988e..0000000
--- a/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser_impl.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file dual_tree_traverser_impl.hpp
- * @author Andrew Wells
- *
- * A class for traversing rectangle type trees with a given set of rules
- * which indicate the branches to prune and the order in which to recurse.
- * This is a depth-first traverser.
- */
-#ifndef __MLPAC_CORE_TREE_RECTANGLE_TREE_DUAL_TREE_TRAVERSER_IMPL_HPP
-#define __MLPAC_CORE_TREE_RECTANGLE_TREE_DUAL_TREE_TRAVERSER_IMPL_HPP
-
-#include "dual_tree_traverser.hpp"
-
-#include <algorithm>
-#include <stack>
-
-namespace mlpack {
-namespace tree {
-
-template<typename SplitType,
- typename DescentType,
- typename StatisticType,
- typename MatType>
-template<typename RuleType>
-RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-DualTreeTraverser<RuleType>::DualTreeTraverser(RuleType& rule) :
- rule(rule),
- numPrunes(0)
-{ /* Nothing to do */ }
-
-template<typename SplitType,
- typename DescentType,
- typename StatisticType,
- typename MatType>
-template<typename RuleType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-DualTreeTraverser<RuleType>::Traverse(RectangleTree<SplitType, DescentType, StatisticType, MatType>& queryNode,
- RectangleTree<SplitType, DescentType, StatisticType, MatType>& referenceNode)
-{
- //Do nothing. Just here to prevent warnings.
- if(queryNode.NumDescendants() > referenceNode.NumDescendants())
- return;
- return;
-}
-
-}; // namespace tree
-}; // namespace mlpack
-
-#endif
\ No newline at end of file
diff --git a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split.hpp
deleted file mode 100644
index 8d1c8b6..0000000
--- a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split.hpp
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split_impl.hpp b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split_impl.hpp
deleted file mode 100644
index 8d1c8b6..0000000
--- a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split_impl.hpp
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/mlpack/core/tree/rectangle_tree/r_star_tree_descent_heuristic.hpp b/src/mlpack/core/tree/rectangle_tree/r_star_tree_descent_heuristic.hpp
deleted file mode 100644
index 035b85f..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_descent_heuristic.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * @file r_star_tree_descent_heuristic.hpp
- * @author Andrew Wells
- *
- * Definition of RStarTreeDescentHeuristic, a class that chooses the best child of a node in
- * an R tree when inserting a new point.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_DESCENT_HEURISTIC_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_DESCENT_HEURISTIC_HPP
-
-#include <mlpack/core.hpp>
-
-namespace mlpack {
-namespace tree /** Trees and tree-building procedures. */ {
-
-/**
- * When descending a Rectangle tree to insert a point, we need to have a way to choose
- * a child node when the point isn't enclosed by any of them. This heuristic is used to do so.
- */
-class RStarTreeDescentHeuristic
-{
- public:
- /**
- * Evaluate the node using a hueristic. The heuristic guarantees two things:
- * 1. If point is contained in (or on) bound, the value returned is zero.
- * 2. If the point is not contained in (or on) bound, the value returned is greater than zero.
- *
- * @param bound The bound used for the node that is being evaluated.
- * @param point The point that is being inserted.
- */
- template<typename TreeType>
- static size_t ChooseDescentNode(const TreeType* node, const arma::vec& point);
-
- template<typename TreeType>
- static size_t ChooseDescentNode(const TreeType* node, const TreeType* insertedNode);
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-// Include implementation.
-#include "r_star_tree_descent_heuristic_impl.hpp"
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/r_star_tree_descent_heuristic_impl.hpp b/src/mlpack/core/tree/rectangle_tree/r_star_tree_descent_heuristic_impl.hpp
deleted file mode 100644
index da6d425..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_descent_heuristic_impl.hpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * @file r_star_tree_descent_heuristic_impl.hpp
- * @author Andrew Wells
- *
- * Implementation of RStarTreeDescentHeuristic, a class that chooses the best child of a node in
- * an R tree when inserting a new point.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_DESCENT_HEURISTIC_IMPL_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_DESCENT_HEURISTIC_IMPL_HPP
-
-#include "r_star_tree_descent_heuristic.hpp"
-
-namespace mlpack {
-namespace tree {
-
-template<typename TreeType>
-inline size_t RStarTreeDescentHeuristic::ChooseDescentNode(const TreeType* node, const arma::vec& point)
-{
- bool tiedOne = false;
- std::vector<double> originalScores(node->NumChildren());
- double origMinScore = DBL_MAX;
-
- if (node->Child(0)->IsLeaf()) { // If its children are leaf nodes, use minimum overlap to choose.
- double bestIndex = 0;
-
- for (size_t i = 0; i < node->NumChildren(); i++) {
- double sc = 0;
- for (size_t j = 0; j < node->NumChildren(); j++) {
- if (j != i) {
- double overlap = 1.0;
- double newOverlap = 1.0;
- for (size_t k = 0; k < node->Bound().Dim(); k++) {
- double newHigh = std::max(point[k], node->Child(i)->Bound()[k].Hi());
- double newLow = std::min(point[k], node->Child(i)->Bound()[k].Lo());
- overlap *= node->Child(i)->Bound()[k].Hi() < node->Child(j)->Bound()[k].Lo() || node->Child(i)->Bound()[k].Lo() > node->Child(j)->Bound()[k].Hi() ? 0 : std::min(node->Child(i)->Bound()[k].Hi(), node->Child(j)->Bound()[k].Hi()) - std::max(node->Child(i)->Bound()[k].Lo(), node->Child(j)->Bound()[k].Lo());
- newOverlap *= newHigh < node->Child(j)->Bound()[k].Lo() || newLow > node->Child(j)->Bound()[k].Hi() ? 0 : std::min(newHigh, node->Child(j)->Bound()[k].Hi()) - std::max(newLow, node->Child(j)->Bound()[k].Lo());
- }
- sc += newOverlap - overlap;
- }
- }
- originalScores[i] = sc;
- if (sc < origMinScore) {
- origMinScore = sc;
- bestIndex = i;
- } else if (sc == origMinScore)
- tiedOne = true;
- }
-
- if (!tiedOne)
- return bestIndex;
- }
-
- // We do this if it is not on the second level or if there was a tie.
- std::vector<double> scores(node->NumChildren());
- if(tiedOne) { // If the first heuristic was tied, we need to eliminate garbage values.
- for(size_t i = 0; i < scores.size(); i++)
- scores[i] = DBL_MAX;
- }
- std::vector<int> vols(node->NumChildren());
- double minScore = DBL_MAX;
- int bestIndex = 0;
- bool tied = false;
-
- for (size_t i = 0; i < node->NumChildren(); i++) {
- if (!tiedOne || originalScores[i] == origMinScore) {
- double v1 = 1.0;
- double v2 = 1.0;
- for (size_t j = 0; j < node->Bound().Dim(); j++) {
- v1 *= node->Child(i)->Bound()[j].Width();
- v2 *= node->Child(i)->Bound()[j].Contains(point[j]) ? node->Child(i)->Bound()[j].Width() : (node->Child(i)->Bound()[j].Hi() < point[j] ? (point[j] - node->Child(i)->Bound()[j].Lo()) :
- (node->Child(i)->Bound()[j].Hi() - point[j]));
- }
- assert(v2 - v1 >= 0);
- vols[i] = v1;
- scores[i] = v2 - v1;
- if (v2 - v1 < minScore) {
- minScore = v2 - v1;
- bestIndex = i;
- } else if (v2 - v1 == minScore)
- tied = true;
- }
- }
- if (tied) { // We break ties by choosing the smallest bound.
- double minVol = DBL_MAX;
- bestIndex = 0;
- for (int i = 0; i < scores.size(); i++) {
- if (scores[i] == minScore) {
- if (vols[i] < minVol) {
- minVol = vols[i];
- bestIndex = i;
- }
- }
- }
- }
-
- return bestIndex;
-}
-
-/**
- * We simplify this to the same code as is used in the regular R tree, since the inserted node should always be above
- * the leaf level. If the tree is eventually changed to support rectangles, this could be changed to match the above code;
- * however, the paper's explanation for their algorithm seems to indicate the above is more for points than for rectangles.
- */
-template<typename TreeType>
-inline size_t RStarTreeDescentHeuristic::ChooseDescentNode(const TreeType* node, const TreeType* insertedNode)
-{
- std::vector<double> scores(node->NumChildren());
- std::vector<int> vols(node->NumChildren());
- double minScore = DBL_MAX;
- int bestIndex = 0;
- bool tied = false;
-
- for (size_t i = 0; i < node->NumChildren(); i++) {
- double v1 = 1.0;
- double v2 = 1.0;
- for (size_t j = 0; j < node->Child(i)->Bound().Dim(); j++) {
- v1 *= node->Child(i)->Bound()[j].Width();
- v2 *= node->Child(i)->Bound()[j].Contains(insertedNode->Bound()[j]) ? node->Child(i)->Bound()[j].Width() :
- (insertedNode->Bound()[j].Contains(node->Child(i)->Bound()[j]) ? insertedNode->Bound()[j].Width() : (insertedNode->Bound()[j].Lo() < node->Child(i)->Bound()[j].Lo() ? (node->Child(i)->Bound()[j].Hi() - insertedNode->Bound()[j].Lo()) : (insertedNode->Bound()[j].Hi() - node->Child(i)->Bound()[j].Lo())));
- }
- assert(v2 - v1 >= 0);
- vols[i] = v1;
- scores[i] = v2-v1;
- if (v2 - v1 < minScore) {
- minScore = v2 - v1;
- bestIndex = i;
- } else if(v2 - v1 == minScore)
- tied = true;
- }
- if(tied) { // We break ties by choosing the smallest bound.
- double minVol = DBL_MAX;
- bestIndex = 0;
- for(int i = 0; i < scores.size(); i++) {
- if(scores[i] == minScore) {
- if(vols[i] < minVol) {
- minVol = vols[i];
- bestIndex = i;
- }
- }
- }
- }
-
- return bestIndex;
-}
-
-}; // namespace tree
-}; // namespace mlpack
-
-#endif
\ No newline at end of file
diff --git a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp
deleted file mode 100644
index 70d3300..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file r_tree_star_split.hpp
- * @author Andrew Wells
- *
- * Defintion of the RStarTreeSplit class, a class that splits the nodes of an R tree, starting
- * at a leaf node and moving upwards if necessary.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_SPLIT_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_SPLIT_HPP
-
-#include <mlpack/core.hpp>
-
-namespace mlpack {
-namespace tree /** Trees and tree-building procedures. */ {
-
-/**
- * A Rectangle Tree has new points inserted at the bottom. When these
- * nodes overflow, we split them, moving up the tree and splitting nodes
- * as necessary.
- */
-template<typename DescentType,
- typename StatisticType,
- typename MatType>
-class RStarTreeSplit
-{
-public:
-
-/**
- * Split a leaf node using the algorithm described in "The R*-tree: An Efficient and Robust Access method
- * for Points and Rectangles." If necessary, this split will propagate
- * upwards through the tree.
- */
-static void SplitLeafNode(RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree, std::vector<bool>& relevels);
-
-/**
- * Split a non-leaf node using the "default" algorithm. If this is a root node, the
- * tree increases in depth.
- */
-static bool SplitNonLeafNode(RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree, std::vector<bool>& relevels);
-
-private:
-/**
- * Class to allow for faster sorting.
- */
-class sortStruct {
-public:
- double d;
- int n;
-};
-
-/**
- * Comparator for sorting with sortStruct.
- */
-static bool structComp(const sortStruct& s1, const sortStruct& s2) {
- return s1.d < s2.d;
-}
-
-/**
- * Insert a node into another node.
- */
-static void InsertNodeIntoTree(
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* destTree,
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* srcNode);
-
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-// Include implementation
-#include "r_star_tree_split_impl.hpp"
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split_impl.hpp b/src/mlpack/core/tree/rectangle_tree/r_star_tree_split_impl.hpp
deleted file mode 100644
index 5e612dc..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split_impl.hpp
+++ /dev/null
@@ -1,479 +0,0 @@
-/**
- * @file r_star_tree_split_impl.hpp
- * @author Andrew Wells
- *
- * Implementation of class (RStarTreeSplit) to split a RectangleTree.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_SPLIT_IMPL_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_STAR_TREE_SPLIT_IMPL_HPP
-
-#include "r_star_tree_split.hpp"
-#include "rectangle_tree.hpp"
-#include <mlpack/core/math/range.hpp>
-
-namespace mlpack {
-namespace tree {
-
-/**
- * We call GetPointSeeds to get the two points which will be the initial points in the new nodes
- * We then call AssignPointDestNode to assign the remaining points to the two new nodes.
- * Finally, we delete the old node and insert the new nodes into the tree, spliting the parent
- * if necessary.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RStarTreeSplit<DescentType, StatisticType, MatType>::SplitLeafNode(
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree,
- std::vector<bool>& relevels)
-{
- // If we are splitting the root node, we need will do things differently so that the constructor
- // and other methods don't confuse the end user by giving an address of another node.
- if (tree->Parent() == NULL) {
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* copy =
- new RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(*tree); // We actually want to copy this way. Pointers and everything.
- copy->Parent() = tree;
- tree->Count() = 0;
- tree->NullifyData();
- tree->Child((tree->NumChildren())++) = copy; // Because this was a leaf node, numChildren must be 0.
- assert(tree->NumChildren() == 1);
- RStarTreeSplit<DescentType, StatisticType, MatType>::SplitLeafNode(copy, relevels);
- return;
- }
-
- int bestOverlapIndexOnBestAxis = 0;
- int bestAreaIndexOnBestAxis = 0;
- bool tiedOnOverlap = false;
- int bestAxis = 0;
- double bestAxisScore = DBL_MAX;
- for (int j = 0; j < tree->Bound().Dim(); j++) {
- double axisScore = 0.0;
- // Since we only have points in the leaf nodes, we only need to sort once.
- std::vector<sortStruct> sorted(tree->Count());
- for (int i = 0; i < sorted.size(); i++) {
- sorted[i].d = tree->LocalDataset().col(i)[j];
- sorted[i].n = i;
- }
-
- std::sort(sorted.begin(), sorted.end(), structComp);
-
- // We'll store each of the three scores for each distribution.
- std::vector<double> areas(tree->MaxLeafSize() - 2 * tree->MinLeafSize() + 2);
- std::vector<double> margins(tree->MaxLeafSize() - 2 * tree->MinLeafSize() + 2);
- std::vector<double> overlapedAreas(tree->MaxLeafSize() - 2 * tree->MinLeafSize() + 2);
- for (int i = 0; i < areas.size(); i++) {
- areas[i] = 0.0;
- margins[i] = 0.0;
- overlapedAreas[i] = 0.0;
- }
- for (int i = 0; i < areas.size(); i++) {
- // The ith arrangement is obtained by placing the first tree->MinLeafSize() + i
- // points in one rectangle and the rest in another. Then we calculate the three
- // scores for that distribution.
-
- int cutOff = tree->MinLeafSize() + i;
- // We'll calculate the max and min in each dimension by hand to save time.
- std::vector<double> maxG1(tree->Bound().Dim());
- std::vector<double> minG1(maxG1.size());
- std::vector<double> maxG2(maxG1.size());
- std::vector<double> minG2(maxG1.size());
- for (int k = 0; k < tree->Bound().Dim(); k++) {
- minG1[k] = maxG1[k] = tree->LocalDataset().col(sorted[0].n)[k];
- minG2[k] = maxG2[k] = tree->LocalDataset().col(sorted[sorted.size() - 1].n)[k];
- for (int l = 1; l < tree->Count() - 1; l++) {
- if (l < cutOff) {
- if (tree->LocalDataset().col(sorted[l].n)[k] < minG1[k])
- minG1[k] = tree->LocalDataset().col(sorted[l].n)[k];
- else if (tree->LocalDataset().col(sorted[l].n)[k] > maxG1[k])
- maxG1[k] = tree->LocalDataset().col(sorted[l].n)[k];
- } else {
- if (tree->LocalDataset().col(sorted[l].n)[k] < minG2[k])
- minG2[k] = tree->LocalDataset().col(sorted[l].n)[k];
- else if (tree->LocalDataset().col(sorted[l].n)[k] > maxG2[k])
- maxG2[k] = tree->LocalDataset().col(sorted[l].n)[k];
- }
- }
- }
- double area1 = 1.0, area2 = 1.0;
- double oArea = 1.0;
- for (int k = 0; k < maxG1.size(); k++) {
- margins[i] += maxG1[k] - minG1[k] + maxG2[k] - minG2[k];
- area1 *= maxG1[k] - minG1[k];
- area2 *= maxG2[k] - minG2[k];
- oArea *= maxG1[k] < minG2[k] || maxG2[k] < minG1[k] ? 0.0 : std::min(maxG1[k], maxG2[k]) - std::max(minG1[k], minG2[k]);
- }
- areas[i] += area1 + area2;
- overlapedAreas[i] += oArea;
- axisScore += margins[i];
- }
-
- if (axisScore < bestAxisScore) {
- bestAxisScore = axisScore;
- bestAxis = j;
- double bestOverlapIndexOnBestAxis = 0;
- double bestAreaIndexOnBestAxis = 0;
- for (int i = 1; i < areas.size(); i++) {
- if (overlapedAreas[i] < overlapedAreas[bestOverlapIndexOnBestAxis]) {
- tiedOnOverlap = false;
- bestAreaIndexOnBestAxis = i;
- bestOverlapIndexOnBestAxis = i;
- } else if (overlapedAreas[i] == overlapedAreas[bestOverlapIndexOnBestAxis]) {
- tiedOnOverlap = true;
- if (areas[i] < areas[bestAreaIndexOnBestAxis])
- bestAreaIndexOnBestAxis = i;
- }
- }
- }
- }
-
- std::vector<sortStruct> sorted(tree->Count());
- for (int i = 0; i < sorted.size(); i++) {
- sorted[i].d = tree->LocalDataset().col(i)[bestAxis];
- sorted[i].n = i;
- }
-
- std::sort(sorted.begin(), sorted.end(), structComp);
-
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeOne = new
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeTwo = new
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
-
- if (tiedOnOverlap) {
- for (int i = 0; i < tree->Count(); i++) {
- if (i < bestAreaIndexOnBestAxis + tree->MinLeafSize())
- treeOne->InsertPoint(tree->Points()[sorted[i].n]);
- else
- treeTwo->InsertPoint(tree->Points()[sorted[i].n]);
- }
- } else {
- for (int i = 0; i < tree->Count(); i++) {
- if (i < bestOverlapIndexOnBestAxis + tree->MinLeafSize())
- treeOne->InsertPoint(tree->Points()[sorted[i].n]);
- else
- treeTwo->InsertPoint(tree->Points()[sorted[i].n]);
- }
- }
-
- //Remove this node and insert treeOne and treeTwo
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* par = tree->Parent();
- int index = 0;
- for (int i = 0; i < par->NumChildren(); i++) {
- if (par->Child(i) == tree) {
- index = i;
- break;
- }
- }
- par->Child(index) = treeOne;
- par->Child(par->NumChildren()++) = treeTwo;
-
- // we only add one at a time, so we should only need to test for equality
- // just in case, we use an assert.
- assert(par->NumChildren() <= par->MaxNumChildren()+1);
- if (par->NumChildren() == par->MaxNumChildren()+1) {
- SplitNonLeafNode(par, relevels);
- }
-
- assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren());
- assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren());
- assert(treeTwo->Parent()->NumChildren() <= treeTwo->MaxNumChildren());
- assert(treeTwo->Parent()->NumChildren() >= treeTwo->MinNumChildren());
-
- tree->SoftDelete();
-
- return;
-}
-
-/**
- * We call GetBoundSeeds to get the two new nodes that this one will be broken
- * into. Then we call AssignNodeDestNode to move the children of this node
- * into either of those two nodes. Finally, we delete the now unused information
- * and recurse up the tree if necessary. We don't need to worry about the bounds
- * higher up the tree because they were already updated if necessary.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-bool RStarTreeSplit<DescentType, StatisticType, MatType>::SplitNonLeafNode(
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree,
- std::vector<bool>& relevels)
-{
- // If we are splitting the root node, we need will do things differently so that the constructor
- // and other methods don't confuse the end user by giving an address of another node.
- if (tree->Parent() == NULL) {
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* copy =
- new RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(*tree); // We actually want to copy this way. Pointers and everything.
- copy->Parent() = tree;
- tree->NumChildren() = 0;
- tree->NullifyData();
- tree->Child((tree->NumChildren())++) = copy;
- RStarTreeSplit<DescentType, StatisticType, MatType>::SplitNonLeafNode(copy, relevels);
- return true;
- }
-
- int bestOverlapIndexOnBestAxis = 0;
- int bestAreaIndexOnBestAxis = 0;
- bool tiedOnOverlap = false;
- bool lowIsBest = true;
- int bestAxis = 0;
- double bestAxisScore = DBL_MAX;
- for (int j = 0; j < tree->Bound().Dim(); j++) {
- double axisScore = 0.0;
-
- // We'll do Bound().Lo() now and use Bound().Hi() later.
- std::vector<sortStruct> sorted(tree->NumChildren());
- for (int i = 0; i < sorted.size(); i++) {
- sorted[i].d = tree->Child(i)->Bound()[j].Lo();
- sorted[i].n = i;
- }
-
- std::sort(sorted.begin(), sorted.end(), structComp);
-
- // We'll store each of the three scores for each distribution.
- std::vector<double> areas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2);
- std::vector<double> margins(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2);
- std::vector<double> overlapedAreas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2);
- for (int i = 0; i < areas.size(); i++) {
- areas[i] = 0.0;
- margins[i] = 0.0;
- overlapedAreas[i] = 0.0;
- }
-
- for (int i = 0; i < areas.size(); i++) {
- // The ith arrangement is obtained by placing the first tree->MinNumChildren() + i
- // points in one rectangle and the rest in another. Then we calculate the three
- // scores for that distribution.
-
- int cutOff = tree->MinNumChildren() + i;
- // We'll calculate the max and min in each dimension by hand to save time.
- std::vector<double> maxG1(tree->Bound().Dim());
- std::vector<double> minG1(maxG1.size());
- std::vector<double> maxG2(maxG1.size());
- std::vector<double> minG2(maxG1.size());
- for (int k = 0; k < tree->Bound().Dim(); k++) {
- minG1[k] = tree->Child(sorted[0].n)->Bound()[k].Lo();
- maxG1[k] = tree->Child(sorted[0].n)->Bound()[k].Hi();
- minG2[k] = tree->Child(sorted[sorted.size() - 1].n)->Bound()[k].Lo();
- maxG2[k] = tree->Child(sorted[sorted.size() - 1].n)->Bound()[k].Hi();
- for (int l = 1; l < tree->NumChildren() - 1; l++) {
- if (l < cutOff) {
- if (tree->Child(sorted[l].n)->Bound()[k].Lo() < minG1[k])
- minG1[k] = tree->Child(sorted[l].n)->Bound()[k].Lo();
- else if (tree->Child(sorted[l].n)->Bound()[k].Hi() > maxG1[k])
- maxG1[k] = tree->Child(sorted[l].n)->Bound()[k].Hi();
- } else {
- if (tree->Child(sorted[l].n)->Bound()[k].Lo() < minG2[k])
- minG2[k] = tree->Child(sorted[l].n)->Bound()[k].Lo();
- else if (tree->Child(sorted[l].n)->Bound()[k].Hi() > maxG2[k])
- maxG2[k] = tree->Child(sorted[l].n)->Bound()[k].Hi();
- }
- }
- }
- double area1 = 1.0, area2 = 1.0;
- double oArea = 1.0;
- for (int k = 0; k < maxG1.size(); k++) {
- margins[i] += maxG1[k] - minG1[k] + maxG2[k] - minG2[k];
- area1 *= maxG1[k] - minG1[k];
- area2 *= maxG2[k] - minG2[k];
- oArea *= maxG1[k] < minG2[k] || maxG2[k] < minG1[k] ? 0.0 : std::min(maxG1[k], maxG2[k]) - std::max(minG1[k], minG2[k]);
- }
- areas[i] += area1 + area2;
- overlapedAreas[i] += oArea;
- axisScore += margins[i];
- }
- if (axisScore < bestAxisScore) {
- bestAxisScore = axisScore;
- bestAxis = j;
- double bestOverlapIndexOnBestAxis = 0;
- double bestAreaIndexOnBestAxis = 0;
- for (int i = 1; i < areas.size(); i++) {
- if (overlapedAreas[i] < overlapedAreas[bestOverlapIndexOnBestAxis]) {
- tiedOnOverlap = false;
- bestAreaIndexOnBestAxis = i;
- bestOverlapIndexOnBestAxis = i;
- } else if (overlapedAreas[i] == overlapedAreas[bestOverlapIndexOnBestAxis]) {
- tiedOnOverlap = true;
- if (areas[i] < areas[bestAreaIndexOnBestAxis])
- bestAreaIndexOnBestAxis = i;
- }
- }
- }
- }
-
- //Now we do the same thing using Bound().Hi() and choose the best of the two.
- for (int j = 0; j < tree->Bound().Dim(); j++) {
- double axisScore = 0.0;
-
- // We'll do Bound().Lo() now and use Bound().Hi() later.
- std::vector<sortStruct> sorted(tree->NumChildren());
- for (int i = 0; i < sorted.size(); i++) {
- sorted[i].d = tree->Child(i)->Bound()[j].Hi();
- sorted[i].n = i;
- }
-
- std::sort(sorted.begin(), sorted.end(), structComp);
-
- // We'll store each of the three scores for each distribution.
- std::vector<double> areas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2);
- std::vector<double> margins(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2);
- std::vector<double> overlapedAreas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2);
- for (int i = 0; i < areas.size(); i++) {
- areas[i] = 0.0;
- margins[i] = 0.0;
- overlapedAreas[i] = 0.0;
- }
-
- for (int i = 0; i < areas.size(); i++) {
- // The ith arrangement is obtained by placing the first tree->MinNumChildren() + i
- // points in one rectangle and the rest in another. Then we calculate the three
- // scores for that distribution.
-
- int cutOff = tree->MinNumChildren() + i;
- // We'll calculate the max and min in each dimension by hand to save time.
- std::vector<double> maxG1(tree->Bound().Dim());
- std::vector<double> minG1(maxG1.size());
- std::vector<double> maxG2(maxG1.size());
- std::vector<double> minG2(maxG1.size());
- for (int k = 0; k < tree->Bound().Dim(); k++) {
- minG1[k] = tree->Child(sorted[0].n)->Bound()[k].Lo();
- maxG1[k] = tree->Child(sorted[0].n)->Bound()[k].Hi();
- minG2[k] = tree->Child(sorted[sorted.size() - 1].n)->Bound()[k].Lo();
- maxG2[k] = tree->Child(sorted[sorted.size() - 1].n)->Bound()[k].Hi();
- for (int l = 1; l < tree->NumChildren() - 1; l++) {
- if (l < cutOff) {
- if (tree->Child(sorted[l].n)->Bound()[k].Lo() < minG1[k])
- minG1[k] = tree->Child(sorted[l].n)->Bound()[k].Lo();
- else if (tree->Child(sorted[l].n)->Bound()[k].Hi() > maxG1[k])
- maxG1[k] = tree->Child(sorted[l].n)->Bound()[k].Hi();
- } else {
- if (tree->Child(sorted[l].n)->Bound()[k].Lo() < minG2[k])
- minG2[k] = tree->Child(sorted[l].n)->Bound()[k].Lo();
- else if (tree->Child(sorted[l].n)->Bound()[k].Hi() > maxG2[k])
- maxG2[k] = tree->Child(sorted[l].n)->Bound()[k].Hi();
- }
- }
- }
- double area1 = 1.0, area2 = 1.0;
- double oArea = 1.0;
- for (int k = 0; k < maxG1.size(); k++) {
- margins[i] += maxG1[k] - minG1[k] + maxG2[k] - minG2[k];
- area1 *= maxG1[k] - minG1[k];
- area2 *= maxG2[k] - minG2[k];
- oArea *= maxG1[k] < minG2[k] || maxG2[k] < minG1[k] ? 0.0 : std::min(maxG1[k], maxG2[k]) - std::max(minG1[k], minG2[k]);
- }
- areas[i] += area1 + area2;
- overlapedAreas[i] += oArea;
- axisScore += margins[i];
- }
- if (axisScore < bestAxisScore) {
- bestAxisScore = axisScore;
- bestAxis = j;
- lowIsBest = false;
- double bestOverlapIndexOnBestAxis = 0;
- double bestAreaIndexOnBestAxis = 0;
- for (int i = 1; i < areas.size(); i++) {
- if (overlapedAreas[i] < overlapedAreas[bestOverlapIndexOnBestAxis]) {
- tiedOnOverlap = false;
- bestAreaIndexOnBestAxis = i;
- bestOverlapIndexOnBestAxis = i;
- } else if (overlapedAreas[i] == overlapedAreas[bestOverlapIndexOnBestAxis]) {
- tiedOnOverlap = true;
- if (areas[i] < areas[bestAreaIndexOnBestAxis])
- bestAreaIndexOnBestAxis = i;
- }
- }
- }
- }
-
- std::vector<sortStruct> sorted(tree->NumChildren());
- if (lowIsBest) {
- for (int i = 0; i < sorted.size(); i++) {
- sorted[i].d = tree->Child(i)->Bound()[bestAxis].Lo();
- sorted[i].n = i;
- }
- } else {
- for (int i = 0; i < sorted.size(); i++) {
- sorted[i].d = tree->Child(i)->Bound()[bestAxis].Hi();
- sorted[i].n = i;
- }
- }
-
- std::sort(sorted.begin(), sorted.end(), structComp);
-
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeOne = new
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeTwo = new
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
-
- if (tiedOnOverlap) {
- for (int i = 0; i < tree->NumChildren(); i++) {
- if (i < bestAreaIndexOnBestAxis + tree->MinNumChildren())
- InsertNodeIntoTree(treeOne, tree->Child(sorted[i].n));
- else
- InsertNodeIntoTree(treeTwo, tree->Child(sorted[i].n));
- }
- } else {
- for (int i = 0; i < tree->NumChildren(); i++) {
- if (i < bestOverlapIndexOnBestAxis + tree->MinNumChildren())
- InsertNodeIntoTree(treeOne, tree->Child(sorted[i].n));
- else
- InsertNodeIntoTree(treeTwo, tree->Child(sorted[i].n));
- }
- }
-
- //Remove this node and insert treeOne and treeTwo
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* par = tree->Parent();
- int index = 0;
- for (int i = 0; i < par->NumChildren(); i++) {
- if (par->Child(i) == tree) {
- index = i;
- break;
- }
- }
- par->Child(index) = treeOne;
- par->Child(par->NumChildren()++) = treeTwo;
-
- // we only add one at a time, so we should only need to test for equality
- // just in case, we use an assert.
- assert(par->NumChildren() <= par->MaxNumChildren()+1);
- if (par->NumChildren() == par->MaxNumChildren()+1) {
- SplitNonLeafNode(par, relevels);
- }
-
- // We have to update the children of each of these new nodes so that they record the
- // correct parent.
- for (int i = 0; i < treeOne->NumChildren(); i++) {
- treeOne->Child(i)->Parent() = treeOne;
- }
- for (int i = 0; i < treeTwo->NumChildren(); i++) {
- treeTwo->Child(i)->Parent() = treeTwo;
- }
-
- assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren());
- assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren());
- assert(treeTwo->Parent()->NumChildren() <= treeTwo->MaxNumChildren());
- assert(treeTwo->Parent()->NumChildren() >= treeTwo->MinNumChildren());
-
- tree->SoftDelete();
-
- return false;
-}
-
-/**
- * Insert a node into another node. Expanding the bounds and updating the numberOfChildren.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RStarTreeSplit<DescentType, StatisticType, MatType>::InsertNodeIntoTree(
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* destTree,
- RectangleTree<RStarTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* srcNode)
-{
- destTree->Bound() |= srcNode->Bound();
- destTree->Child(destTree->NumChildren()++) = srcNode;
-}
-
-}; // namespace tree
-}; // namespace mlpack
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic.hpp b/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic.hpp
deleted file mode 100644
index da5b7a8..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * @file r_tree_descent_heuristic.hpp
- * @author Andrew Wells
- *
- * Definition of RTreeDescentHeuristic, a class that chooses the best child of a node in
- * an R tree when inserting a new point.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_DESCENT_HEURISTIC_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_DESCENT_HEURISTIC_HPP
-
-#include <mlpack/core.hpp>
-
-namespace mlpack {
-namespace tree /** Trees and tree-building procedures. */ {
-
-/**
- * When descending a Rectangle tree to insert a point, we need to have a way to choose
- * a child node when the point isn't enclosed by any of them. This heuristic is used to do so.
- */
-class RTreeDescentHeuristic
-{
- public:
- /**
- * Evaluate the node using a hueristic. The heuristic guarantees two things:
- * 1. If point is contained in (or on) bound, the value returned is zero.
- * 2. If the point is not contained in (or on) bound, the value returned is greater than zero.
- *
- * @param bound The bound used for the node that is being evaluated.
- * @param point The point that is being inserted.
- */
- template<typename TreeType>
- static size_t ChooseDescentNode(const TreeType* node, const arma::vec& point);
-
- template<typename TreeType>
- static size_t ChooseDescentNode(const TreeType* node, const TreeType* insertedNode);
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-// Include implementation.
-#include "r_tree_descent_heuristic_impl.hpp"
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic_impl.hpp b/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic_impl.hpp
deleted file mode 100644
index 337e232..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic_impl.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * @file r_tree_descent_heuristic_impl.hpp
- * @author Andrew Wells
- *
- * Implementation of RTreeDescentHeuristic, a class that chooses the best child of a node in
- * an R tree when inserting a new point.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_DESCENT_HEURISTIC_IMPL_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_DESCENT_HEURISTIC_IMPL_HPP
-
-#include "r_tree_descent_heuristic.hpp"
-
-namespace mlpack {
-namespace tree {
-
-template<typename TreeType>
-inline size_t RTreeDescentHeuristic::ChooseDescentNode(const TreeType* node, const arma::vec& point)
-{
- std::vector<double> scores(node->NumChildren());
- std::vector<int> vols(node->NumChildren());
- double minScore = DBL_MAX;
- int bestIndex = 0;
- bool tied = false;
-
- for (size_t i = 0; i < node->NumChildren(); i++) {
- double v1 = 1.0;
- double v2 = 1.0;
- for (size_t j = 0; j < node->Child(i)->Bound().Dim(); j++) {
- v1 *= node->Child(i)->Bound()[j].Width();
- v2 *= node->Child(i)->Bound()[j].Contains(point[j]) ? node->Child(i)->Bound()[j].Width() : (node->Child(i)->Bound()[j].Hi() < point[j] ? (point[j] - node->Child(i)->Bound()[j].Lo()) :
- (node->Child(i)->Bound()[j].Hi() - point[j]));
- }
- assert(v2 - v1 >= 0);
- vols[i] = v1;
- scores[i] = v2-v1;
- if (v2 - v1 < minScore) {
- minScore = v2 - v1;
- bestIndex = i;
- } else if(v2 - v1 == minScore)
- tied = true;
- }
- if(tied) { // We break ties by choosing the smallest bound.
- double minVol = DBL_MAX;
- bestIndex = 0;
- for(int i = 0; i < scores.size(); i++) {
- if(scores[i] == minScore) {
- if(vols[i] < minVol) {
- minVol = vols[i];
- bestIndex = i;
- }
- }
- }
- }
-
- return bestIndex;
-}
-
-template<typename TreeType>
-inline size_t RTreeDescentHeuristic::ChooseDescentNode(const TreeType* node, const TreeType* insertedNode)
-{
- std::vector<double> scores(node->NumChildren());
- std::vector<int> vols(node->NumChildren());
- double minScore = DBL_MAX;
- int bestIndex = 0;
- bool tied = false;
-
- for (size_t i = 0; i < node->NumChildren(); i++) {
- double v1 = 1.0;
- double v2 = 1.0;
- for (size_t j = 0; j < node->Child(i)->Bound().Dim(); j++) {
- v1 *= node->Child(i)->Bound()[j].Width();
- v2 *= node->Child(i)->Bound()[j].Contains(insertedNode->Bound()[j]) ? node->Child(i)->Bound()[j].Width() :
- (insertedNode->Bound()[j].Contains(node->Child(i)->Bound()[j]) ? insertedNode->Bound()[j].Width() : (insertedNode->Bound()[j].Lo() < node->Child(i)->Bound()[j].Lo() ? (node->Child(i)->Bound()[j].Hi() - insertedNode->Bound()[j].Lo()) : (insertedNode->Bound()[j].Hi() - node->Child(i)->Bound()[j].Lo())));
- }
- assert(v2 - v1 >= 0);
- vols[i] = v1;
- scores[i] = v2-v1;
- if (v2 - v1 < minScore) {
- minScore = v2 - v1;
- bestIndex = i;
- } else if(v2 - v1 == minScore)
- tied = true;
- }
- if(tied) { // We break ties by choosing the smallest bound.
- double minVol = DBL_MAX;
- bestIndex = 0;
- for(int i = 0; i < scores.size(); i++) {
- if(scores[i] == minScore) {
- if(vols[i] < minVol) {
- minVol = vols[i];
- bestIndex = i;
- }
- }
- }
- }
-
- return bestIndex;
-}
-
-}; // namespace tree
-}; // namespace mlpack
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp
deleted file mode 100644
index 0397e04..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * @file r_tree_split.hpp
- * @author Andrew Wells
- *
- * Defintion of the RTreeSplit class, a class that splits the nodes of an R tree, starting
- * at a leaf node and moving upwards if necessary.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_SPLIT_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_SPLIT_HPP
-
-#include <mlpack/core.hpp>
-
-namespace mlpack {
-namespace tree /** Trees and tree-building procedures. */ {
-
-/**
- * A Rectangle Tree has new points inserted at the bottom. When these
- * nodes overflow, we split them, moving up the tree and splitting nodes
- * as necessary.
- */
-template<typename DescentType,
- typename StatisticType,
- typename MatType>
-class RTreeSplit
-{
-public:
-
-/**
- * Split a leaf node using the "default" algorithm. If necessary, this split will propagate
- * upwards through the tree.
- */
-static void SplitLeafNode(RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree,
- std::vector<bool>& relevels);
-
-/**
- * Split a non-leaf node using the "default" algorithm. If this is a root node, the
- * tree increases in depth.
- */
-static bool SplitNonLeafNode(RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree,
- std::vector<bool>& relevels);
-
-private:
-
-/**
- * Get the seeds for splitting a leaf node.
- */
-static void GetPointSeeds(const RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>& tree, int *i, int *j);
-
-/**
- * Get the seeds for splitting a non-leaf node.
- */
-static void GetBoundSeeds(const RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>& tree, int *i, int *j);
-
-/**
- * Assign points to the two new nodes.
- */
-static void AssignPointDestNode(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* oldTree,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeOne,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeTwo,
- const int intI,
- const int intJ);
-
-/**
- * Assign nodes to the two new nodes.
- */
-static void AssignNodeDestNode(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* oldTree,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeOne,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeTwo,
- const int intI,
- const int intJ);
-
-/**
- * Insert a node into another node.
- */
-static void InsertNodeIntoTree(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* destTree,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* srcNode);
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-// Include implementation
-#include "r_tree_split_impl.hpp"
-
-#endif
-
-
diff --git a/src/mlpack/core/tree/rectangle_tree/r_tree_split_impl.hpp b/src/mlpack/core/tree/rectangle_tree/r_tree_split_impl.hpp
deleted file mode 100644
index 54e4ac9..0000000
--- a/src/mlpack/core/tree/rectangle_tree/r_tree_split_impl.hpp
+++ /dev/null
@@ -1,526 +0,0 @@
-/**
- * @file r_tree_split_impl.hpp
- * @author Andrew Wells
- *
- * Implementation of class (RTreeSplit) to split a RectangleTree.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_SPLIT_IMPL_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_SPLIT_IMPL_HPP
-
-#include "r_tree_split.hpp"
-#include "rectangle_tree.hpp"
-#include <mlpack/core/math/range.hpp>
-
-namespace mlpack {
-namespace tree {
-
-/**
- * We call GetPointSeeds to get the two points which will be the initial points in the new nodes
- * We then call AssignPointDestNode to assign the remaining points to the two new nodes.
- * Finally, we delete the old node and insert the new nodes into the tree, spliting the parent
- * if necessary.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RTreeSplit<DescentType, StatisticType, MatType>::SplitLeafNode(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree,
- std::vector<bool>& relevels)
-{
- // If we are splitting the root node, we need will do things differently so that the constructor
- // and other methods don't confuse the end user by giving an address of another node.
- if (tree->Parent() == NULL) {
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* copy =
- new RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(*tree); // We actually want to copy this way. Pointers and everything.
- copy->Parent() = tree;
- tree->Count() = 0;
- tree->NullifyData();
- tree->Child((tree->NumChildren())++) = copy; // Because this was a leaf node, numChildren must be 0.
- RTreeSplit<DescentType, StatisticType, MatType>::SplitLeafNode(copy, relevels);
- return;
- }
- assert(tree->Parent()->NumChildren() <= tree->Parent()->MaxNumChildren());
-
- // Use the quadratic split method from: Guttman "R-Trees: A Dynamic Index Structure for
- // Spatial Searching" It is simplified since we don't handle rectangles, only points.
- // We assume that the tree uses Euclidean Distance.
- int i = 0;
- int j = 0;
- GetPointSeeds(*tree, &i, &j);
-
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeOne = new
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType> *treeTwo = new
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
-
- // This will assign the ith and jth point appropriately.
- AssignPointDestNode(tree, treeOne, treeTwo, i, j);
-
- //Remove this node and insert treeOne and treeTwo
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* par = tree->Parent();
- int index = 0;
- for (int i = 0; i < par->NumChildren(); i++) {
- if (par->Child(i) == tree) {
- index = i;
- break;
- }
- }
- par->Child(index) = treeOne;
- par->Child(par->NumChildren()++) = treeTwo;
-
- // we only add one at a time, so we should only need to test for equality
- // just in case, we use an assert.
- assert(par->NumChildren() <= par->MaxNumChildren()+1);
- if (par->NumChildren() == par->MaxNumChildren()+1) {
- SplitNonLeafNode(par, relevels);
- }
-
- assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren());
- assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren());
- assert(treeTwo->Parent()->NumChildren() <= treeTwo->MaxNumChildren());
- assert(treeTwo->Parent()->NumChildren() >= treeTwo->MinNumChildren());
-
- // We need to delete this carefully since references to points are used.
- tree->SoftDelete();
-
- return;
-}
-
-/**
- * We call GetBoundSeeds to get the two new nodes that this one will be broken
- * into. Then we call AssignNodeDestNode to move the children of this node
- * into either of those two nodes. Finally, we delete the now unused information
- * and recurse up the tree if necessary. We don't need to worry about the bounds
- * higher up the tree because they were already updated if necessary.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-bool RTreeSplit<DescentType, StatisticType, MatType>::SplitNonLeafNode(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree,
- std::vector<bool>& relevels)
-{
- // If we are splitting the root node, we need will do things differently so that the constructor
- // and other methods don't confuse the end user by giving an address of another node.
- if (tree->Parent() == NULL) {
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* copy =
- new RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(*tree); // We actually want to copy this way. Pointers and everything.
- copy->Parent() = tree;
- tree->NumChildren() = 0;
- tree->NullifyData();
- tree->Child((tree->NumChildren())++) = copy;
- RTreeSplit<DescentType, StatisticType, MatType>::SplitNonLeafNode(copy, relevels);
- return true;
- }
-
- int i = 0;
- int j = 0;
- GetBoundSeeds(*tree, &i, &j);
-
- assert(i != j);
-
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeOne = new
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeTwo = new
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>(tree->Parent());
-
- // This will assign the ith and jth rectangles appropriately.
- AssignNodeDestNode(tree, treeOne, treeTwo, i, j);
-
- //Remove this node and insert treeOne and treeTwo
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* par = tree->Parent();
- int index = -1;
- for (int i = 0; i < par->NumChildren(); i++) {
- if (par->Child(i) == tree) {
- index = i;
- break;
- }
- }
- assert(index != -1);
- par->Child(index) = treeOne;
- par->Child(par->NumChildren()++) = treeTwo;
-
- for (int i = 0; i < par->NumChildren(); i++) {
- assert(par->Child(i) != tree);
- }
-
- // we only add one at a time, so should only need to test for equality
- // just in case, we use an assert.
- assert(par->NumChildren() <= par->MaxNumChildren()+1);
-
- if (par->NumChildren() == par->MaxNumChildren()+1) {
- SplitNonLeafNode(par, relevels);
- }
-
- // We have to update the children of each of these new nodes so that they record the
- // correct parent.
- for (int i = 0; i < treeOne->NumChildren(); i++) {
- treeOne->Child(i)->Parent() = treeOne;
- }
- for (int i = 0; i < treeTwo->NumChildren(); i++) {
- treeTwo->Child(i)->Parent() = treeTwo;
- }
-
- assert(treeOne->NumChildren() <= treeOne->MaxNumChildren());
- assert(treeTwo->NumChildren() <= treeTwo->MaxNumChildren());
- assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren());
-
- // Because we now have pointers to the information stored under this tree,
- // we need to delete this node carefully.
- tree->SoftDelete(); //currently does nothing but leak memory.
-
- return false;
-}
-
-/**
- * Get the two points that will be used as seeds for the split of a leaf node.
- * The indices of these points will be stored in iRet and jRet.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RTreeSplit<DescentType, StatisticType, MatType>::GetPointSeeds(
- const RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>& tree,
- int* iRet,
- int* jRet)
-{
- // Here we want to find the pair of points that it is worst to place in the same
- // node. Because we are just using points, we will simply choose the two that would
- // create the most voluminous hyperrectangle.
- double worstPairScore = -1.0;
- int worstI = 0;
- int worstJ = 0;
- for (int i = 0; i < tree.Count(); i++) {
- for (int j = i + 1; j < tree.Count(); j++) {
- double score = 1.0;
- for (int k = 0; k < tree.Bound().Dim(); k++) {
- score *= std::abs(tree.LocalDataset().at(k, i) - tree.LocalDataset().at(k, j)); // Points (in the dataset) are stored by column, but this function takes (row, col).
- }
- if (score > worstPairScore) {
- worstPairScore = score;
- worstI = i;
- worstJ = j;
- }
- }
- }
-
- *iRet = worstI;
- *jRet = worstJ;
- return;
-}
-
-/**
- * Get the two bounds that will be used as seeds for the split of the node.
- * The indices of the bounds will be stored in iRet and jRet.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RTreeSplit<DescentType, StatisticType, MatType>::GetBoundSeeds(
- const RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>& tree,
- int* iRet,
- int* jRet)
-{
- double worstPairScore = -1.0;
- int worstI = 0;
- int worstJ = 0;
- for (int i = 0; i < tree.NumChildren(); i++) {
- for (int j = i + 1; j < tree.NumChildren(); j++) {
- double score = 1.0;
- for (int k = 0; k < tree.Bound().Dim(); k++) {
- score *= std::max(tree.Child(i)->Bound()[k].Hi(), tree.Child(j)->Bound()[k].Hi()) -
- std::min(tree.Child(i)->Bound()[k].Lo(), tree.Child(j)->Bound()[k].Lo());
- }
- if (score > worstPairScore) {
- worstPairScore = score;
- worstI = i;
- worstJ = j;
- }
- }
- }
-
- *iRet = worstI;
- *jRet = worstJ;
- return;
-}
-
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RTreeSplit<DescentType, StatisticType, MatType>::AssignPointDestNode(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* oldTree,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeOne,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeTwo,
- const int intI,
- const int intJ)
-{
-
- int end = oldTree->Count();
-
- assert(end > 1); // If this isn't true, the tree is really weird.
-
- // Restart the point counts since we are going to move them.
- oldTree->Count() = 0;
- treeOne->Count() = 0;
- treeTwo->Count() = 0;
-
- treeOne->InsertPoint(oldTree->Points()[intI]);
- treeTwo->InsertPoint(oldTree->Points()[intJ]);
-
- // If intJ is the last point in the tree, we need to switch the order so that we remove the correct points.
- if (intI > intJ) {
- oldTree->Points()[intI] = oldTree->Points()[--end]; // decrement end
- oldTree->LocalDataset()[intI] = oldTree->LocalDataset()[end];
- oldTree->Points()[intJ] = oldTree->Points()[--end]; // decrement end
- oldTree->LocalDataset()[intJ] = oldTree->LocalDataset()[end];
- } else {
- oldTree->Points()[intJ] = oldTree->Points()[--end]; // decrement end
- oldTree->LocalDataset()[intJ] = oldTree->LocalDataset()[end];
- oldTree->Points()[intI] = oldTree->Points()[--end]; // decrement end
- oldTree->LocalDataset()[intI] = oldTree->LocalDataset()[end];
- }
-
-
- int numAssignedOne = 1;
- int numAssignedTwo = 1;
-
- // In each iteration, we go through all points and find the one that causes the least
- // increase of volume when added to one of the rectangles. We then add it to that
- // rectangle. We stop when we run out of points or when all of the remaining points
- // need to be assigned to the same rectangle to satisfy the minimum fill requirement.
-
- // The below is safe because if end decreases and the right hand side of the second part of the conjunction changes
- // on the same iteration, we added the point to the node with fewer points anyways.
- while (end > 0 && end > oldTree->MinLeafSize() - std::min(numAssignedOne, numAssignedTwo)) {
-
- int bestIndex = 0;
- double bestScore = DBL_MAX;
- int bestRect = 1;
-
- // Calculate the increase in volume for assigning this point to each rectangle.
-
- // First, calculate the starting volume.
- double volOne = 1.0;
- double volTwo = 1.0;
- for (int i = 0; i < oldTree->Bound().Dim(); i++) {
- volOne *= treeOne->Bound()[i].Width();
- volTwo *= treeTwo->Bound()[i].Width();
- }
-
- // Find the point that, when assigned to one of the two new rectangles, minimizes the increase
- // in volume.
- for (int index = 0; index < end; index++) {
- double newVolOne = 1.0;
- double newVolTwo = 1.0;
- for (int i = 0; i < oldTree->Bound().Dim(); i++) {
- double c = oldTree->LocalDataset().col(index)[i];
- newVolOne *= treeOne->Bound()[i].Contains(c) ? treeOne->Bound()[i].Width() :
- (c < treeOne->Bound()[i].Lo() ? (treeOne->Bound()[i].Hi() - c) : (c - treeOne->Bound()[i].Lo()));
- newVolTwo *= treeTwo->Bound()[i].Contains(c) ? treeTwo->Bound()[i].Width() :
- (c < treeTwo->Bound()[i].Lo() ? (treeTwo->Bound()[i].Hi() - c) : (c - treeTwo->Bound()[i].Lo()));
- }
-
- // Choose the rectangle that requires the lesser increase in volume.
- if ((newVolOne - volOne) < (newVolTwo - volTwo)) {
- if (newVolOne - volOne < bestScore) {
- bestScore = newVolOne - volOne;
- bestIndex = index;
- bestRect = 1;
- }
- } else {
- if (newVolTwo - volTwo < bestScore) {
- bestScore = newVolTwo - volTwo;
- bestIndex = index;
- bestRect = 2;
- }
- }
- }
-
- // Assign the point that causes the least increase in volume
- // to the appropriate rectangle.
- if (bestRect == 1) {
- treeOne->InsertPoint(oldTree->Points()[bestIndex]);
- numAssignedOne++;
- } else {
- treeTwo->InsertPoint(oldTree->Points()[bestIndex]);
- numAssignedTwo++;
- }
-
- oldTree->Points()[bestIndex] = oldTree->Points()[--end]; // decrement end.
- oldTree->LocalDataset().col(bestIndex) = oldTree->LocalDataset().col(end);
- }
-
- // See if we need to satisfy the minimum fill.
- if (end > 0) {
- if (numAssignedOne < numAssignedTwo) {
- for (int i = 0; i < end; i++) {
- treeOne->InsertPoint(oldTree->Points()[i]);
- }
- } else {
- for (int i = 0; i < end; i++) {
- treeTwo->InsertPoint(oldTree->Points()[i]);
- }
- }
- }
-}
-
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RTreeSplit<DescentType, StatisticType, MatType>::AssignNodeDestNode(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* oldTree,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeOne,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* treeTwo,
- const int intI,
- const int intJ)
-{
-
- int end = oldTree->NumChildren();
- assert(end > 1); // If this isn't true, the tree is really weird.
-
- assert(intI != intJ);
-
- for (int i = 0; i < oldTree->NumChildren(); i++) {
- for (int j = i + 1; j < oldTree->NumChildren(); j++) {
- assert(oldTree->Child(i) != oldTree->Child(j));
- }
- }
-
- InsertNodeIntoTree(treeOne, oldTree->Child(intI));
- InsertNodeIntoTree(treeTwo, oldTree->Child(intJ));
-
- // If intJ is the last node in the tree, we need to switch the order so that we remove the correct nodes.
- if (intI > intJ) {
- oldTree->Child(intI) = oldTree->Child(--end); // decrement end
- oldTree->Child(intJ) = oldTree->Child(--end); // decrement end
- } else {
- oldTree->Child(intJ) = oldTree->Child(--end); // decrement end
- oldTree->Child(intI) = oldTree->Child(--end); // decrement end
- }
-
- assert(treeOne->NumChildren() == 1);
- assert(treeTwo->NumChildren() == 1);
-
- for (int i = 0; i < end; i++) {
- for (int j = i + 1; j < end; j++) {
- assert(oldTree->Child(i) != oldTree->Child(j));
- }
- }
-
- for (int i = 0; i < end; i++) {
- assert(oldTree->Child(i) != treeOne->Child(0));
- }
-
- for (int i = 0; i < end; i++) {
- assert(oldTree->Child(i) != treeTwo->Child(0));
- }
-
-
- int numAssignTreeOne = 1;
- int numAssignTreeTwo = 1;
-
- // In each iteration, we go through all of the nodes and find the one that causes the least
- // increase of volume when added to one of the two new rectangles. We then add it to that
- // rectangle.
- while (end > 0 && end > oldTree->MinNumChildren() - std::min(numAssignTreeOne, numAssignTreeTwo)) {
- int bestIndex = 0;
- double bestScore = DBL_MAX;
- int bestRect = 0;
-
- // Calculate the increase in volume for assigning this node to each of the new rectangles.
- double volOne = 1.0;
- double volTwo = 1.0;
- for (int i = 0; i < oldTree->Bound().Dim(); i++) {
- volOne *= treeOne->Bound()[i].Width();
- volTwo *= treeTwo->Bound()[i].Width();
- }
-
- for (int index = 0; index < end; index++) {
- double newVolOne = 1.0;
- double newVolTwo = 1.0;
- for (int i = 0; i < oldTree->Bound().Dim(); i++) {
- // For each of the new rectangles, find the width in this dimension if we add the rectangle at index to
- // the new rectangle.
- math::Range range = oldTree->Child(index)->Bound()[i];
- newVolOne *= treeOne->Bound()[i].Contains(range) ? treeOne->Bound()[i].Width() :
- (range.Contains(treeOne->Bound()[i]) ? range.Width() : (range.Lo() < treeOne->Bound()[i].Lo() ? (treeOne->Bound()[i].Hi() - range.Lo()) :
- (range.Hi() - treeOne->Bound()[i].Lo())));
- newVolTwo *= treeTwo->Bound()[i].Contains(range) ? treeTwo->Bound()[i].Width() :
- (range.Contains(treeTwo->Bound()[i]) ? range.Width() : (range.Lo() < treeTwo->Bound()[i].Lo() ? (treeTwo->Bound()[i].Hi() - range.Lo()) :
- (range.Hi() - treeTwo->Bound()[i].Lo())));
- }
-
- // Choose the rectangle that requires the lesser increase in volume.
- if ((newVolOne - volOne) < (newVolTwo - volTwo)) {
- if (newVolOne - volOne < bestScore) {
- bestScore = newVolOne - volOne;
- bestIndex = index;
- bestRect = 1;
- }
- } else {
- if (newVolTwo - volTwo < bestScore) {
- bestScore = newVolTwo - volTwo;
- bestIndex = index;
- bestRect = 2;
- }
- }
- }
-
- // Assign the rectangle that causes the least increase in volume
- // to the appropriate rectangle.
- if (bestRect == 1) {
- InsertNodeIntoTree(treeOne, oldTree->Child(bestIndex));
- numAssignTreeOne++;
- } else {
- InsertNodeIntoTree(treeTwo, oldTree->Child(bestIndex));
- numAssignTreeTwo++;
- }
-
- oldTree->Child(bestIndex) = oldTree->Child(--end); // Decrement end.
- }
- // See if we need to satisfy the minimum fill.
- if (end > 0) {
- if (numAssignTreeOne < numAssignTreeTwo) {
- for (int i = 0; i < end; i++) {
- InsertNodeIntoTree(treeOne, oldTree->Child(i));
- numAssignTreeOne++;
- }
- } else {
- for (int i = 0; i < end; i++) {
- InsertNodeIntoTree(treeTwo, oldTree->Child(i));
- numAssignTreeTwo++;
- }
- }
- }
-
- for (int i = 0; i < treeOne->NumChildren(); i++) {
- for (int j = i + 1; j < treeOne->NumChildren(); j++) {
- assert(treeOne->Child(i) != treeOne->Child(j));
- }
- }
- for (int i = 0; i < treeTwo->NumChildren(); i++) {
- for (int j = i + 1; j < treeTwo->NumChildren(); j++) {
- assert(treeTwo->Child(i) != treeTwo->Child(j));
- }
- }
-}
-
-/**
- * Insert a node into another node. Expanding the bounds and updating the numberOfChildren.
- */
-template<typename DescentType,
-typename StatisticType,
-typename MatType>
-void RTreeSplit<DescentType, StatisticType, MatType>::InsertNodeIntoTree(
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* destTree,
- RectangleTree<RTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* srcNode)
-{
- destTree->Bound() |= srcNode->Bound();
- destTree->Child(destTree->NumChildren()++) = srcNode;
-}
-
-
-}; // namespace tree
-}; // namespace mlpack
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp
deleted file mode 100644
index f8639de..0000000
--- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp
+++ /dev/null
@@ -1,526 +0,0 @@
-/**
- * @file rectangle_tree.hpp
- * @author Andrew Wells
- *
- * Definition of generalized rectangle type trees (r_tree, r_star_tree, x_tree, and hilbert_r_tree).
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_RECTANGLE_TREE_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_RECTANGLE_TREE_HPP
-
-#include <mlpack/core.hpp>
-
-#include "../hrectbound.hpp"
-#include "../statistic.hpp"
-
-namespace mlpack {
-namespace tree /** Trees and tree-building procedures. */ {
-
-using bound::HRectBound;
-
-/**
- * A rectangle type tree tree, such as an R-tree or X-tree. Once the
- * bound and type of dataset is defined, the tree will construct itself. Call
- * the constructor with the dataset to build the tree on, and the entire tree
- * will be built.
- *
- * This tree does allow growth, so you can add and delete nodes
- * from it.
- *
- * @tparam StatisticType Extra data contained in the node. See statistic.hpp
- * for the necessary skeleton interface.
- * @tparam MatType The dataset class.
- * @tparam SplitType The type of split to use when inserting points.
- * @tparam DescentType The heuristic to use when descending the tree to insert points.
- */
-
-template<typename SplitType,
- typename DescentType,
- typename StatisticType = EmptyStatistic,
- typename MatType = arma::mat>
-class RectangleTree
-{
- private:
- //! The max number of child nodes a non-leaf node can have.
- size_t maxNumChildren;
- //! The minimum number of child nodes a non-leaf node can have.
- size_t minNumChildren;
- //! The number of child nodes actually in use (0 if this is a leaf node).
- size_t numChildren;
- //! The child nodes (Starting at 0 and ending at (numChildren-1) ).
- std::vector<RectangleTree*> children;
- //! The parent node (NULL if this is the root of the tree).
- RectangleTree* parent;
- //! The index of the first point in the dataset contained in this node (and
- //! its children). THIS IS ALWAYS 0 AT THE MOMENT. IT EXISTS MERELY IN CASE
- //! I THINK OF A WAY TO CHANGE THAT. IN OTHER WORDS, IT WILL PROBABLY BE
- //! REMOVED.
- size_t begin;
- //! The number of points in the dataset contained in this node (and its
- //! children).
- size_t count;
- //! The max leaf size.
- size_t maxLeafSize;
- //! The minimum leaf size.
- size_t minLeafSize;
- //! The bound object for this node.
- HRectBound<> bound;
- //! Any extra data contained in the node.
- StatisticType stat;
- //! The distance from the centroid of this node to the centroid of the parent.
- double parentDistance;
- //! The discance to the furthest descendant, cached to speed things up.
- double furthestDescendantDistance;
- //! The dataset.
- MatType& dataset;
- //! The mapping to the dataset
- std::vector<size_t> points;
- //! The local dataset
- MatType* localDataset;
-
- public:
- //! So other classes can use TreeType::Mat.
- typedef MatType Mat;
-
- //! A single traverser for rectangle type trees. See
- //! single_tree_traverser.hpp for implementation.
- template<typename RuleType>
- class SingleTreeTraverser;
- //! A dual tree traverser for rectangle type trees.
- template<typename RuleType>
- class DualTreeTraverser;
-
- /**
- * Construct this as the root node of a rectangle type tree using the given
- * dataset. This will modify the ordering of the points in the dataset!
- *
- * @param data Dataset from which to create the tree. This will be modified!
- * @param maxLeafSize Maximum size of each leaf in the tree.
- * @param minLeafSize Minimum size of each leaf in the tree.
- * @param maxNumChildren The maximum number of child nodes a non-leaf node may have.
- * @param minNumChildren The minimum number of child nodes a non-leaf node may have.
- * @param firstDataIndex The index of the first data point. UNUSED UNLESS WE ADD SUPPORT FOR HAVING A
- * "CENTERAL" DATA MATRIX.
- */
- RectangleTree(MatType& data,
- const size_t maxLeafSize = 20,
- const size_t minLeafSize = 6,
- const size_t maxNumChildren = 4,
- const size_t minNumChildren = 0,
- const size_t firstDataIndex = 0
- );
-
- /**
- * Construct this as an empty node with the specified parent. Copying the parameters
- * (maxLeafSize, minLeafSize, maxNumChildren, minNumChildren, firstDataIndex) from the parent.
- *
- * @param parentNode The parent of the node that is being constructed.
- */
- explicit RectangleTree(RectangleTree<SplitType, DescentType, StatisticType, MatType>* parentNode);
-
-
- //TODO implement the oldFromNew stuff if applicable.
-
- /**
- * Deletes this node, deallocating the memory for the children and calling
- * their destructors in turn. This will invalidate any younters or references
- * to any nodes which are children of this one.
- */
- ~RectangleTree();
-
- /**
- * Delete this node of the tree, but leave the stuff contained in it intact.
- * This is used when splitting a node, where the data in this tree is moved to two
- * other trees.
- */
- void SoftDelete();
-
- /**
- * Set dataset to null. Used for memory management. Be cafeful.
- */
- void NullifyData();
-
- /**
- * Inserts a point into the tree. The point will be copied to the data matrix
- * of the leaf node where it is finally inserted, but we pass by reference since
- * it may be passed many times before it actually reaches a leaf.
- * @param point The point (arma::vec&) to be inserted.
- */
- void InsertPoint(const size_t point);
-
- /**
- * Inserts a point into the tree, tracking which levels have been inserted into.
- * The point will be copied to the data matrix of the leaf node where it is
- * finally inserted, but we pass by reference since it may be passed many times
- * before it actually reaches a leaf.
- * @param point The point (arma::vec&) to be inserted.
- * @param relevels The levels that have been reinserted to on this top level insertion.
- */
- void InsertPoint(const size_t point, std::vector<bool>& relevels);
-
- /**
- * Inserts a node into the tree, tracking which levels have been inserted into.
- * The node will be inserted so that the tree remains valid.
- * @param node The node to be inserted.
- * @param level The depth that should match the node where this node is finally inserted.
- * This should be the number returned by calling TreeDepth() from the node that originally
- * contained "node".
- * @param relevels The levels that have been reinserted to on this top level insertion.
- */
- void InsertNode(const RectangleTree* node, const size_t level, std::vector<bool>& relevels);
-
- /**
- * Deletes a point in the tree. The point will be removed from the data matrix
- * of the leaf node where it is store and the bounding rectangles will be updated.
- * However, the point will be kept in the centeral dataset. (The user may remove it
- * from there if he wants, but he must not change the indices of the other points.)
- * Returns true if the point is successfully removed and false if it is not.
- * (ie. the point is not in the tree)
- */
- bool DeletePoint(const size_t point);
-
- /**
- * Deletes a point in the tree, tracking levels. The point will be removed from the data matrix
- * of the leaf node where it is store and the bounding rectangles will be updated.
- * However, the point will be kept in the centeral dataset. (The user may remove it
- * from there if he wants, but he must not change the indices of the other points.)
- * Returns true if the point is successfully removed and false if it is not.
- * (ie. the point is not in the tree)
- */
- bool DeletePoint(const size_t point, std::vector<bool>& relevels);
-
- /**
- * Deletes a node from the tree (along with all descendants).
- */
- bool DeleteNode(const RectangleTree* node, std::vector<bool>& relevels);
-
- /**
- * Find a node in this tree by its begin and count (const).
- *
- * Every node is uniquely identified by these two numbers.
- * This is useful for communicating position over the network,
- * when pointers would be invalid.
- *
- * @param begin The begin() of the node to find.
- * @param count The count() of the node to find.
- * @return The found node, or NULL if not found.
- */
- const RectangleTree* FindByBeginCount(size_t begin, size_t count) const;
-
- /**
- * Find a node in this tree by its begin and count.
- *
- * Every node is uniquely identified by these two numbers.
- * This is useful for communicating position over the network,
- * when pointers would be invalid.
- *
- * @param begin The begin() of the node to find.
- * @param count The count() of the node to find.
- * @return The found node, or NULL if not found.
- */
- RectangleTree* FindByBeginCount(size_t begin, size_t count);
-
- //! Return the bound object for this node.
- const HRectBound<>& Bound() const { return bound; }
- //! Modify the bound object for this node.
- HRectBound<>& Bound() { return bound; }
-
- //! Return the statistic object for this node.
- const StatisticType& Stat() const { return stat; }
- //! Modify the statistic object for this node.
- StatisticType& Stat() { return stat; }
-
- //! Return whether or not this node is a leaf (true if it has no children).
- bool IsLeaf() const;
-
- //! Return the maximum leaf size.
- size_t MaxLeafSize() const { return maxLeafSize; }
- //! Modify the maximum leaf size.
- size_t& MaxLeafSize() { return maxLeafSize; }
-
- //! Return the minimum leaf size.
- size_t MinLeafSize() const { return minLeafSize; }
- //! Modify the minimum leaf size.
- size_t& MinLeafSize() { return minLeafSize; }
-
- //! Return the maximum number of children (in a non-leaf node).
- size_t MaxNumChildren() const { return maxNumChildren; }
- //! Modify the maximum number of children (in a non-leaf node).
- size_t& MaxNumChildren() { return maxNumChildren; }
-
- //! Return the minimum number of children (in a non-leaf node).
- size_t MinNumChildren() const { return minNumChildren; }
- //! Modify the minimum number of children (in a non-leaf node).
- size_t& MinNumChildren() { return minNumChildren; }
-
- //! Gets the parent of this node.
- RectangleTree* Parent() const { return parent; }
- //! Modify the parent of this node.
- RectangleTree*& Parent() { return parent; }
-
- //! Get the dataset which the tree is built on.
- const arma::mat& Dataset() const { return dataset; }
- //! Modify the dataset which the tree is built on. Be careful!
- arma::mat& Dataset() { return dataset; }
-
- //! Get the points vector for this node.
- const std::vector<size_t>& Points() const { return points; }
- //! Modify the points vector for this node. Be careful!
- std::vector<size_t>& Points() { return points; }
-
- //! Get the local dataset of this node.
- const arma::mat& LocalDataset() const { return *localDataset; }
- //! Modify the local dataset of this node.
- arma::mat& LocalDataset() { return *localDataset; }
-
- //! Get the metric which the tree uses.
- typename HRectBound<>::MetricType Metric() const { return bound.Metric(); }
-
- //! Get the centroid of the node and store it in the given vector.
- void Centroid(arma::vec& centroid) { bound.Centroid(centroid); }
-
- //! Return the number of child nodes. (One level beneath this one only.)
- size_t NumChildren() const { return numChildren; }
- //! Modify the number of child nodes. Be careful.
- size_t& NumChildren() { return numChildren; }
-
- //! Get the children of this node.
- const std::vector<RectangleTree*>& Children() const { return children; }
- //! Modify the children of this node.
- std::vector<RectangleTree*>& Children() { return children; }
-
- /**
- * Return the furthest distance to a point held in this node. If this is not
- * a leaf node, then the distance is 0 because the node holds no points.
- */
- double FurthestPointDistance() const;
-
- /**
- * Return the furthest possible descendant distance. This returns the maximum
- * distance from the centroid to the edge of the bound and not the empirical
- * quantity which is the actual furthest descendant distance. So the actual
- * furthest descendant distance may be less than what this method returns (but
- * it will never be greater than this).
- */
- double FurthestDescendantDistance() const;
-
- //! Return the minimum distance from the center to any edge of the bound.
- //! Currently, this returns 0, which doesn't break algorithms, but it isn't
- //! necessarily correct, either.
- double MinimumBoundDistance() const { return bound.MinWidth() / 2.0; }
-
- //! Return the distance from the center of this node to the center of the
- //! parent node.
- double ParentDistance() const { return parentDistance; }
- //! Modify the distance from the center of this node to the center of the
- //! parent node.
- double& ParentDistance() { return parentDistance; }
-
- /**
- * Get the specified child.
- *
- * @param child Index of child to return.
- */
- inline RectangleTree<SplitType, DescentType, StatisticType, MatType>*
- Child(const size_t child) const
- {
- return children[child];
- }
-
- /**
- * Modify the specified child.
- *
- * @param child Index of child to return.
- */
- inline RectangleTree<SplitType, DescentType, StatisticType, MatType>*&
- Child(const size_t child)
- {
- return children[child];
- }
-
- //! Return the number of points in this node (returns 0 if this node is not a leaf).
- size_t NumPoints() const;
-
- /**
- * Return the number of descendants of this node. For a non-leaf in a binary
- * space tree, this is the number of points at the descendant leaves. For a
- * leaf, this is the number of points in the leaf.
- */
- size_t NumDescendants() const;
-
- /**
- * Return the index (with reference to the dataset) of a particular descendant
- * of this node. The index should be greater than zero but less than the
- * number of descendants.
- *
- * @param index Index of the descendant.
- */
- size_t Descendant(const size_t index) const;
-
- /**
- * Return the index (with reference to the dataset) of a particular point in
- * this node. This will happily return invalid indices if the given index is
- * greater than the number of points in this node (obtained with NumPoints())
- * -- be careful.
- *
- * @param index Index of point for which a dataset index is wanted.
- */
- size_t Point(const size_t index) const;
-
- //! Return the minimum distance to another node.
- double MinDistance(const RectangleTree* other) const
- {
- return bound.MinDistance(other->Bound());
- }
-
- //! Return the maximum distance to another node.
- double MaxDistance(const RectangleTree* other) const
- {
- return bound.MaxDistance(other->Bound());
- }
-
- //! Return the minimum and maximum distance to another node.
- math::Range RangeDistance(const RectangleTree* other) const
- {
- return bound.RangeDistance(other->Bound());
- }
-
-
- //! Return the minimum distance to another point.
- template<typename VecType>
- double MinDistance(const VecType& point,
- typename boost::enable_if<IsVector<VecType> >::type* = 0)
- const
- {
- return bound.MinDistance(point);
- }
-
- //! Return the maximum distance to another point.
- template<typename VecType>
- double MaxDistance(const VecType& point,
- typename boost::enable_if<IsVector<VecType> >::type* = 0)
- const
- {
- return bound.MaxDistance(point);
- }
-
- //! Return the minimum and maximum distance to another point.
- template<typename VecType>
- math::Range
- RangeDistance(const VecType& point,
- typename boost::enable_if<IsVector<VecType> >::type* = 0) const
- {
- return bound.RangeDistance(point);
- }
-
- /**
- * Obtains the number of nodes in the tree, starting with this.
- */
- size_t TreeSize() const;
-
- /**
- * Obtains the number of levels below this node in the tree, starting with
- * this.
- */
- size_t TreeDepth() const;
-
- //! Return the index of the beginning point of this subset.
- size_t Begin() const { return begin; }
- //! Modify the index of the beginning point of this subset.
- size_t& Begin() { return begin; }
-
- /**
- * Gets the index one beyond the last index in the subset. CURRENTLY MEANINGLESS!
- */
- size_t End() const;
-
- //! Return the number of points in this subset.
- size_t Count() const { return count; }
- //! Modify the number of points in this subset.
- size_t& Count() { return count; }
-
- //! Returns false: this tree type does not have self children.
- static bool HasSelfChildren() { return false; }
-
- private:
- /**
- * Private copy constructor, available only to fill (pad) the tree to a
- * specified level. TO BE REMOVED
- */
- RectangleTree(const size_t begin,
- const size_t count,
- HRectBound<> bound,
- StatisticType stat,
- const int maxLeafSize = 20) :
- begin(begin),
- count(count),
- bound(bound),
- stat(stat),
- maxLeafSize(maxLeafSize) { }
-
- RectangleTree* CopyMe()
- {
- return new RectangleTree(begin, count, bound, stat, maxLeafSize);
- }
-
- /**
- * Splits the current node, recursing up the tree.
- *
- * @param relevels Vector to track which levels have been inserted to.
- */
- void SplitNode(std::vector<bool>& relevels);
-
- /**
- * Splits the current node, recursing up the tree.
- * CURRENTLY IT DOES NOT Also returns a list of the changed indices (because there are none).
- *
- * @param data Dataset which we are using.
- * @param oldFromNew Vector holding permuted indices NOT IMPLEMENTED.
- */
- void SplitNode(std::vector<size_t>& oldFromNew);
-
- public:
- /**
- * Condense the bounding rectangles for this node based on the removal of
- * the point specified by the arma::vec&. This recurses up the tree. If a node
- * goes below the minimum fill, this function will fix the tree.
- *
- * @param point The arma::vec& of the point that was removed to require this
- * condesation of the tree.
- * @param usePoint True if we use the optimized version of the algorithm that is
- * possible when we now what point was deleted. False otherwise (eg. if we
- * deleted a node instead of a point).
- */
- void CondenseTree(const arma::vec& point, std::vector<bool>& relevels, const bool usePoint);
-
- /**
- * Shrink the bound object of this node for the removal of a point.
- *
- * @param point The arma::vec& of the point that was removed to require this
- * shrinking.
- * @return true if the bound needed to be changed, false if it did not.
- */
- bool ShrinkBoundForPoint(const arma::vec& point);
-
- /**
- * Shrink the bound object of this node for the removal of a child node.
- *
- * @param bound The HRectBound<>& of the bound that was removed to reqire this
- * shrinking.
- * @return true if the bound needed to be changed, false if it did not.
- */
- bool ShrinkBoundForBound(const HRectBound<>& changedBound);
-
- /**
- * Returns a string representation of this object.
- */
- std::string ToString() const;
-
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-// Include implementation.
-#include "rectangle_tree_impl.hpp"
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp
deleted file mode 100644
index b642048..0000000
--- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/**
- * @file rectangle_tree_impl.hpp
- * @author Andrew Wells
- *
- * Implementation of generalized rectangle tree.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_RECTANGLE_TREE_IMPL_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_RECTANGLE_TREE_IMPL_HPP
-
-// In case it wasn't included already for some reason.
-#include "rectangle_tree.hpp"
-
-#include <mlpack/core/util/cli.hpp>
-#include <mlpack/core/util/log.hpp>
-#include <mlpack/core/util/string_util.hpp>
-
-namespace mlpack {
-namespace tree {
-
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-RectangleTree<SplitType, DescentType, StatisticType, MatType>::RectangleTree(
- MatType& data,
- const size_t maxLeafSize,
- const size_t minLeafSize,
- const size_t maxNumChildren,
- const size_t minNumChildren,
- const size_t firstDataIndex) :
-maxNumChildren(maxNumChildren),
-minNumChildren(minNumChildren),
-numChildren(0),
-children(maxNumChildren + 1), // Add one to make splitting the node simpler
-parent(NULL),
-begin(0),
-count(0),
-maxLeafSize(maxLeafSize),
-minLeafSize(minLeafSize),
-bound(data.n_rows),
-parentDistance(0),
-dataset(data),
-points(maxLeafSize + 1), // Add one to make splitting the node simpler.
-localDataset(new MatType(data.n_rows, static_cast<int> (maxLeafSize) + 1)) // Add one to make splitting the node simpler
-{
- stat = StatisticType(*this);
-
- // For now, just insert the points in order.
- RectangleTree* root = this;
-
- //for(int i = firstDataIndex; i < 57; i++) { // 56,57 are the bound for where it works/breaks
- for (size_t i = firstDataIndex; i < data.n_cols; i++) {
- root->InsertPoint(i);
- }
-}
-
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-RectangleTree<SplitType, DescentType, StatisticType, MatType>::RectangleTree(
- RectangleTree<SplitType, DescentType, StatisticType, MatType>* parentNode) :
-maxNumChildren(parentNode->MaxNumChildren()),
-minNumChildren(parentNode->MinNumChildren()),
-numChildren(0),
-children(maxNumChildren + 1),
-parent(parentNode),
-begin(0),
-count(0),
-maxLeafSize(parentNode->MaxLeafSize()),
-minLeafSize(parentNode->MinLeafSize()),
-bound(parentNode->Bound().Dim()),
-parentDistance(0),
-dataset(parentNode->Dataset()),
-points(maxLeafSize + 1), // Add one to make splitting the node simpler.
-localDataset(new MatType(static_cast<int> (parentNode->Bound().Dim()), static_cast<int> (maxLeafSize) + 1)) // Add one to make splitting the node simpler
-{
- stat = StatisticType(*this);
-}
-
-/**
- * Deletes this node, deallocating the memory for the children and calling
- * their destructors in turn. This will invalidate any pointers or references
- * to any nodes which are children of this one.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-~RectangleTree()
-{
- for (int i = 0; i < numChildren; i++) {
- delete children[i];
- }
- //if(numChildren == 0)
- delete localDataset;
-}
-
-/**
- * Deletes this node but leaves the children untouched. Needed for when we
- * split nodes and remove nodes (inserting and deleting points).
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-SoftDelete()
-{
- //if(numChildren != 0)
- //dataset = NULL;
- parent = NULL;
- for (int i = 0; i < children.size(); i++) {
- children[i] = NULL;
- }
- numChildren = 0;
- delete this;
-}
-
-/**
- * Set the dataset to null.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-NullifyData()
-{
- localDataset = NULL;
-}
-
-/**
- * Recurse through the tree and insert the point at the leaf node chosen
- * by the heuristic.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-InsertPoint(const size_t point)
-{
- // Expand the bound regardless of whether it is a leaf node.
- bound |= dataset.col(point);
-
- // If this is a leaf node, we stop here and add the point.
- if (numChildren == 0) {
- localDataset->col(count) = dataset.col(point);
- points[count++] = point;
- std::vector<bool> lvls(TreeDepth());
- SplitNode(lvls);
- return;
- }
-
- // If it is not a leaf node, we use the DescentHeuristic to choose a child
- // to which we recurse.
- children[DescentType::ChooseDescentNode(this, dataset.col(point))]->InsertPoint(point);
-}
-
-/**
- * Inserts a point into the tree, tracking which levels have been inserted into.
- * The point will be copied to the data matrix
- * of the leaf node where it is finally inserted, but we pass by reference since
- * it may be passed many times before it actually reaches a leaf.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::InsertPoint(const size_t point, std::vector<bool>& relevels)
-{
- // Expand the bound regardless of whether it is a leaf node.
- bound |= dataset.col(point);
-
- // If this is a leaf node, we stop here and add the point.
- if (numChildren == 0) {
- localDataset->col(count) = dataset.col(point);
- points[count++] = point;
- std::vector<bool> lvls(TreeDepth());
- SplitNode(lvls);
- return;
- }
-
- // If it is not a leaf node, we use the DescentHeuristic to choose a child
- // to which we recurse.
- children[DescentType::ChooseDescentNode(this, dataset.col(point))]->InsertPoint(point);
-}
-
-/**
- * Inserts a node into the tree, tracking which levels have been inserted into.
- * @param node The node to be inserted.
- * @param level The level on which this node should be inserted.
- * @param relevels The levels that have been reinserted to on this top level insertion.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::InsertNode(const RectangleTree* node, const size_t level, std::vector<bool>& relevels)
-{
- // Expand the bound regardless of the level.
- bound |= node->Bound();
-
- if (level == TreeDepth()) {
- children[numChildren++] = const_cast<RectangleTree*> (node);
- assert(numChildren <= maxNumChildren); // We should never have increased without splitting.
- if (numChildren == maxNumChildren)
- SplitType::SplitNonLeafNode(this, relevels);
- } else {
- children[DescentType::ChooseDescentNode(this, node)]->InsertNode(node, level, relevels);
- }
-}
-
-/**
- * Recurse through the tree to remove the point. Once we find the point, we
- * shrink the rectangles if necessary.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-bool RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-DeletePoint(const size_t point)
-{
- if (numChildren == 0) {
- for (size_t i = 0; i < count; i++) {
- if (points[i] == point) {
- localDataset->col(i) = localDataset->col(--count); // decrement count
- points[i] = points[count];
- //It is possible that this will cause a reinsertion, so we need to handle the lvls properly.
- RectangleTree* root = this;
- while(root->Parent() != NULL)
- root = root->Parent();
- std::vector<bool> lvls(root->TreeDepth());
- CondenseTree(dataset.col(point), lvls, true); // This function will ensure that minFill is satisfied.
- return true;
- }
- }
- }
- for (size_t i = 0; i < numChildren; i++) {
- if (children[i]->Bound().Contains(dataset.col(point)))
- if (children[i]->DeletePoint(point))
- return true;
- }
- return false;
-}
-
-/**
- * Recurse through the tree to remove the point. Once we find the point, we
- * shrink the rectangles if necessary.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-bool RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-DeletePoint(const size_t point, std::vector<bool>& relevels)
-{
- if (numChildren == 0) {
- for (size_t i = 0; i < count; i++) {
- if (points[i] == point) {
- localDataset->col(i) = localDataset->col(--count); // decrement count
- points[i] = points[count];
- CondenseTree(dataset.col(point), relevels, true); // This function will ensure that minFill is satisfied.
- return true;
- }
- }
- }
- for (size_t i = 0; i < numChildren; i++) {
- if (children[i]->Bound().Contains(dataset.col(point)))
- if (children[i]->DeletePoint(point))
- return true;
- }
- return false;
-}
-
-/**
- * Recurse through the tree to remove the node. Once we find the node, we
- * shrink the rectangles if necessary.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-bool RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-DeleteNode(const RectangleTree* node, std::vector<bool>& relevels)
-{
- for (size_t i = 0; i < numChildren; i++) {
- if (children[i] == node) {
- children[i] = children[--numChildren]; // Decrement numChildren
- CondenseTree(arma::vec(), false);
- return true;
- }
- if (children[i]->Bound().Contains(node->Bound()))
- if (children[i]->DeleteNode(node))
- return true;
- }
- return false;
-}
-
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-size_t RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-TreeSize() const
-{
- int n = 0;
- for (int i = 0; i < numChildren; i++) {
- n += children[i]->TreeSize();
- }
- return n + 1; // we add one for this node
-}
-
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-size_t RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-TreeDepth() const
-{
- /* Because R trees are balanced, we could simplify this. However, X trees are not
- guaranteed to be balanced so I keep it as is: */
- int n = 1;
- RectangleTree<SplitType, DescentType, StatisticType, MatType>* currentNode =
- const_cast<RectangleTree*> (this);
- while (!currentNode->IsLeaf()) {
- currentNode = currentNode->Children()[0];
- n++;
- }
- return n;
-}
-
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline bool RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-IsLeaf() const
-{
- return numChildren == 0;
-}
-
-/**
- * Return a bound on the furthest point in the node form the centroid.
- * This returns 0 unless the node is a leaf.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline double RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-FurthestPointDistance() const
-{
- if (!IsLeaf())
- return 0.0;
-
- // Otherwise return the distance from the centroid to a corner of the bound.
- return 0.5 * bound.Diameter();
-}
-
-/**
- * Return the furthest possible descendant distance. This returns the maximum
- * distance from the centroid to the edge of the bound and not the empirical
- * quantity which is the actual furthest descendant distance. So the actual
- * furthest descendant distance may be less than what this method returns (but
- * it will never be greater than this).
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline double RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-FurthestDescendantDistance() const
-{
- //return the distance from the centroid to a corner of the bound.
- return 0.5 * bound.Diameter();
-}
-
-/**
- * Return the number of points contained in this node. Zero if it is a non-leaf node.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline size_t RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-NumPoints() const
-{
- if (numChildren != 0) // This is not a leaf node.
- return 0;
-
- return count;
-}
-
-/**
- * Return the number of descendants under or in this node.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline size_t RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-NumDescendants() const
-{
- if (numChildren == 0)
- return count;
- else {
- size_t n = 0;
- for (int i = 0; i < numChildren; i++) {
- n += children[i]->NumDescendants();
- }
- return n;
- }
-}
-
-/**
- * Return the index of a particular descendant contained in this node.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline size_t RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-Descendant(const size_t index) const
-{
- return (points[index]);
-}
-
-/**
- * Return the index of a particular point contained in this node.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline size_t RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-Point(const size_t index) const
-{
- return dataset(points[index]);
-}
-
-/**
- * Return the last point in the tree. WARNING: POINTS ARE NOT MOVED IN THE ORIGINAL DATASET,
- * SO THIS IS RATHER POINTLESS.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-inline size_t RectangleTree<SplitType, DescentType, StatisticType, MatType>::End() const
-{
- if (numChildren)
- return begin + count;
- return children[numChildren - 1]->End();
-}
-
-//have functions for returning the list of modified indices if we end up doing it that way.
-
-/**
- * Split the tree. This calls the SplitType code to split a node. This method should only
- * be called on a leaf node.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::SplitNode(std::vector<bool>& relevels)
-{
- // This should always be a leaf node. When we need to split other nodes,
- // the split will be called from here but will take place in the SplitType code.
- assert(numChildren == 0);
-
- // Check to see if we are full.
- if (count < maxLeafSize)
- return; // We don't need to split.
-
- // If we are full, then we need to split (or at least try). The SplitType takes
- // care of this and of moving up the tree if necessary.
- SplitType::SplitLeafNode(this, relevels);
-}
-
-/**
- * Condense the tree. This shrinks the bounds and moves up the tree if applicable.
- * If a node goes below minimum fill, this code will deal with it.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::CondenseTree(const arma::vec& point, std::vector<bool>& relevels, const bool usePoint)
-{
- // First delete the node if we need to. There's no point in shrinking the bound first.
- if (IsLeaf() && count < minLeafSize && parent != NULL) { //We can't delete the root node
- for (size_t i = 0; i < parent->NumChildren(); i++) {
- if (parent->Children()[i] == this) {
- parent->Children()[i] = parent->Children()[--parent->NumChildren()]; // decrement numChildren
- parent->ShrinkBoundForBound(bound); // We want to do this before reinserting points.
-
- // Reinsert the points at the root node.
- RectangleTree<SplitType, DescentType, StatisticType, MatType>* root = parent;
- while (root->Parent() != NULL)
- root = root->Parent();
-
- for (size_t j = 0; j < count; j++) {
- root->InsertPoint(points[j]);
- }
-
- parent->CondenseTree(point, relevels, usePoint); // This will check the MinFill of the parent.
- //Now it should be safe to delete this node.
- SoftDelete();
- return;
- }
- }
- // Control should never reach here.
- assert(true == false);
- } else if (!IsLeaf() && numChildren < minNumChildren) {
-
- if (parent != NULL) { // The normal case. We need to be careful with the root.
- for (size_t j = 0; j < parent->NumChildren(); j++) {
- if (parent->Children()[j] == this) {
- parent->Children()[j] = parent->Children()[--parent->NumChildren()]; // decrement numChildren
- parent->ShrinkBoundForBound(bound); // We want to do this before reinserting nodes.
-
- size_t level = TreeDepth();
- // Reinsert the nodes at the root node.
- RectangleTree<SplitType, DescentType, StatisticType, MatType>* root = this;
- while (root->Parent() != NULL)
- root = root->Parent();
- for (size_t i = 0; i < numChildren; i++)
- root->InsertNode(children[i], level, relevels);
-
- parent->CondenseTree(point, relevels, usePoint); // This will check the MinFill of the parent.
- //Now it should be safe to delete this node.
- SoftDelete();
- return;
- }
- }
- } else if (numChildren == 1) { // If there are multiple children, we can't do anything to the root.
- RectangleTree<SplitType, DescentType, StatisticType, MatType>* child = children[0];
- for (size_t i = 0; i < child->NumChildren(); i++) {
- children[i] = child->Children()[i];
- }
- numChildren = child->NumChildren();
- for (size_t i = 0; i < child->Count(); i++) { // In case the tree has a height of two.
- points[i] = child->Points()[i];
- localDataset->col(i) = child->LocalDataset().col(i);
- }
- count = child->Count();
- child->SoftDelete();
- }
- }
-
- // If we didn't delete it, shrink the bound if we need to.
- if (usePoint && ShrinkBoundForPoint(point) && parent != NULL) {
- parent->CondenseTree(point, relevels, usePoint);
- } else if (!usePoint && ShrinkBoundForBound(bound) && parent != NULL) {
- parent->CondenseTree(point, relevels, usePoint);
- }
-}
-
-/**
- * Shrink the bound so it fits tightly after the removal of this point.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-bool RectangleTree<SplitType, DescentType, StatisticType, MatType>::ShrinkBoundForPoint(const arma::vec& point)
-{
- bool shrunk = false;
- if (IsLeaf()) {
- for (size_t i = 0; i < bound.Dim(); i++) {
- if (bound[i].Lo() == point[i]) {
- double min = DBL_MAX;
- for (size_t j = 0; j < count; j++) {
- if (localDataset->col(j)[i] < min)
- min = localDataset->col(j)[i];
- }
- if (bound[i].Lo() < min) {
- shrunk = true;
- bound[i].Lo() = min;
- } else if (min < bound[i].Lo()) {
- assert(true == false); // we have a problem.
- }
- } else if (bound[i].Hi() == point[i]) {
- double max = -1 * DBL_MAX;
- for (size_t j = 0; j < count; j++) {
- if (localDataset->col(j)[i] > max)
- max = localDataset->col(j)[i];
- }
- if (bound[i].Hi() > max) {
- shrunk = true;
- bound[i].Hi() = max;
- } else if (max > bound[i].Hi()) {
- assert(true == false); // we have a problem.
- }
- }
- }
- } else {
- for (size_t i = 0; i < point.n_elem; i++) {
- if (bound[i].Lo() == point[i]) {
- double min = DBL_MAX;
- double max = -1 * DBL_MAX;
- for (size_t j = 0; j < numChildren; j++) {
- if (children[j]->Bound()[i].Lo() < min)
- min = children[j]->Bound()[i].Lo();
- if (children[j]->Bound()[i].Hi() > max)
- max = children[j]->Bound()[i].Hi();
- }
- if (bound[i].Lo() < min) {
- shrunk = true;
- bound[i].Lo() = min;
- }
- if (bound[i].Hi() > max) {
- shrunk = true;
- bound[i].Hi() = max;
- }
- }
- }
- }
- return shrunk;
-}
-
-/**
- * Shrink the bound so it fits tightly after the removal of this bound.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-bool RectangleTree<SplitType, DescentType, StatisticType, MatType>::ShrinkBoundForBound(const HRectBound<>& /* unused */)
-{
- double sum = 0; // Using the sum is safe since none of the dimensions can increase.
- //I think it may be faster to just recalculate the whole thing.
- for (size_t i = 0; i < bound.Dim(); i++) {
- sum += bound[i].Width();
- bound[i].Lo() = DBL_MAX;
- bound[i].Hi() = -1 * DBL_MAX;
- }
- for (size_t i = 0; i < numChildren; i++) {
- bound |= children[i]->Bound();
- }
- double sum2 = 0;
- for (size_t i = 0; i < bound.Dim(); i++)
- sum2 += bound[i].Width();
-
- return sum != sum2;
-}
-
-/**
- * Returns a string representation of this object.
- */
-template<typename SplitType,
-typename DescentType,
-typename StatisticType,
-typename MatType>
-std::string RectangleTree<SplitType, DescentType, StatisticType, MatType>::ToString() const
-{
- std::ostringstream convert;
- convert << "RectangleTree [" << this << "]" << std::endl;
- convert << " First point: " << begin << std::endl;
- convert << " Number of descendants: " << numChildren << std::endl;
- convert << " Number of points: " << count << std::endl;
- convert << " Bound: " << std::endl;
- convert << mlpack::util::Indent(bound.ToString(), 2);
- convert << " Statistic: " << std::endl;
- //convert << mlpack::util::Indent(stat.ToString(), 2);
- convert << " Max leaf size: " << maxLeafSize << std::endl;
- convert << " Min leaf size: " << minLeafSize << std::endl;
- convert << " Max num of children: " << maxNumChildren << std::endl;
- convert << " Min num of children: " << minNumChildren << std::endl;
- convert << " Parent address: " << parent << std::endl;
-
- // How many levels should we print? This will print 3 levels (counting the root).
- if (parent == NULL || parent->Parent() == NULL) {
- for (int i = 0; i < numChildren; i++) {
- convert << children[i]->ToString();
- }
- }
- return convert.str();
-}
-
-}; //namespace tree
-}; //namespace mlpack
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/single_tree_traverser.hpp b/src/mlpack/core/tree/rectangle_tree/single_tree_traverser.hpp
deleted file mode 100644
index e8620e4..0000000
--- a/src/mlpack/core/tree/rectangle_tree/single_tree_traverser.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * @file single_tree_traverser.hpp
- * @author Andrew Wells
- *
- * A nested class of Rectangle Tree for traversing rectangle type trees
- * with a given set of rules which indicate the branches to prune and the
- * order in which to recurse. This is a depth-first traverser.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_SINGLE_TREE_TRAVERSER_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_SINGLE_TREE_TRAVERSER_HPP
-
-#include <mlpack/core.hpp>
-
-#include "rectangle_tree.hpp"
-
-namespace mlpack {
-namespace tree {
-
-template<typename SplitType,
- typename DescentType,
- typename StatisticType,
- typename MatType>
-template<typename RuleType>
-class RectangleTree<SplitType, DescentType, StatisticType, MatType>::
- SingleTreeTraverser
-{
- public:
- /**
- * Instantiate the traverser with the given rule set.
- */
- SingleTreeTraverser(RuleType& rule);
-
- /**
- * Traverse the tree with the given point.
- *
- * @param queryIndex The index of the point in the query set which is being
- * used as the query point.
- * @param referenceNode The tree node to be traversed.
- */
- void Traverse(const size_t queryIndex, const RectangleTree& referenceNode);
-
- //! Get the number of prunes.
- size_t NumPrunes() const { return numPrunes; }
- //! Modify the number of prunes.
- size_t& NumPrunes() { return numPrunes; }
-
- //We use this struct and this function to make the sorting and scoring easy and efficient:
- class NodeAndScore {
- public:
- RectangleTree<SplitType, DescentType, StatisticType, MatType>* node;
- double score;
- };
-
- static bool nodeComparator(const NodeAndScore& obj1,
- const NodeAndScore& obj2)
- {
- return obj1.score < obj2.score;
- }
-
- private:
- //! Reference to the rules with which the tree will be traversed.
- RuleType& rule;
-
- //! The number of nodes which have been prenud during traversal.
- size_t numPrunes;
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-// Include implementation.
-#include "single_tree_traverser_impl.hpp"
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/single_tree_traverser_impl.hpp b/src/mlpack/core/tree/rectangle_tree/single_tree_traverser_impl.hpp
deleted file mode 100644
index 5168fc0..0000000
--- a/src/mlpack/core/tree/rectangle_tree/single_tree_traverser_impl.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * @file single_tree_traverser_impl.hpp
- * @author Andrew Wells
- *
- * A class for traversing rectangle type trees with a given set of rules
- * which indicate the branches to prune and the order in which to recurse.
- * This is a depth-first traverser.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_SINGLE_TREE_TRAVERSER_IMPL_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_SINGLE_TREE_TRAVERSER_IMPL_HPP
-
-#include "single_tree_traverser.hpp"
-
-#include <algorithm>
-#include <stack>
-
-namespace mlpack {
-namespace tree {
-
-template<typename SplitType,
- typename DescentType,
- typename StatisticType,
- typename MatType>
-template<typename RuleType>
-RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-SingleTreeTraverser<RuleType>::SingleTreeTraverser(RuleType& rule) :
- rule(rule),
- numPrunes(0)
-{ /* Nothing to do */ }
-
-template<typename SplitType,
- typename DescentType,
- typename StatisticType,
- typename MatType>
-template<typename RuleType>
-void RectangleTree<SplitType, DescentType, StatisticType, MatType>::
-SingleTreeTraverser<RuleType>::Traverse(
- const size_t queryIndex,
- const RectangleTree<SplitType, DescentType, StatisticType, MatType>&
- referenceNode)
-{
-
- // If we reach a leaf node, we need to run the base case.
- if(referenceNode.IsLeaf()) {
- for(size_t i = 0; i < referenceNode.Count(); i++) {
- rule.BaseCase(queryIndex, referenceNode.Points()[i]);
- }
- return;
- }
-
- // This is not a leaf node so we sort the children of this node by their scores.
- std::vector<NodeAndScore> nodesAndScores(referenceNode.NumChildren());
- for(int i = 0; i < referenceNode.NumChildren(); i++) {
- nodesAndScores[i].node = referenceNode.Children()[i];
- nodesAndScores[i].score = rule.Score(queryIndex, *nodesAndScores[i].node);
- }
-
- std::sort(nodesAndScores.begin(), nodesAndScores.end(), nodeComparator);
-
- // Now iterate through them starting with the best and stopping when we reach
- // one that isn't good enough.
- for(int i = 0; i < referenceNode.NumChildren(); i++) {
- if(rule.Rescore(queryIndex, *nodesAndScores[i].node, nodesAndScores[i].score) != DBL_MAX)
- Traverse(queryIndex, *nodesAndScores[i].node);
- else {
- numPrunes += referenceNode.NumChildren() - i;
- return;
- }
- }
- // We only get here if we couldn't prune any of them.
- return;
-}
-
-}; // namespace tree
-}; // namespace mlpack
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/traits.hpp b/src/mlpack/core/tree/rectangle_tree/traits.hpp
deleted file mode 100644
index 46848b9..0000000
--- a/src/mlpack/core/tree/rectangle_tree/traits.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file traits.hpp
- * @author Andrew Wells
- *
- * Specialization of the TreeTraits class for the RectangleTree type of tree.
- */
-#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_TRAITS_HPP
-#define __MLPACK_CORE_TREE_RECTANGLE_TREE_TRAITS_HPP
-
-#include <mlpack/core/tree/tree_traits.hpp>
-
-namespace mlpack {
-namespace tree {
-
-/**
- * This is a specialization of the TreeType class to the RectangleTree tree
- * type. It defines characteristics of the rectangle type trees, and is used to
- * help write tree-independent (but still optimized) tree-based algorithms. See
- * mlpack/core/tree/tree_traits.hpp for more information.
- */
-template<typename StatisticType,
- typename MatType>
-class TreeTraits<RectangleTree<StatisticType, MatType> >
-{
- public:
- /**
- * An R-tree can have overlapping children.
- */
- static const bool HasOverlappingChildren = true;
-
- /**
- * There is no guarantee that the first point in a node is its centroid.
- */
- static const bool FirstPointIsCentroid = false;
-
- /**
- * Points are not contained at multiple levels of the R-tree.
- */
- static const bool HasSelfChildren = false;
-
- /**
- * Points are rearranged during building of the tree.
- * THIS MAY NOT BE TRUE. IT'S HARD TO DYNAMICALLY INSERT POINTS
- * AND REARRANGE THE MATRIX
- */
- static const bool RearrangesDataset = true;
-};
-
-}; // namespace tree
-}; // namespace mlpack
-
-#endif
diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp
deleted file mode 100644
index 8d1c8b6..0000000
--- a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp
deleted file mode 100644
index 8d1c8b6..0000000
--- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/mlpack/methods/neighbor_search/allknn_main.cpp b/src/mlpack/methods/neighbor_search/allknn_main.cpp
index 7510746..1897ed6 100644
--- a/src/mlpack/methods/neighbor_search/allknn_main.cpp
+++ b/src/mlpack/methods/neighbor_search/allknn_main.cpp
@@ -57,8 +57,6 @@ PARAM_FLAG("single_mode", "If true, single-tree search is used (as opposed to "
"dual-tree search).", "S");
PARAM_FLAG("cover_tree", "If true, use cover trees to perform the search "
"(experimental, may be slow).", "c");
-PARAM_FLAG("r_tree", "If true, use an R-Tree to perform the search "
- "(experimental, may be slow. Currently automatically sets single_mode.).", "T");
PARAM_FLAG("random_basis", "Before tree-building, project the data onto a "
"random orthogonal basis.", "R");
PARAM_INT("seed", "Random seed (if 0, std::time(NULL) is used).", "s", 0);
@@ -125,16 +123,6 @@ int main(int argc, char *argv[])
Log::Warn << "--single_mode ignored because --naive is present." << endl;
}
- // cover_tree overrides r_tree.
- if (CLI::HasParam("cover_tree") && CLI::HasParam("r_tree"))
- {
- Log::Warn << "--cover_tree overrides --r_tree." << endl;
- } else if (!singleMode && CLI::HasParam("r_tree")) // R_tree requires single mode.
- {
- Log::Warn << "--single_mode assumed because --r_tree is present." << endl;
- singleMode = true;
- }
-
if (naive)
leafSize = referenceData.n_cols;
@@ -180,156 +168,90 @@ int main(int argc, char *argv[])
if (!CLI::HasParam("cover_tree"))
{
- if(!CLI::HasParam("r_tree"))
- {
- // Because we may construct it differently, we need a pointer.
- AllkNN* allknn = NULL;
+ // Because we may construct it differently, we need a pointer.
+ AllkNN* allknn = NULL;
- // Mappings for when we build the tree.
- std::vector<size_t> oldFromNewRefs;
+ // Mappings for when we build the tree.
+ std::vector<size_t> oldFromNewRefs;
- // Build trees by hand, so we can save memory: if we pass a tree to
- // NeighborSearch, it does not copy the matrix.
- Log::Info << "Building reference tree..." << endl;
- Timer::Start("tree_building");
+ // Build trees by hand, so we can save memory: if we pass a tree to
+ // NeighborSearch, it does not copy the matrix.
+ Log::Info << "Building reference tree..." << endl;
+ Timer::Start("tree_building");
- BinarySpaceTree<bound::HRectBound<2>,
- NeighborSearchStat<NearestNeighborSort> >
- refTree(referenceData, oldFromNewRefs, leafSize);
- BinarySpaceTree<bound::HRectBound<2>,
- NeighborSearchStat<NearestNeighborSort> >*
- queryTree = NULL; // Empty for now.
+ BinarySpaceTree<bound::HRectBound<2>,
+ NeighborSearchStat<NearestNeighborSort> >
+ refTree(referenceData, oldFromNewRefs, leafSize);
+ BinarySpaceTree<bound::HRectBound<2>,
+ NeighborSearchStat<NearestNeighborSort> >*
+ queryTree = NULL; // Empty for now.
- Timer::Stop("tree_building");
+ Timer::Stop("tree_building");
- std::vector<size_t> oldFromNewQueries;
+ std::vector<size_t> oldFromNewQueries;
- if (CLI::GetParam<string>("query_file") != "")
- {
- if (naive && leafSize < queryData.n_cols)
- leafSize = queryData.n_cols;
+ if (CLI::GetParam<string>("query_file") != "")
+ {
+ if (naive && leafSize < queryData.n_cols)
+ leafSize = queryData.n_cols;
- Log::Info << "Loaded query data from '" << queryFile << "' ("
- << queryData.n_rows << " x " << queryData.n_cols << ")." << endl;
+ Log::Info << "Loaded query data from '" << queryFile << "' ("
+ << queryData.n_rows << " x " << queryData.n_cols << ")." << endl;
- Log::Info << "Building query tree..." << endl;
+ Log::Info << "Building query tree..." << endl;
- // Build trees by hand, so we can save memory: if we pass a tree to
- // NeighborSearch, it does not copy the matrix.
- if (!singleMode)
- {
- Timer::Start("tree_building");
+ // Build trees by hand, so we can save memory: if we pass a tree to
+ // NeighborSearch, it does not copy the matrix.
+ if (!singleMode)
+ {
+ Timer::Start("tree_building");
- queryTree = new BinarySpaceTree<bound::HRectBound<2>,
- NeighborSearchStat<NearestNeighborSort> >(queryData,
- oldFromNewQueries, leafSize);
+ queryTree = new BinarySpaceTree<bound::HRectBound<2>,
+ NeighborSearchStat<NearestNeighborSort> >(queryData,
+ oldFromNewQueries, leafSize);
- Timer::Stop("tree_building");
- }
+ Timer::Stop("tree_building");
+ }
- allknn = new AllkNN(&refTree, queryTree, referenceData, queryData,
- singleMode);
+ allknn = new AllkNN(&refTree, queryTree, referenceData, queryData,
+ singleMode);
- Log::Info << "Tree built." << endl;
- }
- else
- {
- allknn = new AllkNN(&refTree, referenceData, singleMode);
+ Log::Info << "Tree built." << endl;
+ }
+ else
+ {
+ allknn = new AllkNN(&refTree, referenceData, singleMode);
- Log::Info << "Trees built." << endl;
- }
+ Log::Info << "Trees built." << endl;
+ }
- arma::mat distancesOut;
- arma::Mat<size_t> neighborsOut;
-
- Log::Info << "Computing " << k << " nearest neighbors..." << endl;
- allknn->Search(k, neighborsOut, distancesOut);
-
- Log::Info << "Neighbors computed." << endl;
-
- // We have to map back to the original indices from before the tree
- // construction.
- Log::Info << "Re-mapping indices..." << endl;
-
- // Map the results back to the correct places.
- if ((CLI::GetParam<string>("query_file") != "") && !singleMode)
- Unmap(neighborsOut, distancesOut, oldFromNewRefs, oldFromNewQueries,
- neighbors, distances);
- else if ((CLI::GetParam<string>("query_file") != "") && singleMode)
- Unmap(neighborsOut, distancesOut, oldFromNewRefs, neighbors, distances);
- else
- Unmap(neighborsOut, distancesOut, oldFromNewRefs, oldFromNewRefs,
- neighbors, distances);
-
- // Clean up.
- if (queryTree)
- delete queryTree;
-
- delete allknn;
- } else { // R tree.
- // Make sure to notify the user that they are using an r tree.
- Log::Info << "Using r tree for nearest-neighbor calculation." << endl;
-
- // Because we may construct it differently, we need a pointer.
- NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>,
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> >* allknn = NULL;
+ arma::mat distancesOut;
+ arma::Mat<size_t> neighborsOut;
- // Build trees by hand, so we can save memory: if we pass a tree to
- // NeighborSearch, it does not copy the matrix.
- Log::Info << "Building reference tree..." << endl;
- Timer::Start("tree_building");
-
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>
- refTree(referenceData, leafSize, leafSize/3, 5, 2, 0);
-
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>*
- queryTree = NULL; // Empty for now.
-
- Timer::Stop("tree_building");
-
- if (CLI::GetParam<string>("query_file") != "")
- {
- Log::Info << "Loaded query data from '" << queryFile << "' ("
- << queryData.n_rows << " x " << queryData.n_cols << ")." << endl;
-
- allknn = new NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>,
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> >(&refTree, queryTree,
- referenceData, queryData, singleMode);
- } else
- {
- allknn = new NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>,
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> >(&refTree,
- referenceData, singleMode);
- }
- Log::Info << "Tree built." << endl;
-
- //arma::mat distancesOut;
- //arma::Mat<size_t> neighborsOut;
+ Log::Info << "Computing " << k << " nearest neighbors..." << endl;
+ allknn->Search(k, neighborsOut, distancesOut);
- Log::Info << "Computing " << k << " nearest neighbors..." << endl;
- allknn->Search(k, neighbors, distances);
+ Log::Info << "Neighbors computed." << endl;
- Log::Info << "Neighbors computed." << endl;
+ // We have to map back to the original indices from before the tree
+ // construction.
+ Log::Info << "Re-mapping indices..." << endl;
+ // Map the results back to the correct places.
+ if ((CLI::GetParam<string>("query_file") != "") && !singleMode)
+ Unmap(neighborsOut, distancesOut, oldFromNewRefs, oldFromNewQueries,
+ neighbors, distances);
+ else if ((CLI::GetParam<string>("query_file") != "") && singleMode)
+ Unmap(neighborsOut, distancesOut, oldFromNewRefs, neighbors, distances);
+ else
+ Unmap(neighborsOut, distancesOut, oldFromNewRefs, oldFromNewRefs,
+ neighbors, distances);
+ // Clean up.
+ if (queryTree)
+ delete queryTree;
- delete allknn;
- }
+ delete allknn;
}
else // Cover trees.
{
@@ -388,7 +310,7 @@ int main(int argc, char *argv[])
delete queryTree;
}
- // Save put.
+ // Save output.
data::Save(distancesFile, distances);
data::Save(neighborsFile, neighbors);
}
diff --git a/src/mlpack/methods/neighbor_search/neighbor_search.hpp b/src/mlpack/methods/neighbor_search/neighbor_search.hpp
index 64f71a2..71ad1fc 100644
--- a/src/mlpack/methods/neighbor_search/neighbor_search.hpp
+++ b/src/mlpack/methods/neighbor_search/neighbor_search.hpp
@@ -13,7 +13,6 @@
#include <string>
#include <mlpack/core/tree/binary_space_tree.hpp>
-#include <mlpack/core/tree/rectangle_tree.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include "neighbor_search_stat.hpp"
diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt
index 6257181..4265692 100644
--- a/src/mlpack/tests/CMakeLists.txt
+++ b/src/mlpack/tests/CMakeLists.txt
@@ -40,7 +40,6 @@ add_executable(mlpack_test
quic_svd_test.cpp
radical_test.cpp
range_search_test.cpp
- rectangle_tree_test.cpp
regularized_svd_test.cpp
sa_test.cpp
save_restore_utility_test.cpp
diff --git a/src/mlpack/tests/rectangle_tree_test.cpp b/src/mlpack/tests/rectangle_tree_test.cpp
deleted file mode 100644
index cc559c9..0000000
--- a/src/mlpack/tests/rectangle_tree_test.cpp
+++ /dev/null
@@ -1,654 +0,0 @@
-/**
- * @file tree_traits_test.cpp
- * @author Andrew Wells
- *
- * Tests for the RectangleTree class. This should ensure that the class works correctly
- * and that subsequent changes don't break anything. Because it's only used to test the trees,
- * it is slow.
- */
-#include <mlpack/core.hpp>
-#include <mlpack/core/tree/tree_traits.hpp>
-#include <mlpack/core/tree/rectangle_tree.hpp>
-#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
-
-#include <boost/test/unit_test.hpp>
-#include "old_boost_test_definitions.hpp"
-
-using namespace mlpack;
-using namespace mlpack::neighbor;
-using namespace mlpack::tree;
-using namespace mlpack::metric;
-
-BOOST_AUTO_TEST_SUITE(RectangleTreeTest);
-
-// Be careful! When writing new tests, always get the boolean value and store
-// it in a temporary, because the Boost unit test macros do weird things and
-// will cause bizarre problems.
-
-// Test the traits on RectangleTrees.
-
-BOOST_AUTO_TEST_CASE(RectangeTreeTraitsTest) {
- // Children may be overlapping.
- bool b = TreeTraits<RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> >::HasOverlappingChildren;
- BOOST_REQUIRE_EQUAL(b, true);
-
- // Points are not contained in multiple levels.
- b = TreeTraits<RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> >::HasSelfChildren;
- BOOST_REQUIRE_EQUAL(b, false);
-}
-
-// Test to make sure the tree can be contains the correct number of points after it is
-// constructed.
-
-BOOST_AUTO_TEST_CASE(RectangleTreeConstructionCountTest) {
- arma::mat dataset;
- dataset.randu(3, 1000); // 1000 points in 3 dimensions.
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
- BOOST_REQUIRE_EQUAL(tree.NumDescendants(), 1000);
-}
-
-/**
- * A function to return a std::vector containing pointers to each point in the tree.
- * @param tree The tree that we want to extract all of the points from.
- * @return A vector containing pointers to each point in this tree.
- */
-std::vector<arma::vec*> getAllPointsInTree(const RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- std::vector<arma::vec*> vec;
- if (tree.NumChildren() > 0) {
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- std::vector<arma::vec*> tmp = getAllPointsInTree(*(tree.Child(i)));
- vec.insert(vec.begin(), tmp.begin(), tmp.end());
- }
- } else {
- for (size_t i = 0; i < tree.Count(); i++) {
- arma::vec* c = new arma::vec(tree.Dataset().col(tree.Points()[i]));
- vec.push_back(c);
- }
- }
- return vec;
-}
-
-// Test to ensure that none of the points in the tree are duplicates. This,
-// combined with the above test to see how many points are in the tree, should
-// ensure that we inserted all points.
-BOOST_AUTO_TEST_CASE(RectangleTreeConstructionRepeatTest) {
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
-
- std::vector<arma::vec*> allPoints = getAllPointsInTree(tree);
- for (size_t i = 0; i < allPoints.size(); i++) {
- for (size_t j = i + 1; j < allPoints.size(); j++) {
- arma::vec v1 = *(allPoints[i]);
- arma::vec v2 = *(allPoints[j]);
- bool same = true;
- for (size_t k = 0; k < v1.n_rows; k++) {
- same &= (v1[k] == v2[k]);
- }
- BOOST_REQUIRE_NE(same, true);
- }
- }
- for (size_t i = 0; i < allPoints.size(); i++) {
- delete allPoints[i];
- }
-}
-
-/**
- * A function to check that each non-leaf node fully encloses its child nodes
- * and that each leaf node encloses its points. It recurses so that it checks
- * each node under (and including) this one.
- * @param tree The tree to check.
- */
-void checkContainment(const RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- if (tree.NumChildren() == 0) {
- for (size_t i = 0; i < tree.Count(); i++) {
- BOOST_REQUIRE_EQUAL(tree.Bound().Contains(tree.Dataset().unsafe_col(tree.Points()[i])), true);
- }
- } else {
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- for (size_t j = 0; j < tree.Bound().Dim(); j++) {
- BOOST_REQUIRE_EQUAL(tree.Bound()[j].Contains(tree.Children()[i]->Bound()[j]), true);
- }
- checkContainment(*(tree.Child(i)));
- }
- }
- return;
-}
-
-// Test to see if the bounds of the tree are correct. (Cover all bounds and points
-// beneath this node of the tree).
-BOOST_AUTO_TEST_CASE(RectangleTreeContainmentTest) {
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
- checkContainment(tree);
-}
-
-/**
- * A function to ensure that the dataset for the tree, and the datasets stored
- * in each leaf node are in sync.
- * @param tree The tree to check.
- */
-void checkSync(const RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- if (tree.IsLeaf()) {
- for (size_t i = 0; i < tree.Count(); i++) {
- for (size_t j = 0; j < tree.LocalDataset().n_rows; j++) {
- BOOST_REQUIRE_EQUAL(tree.LocalDataset().col(i)[j], tree.Dataset().col(tree.Points()[i])[j]);
- }
- }
- } else {
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- checkSync(*tree.Child(i));
- }
- }
- return;
-}
-
-// Test to ensure that the dataset used by the whole tree (and the traversers)
-// is in sync with the datasets stored in each leaf node.
-BOOST_AUTO_TEST_CASE(TreeLocalDatasetInSync) {
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
- checkSync(tree);
-}
-
-/**
- * A function to check that each of the fill requirements is met. For a non-leaf node:
- * MinNumChildren() <= NumChildren() <= MaxNumChildren()
- * For a leaf node:
- * MinLeafSize() <= Count() <= MaxLeafSize
- *
- * It recurses so that it checks each node under (and including) this one.
- * @param tree The tree to check.
- */
-void checkFills(const RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- if (tree.IsLeaf()) {
- BOOST_REQUIRE_EQUAL((tree.Count() >= tree.MinLeafSize() || tree.Parent() == NULL) && tree.Count() <= tree.MaxLeafSize(), true);
- } else {
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- BOOST_REQUIRE_EQUAL((tree.NumChildren() >= tree.MinNumChildren() || tree.Parent() == NULL) && tree.NumChildren() <= tree.MaxNumChildren(), true);
- checkFills(*tree.Child(i));
- }
- }
- return;
-}
-
-// Test to ensure that the minimum and maximum fills are satisfied.
-BOOST_AUTO_TEST_CASE(CheckMinAndMaxFills) {
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
- checkFills(tree);
-}
-
-/**
- * A function to get the height of this tree. Though it should equal tree.TreeDepth(), we ensure
- * that every leaf node is on the same level by doing it this way.
- * @param tree The tree for which we want the height.
- * @return The height of this tree.
- */
-int getMaxLevel(const RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- int max = 1;
- if (!tree.IsLeaf()) {
- int m = 0;
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- int n = getMaxLevel(*tree.Child(i));
- if (n > m)
- m = n;
- }
- max += m;
- }
- return max;
-}
-
-/**
- * A function to get the "shortest height" of this tree. Though it should equal tree.TreeDepth(), we ensure
- * that every leaf node is on the same level by doing it this way.
- * @param tree The tree for which we want the height.
- * @return The "shortest height" of the tree.
- */
-int getMinLevel(const RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- int min = 1;
- if (!tree.IsLeaf()) {
- int m = INT_MAX;
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- int n = getMinLevel(*tree.Child(i));
- if (n < m)
- m = n;
- }
- min += m;
- }
- return min;
-}
-
-// A test to ensure that all leaf nodes are stored on the same level of the tree.
-BOOST_AUTO_TEST_CASE(TreeBalance) {
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
-
- BOOST_REQUIRE_EQUAL(getMinLevel(tree), getMaxLevel(tree));
- BOOST_REQUIRE_EQUAL(tree.TreeDepth(), getMinLevel(tree));
-}
-
-// A test to see if point deletion is working correctly.
-// We build a tree, then delete numIter points and test that the query gives correct
-// results. It is remotely possible that this test will give a false negative if
-// it should happen that two points are the same distance from a third point.
-BOOST_AUTO_TEST_CASE(PointDeletion) {
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
-
- arma::mat querySet;
- querySet.randu(8, 500);
-
- const int numIter = 50;
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
-
- for (int i = 0; i < numIter; i++) {
- tree.DeletePoint(999 - i);
- }
-
- // Do a few sanity checks. Ensure each point is unique, the tree has the correct
- // number of points, the tree has legal containment, and the tree's data is in sync.
- std::vector<arma::vec*> allPoints = getAllPointsInTree(tree);
- for (size_t i = 0; i < allPoints.size(); i++) {
- for (size_t j = i + 1; j < allPoints.size(); j++) {
- arma::vec v1 = *(allPoints[i]);
- arma::vec v2 = *(allPoints[j]);
- bool same = true;
- for (size_t k = 0; k < v1.n_rows; k++) {
- same &= (v1[k] == v2[k]);
- }
- BOOST_REQUIRE_NE(same, true);
- }
- }
- for (size_t i = 0; i < allPoints.size(); i++) {
- delete allPoints[i];
- }
- BOOST_REQUIRE_EQUAL(tree.NumDescendants(), 1000 - numIter);
- checkContainment(tree);
- checkSync(tree);
-
- mlpack::neighbor::NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>,
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> > allknn1(&tree, NULL,
- dataset, querySet, true);
-
- arma::Mat<size_t> neighbors1;
- arma::mat distances1;
- allknn1.Search(5, neighbors1, distances1);
-
- arma::mat newDataset;
- newDataset = dataset;
- newDataset.resize(8, 1000-numIter);
-
- arma::Mat<size_t> neighbors2;
- arma::mat distances2;
-
- // nearest neighbor search the naive way.
- mlpack::neighbor::AllkNN allknn2(newDataset, querySet,
- true, true);
-
- allknn2.Search(5, neighbors2, distances2);
-
- for (size_t i = 0; i < neighbors1.size(); i++) {
- BOOST_REQUIRE_EQUAL(distances1[i], distances2[i]);
- BOOST_REQUIRE_EQUAL(neighbors1[i], neighbors2[i]);
- }
-}
-
-// A test to see if dynamic point insertion is working correctly.
-// We build a tree, then add numIter points and test that the query gives correct
-// results. It is remotely possible that this test will give a false negative if
-// it should happen that two points are the same distance from a third point.
-// Note that this is extremely inefficient. You should not use dynamic insertion until
-// a better solution for resizing matrices is available.
-
-BOOST_AUTO_TEST_CASE(PointDynamicAdd) {
- const int numIter = 50;
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> tree(dataset, 20, 6, 5, 2, 0);
-
- // Add numIter new points to the dataset.
- dataset.reshape(8, 1000+numIter);
- arma::mat tmpData;
- tmpData.randu(8, numIter);
- for (int i = 0; i < numIter; i++) {
- dataset.col(1000 + i) = tmpData.col(i);
- tree.InsertPoint(1000 + i);
- }
-
- // Do a few sanity checks. Ensure each point is unique, the tree has the correct
- // number of points, the tree has legal containment, and the tree's data is in sync.
- std::vector<arma::vec*> allPoints = getAllPointsInTree(tree);
- for (size_t i = 0; i < allPoints.size(); i++) {
- for (size_t j = i + 1; j < allPoints.size(); j++) {
- arma::vec v1 = *(allPoints[i]);
- arma::vec v2 = *(allPoints[j]);
- bool same = true;
- for (size_t k = 0; k < v1.n_rows; k++) {
- same &= (v1[k] == v2[k]);
- }
- BOOST_REQUIRE_NE(same, true);
- }
- }
- for (size_t i = 0; i < allPoints.size(); i++) {
- delete allPoints[i];
- }
- BOOST_REQUIRE_EQUAL(tree.NumDescendants(), 1000 + numIter);
- checkContainment(tree);
- checkSync(tree);
-
- // Now we will compare the output of the R Tree vs the output of a naive search.
- arma::Mat<size_t> neighbors1;
- arma::mat distances1;
- arma::Mat<size_t> neighbors2;
- arma::mat distances2;
-
- // nearest neighbor search with the R tree.
- mlpack::neighbor::NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>,
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> > allknn1(&tree,
- dataset, true);
-
- allknn1.Search(5, neighbors1, distances1);
-
- // nearest neighbor search the naive way.
- mlpack::neighbor::AllkNN allknn2(dataset,
- true, true);
-
- allknn2.Search(5, neighbors2, distances2);
-
- for (size_t i = 0; i < neighbors1.size(); i++) {
- BOOST_REQUIRE_EQUAL(distances1[i], distances2[i]);
- BOOST_REQUIRE_EQUAL(neighbors1[i], neighbors2[i]);
- }
-}
-
-/**
- * A function to check that each non-leaf node fully encloses its child nodes
- * and that each leaf node encloses its points. It recurses so that it checks
- * each node under (and including) this one.
- * @param tree The tree to check.
- */
-void checkContainment(const RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- if (tree.NumChildren() == 0) {
- for (size_t i = 0; i < tree.Count(); i++) {
- BOOST_REQUIRE_EQUAL(tree.Bound().Contains(tree.Dataset().unsafe_col(tree.Points()[i])), true);
- }
- } else {
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- for (size_t j = 0; j < tree.Bound().Dim(); j++) {
- BOOST_REQUIRE_EQUAL(tree.Bound()[j].Contains(tree.Children()[i]->Bound()[j]), true);
- }
- checkContainment(*(tree.Child(i)));
- }
- }
- return;
-}
-
-/**
- * A function to ensure that the dataset for the tree, and the datasets stored
- * in each leaf node are in sync.
- * @param tree The tree to check.
- */
-void checkSync(const RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat>& tree) {
- if (tree.IsLeaf()) {
- for (size_t i = 0; i < tree.Count(); i++) {
- for (size_t j = 0; j < tree.LocalDataset().n_rows; j++) {
- BOOST_REQUIRE_EQUAL(tree.LocalDataset().col(i)[j], tree.Dataset().col(tree.Points()[i])[j]);
- }
- }
- } else {
- for (size_t i = 0; i < tree.NumChildren(); i++) {
- checkSync(*tree.Child(i));
- }
- }
- return;
-}
-
-// A test to ensure that the SingleTreeTraverser is working correctly by comparing
-// its results to the results of a naive search.
-BOOST_AUTO_TEST_CASE(SingleTreeTraverserTest) {
- arma::mat dataset;
- dataset.randu(8, 1000); // 1000 points in 8 dimensions.
- arma::Mat<size_t> neighbors1;
- arma::mat distances1;
- arma::Mat<size_t> neighbors2;
- arma::mat distances2;
-
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> RTree(dataset, 20, 6, 5, 2, 0);
-
- // nearest neighbor search with the R tree.
- mlpack::neighbor::NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>,
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> > allknn1(&RTree,
- dataset, true);
-
- BOOST_REQUIRE_EQUAL(RTree.NumDescendants(), 1000);
- checkSync(RTree);
- checkContainment(RTree);
-
-
- allknn1.Search(5, neighbors1, distances1);
-
- // nearest neighbor search the naive way.
- mlpack::neighbor::AllkNN allknn2(dataset,
- true, true);
-
- allknn2.Search(5, neighbors2, distances2);
-
- for (size_t i = 0; i < neighbors1.size(); i++) {
- BOOST_REQUIRE_EQUAL(neighbors1[i], neighbors2[i]);
- BOOST_REQUIRE_EQUAL(distances1[i], distances2[i]);
- }
-}
-
-// Test the tree splitting. We set MaxLeafSize and MaxNumChildren rather low
-// to allow us to test by hand without adding hundreds of points.
-BOOST_AUTO_TEST_CASE(RTreeSplitTest) {
- arma::mat data = arma::trans(arma::mat("0.0 0.0;"
- "0.0 1.0;"
- "1.0 0.1;"
- "1.0 0.5;"
- "0.7 0.3;"
- "0.9 0.9;"
- "0.5 0.6;"
- "0.6 0.3;"
- "0.1 0.5;"
- "0.3 0.7;"));
-
- RectangleTree<tree::RTreeSplit<tree::RTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> RTree(data, 5, 2, 2, 1, 0);
-
- //There's technically no reason they have to be in a certain order, so we
- //use firstChild etc. to arbitrarily name them.
- BOOST_REQUIRE_EQUAL(RTree.NumChildren(), 2);
- BOOST_REQUIRE_EQUAL(RTree.NumDescendants(), 10);
- BOOST_REQUIRE_EQUAL(RTree.TreeDepth(), 3);
-
- int firstChild = 0, secondChild = 1;
- if(RTree.Child(firstChild)->NumChildren() == 2) {
- firstChild = 1;
- secondChild = 0;
- }
-
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[0].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[0].Hi(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[1].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[1].Hi(), 1.0);
-
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[0].Lo(), 0.3);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[0].Hi(), 1.0);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[1].Lo(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[1].Hi(), 0.9);
-
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->NumChildren(), 1);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[0].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[0].Hi(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[1].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[1].Hi(), 1.0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Count(), 3);
-
- int firstPrime = 0, secondPrime = 1;
- if(RTree.Child(secondChild)->Child(firstPrime)->Count() == 3) {
- firstPrime = 1;
- secondPrime = 0;
- }
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->NumChildren(), 2);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Count(), 4);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[0].Lo(), 0.3);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[0].Hi(), 0.7);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[1].Lo(), 0.3);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[1].Hi(), 0.7);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Count(), 3);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[0].Lo(), 0.9);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[0].Hi(), 1.0);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[1].Lo(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[1].Hi(), 0.9);
-
-}
-
-// Test the tree splitting. We set MaxLeafSize and MaxNumChildren rather low
-// to allow us to test by hand without adding hundreds of points.
-BOOST_AUTO_TEST_CASE(RStarTreeSplitTest) {
- arma::mat data = arma::trans(arma::mat("0.0 0.0;"
- "0.0 1.0;"
- "1.0 0.1;"
- "1.0 0.5;"
- "0.7 0.3;"
- "0.9 0.9;"
- "0.5 0.6;"
- "0.6 0.3;"
- "0.1 0.5;"
- "0.3 0.7;"));
-
- RectangleTree<tree::RStarTreeSplit<tree::RStarTreeDescentHeuristic, NeighborSearchStat<NearestNeighborSort>, arma::mat>,
- tree::RStarTreeDescentHeuristic,
- NeighborSearchStat<NearestNeighborSort>,
- arma::mat> RTree(data, 5, 2, 2, 1, 0);
-
- //There's technically no reason they have to be in a certain order, so we
- //use firstChild etc. to arbitrarily name them.
- BOOST_REQUIRE_EQUAL(RTree.NumChildren(), 2);
- BOOST_REQUIRE_EQUAL(RTree.NumDescendants(), 10);
- BOOST_REQUIRE_EQUAL(RTree.TreeDepth(), 3);
-
- int firstChild = 0, secondChild = 1;
- if(RTree.Child(firstChild)->NumChildren() == 2) {
- firstChild = 1;
- secondChild = 0;
- }
-
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[0].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[0].Hi(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[1].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Bound()[1].Hi(), 1.0);
-
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[0].Lo(), 0.3);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[0].Hi(), 1.0);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[1].Lo(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Bound()[1].Hi(), 0.9);
-
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->NumChildren(), 1);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[0].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[0].Hi(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[1].Lo(), 0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Bound()[1].Hi(), 1.0);
- BOOST_REQUIRE_EQUAL(RTree.Child(firstChild)->Child(0)->Count(), 3);
-
- int firstPrime = 0, secondPrime = 1;
- if(RTree.Child(secondChild)->Child(firstPrime)->Count() == 3) {
- firstPrime = 1;
- secondPrime = 0;
- }
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->NumChildren(), 2);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Count(), 4);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[0].Lo(), 0.3);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[0].Hi(), 1.0);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[1].Lo(), 0.5);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(firstPrime)->Bound()[1].Hi(), 0.9);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Count(), 3);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[0].Lo(), 0.6);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[0].Hi(), 1.0);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[1].Lo(), 0.1);
- BOOST_REQUIRE_EQUAL(RTree.Child(secondChild)->Child(secondPrime)->Bound()[1].Hi(), 0.3);
-}
-
-BOOST_AUTO_TEST_SUITE_END();
diff --git a/src/mlpack/tests/tree_test.cpp b/src/mlpack/tests/tree_test.cpp
index eaa6c79..29ebd8b 100644
--- a/src/mlpack/tests/tree_test.cpp
+++ b/src/mlpack/tests/tree_test.cpp
@@ -8,7 +8,6 @@
#include <mlpack/core/tree/binary_space_tree/binary_space_tree.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include <mlpack/core/tree/cover_tree/cover_tree.hpp>
-#include <mlpack/core/tree/rectangle_tree.hpp>
#include <queue>
#include <stack>
diff --git a/src/mlpack/tests/tree_traits_test.cpp b/src/mlpack/tests/tree_traits_test.cpp
index f4182b0..df220fc 100644
--- a/src/mlpack/tests/tree_traits_test.cpp
+++ b/src/mlpack/tests/tree_traits_test.cpp
@@ -12,7 +12,6 @@
#include <mlpack/core/tree/tree_traits.hpp>
#include <mlpack/core/tree/binary_space_tree.hpp>
#include <mlpack/core/tree/cover_tree.hpp>
-#include <mlpack/core/tree/rectangle_tree.hpp>
#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/mlpack.git
More information about the debian-science-commits
mailing list