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 index c80608c1d0..c6593b20b2 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_descent_heuristic.hpp @@ -14,11 +14,9 @@ namespace mlpack { namespace tree /** Trees and tree-building procedures. */ { /** - * A binary space partitioning tree node is split into its left and right child. - * The split is done in the dimension that has the maximum width. The points are - * divided into two parts based on the mean in this dimension. + * 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. */ -template class RTreeDescentHueristic { public: @@ -30,7 +28,7 @@ class RTreeDescentHueristic * @param bound The bound used for the node that is being evaluated. * @param point The point that is being inserted. */ - static double EvalNode(const HRectBound& bound, const arma::vec& point); + static double EvalNode(const HRectBound<>& bound, const arma::vec& point); }; }; // namespace tree 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 index 67fc837c8d..1ec8130417 100644 --- 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 @@ -2,7 +2,7 @@ * @file r_tree_descent_heuristic_impl.hpp * @author Andrew Wells * - * Definition of RTreeDescentHeuristic, a class that chooses the best child of a node in + * 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 @@ -10,18 +10,16 @@ #include "r_tree_descent_heuristic.hpp" +#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_R_TREE_DESCENT_HEURISTIC_HPP +#define max(a, b) 4*max(a-1, b-1) +#endif + namespace mlpack { namespace tree { -/** - * A binary space partitioning tree node is split into its left and right child. - * The split is done in the dimension that has the maximum width. The points are - * divided into two parts based on the mean in this dimension. - */ -template -double RTreeDescentHeuristic::EvalNode(const HRectBound& bound, const arma::vec& point) +double RTreeDescentHeuristic::EvalNode(const HRectBound<>& bound, const arma::vec& point) { - return bound.contains(point) ? 0 : bound.minDistance(point); + return bound.Contains(point) ? 0 : bound.MinDistance(point); } }; // namespace tree diff --git a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp index bb2b75f8c8..08a3c9a0d9 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp @@ -18,7 +18,10 @@ namespace tree /** Trees and tree-building procedures. */ { * nodes overflow, we split them, moving up the tree and splitting nodes * as necessary. */ -template +template class RTreeSplit { public: @@ -28,7 +31,7 @@ public: * upwards through the tree. The methods for splitting non-leaf nodes are private since * they should only be called if a leaf node overflows. */ -static bool SplitLeafNode(const RectangleTree& tree); +static void SplitLeafNode(const RectangleTree& tree); private: @@ -36,25 +39,25 @@ private: * Split a non-leaf node using the "default" algorithm. If this is the root node and * we need to move up the tree, a new root node is created. */ -static bool SplitNonLeafNode(const RectangleTree& tree); +static bool SplitNonLeafNode(const RectangleTree& tree); /** * Get the seeds for splitting a leaf node. */ -static void GetPointSeeds(const RectangleTree& tree, int &i, int &j); +static void GetPointSeeds(const RectangleTree& tree, int *i, int *j); /** * Get the seeds for splitting a non-leaf node. */ -static void GetBoundSeeds(const RectangleTree& tree, int &i, int &j); +static void GetBoundSeeds(const RectangleTree& tree, int *i, int *j); /** * Assign points to the two new nodes. */ static void AssignPointDestNode( - const RectangleTree& oldTree, - RectangleTree& treeOne, - RectangleTree& treeTwo, + const RectangleTree& oldTree, + RectangleTree& treeOne, + RectangleTree& treeTwo, const int intI, const int intJ); @@ -62,9 +65,9 @@ static void AssignPointDestNode( * Assign nodes to the two new nodes. */ static void AssignNodeDestNode( - const RectangleTree& oldTree, - RectangleTree& treeOne, - RectangleTree& treeTwo, + const RectangleTree& oldTree, + RectangleTree& treeOne, + RectangleTree& treeTwo, const int intI, const int intJ); @@ -72,8 +75,9 @@ static void AssignNodeDestNode( * Insert a node into another node. */ static void insertNodeIntoTree( - RectangleTree& destTree, - RectangleTree& srcNode); + RectangleTree& destTree, + RectangleTree& srcNode); +}; }; // namespace tree }; // namespace mlpack 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 index 79979aa75d..6318efab07 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_split_impl.hpp @@ -19,8 +19,12 @@ namespace tree { * Finally, we delete the old node and insert the new nodes into the tree, spliting the parent * if necessary. */ -template -void RTreeSplit::SplitLeafNode(const RectangleTree& tree) +template +void RTreeSplit::SplitLeafNode( + const RectangleTree& tree) { // 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. @@ -29,19 +33,24 @@ void RTreeSplit::SplitLeafNode(const RectangleTree& tree) int j = 0; GetPointSeeds(tree, &i, &j); + RectangleTree treeOne = new + RectangleTree(tree.Parent()); + RectangleTree treeTwo = new + RectangleTree(tree.Parent()); + // This will assign the ith and jth point appropriately. AssignPointDestNode(tree, treeOne, treeTwo, i, j); // create the parent node if necessary - if(par == NULL) { + if(tree.Parent() == NULL) { } //Remove this node and insert treeOne and treeTwo - RectangleTree* par = tree.parent(); + RectangleTree* par = tree.Parent(); int index = 0; for(int i = 0; i < par.numOfChildren(); i++) { - if(par.getChildren()[i] == this) { + if(par.getChildren()[i] == tree) { index = i; break; } @@ -54,9 +63,9 @@ void RTreeSplit::SplitLeafNode(const RectangleTree& tree) // we only add one at a time, so should only need to test for equality // just in case, we use an assert. - boost::assert(numChildren <= maxNumChildren); + assert(par.NumChildren() <= par.MaxNumChildren()); - if(par.numOfChildren() == par.maxNumChildren) { + if(par.NumChildren() == par.MaxNumChildren()) { SplitNonLeafNode(par); } return; @@ -69,25 +78,35 @@ void RTreeSplit::SplitLeafNode(const RectangleTree& tree) * 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. */ -bool RTreeSplit::SplitNonLeafNode(const RectangleTree& tree) +template +bool RTreeSplit::SplitNonLeafNode( + const RectangleTree& tree) { int i = 0; int j = 0; GetBoundSeeds(tree, &i, &j); + RectangleTree treeOne = new + RectangleTree(tree.Parent()); + RectangleTree treeTwo = new + RectangleTree(tree.Parent()); + // This will assign the ith and jth rectangles appropriately. AssignNodeDestNode(tree, treeOne, treeTwo, i, j); // create the parent node if necessary - if(par == NULL) { - + if(tree.Parent() == NULL) { + tree.Parent() = new RectangleTree(); } //Remove this node and insert treeOne and treeTwo - RectangleTree* par = tree.parent(); + RectangleTree* par = tree.parent(); int index = 0; for(int i = 0; i < par.numOfChildren(); i++) { - if(par.getChildren()[i] == this) { + if(par.getChildren()[i] == tree) { index = i; break; } @@ -101,9 +120,9 @@ bool RTreeSplit::SplitNonLeafNode(const RectangleTree& tree) // we only add one at a time, so should only need to test for equality // just in case, we use an assert. - boost::assert(numChildren <= maxNumChildren); + assert(par.NumChildren() <= par.MaxNumChildren()); - if(par.numOfChildren() == par.maxNumChildren) { + if(par.NumChildren() == par.MaxNumChildren()) { SplitNonLeafNode(par); } return; @@ -113,7 +132,14 @@ bool RTreeSplit::SplitNonLeafNode(const RectangleTree& tree) * 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. */ -void RTreeSplit::GetPointSeeds(const RectangleTree& tree, int* iRet, int* jRet) +template +void RTreeSplit::GetPointSeeds( + const RectangleTree& 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 @@ -124,7 +150,7 @@ void RTreeSplit::GetPointSeeds(const RectangleTree& tree, int* iRet, in 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 < dimensions; k++) { + for(int k = 0; k < tree.Bound().Dim(); k++) { score *= std::abs(tree.dataset[i][k] - tree.dataset[j][k]); } if(score > worstPairScore) { @@ -144,7 +170,14 @@ void RTreeSplit::GetPointSeeds(const RectangleTree& tree, int* iRet, in * 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. */ -void RTreeSplit::GetBoundSeeds(const RectangleTree& tree, int* iRet, int* jRet) +template +void RTreeSplit::GetBoundSeeds( + const RectangleTree& tree, + int* iRet, + int* jRet) { double worstPairScore = 0.0; int worstI = 0; @@ -152,7 +185,7 @@ void RTreeSplit::GetBoundSeeds(const RectangleTree& tree, int* iRet, in 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 < dimensions; k++) { + for(int k = 0; k < tree.Bound().Dim(); k++) { score *= std::max(tree.children[i].bound[k].hi(), tree.children[j].bound[k].hi) - std::min(tree.children[i].bound[k].low(), tree.children[j].bound[k].low()); } @@ -169,15 +202,19 @@ void RTreeSplit::GetBoundSeeds(const RectangleTree& tree, int* iRet, in return; } -void RTreeSplit::AssignPointDestNode( - const RectangleTree& oldTree, - RectangleTree& treeOne, - RectangleTree& treeTwo, +template +void RTreeSplit::AssignPointDestNode( + const RectangleTree& oldTree, + RectangleTree& treeOne, + RectangleTree& treeTwo, const int intI, const int intJ) { int end = oldTree.count; - Log::assert(end > 1); // If this isn't true, the tree is really weird. + assert(end > 1); // If this isn't true, the tree is really weird. treeOne.insertPoint(oldTree.dataset.col(intI)); oldTree.dataset.col(intI) = oldTree.dataset.col(--end); // decrement end @@ -200,7 +237,7 @@ void RTreeSplit::AssignPointDestNode( // Calculate the increase in volume for assigning this point to each rectangle. double volOne = 1.0; double volTwo = 1.0; - for(int i = 0; i < bound.Dim(); i++) { + for(int i = 0; i < oldTree.Bound().Dim(); i++) { volOne *= treeOne.bound[i].width(); volTwo *= treeTwo.bound[i].width(); } @@ -210,12 +247,12 @@ void RTreeSplit::AssignPointDestNode( for(int index = 0; index < end; index++) { double newVolOne = 1.0; double newVolTwo = 1.0; - for(int i = 0; i < bound.Dim(); i++) { + for(int i = 0; i < oldTree.Bound().Dim(); i++) { double c = oldTree.dataset.col(index)[i]; newVolOne *= treeOne.bound[i].contains(c) ? treeOne.bound[i].width() : - (c < treeOne.bound[i].low() ? (high - c) : (c - low)); + (c < treeOne.bound[i].low() ? (treeOne.bound[i].high() - c) : (c - treeOne.bound[i].low())); newVolTwo *= treeTwo.bound[i].contains(c) ? treeTwo.bound[i].width() : - (c < treeTwo.bound[i].low() ? (high - c) : (c - low)); + (c < treeTwo.bound[i].low() ? (treeTwo.bound[i].high() - c) : (c - treeTwo.bound[i].low())); } // Choose the rectangle that requires the lesser increase in volume. @@ -237,9 +274,9 @@ void RTreeSplit::AssignPointDestNode( // Assign the point that causes the least increase in volume // to the appropriate rectangle. if(bestRect == 1) - treeOne.insertPoint(oldTree.dataset(bestIndex); + treeOne.insertPoint(oldTree.dataset(bestIndex)); else - treeTwo.insertPoint(oldTree.dataset(bestIndex); + treeTwo.insertPoint(oldTree.dataset(bestIndex)); oldTree.dataset.col(bestIndex) = oldTree.dataset.col(--end); // decrement end. } @@ -248,26 +285,30 @@ void RTreeSplit::AssignPointDestNode( if(end > 1) { if(numAssignedOne < numAssignedTwo) { for(int i = 0; i < end; i++) { - treeOne.insertPoint(oldTree.dataset(i); + treeOne.insertPoint(oldTree.dataset(i)); } } else { for(int i = 0; i < end; i++) { - treeTwo.insertPoint(oldTree.dataset(i); + treeTwo.insertPoint(oldTree.dataset(i)); } } } } -void RTreeSplit::AssignNodeDestNode( - const RectangleTree& oldTree, - RectangleTree& treeOne, - RectangleTree& treeTwo, +template +void RTreeSplit::AssignNodeDestNode( + const RectangleTree& oldTree, + RectangleTree& treeOne, + RectangleTree& treeTwo, const int intI, const int intJ) { int end = oldTree.getNumChildren(); - Log::assert(end > 1); // If this isn't true, the tree is really weird. + assert(end > 1); // If this isn't true, the tree is really weird. treeOne.getChildren()[0] = oldTree.getChildren()[intI]; oldTree.getChildren[intI] = oldTree.getChildren()[--end]; // decrement end @@ -288,7 +329,7 @@ void RTreeSplit::AssignNodeDestNode( // 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 < bound.Dim(); i++) { + for(int i = 0; i < oldTree.Bound().Dim(); i++) { volOne *= treeOne.bound[i].width(); volTwo *= treeTwo.bound[i].width(); } @@ -296,15 +337,15 @@ void RTreeSplit::AssignNodeDestNode( for(int index = 0; index < end; index++) { double newVolOne = 1.0; double newVolTwo = 1.0; - for(int i = 0; i < bound.Dim(); i++) { + 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.getChildren()[index].Bound(i); + math::Range range = oldTree.getChildren()[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()))) + (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.Contains(treeTwo.Bound(i)) ? range.Width() : (range.lo() < treeTwo.Bound(i).lo() ? (treeTwo.Bound(i).hi() - range.lo()) : (range.hi() - treeTwo.Bound(i).lo()))); } @@ -327,15 +368,15 @@ void RTreeSplit::AssignNodeDestNode( // Assign the rectangle that causes the least increase in volume // to the appropriate rectangle. if(bestRect == 1) - insertNodeIntoTree(treeOne, oldTree.Children()[bestIndex]; + insertNodeIntoTree(treeOne, oldTree.Children()[bestIndex]); else - insertNodeIntoTree(treeTwo, oldTree.Children()[bestIndex]; + insertNodeIntoTree(treeTwo, oldTree.Children()[bestIndex]); oldTree.Children()[bestIndex] = oldTree.Children()[--end]; // Decrement end. } // See if we need to satisfy the minimum fill. if(end > 1) { - if(numAssignedOne < numAssignedTwo) { + if(numAssignTreeOne < numAssignTreeTwo) { for(int i = 0; i < end; i++) { insertNodeIntoTree(treeOne, oldTree.Children()[i]); } @@ -350,9 +391,13 @@ void RTreeSplit::AssignNodeDestNode( /** * Insert a node into another node. Expanding the bounds and updating the numberOfChildren. */ -static void insertNodeIntoTree( - RectangleTree& destTree, - RectangleTree& srcNode) +template +void RTreeSplit::insertNodeIntoTree( + RectangleTree& destTree, + RectangleTree& srcNode) { destTree.Bound() |= srcNode.Bound(); destTree.Children()[destTree.getNumOfChildren()++] = &srcNode; diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp index 3b7cbc4878..5cc33f7f00 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp @@ -12,13 +12,15 @@ #include "../hrectbound.hpp" #include "../statistic.hpp" -#ifdef __MLPACK_CORE_TREE_HRECTBOUND_HPP -#define max(a, b) 5 //something to break the build -#endif +// #ifdef __MLPACK_CORE_TREE_HRECTBOUND_HPP +// #define max(a, b) 5 //something to break the build +// #endif 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 @@ -65,7 +67,7 @@ class RectangleTree //! The minimum leaf size. size_t minLeafSize; //! The bound object for this node. - HRectBound bound; + 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. @@ -89,10 +91,29 @@ class RectangleTree * 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 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 maxNumChildren = 4); + RectangleTree(MatType& data, + const size_t maxLeafSize, + const size_t minLeafSize, + const size_t maxNumChildren, + const size_t minNumChildren, + const size_t firstDataIndex + ); + + /** + * 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. + */ + RectangleTree(const RectangleTree& parentNode); + //TODO implement the oldFromNew stuff if applicable. @@ -145,9 +166,9 @@ class RectangleTree RectangleTree* FindByBeginCount(size_t begin, size_t count); //! Return the bound object for this node. - const HRectBound& Bound() const { return bound; } + const HRectBound<>& Bound() const { return bound; } //! Modify the bound object for this node. - HRectBound& Bound() { return bound; } + HRectBound<>& Bound() { return bound; } //! Return the statistic object for this node. const StatisticType& Stat() const { return stat; } @@ -188,7 +209,7 @@ class RectangleTree arma::mat& Dataset() { return dataset; } //! Get the metric which the tree uses. - typename HRectBound::MetricType Metric() const { return bound.Metric(); } + 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); } @@ -343,7 +364,7 @@ class RectangleTree */ RectangleTree(const size_t begin, const size_t count, - HRectBound bound, + HRectBound<> bound, StatisticType stat, const int maxLeafSize = 20) : begin(begin), @@ -362,7 +383,7 @@ class RectangleTree * * @param tree The RectangleTree object (node) to split. */ - void SplitNode(RectangleTree& tree); + void SplitNode(); /** * Splits the current node, recursing up the tree. @@ -371,7 +392,7 @@ class RectangleTree * @param data Dataset which we are using. * @param oldFromNew Vector holding permuted indices NOT IMPLEMENTED. */ - void SplitNode(MatType& data, std::vector& oldFromNew); + void SplitNode(std::vector& oldFromNew); public: /** diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp index 430919a508..19ebf848e8 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -21,33 +21,32 @@ template -RectangleTree::RectangleTree( +RectangleTree::RectangleTree( MatType& data, - const size_t maxLeafSize, - const size_t minLeafSize, - const size_t maxNumChildren, - const size_t minNumChildren, + 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): + 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) { - this.maxNumChildren = maxNumChildren; - this.minNumChildren = minNumChildren; - this.numChildren = 0; - this.parent = NULL; - this.begin = 0; - this.count = 0; - this.maxLeafSize = maxLeafSize; - this.minLeafSize = minLeafSize; - this.bound = new HRectBound(data.n_rows); - this.stat = EmptyStatistic; - this.parentDistance = 0.0; - this.furthestDescendantDistance = 0.0; + this.stat = EmptyStatistic(*this); this.dataset = new MatType(maxLeafSize+1); // Add one to make splitting the node simpler - this.children = new std::vector(maxNumChildren+1); // ibid. // For now, just insert the points in order. RectangleTree* root = this; - for(int i = firstDataIndex; i < n_cols; i++) { + for(int i = firstDataIndex; i < data.n_cols; i++) { root.insertPoint(data.col(i)); if(root.Parent() != NULL) { root = root.Parent(); // OK since the level increases by at most one per iteration. @@ -56,21 +55,44 @@ RectangleTree::RectangleTree( } +template +RectangleTree::RectangleTree( + const RectangleTree& 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) + { + this.stat = EmptyStatistic(*this); + this.dataset = new MatType(maxLeafSize+1); // Add one to make splitting the node simpler + } + /** * 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 -RectangleTree:: +template +RectangleTree:: ~RectangleTree() { - for(int i = 0; i < numOfChildren; i++) { + for(int i = 0; i < numChildren; i++) { delete children[i]; } + delete dataset; } @@ -78,11 +100,11 @@ RectangleTree:: * Recurse through the tree and insert the point at the leaf node chosen * by the heuristic. */ -template -RectangleTree:: +template +void RectangleTree:: InsertPoint(const arma::vec& point) { // Expand the bound regardless of whether it is a leaf node. @@ -90,34 +112,34 @@ RectangleTree:: // If this is a leaf node, we stop here and add the point. if(numChildren == 0) { - data.col(points++) = point; - splitNode(); + dataset.col(count++) = point; + SplitNode(); return; } // If it is not a leaf node, we use the DescentHeuristic to choose a child // to which we recurse. - double minScore = DescentType.EvalNode(children[0].bound, point); + double minScore = DescentType::EvalNode(children[0].bound, point); int bestIndex = 0; for(int i = 1; i < numChildren; i++) { - double score = DescentType.EvalNode(children[i].bound, point); + double score = DescentType::EvalNode(children[i].bound, point); if(score < minScore) { minScore = score; - bestIndex = i + bestIndex = i; } } children[bestIndex].InsertPoint(point); } -template -size_t RectangleTree:: +template +size_t RectangleTree:: TreeSize() const { int n = 0; - for(int i = 0; i < numOfChildren; i++) { + for(int i = 0; i < numChildren; i++) { n += children[i].TreeSize(); } return n + 1; // we add one for this node @@ -125,17 +147,17 @@ size_t RectangleTree:: -template -size_t RectangleTree:: +template +size_t RectangleTree:: TreeDepth() const { // Recursively count the depth of each subtree. The plus one is // because we have to count this node, too. int maxSubDepth = 0; - for(int i = 0; i < numOfChildren; i++) { + for(int i = 0; i < numChildren; i++) { int d = children[i].depth(); if(d > maxSubDepth) maxSubDepth = d; @@ -143,38 +165,26 @@ size_t RectangleTree:: return maxSubDepth + 1; } -template -inline bool BinarySpaceTree:: +template +inline bool RectangleTree:: IsLeaf() const { - return numOfChildren == 0; + return numChildren == 0; } -/** - * Returns the number of children in this node. - */ -template -inline size_t RectangleTree:: - NumChildren() const -{ - return NumChildren; -} /** * Return a bound on the furthest point in the node form the centroid. * This returns 0 unless the node is a leaf. */ -template -inline double RectangleTree:: +template +inline double RectangleTree:: FurthestPointDistance() const { if(!IsLeaf()) @@ -191,11 +201,11 @@ FurthestPointDistance() const * furthest descendant distance may be less than what this method returns (but * it will never be greater than this). */ -template -inline double RectangleTree:: +template +inline double RectangleTree:: FurthestDescendantDistance() const { return furthestDescendantDistance; @@ -204,12 +214,12 @@ inline double RectangleTree:: /** * Return the specified child. */ -template -inline RectangleTree& - RectangleTree:: +template +inline RectangleTree& + RectangleTree:: Child(const size_t child) const { return children[child]; @@ -218,11 +228,11 @@ inline RectangleTree& /** * Return the number of points contained in this node. Zero if it is not a leaf. */ -template -inline size_t RectangleTree:: +template +inline size_t RectangleTree:: NumPoints() const { if(numChildren == 0) @@ -234,11 +244,11 @@ inline size_t RectangleTree:: /** * Return the number of descendants contained in this node. MEANINIGLESS AS IT CURRENTLY STANDS. */ -template -inline size_t RectangleTree:: +template +inline size_t RectangleTree:: NumDescendants() const { return count; @@ -247,12 +257,12 @@ inline size_t RectangleTree:: /** * Return the index of a particular descendant contained in this node. SEE OTHER WARNINGS */ -template -inline size_t RectangleTree:: - Descendant(const size_t index> const +template +inline size_t RectangleTree:: + Descendant(const size_t index) const { return (begin + index); } @@ -260,12 +270,12 @@ inline size_t RectangleTree:: /** * Return the index of a particular point contained in this node. SEE OTHER WARNINGS */ -template -inline size_t RectangleTree:: - Point(const size_t index> const +template +inline size_t RectangleTree:: + Point(const size_t index) const { return (begin + index); } @@ -274,15 +284,15 @@ inline size_t RectangleTree:: * Return the last point in the tree. SINCE THE TREE STORES DATA SEPARATELY IN EACH LEAF * THIS IS CURRENTLY MEANINGLESS. */ -template -inline size_t RectangleTree::End() const +template +inline size_t RectangleTree::End() const { - if(numOfChildren) + if(numChildren) return begin + count; - return children[numOfChildren-1].End(); + return children[numChildren-1].End(); } //have functions for returning the list of modified indices if we end up doing it that way. @@ -291,53 +301,53 @@ inline size_t RectangleTree::End * Split the tree. This calls the SplitType code to split a node. This method should only * be called on a leaf node. */ -template -void RectangleTree::SplitNode( - RetangleTree& tree) +template +void RectangleTree::SplitNode() { // 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. - boost::assert(numChildren == 0); + assert(numChildren == 0); // See if we are full. - if(points < maxLeafSize) + if(count < maxLeafSize) return; // If we are full, then we need to move up the tree. The SplitType takes // care of this. - SplitType.SplitLeafNode(this); + SplitType::SplitLeafNode(this); } /** * Returns a string representation of this object. */ - template -std::string RectangleTree::ToString() const +template +std::string RectangleTree::ToString() const { std::ostringstream convert; convert << "RectangleTree [" << this << "]" << std::endl; convert << " First point: " << begin << std::endl; - convert << " Number of descendants: " << count << 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 << " Split dimension: " << splitDimension << std::endl; // How many levels should we print? This will print the root and it's children. if(parent == NULL) { for(int i = 0; i < numChildren; i++) { - children[i].ToString(); + convert << children[i].ToString(); } } + return convert.str(); } }; //namespace tree diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser.hpp index 0ed388bf32..1d570f6135 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser.hpp @@ -21,7 +21,7 @@ template template -class RectangleTree:: +class RectangleTree:: RectangleTreeTraverser { public: @@ -52,7 +52,6 @@ class RectangleTree:: size_t numPrunes; }; - }; // namespace tree }; // namespace mlpack diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser_impl.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser_impl.hpp index fef06163c3..482221add2 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_traverser_impl.hpp @@ -22,21 +22,21 @@ template template -RectangleTree:: +RectangleTree:: RectangleTreeTraverser::RectangleTreeTraverser(RuleType& rule) : rule(rule), numPrunes(0) { /* Nothing to do */ } -template +template template -void RectangleTree:: +void RectangleTree:: RectangleTreeTraverser::Traverse( const size_t queryIndex, - RectangeTree& + const RectangleTree& referenceNode) { // If we reach a leaf node, we need to run the base case. @@ -53,14 +53,14 @@ RectangleTreeTraverser::Traverse( std::vector scores = new std::vector(referenceNode.NumChildren()); for(int i = 0; i < referenceNode.NumChildren(); i++) { nodes[i] = referenceNode.Children()[i]; - scores[i] = Rule.Score(nodes[i]); + scores[i] = rule.Score(nodes[i]); } - Rule.sortNodesAndScores(&nodes, &scores); + rule.sortNodesAndScores(&nodes, &scores); // 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, nodes[i], scores[i]) != DBL_MAX) + if(rule.Rescore(queryIndex, nodes[i], scores[i]) != DBL_MAX) Traverse(queryIndex, nodes[i]); else { numPrunes += referenceNode.NumChildren - i;