From 256cd1c179c0114aaf1c8073a6ab73b37fe667f1 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Wed, 9 Mar 2016 01:58:34 +0300 Subject: [PATCH 01/17] Fix invalid memory access during XTreeSplit #350 --- .../core/tree/rectangle_tree/typedef.hpp | 12 ++++++------ .../tree/rectangle_tree/x_tree_split_impl.hpp | 16 ++++++++++------ src/mlpack/tests/rectangle_tree_test.cpp | 18 +++++++----------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/mlpack/core/tree/rectangle_tree/typedef.hpp b/src/mlpack/core/tree/rectangle_tree/typedef.hpp index 89924b7be9..5007d2b266 100644 --- a/src/mlpack/core/tree/rectangle_tree/typedef.hpp +++ b/src/mlpack/core/tree/rectangle_tree/typedef.hpp @@ -71,12 +71,12 @@ using RStarTree = RectangleTree -//using XTree = RectangleTree; +template +using XTree = RectangleTree; } // namespace tree } // namespace mlpack 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 index 4472e23eb7..afca25b3da 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -63,7 +63,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) tree->Bound().Center(center); // Modifies centroid. for (size_t i = 0; i < sorted.size(); i++) { - sorted[i].d = tree->Bound().Metric().Evaluate(center, + sorted[i].d = tree->Metric().Evaluate(center, tree->LocalDataset().col(i)); sorted[i].n = i; } @@ -453,8 +453,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) { bestAxisScore = axisScore; bestAxis = j; - double bestOverlapIndexOnBestAxis = 0; - double bestAreaIndexOnBestAxis = 0; + bestOverlapIndexOnBestAxis = 0; + bestAreaIndexOnBestAxis = 0; + overlapBestOverlapAxis = overlapedAreas[bestOverlapIndexOnBestAxis]; + areaBestOverlapAxis = areas[bestAreaIndexOnBestAxis]; for (size_t i = 1; i < areas.size(); i++) { if (overlapedAreas[i] < overlapedAreas[bestOverlapIndexOnBestAxis]) @@ -584,8 +586,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) bestAxisScore = axisScore; bestAxis = j; lowIsBest = false; - double bestOverlapIndexOnBestAxis = 0; - double bestAreaIndexOnBestAxis = 0; + bestOverlapIndexOnBestAxis = 0; + bestAreaIndexOnBestAxis = 0; + overlapBestOverlapAxis = overlapedAreas[bestOverlapIndexOnBestAxis]; + areaBestOverlapAxis = areas[bestAreaIndexOnBestAxis]; for (size_t i = 1; i < areas.size(); i++) { if (overlapedAreas[i] < overlapedAreas[bestOverlapIndexOnBestAxis]) @@ -822,7 +826,7 @@ template void XTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode) { destTree->Bound() |= srcNode->Bound(); - destTree->Children().push_back(srcNode); + destTree->Children()[destTree->NumChildren()] = srcNode; destTree->NumChildren()++; } diff --git a/src/mlpack/tests/rectangle_tree_test.cpp b/src/mlpack/tests/rectangle_tree_test.cpp index 15f859eaa3..f3c4474d7b 100644 --- a/src/mlpack/tests/rectangle_tree_test.cpp +++ b/src/mlpack/tests/rectangle_tree_test.cpp @@ -575,7 +575,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeTraverserTest) // A test to ensure that the SingleTreeTraverser is working correctly by // comparing its results to the results of a naive search. -/** This is known to not work: see #368. +//* This is known to not work: see #368. BOOST_AUTO_TEST_CASE(XTreeTraverserTest) { arma::mat dataset; @@ -588,23 +588,19 @@ BOOST_AUTO_TEST_CASE(XTreeTraverserTest) arma::Mat neighbors2; arma::mat distances2; - typedef RectangleTree< - XTreeSplit, - arma::mat>, - RStarTreeDescentHeuristic, - NeighborSearchStat, + typedef XTree, arma::mat> TreeType; TreeType xTree(dataset, 20, 6, 5, 2, 0); // Nearest neighbor search with the X tree. - NeighborSearch, TreeType> - allknn1(&xTree, dataset, true); + + NeighborSearch, arma::mat, XTree > + allknn1(&xTree, true); BOOST_REQUIRE_EQUAL(xTree.NumDescendants(), numP); CheckSync(xTree); - //CheckContainment(xTree); + CheckContainment(xTree); CheckExactContainment(xTree); CheckHierarchy(xTree); @@ -621,7 +617,7 @@ BOOST_AUTO_TEST_CASE(XTreeTraverserTest) 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. From 9467a92e626181a8b1378895742fab11954b747b Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Wed, 9 Mar 2016 02:12:16 +0300 Subject: [PATCH 02/17] Fix redefinition in RStarTreeSplit::SplitNonLeafNode. --- .../core/tree/rectangle_tree/r_star_tree_split_impl.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 584466a8e9..cf4b7d0890 100644 --- 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 @@ -450,8 +450,8 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree, { bestAxisScore = axisScore; bestAxis = j; - ElemType bestOverlapIndexOnBestAxis = 0; - ElemType bestAreaIndexOnBestAxis = 0; + bestOverlapIndexOnBestAxis = 0; + bestAreaIndexOnBestAxis = 0; for (size_t i = 1; i < areas.size(); i++) { if (overlapedAreas[i] < overlapedAreas[bestOverlapIndexOnBestAxis]) @@ -565,8 +565,8 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree, bestAxisScore = axisScore; bestAxis = j; lowIsBest = false; - ElemType bestOverlapIndexOnBestAxis = 0; - ElemType bestAreaIndexOnBestAxis = 0; + bestOverlapIndexOnBestAxis = 0; + bestAreaIndexOnBestAxis = 0; for (size_t i = 1; i < areas.size(); i++) { From 8921d0349ed463b8c4aa96e4d6d9fa1aa01f7d6f Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Wed, 9 Mar 2016 02:49:14 +0300 Subject: [PATCH 03/17] Update XTreeSplit API according to recent RStarTreeSplit API --- .../core/tree/rectangle_tree/x_tree_split.hpp | 7 +- .../tree/rectangle_tree/x_tree_split_impl.hpp | 112 +++++++++--------- 2 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp index 9c37ca5e20..ef9224c99e 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp @@ -50,17 +50,20 @@ class XTreeSplit /** * Class to allow for faster sorting. */ + template class sortStruct { public: - double d; + ElemType d; int n; }; /** * Comparator for sorting with sortStruct. */ - static bool structComp(const sortStruct& s1, const sortStruct& s2) + template + static bool structComp(const sortStruct& s1, + const sortStruct& s2) { return s1.d < s2.d; } 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 index afca25b3da..e88304914d 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -23,6 +23,9 @@ namespace tree { template void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) { + // Convenience typedef. + typedef typename TreeType::ElemType ElemType; + // 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. @@ -58,8 +61,8 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) return; } - std::vector sorted(tree->Count()); - arma::vec center; + std::vector> sorted(tree->Count()); + arma::Col center; tree->Bound().Center(center); // Modifies centroid. for (size_t i = 0; i < sorted.size(); i++) { @@ -68,7 +71,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) sorted[i].n = i; } - std::sort(sorted.begin(), sorted.end(), structComp); + std::sort(sorted.begin(), sorted.end(), structComp); std::vector pointIndices(p); for (size_t i = 0; i < p; i++) { @@ -103,25 +106,25 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) int bestAreaIndexOnBestAxis = 0; bool tiedOnOverlap = false; int bestAxis = 0; - double bestAxisScore = DBL_MAX; + ElemType bestAxisScore = DBL_MAX; for (size_t j = 0; j < tree->Bound().Dim(); j++) { - double axisScore = 0.0; + ElemType axisScore = 0.0; // Since we only have points in the leaf nodes, we only need to sort once. - std::vector sorted(tree->Count()); + std::vector> sorted(tree->Count()); for (size_t 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); + std::sort(sorted.begin(), sorted.end(), structComp); // We'll store each of the three scores for each distribution. - std::vector areas(tree->MaxLeafSize() - + std::vector areas(tree->MaxLeafSize() - 2 * tree->MinLeafSize() + 2); - std::vector margins(tree->MaxLeafSize() - + std::vector margins(tree->MaxLeafSize() - 2 * tree->MinLeafSize() + 2); - std::vector overlapedAreas(tree->MaxLeafSize() - + std::vector overlapedAreas(tree->MaxLeafSize() - 2 * tree->MinLeafSize() + 2); for (size_t i = 0; i < areas.size(); i++) { @@ -137,10 +140,10 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) size_t cutOff = tree->MinLeafSize() + i; // We'll calculate the max and min in each dimension by hand to save time. - std::vector maxG1(tree->Bound().Dim()); - std::vector minG1(maxG1.size()); - std::vector maxG2(maxG1.size()); - std::vector minG2(maxG1.size()); + std::vector maxG1(tree->Bound().Dim()); + std::vector minG1(maxG1.size()); + std::vector maxG2(maxG1.size()); + std::vector minG2(maxG1.size()); for (size_t k = 0; k < tree->Bound().Dim(); k++) { minG1[k] = maxG1[k] = tree->LocalDataset().col(sorted[0].n)[k]; @@ -166,8 +169,8 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) } } - double area1 = 1.0, area2 = 1.0; - double oArea = 1.0; + ElemType area1 = 1.0, area2 = 1.0; + ElemType oArea = 1.0; for (size_t k = 0; k < maxG1.size(); k++) { margins[i] += maxG1[k] - minG1[k] + maxG2[k] - minG2[k]; @@ -206,14 +209,14 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) } } - std::vector sorted(tree->Count()); + std::vector> sorted(tree->Count()); for (size_t 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); + std::sort(sorted.begin(), sorted.end(), structComp); TreeType* treeOne = new TreeType(tree->Parent()); TreeType* treeTwo = new TreeType(tree->Parent()); @@ -291,6 +294,9 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) template bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) { + // Convenience typedef. + typedef typename TreeType::ElemType ElemType; + // 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. @@ -352,8 +358,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) } bool minOverlapSplitUsesHi = false; - double bestScoreMinOverlapSplit = DBL_MAX; - double areaOfBestMinOverlapSplit = 0; + ElemType bestScoreMinOverlapSplit = DBL_MAX; + ElemType areaOfBestMinOverlapSplit = 0; int bestIndexMinOverlapSplit = 0; int bestOverlapIndexOnBestAxis = 0; @@ -361,32 +367,32 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) bool tiedOnOverlap = false; bool lowIsBest = true; int bestAxis = 0; - double bestAxisScore = DBL_MAX; - double overlapBestOverlapAxis = 0; - double areaBestOverlapAxis = 0; - double overlapBestAreaAxis = 0; - double areaBestAreaAxis = 0; + ElemType bestAxisScore = DBL_MAX; + ElemType overlapBestOverlapAxis = 0; + ElemType areaBestOverlapAxis = 0; + ElemType overlapBestAreaAxis = 0; + ElemType areaBestAreaAxis = 0; for (size_t j = 0; j < tree->Bound().Dim(); j++) { - double axisScore = 0.0; + ElemType axisScore = 0.0; // We'll do Bound().Lo() now and use Bound().Hi() later. - std::vector sorted(tree->NumChildren()); + std::vector> sorted(tree->NumChildren()); for (size_t i = 0; i < sorted.size(); i++) { sorted[i].d = tree->Children()[i]->Bound()[j].Lo(); sorted[i].n = i; } - std::sort(sorted.begin(), sorted.end(), structComp); + std::sort(sorted.begin(), sorted.end(), structComp); // We'll store each of the three scores for each distribution. - std::vector areas(tree->MaxNumChildren() - + std::vector areas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2); - std::vector margins(tree->MaxNumChildren() - + std::vector margins(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2); - std::vector overlapedAreas(tree->MaxNumChildren() - + std::vector overlapedAreas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2); for (size_t i = 0; i < areas.size(); i++) { @@ -403,10 +409,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) size_t cutOff = tree->MinNumChildren() + i; // We'll calculate the max and min in each dimension by hand to save time. - std::vector maxG1(tree->Bound().Dim()); - std::vector minG1(maxG1.size()); - std::vector maxG2(maxG1.size()); - std::vector minG2(maxG1.size()); + std::vector maxG1(tree->Bound().Dim()); + std::vector minG1(maxG1.size()); + std::vector maxG2(maxG1.size()); + std::vector minG2(maxG1.size()); for (size_t k = 0; k < tree->Bound().Dim(); k++) { minG1[k] = tree->Children()[sorted[0].n]->Bound()[k].Lo(); @@ -434,8 +440,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) } } - double area1 = 1.0, area2 = 1.0; - double oArea = 1.0; + ElemType area1 = 1.0, area2 = 1.0; + ElemType oArea = 1.0; for (size_t k = 0; k < maxG1.size(); k++) { margins[i] += maxG1[k] - minG1[k] + maxG2[k] - minG2[k]; @@ -500,24 +506,24 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) // Now we do the same thing using Bound().Hi() and choose the best of the two. for (size_t j = 0; j < tree->Bound().Dim(); j++) { - double axisScore = 0.0; + ElemType axisScore = 0.0; // We'll do Bound().Lo() now and use Bound().Hi() later. - std::vector sorted(tree->NumChildren()); + std::vector> sorted(tree->NumChildren()); for (size_t i = 0; i < sorted.size(); i++) { sorted[i].d = tree->Children()[i]->Bound()[j].Hi(); sorted[i].n = i; } - std::sort(sorted.begin(), sorted.end(), structComp); + std::sort(sorted.begin(), sorted.end(), structComp); // We'll store each of the three scores for each distribution. - std::vector areas(tree->MaxNumChildren() - + std::vector areas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2); - std::vector margins(tree->MaxNumChildren() - + std::vector margins(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2); - std::vector overlapedAreas(tree->MaxNumChildren() - + std::vector overlapedAreas(tree->MaxNumChildren() - 2 * tree->MinNumChildren() + 2); for (size_t i = 0; i < areas.size(); i++) { @@ -534,10 +540,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) size_t cutOff = tree->MinNumChildren() + i; // We'll calculate the max and min in each dimension by hand to save time. - std::vector maxG1(tree->Bound().Dim()); - std::vector minG1(maxG1.size()); - std::vector maxG2(maxG1.size()); - std::vector minG2(maxG1.size()); + std::vector maxG1(tree->Bound().Dim()); + std::vector minG1(maxG1.size()); + std::vector maxG2(maxG1.size()); + std::vector minG2(maxG1.size()); for (size_t k = 0; k < tree->Bound().Dim(); k++) { minG1[k] = tree->Children()[sorted[0].n]->Bound()[k].Lo(); @@ -565,8 +571,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) } } - double area1 = 1.0, area2 = 1.0; - double oArea = 1.0; + ElemType area1 = 1.0, area2 = 1.0; + ElemType oArea = 1.0; for (size_t k = 0; k < maxG1.size(); k++) { margins[i] += maxG1[k] - minG1[k] + maxG2[k] - minG2[k]; @@ -631,7 +637,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) } } - std::vector sorted(tree->NumChildren()); + std::vector> sorted(tree->NumChildren()); if (lowIsBest) { for (size_t i = 0; i < sorted.size(); i++) @@ -649,7 +655,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) } } - std::sort(sorted.begin(), sorted.end(), structComp); + std::sort(sorted.begin(), sorted.end(), structComp); TreeType* treeOne = new TreeType(tree->Parent()); TreeType* treeTwo = new TreeType(tree->Parent()); @@ -696,7 +702,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) if ((minOverlapSplitDimension != tree->Bound().Dim()) && (bestScoreMinOverlapSplit / areaOfBestMinOverlapSplit < MAX_OVERLAP)) { - std::vector sorted2(tree->NumChildren()); + std::vector> sorted2(tree->NumChildren()); if (minOverlapSplitUsesHi) { for (size_t i = 0; i < sorted2.size(); i++) @@ -713,7 +719,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) sorted2[i].n = i; } } - std::sort(sorted2.begin(), sorted2.end(), structComp); + std::sort(sorted2.begin(), sorted2.end(), structComp); for (size_t i = 0; i < tree->NumChildren(); i++) { if (i < bestIndexMinOverlapSplit + tree->MinNumChildren()) From 72e7bff972436d800c21c7d1844a17d719f450f1 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Thu, 10 Mar 2016 11:22:22 +0300 Subject: [PATCH 04/17] Added XTree to allkfn, allknn, range_search and allkrann --- .../methods/neighbor_search/allkfn_main.cpp | 6 +- .../methods/neighbor_search/allknn_main.cpp | 6 +- .../methods/neighbor_search/ns_model.hpp | 2 + .../methods/neighbor_search/ns_model_impl.hpp | 36 ++++++++++++ .../range_search/range_search_main.cpp | 6 +- src/mlpack/methods/range_search/rs_model.cpp | 19 +++++++ src/mlpack/methods/range_search/rs_model.hpp | 3 + .../methods/range_search/rs_model_impl.hpp | 14 +++++ src/mlpack/methods/rann/allkrann_main.cpp | 6 +- src/mlpack/methods/rann/ra_model.hpp | 5 +- src/mlpack/methods/rann/ra_model_impl.hpp | 56 ++++++++++++++++++- 11 files changed, 149 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/neighbor_search/allkfn_main.cpp b/src/mlpack/methods/neighbor_search/allkfn_main.cpp index c8ebbfe350..975b23f069 100644 --- a/src/mlpack/methods/neighbor_search/allkfn_main.cpp +++ b/src/mlpack/methods/neighbor_search/allkfn_main.cpp @@ -62,7 +62,7 @@ PARAM_INT("k", "Number of furthest neighbors to find.", "k", 0); // The user may specify the type of tree to use, and a few pararmeters for tree // building. PARAM_STRING("tree_type", "Type of tree to use: 'kd', 'cover', 'r', 'r-star', " - "'ball'.", "t", "kd"); + "'x', 'ball'.", "t", "kd"); PARAM_INT("leaf_size", "Leaf size for tree building.", "l", 20); PARAM_FLAG("random_basis", "Before tree-building, project the data onto a " "random orthogonal basis.", "R"); @@ -158,11 +158,13 @@ int main(int argc, char *argv[]) tree = KFNModel::R_TREE; else if (treeType == "r-star") tree = KFNModel::R_STAR_TREE; + else if (treeType == "x") + tree = KFNModel::X_TREE; else if (treeType == "ball") tree = KFNModel::BALL_TREE; else Log::Fatal << "Unknown tree type '" << treeType << "'; valid choices are " - << "'kd', 'cover', 'r', 'r-star', and 'ball'." << endl; + << "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl; kfn.TreeType() = tree; kfn.RandomBasis() = randomBasis; diff --git a/src/mlpack/methods/neighbor_search/allknn_main.cpp b/src/mlpack/methods/neighbor_search/allknn_main.cpp index 172f897d62..5440e26454 100644 --- a/src/mlpack/methods/neighbor_search/allknn_main.cpp +++ b/src/mlpack/methods/neighbor_search/allknn_main.cpp @@ -63,7 +63,7 @@ PARAM_INT("k", "Number of nearest neighbors to find.", "k", 0); // The user may specify the type of tree to use, and a few parameters for tree // building. PARAM_STRING("tree_type", "Type of tree to use: 'kd', 'cover', 'r', 'r-star', " - "'ball'.", "t", "kd"); + "'x', 'ball'.", "t", "kd"); PARAM_INT("leaf_size", "Leaf size for tree building (used for kd-trees, R " "trees, and R* trees).", "l", 20); PARAM_FLAG("random_basis", "Before tree-building, project the data onto a " @@ -162,11 +162,13 @@ int main(int argc, char *argv[]) tree = KNNModel::R_TREE; else if (treeType == "r-star") tree = KNNModel::R_STAR_TREE; + else if (treeType == "x") + tree = KNNModel::X_TREE; else if (treeType == "ball") tree = KNNModel::BALL_TREE; else Log::Fatal << "Unknown tree type '" << treeType << "'; valid choices are " - << "'kd', 'cover', 'r', 'r-star', and 'ball'." << endl; + << "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl; knn.TreeType() = tree; knn.RandomBasis() = randomBasis; diff --git a/src/mlpack/methods/neighbor_search/ns_model.hpp b/src/mlpack/methods/neighbor_search/ns_model.hpp index b8767e3d78..a4613e9a5a 100644 --- a/src/mlpack/methods/neighbor_search/ns_model.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model.hpp @@ -47,6 +47,7 @@ class NSModel COVER_TREE, R_TREE, R_STAR_TREE, + X_TREE, BALL_TREE }; @@ -74,6 +75,7 @@ class NSModel NSType* coverTreeNS; NSType* rTreeNS; NSType* rStarTreeNS; + NSType* xTreeNS; NSType* ballTreeNS; public: diff --git a/src/mlpack/methods/neighbor_search/ns_model_impl.hpp b/src/mlpack/methods/neighbor_search/ns_model_impl.hpp index 1245ab83b7..8155edad1a 100644 --- a/src/mlpack/methods/neighbor_search/ns_model_impl.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model_impl.hpp @@ -28,6 +28,7 @@ NSModel::NSModel(int treeType, bool randomBasis) : coverTreeNS(NULL), rTreeNS(NULL), rStarTreeNS(NULL), + xTreeNS(NULL), ballTreeNS(NULL) { // Nothing to do. @@ -45,6 +46,8 @@ NSModel::~NSModel() delete rTreeNS; if (rStarTreeNS) delete rStarTreeNS; + if (xTreeNS) + delete xTreeNS; if (ballTreeNS) delete ballTreeNS; } @@ -70,6 +73,8 @@ void NSModel::Serialize(Archive& ar, delete rTreeNS; if (rStarTreeNS) delete rStarTreeNS; + if (xTreeNS) + delete xTreeNS; if (ballTreeNS) delete ballTreeNS; @@ -78,6 +83,8 @@ void NSModel::Serialize(Archive& ar, coverTreeNS = NULL; rTreeNS = NULL; rStarTreeNS = NULL; + xTreeNS = NULL; + ballTreeNS = NULL; } // We'll only need to serialize one of the kNN objects, based on the type. @@ -96,6 +103,9 @@ void NSModel::Serialize(Archive& ar, case R_STAR_TREE: ar & data::CreateNVP(rStarTreeNS, name); break; + case X_TREE: + ar & data::CreateNVP(xTreeNS, name); + break; case BALL_TREE: ar & data::CreateNVP(ballTreeNS, name); break; @@ -113,6 +123,8 @@ const arma::mat& NSModel::Dataset() const return rTreeNS->ReferenceSet(); else if (rStarTreeNS) return rStarTreeNS->ReferenceSet(); + else if (xTreeNS) + return xTreeNS->ReferenceSet(); else if (ballTreeNS) return ballTreeNS->ReferenceSet(); @@ -131,6 +143,8 @@ bool NSModel::SingleMode() const return rTreeNS->SingleMode(); else if (rStarTreeNS) return rStarTreeNS->SingleMode(); + else if (xTreeNS) + return xTreeNS->SingleMode(); else if (ballTreeNS) return ballTreeNS->SingleMode(); @@ -148,6 +162,8 @@ bool& NSModel::SingleMode() return rTreeNS->SingleMode(); else if (rStarTreeNS) return rStarTreeNS->SingleMode(); + else if (xTreeNS) + return xTreeNS->SingleMode(); else if (ballTreeNS) return ballTreeNS->SingleMode(); @@ -165,6 +181,8 @@ bool NSModel::Naive() const return rTreeNS->Naive(); else if (rStarTreeNS) return rStarTreeNS->Naive(); + else if (xTreeNS) + return xTreeNS->Naive(); else if (ballTreeNS) return ballTreeNS->Naive(); @@ -182,6 +200,8 @@ bool& NSModel::Naive() return rTreeNS->Naive(); else if (rStarTreeNS) return rStarTreeNS->Naive(); + else if (xTreeNS) + return xTreeNS->Naive(); else if (ballTreeNS) return ballTreeNS->Naive(); @@ -236,6 +256,8 @@ void NSModel::BuildModel(arma::mat&& referenceSet, delete rTreeNS; if (rStarTreeNS) delete rStarTreeNS; + if (xTreeNS) + delete xTreeNS; if (ballTreeNS) delete ballTreeNS; @@ -287,6 +309,11 @@ void NSModel::BuildModel(arma::mat&& referenceSet, rStarTreeNS = new NSType(std::move(referenceSet), naive, singleMode); break; + case X_TREE: + // If necessary, build the X tree. + xTreeNS = new NSType(std::move(referenceSet), naive, + singleMode); + break; case BALL_TREE: // If necessary, build the ball tree. if (naive) @@ -381,6 +408,10 @@ void NSModel::Search(arma::mat&& querySet, // No mapping necessary. rStarTreeNS->Search(querySet, k, neighbors, distances); break; + case X_TREE: + // No mapping necessary. + xTreeNS->Search(querySet, k, neighbors, distances); + break; case BALL_TREE: if (!ballTreeNS->Naive() && !ballTreeNS->SingleMode()) { @@ -444,6 +475,9 @@ void NSModel::Search(const size_t k, case R_STAR_TREE: rStarTreeNS->Search(k, neighbors, distances); break; + case X_TREE: + xTreeNS->Search(k, neighbors, distances); + break; case BALL_TREE: ballTreeNS->Search(k, neighbors, distances); break; @@ -464,6 +498,8 @@ std::string NSModel::TreeName() const return "R tree"; case R_STAR_TREE: return "R* tree"; + case X_TREE: + return "X tree"; case BALL_TREE: return "ball tree"; default: diff --git a/src/mlpack/methods/range_search/range_search_main.cpp b/src/mlpack/methods/range_search/range_search_main.cpp index f012ce864a..fe870c442d 100644 --- a/src/mlpack/methods/range_search/range_search_main.cpp +++ b/src/mlpack/methods/range_search/range_search_main.cpp @@ -70,7 +70,7 @@ PARAM_DOUBLE("min", "Lower bound in range.", "L", 0.0); // The user may specify the type of tree to use, and a few parameters for tree // building. PARAM_STRING("tree_type", "Type of tree to use: 'kd', 'cover', 'r', 'r-star', " - "'ball'.", "t", "kd"); + "'x', 'ball'.", "t", "kd"); PARAM_INT("leaf_size", "Leaf size for tree building.", "l", 20); PARAM_FLAG("random_basis", "Before tree-building, project the data onto a " "random orthogonal basis.", "R"); @@ -169,11 +169,13 @@ int main(int argc, char *argv[]) tree = RSModel::R_TREE; else if (treeType == "r-star") tree = RSModel::R_STAR_TREE; + else if (treeType == "x") + tree = RSModel::X_TREE; else if (treeType == "ball") tree = RSModel::BALL_TREE; else Log::Fatal << "Unknown tree type '" << treeType << "; valid choices are " - << "'kd', 'cover', 'r', 'r-star', and 'ball'." << endl; + << "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl; rs.TreeType() = tree; rs.RandomBasis() = randomBasis; diff --git a/src/mlpack/methods/range_search/rs_model.cpp b/src/mlpack/methods/range_search/rs_model.cpp index 8b735faf1d..27f05ad741 100644 --- a/src/mlpack/methods/range_search/rs_model.cpp +++ b/src/mlpack/methods/range_search/rs_model.cpp @@ -21,6 +21,7 @@ RSModel::RSModel(int treeType, bool randomBasis) : coverTreeRS(NULL), rTreeRS(NULL), rStarTreeRS(NULL), + xTreeRS(NULL), ballTreeRS(NULL) { // Nothing to do. @@ -95,6 +96,11 @@ void RSModel::BuildModel(arma::mat&& referenceSet, singleMode); break; + case X_TREE: + xTreeRS = new RSType(move(referenceSet), naive, + singleMode); + break; + case BALL_TREE: // If necessary, build the ball tree. if (naive) @@ -190,6 +196,10 @@ void RSModel::Search(arma::mat&& querySet, rStarTreeRS->Search(querySet, range, neighbors, distances); break; + case X_TREE: + xTreeRS->Search(querySet, range, neighbors, distances); + break; + case BALL_TREE: if (!ballTreeRS->Naive() && !ballTreeRS->SingleMode()) { @@ -256,6 +266,10 @@ void RSModel::Search(const math::Range& range, rStarTreeRS->Search(range, neighbors, distances); break; + case X_TREE: + xTreeRS->Search(range, neighbors, distances); + break; + case BALL_TREE: ballTreeRS->Search(range, neighbors, distances); break; @@ -275,6 +289,8 @@ std::string RSModel::TreeName() const return "R tree"; case R_STAR_TREE: return "R* tree"; + case X_TREE: + return "X tree"; case BALL_TREE: return "ball tree"; default: @@ -293,6 +309,8 @@ void RSModel::CleanMemory() delete rTreeRS; if (rStarTreeRS) delete rStarTreeRS; + if (xTreeRS) + delete xTreeRS; if (ballTreeRS) delete ballTreeRS; @@ -300,5 +318,6 @@ void RSModel::CleanMemory() coverTreeRS = NULL; rTreeRS = NULL; rStarTreeRS = NULL; + xTreeRS = NULL; ballTreeRS = NULL; } diff --git a/src/mlpack/methods/range_search/rs_model.hpp b/src/mlpack/methods/range_search/rs_model.hpp index 0a249fd2d2..b2b809bb26 100644 --- a/src/mlpack/methods/range_search/rs_model.hpp +++ b/src/mlpack/methods/range_search/rs_model.hpp @@ -28,6 +28,7 @@ class RSModel COVER_TREE, R_TREE, R_STAR_TREE, + X_TREE, BALL_TREE }; @@ -55,6 +56,8 @@ class RSModel RSType* rTreeRS; //! R* tree based range search object (NULL if not in use). RSType* rStarTreeRS; + //! X tree based range search object (NULL if not in use). + RSType* xTreeRS; //! Ball tree based range search object (NULL if not in use). RSType* ballTreeRS; diff --git a/src/mlpack/methods/range_search/rs_model_impl.hpp b/src/mlpack/methods/range_search/rs_model_impl.hpp index 55f38d046c..77a806898d 100644 --- a/src/mlpack/methods/range_search/rs_model_impl.hpp +++ b/src/mlpack/methods/range_search/rs_model_impl.hpp @@ -46,6 +46,10 @@ void RSModel::Serialize(Archive& ar, const unsigned int /* version */) ar & CreateNVP(rStarTreeRS, "range_search_model"); break; + case X_TREE: + ar & CreateNVP(xTreeRS, "range_search_model"); + break; + case BALL_TREE: ar & CreateNVP(ballTreeRS, "range_search_model"); break; @@ -62,6 +66,8 @@ inline const arma::mat& RSModel::Dataset() const return rTreeRS->ReferenceSet(); else if (rStarTreeRS) return rStarTreeRS->ReferenceSet(); + else if (xTreeRS) + return xTreeRS->ReferenceSet(); else if (ballTreeRS) return ballTreeRS->ReferenceSet(); @@ -78,6 +84,8 @@ inline bool RSModel::SingleMode() const return rTreeRS->SingleMode(); else if (rStarTreeRS) return rStarTreeRS->SingleMode(); + else if (xTreeRS) + return xTreeRS->SingleMode(); else if (ballTreeRS) return ballTreeRS->SingleMode(); @@ -94,6 +102,8 @@ inline bool& RSModel::SingleMode() return rTreeRS->SingleMode(); else if (rStarTreeRS) return rStarTreeRS->SingleMode(); + else if (xTreeRS) + return xTreeRS->SingleMode(); else if (ballTreeRS) return ballTreeRS->SingleMode(); @@ -110,6 +120,8 @@ inline bool RSModel::Naive() const return rTreeRS->Naive(); else if (rStarTreeRS) return rStarTreeRS->Naive(); + else if (xTreeRS) + return xTreeRS->Naive(); else if (ballTreeRS) return ballTreeRS->Naive(); @@ -126,6 +138,8 @@ inline bool& RSModel::Naive() return rTreeRS->Naive(); else if (rStarTreeRS) return rStarTreeRS->Naive(); + else if (xTreeRS) + return xTreeRS->Naive(); else if (ballTreeRS) return ballTreeRS->Naive(); diff --git a/src/mlpack/methods/rann/allkrann_main.cpp b/src/mlpack/methods/rann/allkrann_main.cpp index 430eae3338..6efb097fd4 100644 --- a/src/mlpack/methods/rann/allkrann_main.cpp +++ b/src/mlpack/methods/rann/allkrann_main.cpp @@ -64,7 +64,7 @@ PARAM_INT("k", "Number of nearest neighbors to find.", "k", 0); // The user may specify the type of tree to use, and a few parameters for tree // building. PARAM_STRING("tree_type", "Type of tree to use: 'kd', 'cover', 'r', or " - "'r-star'.", "t", "kd"); + "'x', 'r-star'.", "t", "kd"); PARAM_INT("leaf_size", "Leaf size for tree building (used for kd-trees, R " "trees, and R* trees).", "l", 20); PARAM_FLAG("random_basis", "Before tree-building, project the data onto a " @@ -170,9 +170,11 @@ int main(int argc, char *argv[]) tree = RANNModel::R_TREE; else if (treeType == "r-star") tree = RANNModel::R_STAR_TREE; + else if (treeType == "x") + tree = RANNModel::X_TREE; else Log::Fatal << "Unknown tree type '" << treeType << "'; valid choices are " - << "'kd', 'cover', 'r', and 'r-star'." << endl; + << "'kd', 'cover', 'r', 'r-star' and 'x'." << endl; rann.TreeType() = tree; rann.RandomBasis() = randomBasis; diff --git a/src/mlpack/methods/rann/ra_model.hpp b/src/mlpack/methods/rann/ra_model.hpp index 26af54b0f6..47f2430e4f 100644 --- a/src/mlpack/methods/rann/ra_model.hpp +++ b/src/mlpack/methods/rann/ra_model.hpp @@ -39,7 +39,8 @@ class RAModel KD_TREE, COVER_TREE, R_TREE, - R_STAR_TREE + R_STAR_TREE, + X_TREE }; private: @@ -70,6 +71,8 @@ class RAModel RAType* rTreeRA; //! Non-NULL if the R* tree is used. RAType* rStarTreeRA; + //! Non-NULL if the X tree is used. + RAType* xTreeRA; public: /** diff --git a/src/mlpack/methods/rann/ra_model_impl.hpp b/src/mlpack/methods/rann/ra_model_impl.hpp index 390de0943e..f7f9f9cfe9 100644 --- a/src/mlpack/methods/rann/ra_model_impl.hpp +++ b/src/mlpack/methods/rann/ra_model_impl.hpp @@ -21,7 +21,8 @@ RAModel::RAModel(const int treeType, const bool randomBasis) : kdTreeRA(NULL), coverTreeRA(NULL), rTreeRA(NULL), - rStarTreeRA(NULL) + rStarTreeRA(NULL), + xTreeRA(NULL) { // Nothing to do. } @@ -37,6 +38,8 @@ RAModel::~RAModel() delete rTreeRA; if (rStarTreeRA) delete rStarTreeRA; + if (xTreeRA) + delete xTreeRA; } template @@ -59,12 +62,15 @@ void RAModel::Serialize(Archive& ar, delete rTreeRA; if (rStarTreeRA) delete rStarTreeRA; + if (xTreeRA) + delete xTreeRA; // Set all the pointers to NULL. kdTreeRA = NULL; coverTreeRA = NULL; rTreeRA = NULL; rStarTreeRA = NULL; + xTreeRA = NULL; } // We only need to serialize one of the kRANN objects. @@ -82,6 +88,9 @@ void RAModel::Serialize(Archive& ar, case R_STAR_TREE: ar & data::CreateNVP(rStarTreeRA, "ra_model"); break; + case X_TREE: + ar & data::CreateNVP(xTreeRA, "ra_model"); + break; } } @@ -96,6 +105,8 @@ const arma::mat& RAModel::Dataset() const return rTreeRA->ReferenceSet(); else if (rStarTreeRA) return rStarTreeRA->ReferenceSet(); + else if (xTreeRA) + return xTreeRA->ReferenceSet(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -112,6 +123,8 @@ bool RAModel::Naive() const return rTreeRA->Naive(); else if (rStarTreeRA) return rStarTreeRA->Naive(); + else if (xTreeRA) + return xTreeRA->Naive(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -128,6 +141,8 @@ bool& RAModel::Naive() return rTreeRA->Naive(); else if (rStarTreeRA) return rStarTreeRA->Naive(); + else if (xTreeRA) + return xTreeRA->Naive(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -144,6 +159,8 @@ bool RAModel::SingleMode() const return rTreeRA->SingleMode(); else if (rStarTreeRA) return rStarTreeRA->SingleMode(); + else if (xTreeRA) + return xTreeRA->SingleMode(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -160,6 +177,8 @@ bool& RAModel::SingleMode() return rTreeRA->SingleMode(); else if (rStarTreeRA) return rStarTreeRA->SingleMode(); + else if (xTreeRA) + return xTreeRA->SingleMode(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -176,6 +195,8 @@ double RAModel::Tau() const return rTreeRA->Tau(); else if (rStarTreeRA) return rStarTreeRA->Tau(); + else if (xTreeRA) + return xTreeRA->Tau(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -192,6 +213,8 @@ double& RAModel::Tau() return rTreeRA->Tau(); else if (rStarTreeRA) return rStarTreeRA->Tau(); + else if (xTreeRA) + return xTreeRA->Tau(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -208,6 +231,8 @@ double RAModel::Alpha() const return rTreeRA->Alpha(); else if (rStarTreeRA) return rStarTreeRA->Alpha(); + else if (xTreeRA) + return xTreeRA->Alpha(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -224,6 +249,8 @@ double& RAModel::Alpha() return rTreeRA->Alpha(); else if (rStarTreeRA) return rStarTreeRA->Alpha(); + else if (xTreeRA) + return xTreeRA->Alpha(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -240,6 +267,8 @@ bool RAModel::SampleAtLeaves() const return rTreeRA->SampleAtLeaves(); else if (rStarTreeRA) return rStarTreeRA->SampleAtLeaves(); + else if (xTreeRA) + return xTreeRA->SampleAtLeaves(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -256,6 +285,8 @@ bool& RAModel::SampleAtLeaves() return rTreeRA->SampleAtLeaves(); else if (rStarTreeRA) return rStarTreeRA->SampleAtLeaves(); + else if (xTreeRA) + return xTreeRA->SampleAtLeaves(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -272,6 +303,8 @@ bool RAModel::FirstLeafExact() const return rTreeRA->FirstLeafExact(); else if (rStarTreeRA) return rStarTreeRA->FirstLeafExact(); + else if (xTreeRA) + return xTreeRA->FirstLeafExact(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -288,6 +321,8 @@ bool& RAModel::FirstLeafExact() return rTreeRA->FirstLeafExact(); else if (rStarTreeRA) return rStarTreeRA->FirstLeafExact(); + else if (xTreeRA) + return xTreeRA->FirstLeafExact(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -304,6 +339,8 @@ size_t RAModel::SingleSampleLimit() const return rTreeRA->SingleSampleLimit(); else if (rStarTreeRA) return rStarTreeRA->SingleSampleLimit(); + else if (xTreeRA) + return xTreeRA->SingleSampleLimit(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -320,6 +357,8 @@ size_t& RAModel::SingleSampleLimit() return rTreeRA->SingleSampleLimit(); else if (rStarTreeRA) return rStarTreeRA->SingleSampleLimit(); + else if (xTreeRA) + return xTreeRA->SingleSampleLimit(); throw std::runtime_error("no rank-approximate nearest neighbor search model " "initialized"); @@ -383,6 +422,8 @@ void RAModel::BuildModel(arma::mat&& referenceSet, delete rTreeRA; if (rStarTreeRA) delete rStarTreeRA; + if (xTreeRA) + delete xTreeRA; if (randomBasis) referenceSet = q * referenceSet; @@ -427,6 +468,10 @@ void RAModel::BuildModel(arma::mat&& referenceSet, rStarTreeRA = new RAType(std::move(referenceSet), naive, singleMode); break; + case X_TREE: + xTreeRA = new RAType(std::move(referenceSet), naive, + singleMode); + break; } if (!naive) @@ -500,6 +545,10 @@ void RAModel::Search(arma::mat&& querySet, // No mapping necessary. rStarTreeRA->Search(querySet, k, neighbors, distances); break; + case X_TREE: + // No mapping necessary. + xTreeRA->Search(querySet, k, neighbors, distances); + break; } } @@ -531,6 +580,9 @@ void RAModel::Search(const size_t k, case R_STAR_TREE: rStarTreeRA->Search(k, neighbors, distances); break; + case X_TREE: + xTreeRA->Search(k, neighbors, distances); + break; } } @@ -547,6 +599,8 @@ std::string RAModel::TreeName() const return "R tree"; case R_STAR_TREE: return "R* tree"; + case X_TREE: + return "X tree"; default: return "unknown tree"; } From c3300ce70581ccf978a28640b7575b4e31c9528c Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Thu, 10 Mar 2016 11:54:51 +0300 Subject: [PATCH 05/17] Fix DBL_MAX in r/r*/x_tree_split and r_tree_descent_heuristic --- .../core/tree/rectangle_tree/r_star_tree_split_impl.hpp | 4 ++-- .../tree/rectangle_tree/r_tree_descent_heuristic_impl.hpp | 4 ++-- src/mlpack/core/tree/rectangle_tree/r_tree_split_impl.hpp | 4 ++-- src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) 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 index cf4b7d0890..9c0e95cc33 100644 --- 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 @@ -95,7 +95,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) int bestAreaIndexOnBestAxis = 0; bool tiedOnOverlap = false; int bestAxis = 0; - ElemType bestAxisScore = DBL_MAX; + ElemType bestAxisScore = std::numeric_limits::max(); for (size_t j = 0; j < tree->Bound().Dim(); j++) { @@ -359,7 +359,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree, bool tiedOnOverlap = false; bool lowIsBest = true; int bestAxis = 0; - ElemType bestAxisScore = DBL_MAX; + ElemType bestAxisScore = std::numeric_limits::max(); for (size_t j = 0; j < tree->Bound().Dim(); j++) { ElemType axisScore = 0.0; 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 c061801795..19cd511c13 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 @@ -20,7 +20,7 @@ inline size_t RTreeDescentHeuristic::ChooseDescentNode(const TreeType* node, // Convenience typedef. typedef typename TreeType::ElemType ElemType; - ElemType minScore = DBL_MAX; + ElemType minScore = std::numeric_limits::max(); int bestIndex = 0; ElemType bestVol = 0.0; @@ -64,7 +64,7 @@ inline size_t RTreeDescentHeuristic::ChooseDescentNode( // Convenience typedef. typedef typename TreeType::ElemType ElemType; - ElemType minScore = DBL_MAX; + ElemType minScore = std::numeric_limits::max(); int bestIndex = 0; ElemType bestVol = 0.0; 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 66fcaeffd0..15d70bda09 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 @@ -270,7 +270,7 @@ void RTreeSplit::AssignPointDestNode(TreeType* oldTree, std::min(numAssignedOne, numAssignedTwo))) { int bestIndex = 0; - ElemType bestScore = DBL_MAX; + ElemType bestScore = std::numeric_limits::max(); int bestRect = 1; // Calculate the increase in volume for assigning this point to each @@ -414,7 +414,7 @@ void RTreeSplit::AssignNodeDestNode(TreeType* oldTree, std::min(numAssignTreeOne, numAssignTreeTwo))) { int bestIndex = 0; - ElemType bestScore = DBL_MAX; + ElemType bestScore = std::numeric_limits::max(); int bestRect = 0; // Calculate the increase in volume for assigning this node to each of the 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 index e88304914d..ae4bad1045 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -106,7 +106,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) int bestAreaIndexOnBestAxis = 0; bool tiedOnOverlap = false; int bestAxis = 0; - ElemType bestAxisScore = DBL_MAX; + ElemType bestAxisScore = std::numeric_limits::max(); for (size_t j = 0; j < tree->Bound().Dim(); j++) { ElemType axisScore = 0.0; @@ -358,7 +358,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) } bool minOverlapSplitUsesHi = false; - ElemType bestScoreMinOverlapSplit = DBL_MAX; + ElemType bestScoreMinOverlapSplit = std::numeric_limits::max(); ElemType areaOfBestMinOverlapSplit = 0; int bestIndexMinOverlapSplit = 0; @@ -367,7 +367,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) bool tiedOnOverlap = false; bool lowIsBest = true; int bestAxis = 0; - ElemType bestAxisScore = DBL_MAX; + ElemType bestAxisScore = std::numeric_limits::max(); ElemType overlapBestOverlapAxis = 0; ElemType areaBestOverlapAxis = 0; ElemType overlapBestAreaAxis = 0; From cf233aacc133b39b086ab311390ab3c91ca8a10e Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Thu, 10 Mar 2016 14:28:40 +0300 Subject: [PATCH 06/17] Replace numeric_limits::min() by numeric_limits::lowest() since min() returns the lowest positive for floating point datatypes --- src/mlpack/core/tree/ballbound_impl.hpp | 4 ++-- src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlpack/core/tree/ballbound_impl.hpp b/src/mlpack/core/tree/ballbound_impl.hpp index 66d6a122dd..1957c21b9a 100644 --- a/src/mlpack/core/tree/ballbound_impl.hpp +++ b/src/mlpack/core/tree/ballbound_impl.hpp @@ -20,7 +20,7 @@ namespace bound { //! Empty Constructor. template BallBound::BallBound() : - radius(std::numeric_limits::min()), + radius(std::numeric_limits::lowest()), metric(new TMetricType()), ownsMetric(true) { /* Nothing to do. */ } @@ -32,7 +32,7 @@ BallBound::BallBound() : */ template BallBound::BallBound(const size_t dimension) : - radius(std::numeric_limits::min()), + radius(std::numeric_limits::lowest()), center(dimension), metric(new TMetricType()), ownsMetric(true) 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 b033e14751..c95eef6483 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -865,7 +865,7 @@ bool RectangleTree:: } else if (bound[i].Hi() == point[i]) { - ElemType max = std::numeric_limits::min(); + ElemType max = std::numeric_limits::lowest(); for (size_t j = 0; j < count; j++) { if (localDataset->col(j)[i] > max) @@ -905,7 +905,7 @@ bool RectangleTree:: } else if (bound[i].Hi() == point[i]) { - ElemType max = std::numeric_limits::min(); + ElemType max = std::numeric_limits::lowest(); for (size_t j = 0; j < numChildren; j++) { if (children[j]->Bound()[i].Hi() > max) @@ -943,7 +943,7 @@ bool RectangleTree:: { sum += bound[i].Width(); bound[i].Lo() = std::numeric_limits::max(); - bound[i].Hi() = std::numeric_limits::min(); + bound[i].Hi() = std::numeric_limits::lowest(); } for (size_t i = 0; i < numChildren; i++) From 18b10e14e4cd903be3bb4cf144864337f5943689 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Fri, 11 Mar 2016 13:17:06 +0300 Subject: [PATCH 07/17] Update allknn, allkran, nrange_search tests. --- src/mlpack/tests/allknn_test.cpp | 20 ++++++++++++-------- src/mlpack/tests/allkrann_search_test.cpp | 6 ++++-- src/mlpack/tests/range_search_test.cpp | 20 ++++++++++++-------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/mlpack/tests/allknn_test.cpp b/src/mlpack/tests/allknn_test.cpp index 54ff6e8582..ad4f286bbb 100644 --- a/src/mlpack/tests/allknn_test.cpp +++ b/src/mlpack/tests/allknn_test.cpp @@ -975,7 +975,7 @@ BOOST_AUTO_TEST_CASE(KNNModelTest) arma::mat referenceData = arma::randu(10, 200); // Build all the possible models. - KNNModel models[10]; + KNNModel models[12]; models[0] = KNNModel(KNNModel::TreeTypes::KD_TREE, true); models[1] = KNNModel(KNNModel::TreeTypes::KD_TREE, false); models[2] = KNNModel(KNNModel::TreeTypes::COVER_TREE, true); @@ -984,8 +984,10 @@ BOOST_AUTO_TEST_CASE(KNNModelTest) models[5] = KNNModel(KNNModel::TreeTypes::R_TREE, false); models[6] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, true); models[7] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, false); - models[8] = KNNModel(KNNModel::TreeTypes::BALL_TREE, true); - models[9] = KNNModel(KNNModel::TreeTypes::BALL_TREE, false); + models[8] = KNNModel(KNNModel::TreeTypes::X_TREE, true); + models[9] = KNNModel(KNNModel::TreeTypes::X_TREE, false); + models[10] = KNNModel(KNNModel::TreeTypes::BALL_TREE, true); + models[11] = KNNModel(KNNModel::TreeTypes::BALL_TREE, false); for (size_t j = 0; j < 2; ++j) { @@ -995,7 +997,7 @@ BOOST_AUTO_TEST_CASE(KNNModelTest) arma::mat baselineDistances; knn.Search(queryData, 3, baselineNeighbors, baselineDistances); - for (size_t i = 0; i < 10; ++i) + for (size_t i = 0; i < 12; ++i) { // We only have std::move() constructors so make a copy of our data. arma::mat referenceCopy(referenceData); @@ -1039,7 +1041,7 @@ BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) arma::mat referenceData = arma::randu(10, 200); // Build all the possible models. - KNNModel models[10]; + KNNModel models[12]; models[0] = KNNModel(KNNModel::TreeTypes::KD_TREE, true); models[1] = KNNModel(KNNModel::TreeTypes::KD_TREE, false); models[2] = KNNModel(KNNModel::TreeTypes::COVER_TREE, true); @@ -1048,8 +1050,10 @@ BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) models[5] = KNNModel(KNNModel::TreeTypes::R_TREE, false); models[6] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, true); models[7] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, false); - models[8] = KNNModel(KNNModel::TreeTypes::BALL_TREE, true); - models[0] = KNNModel(KNNModel::TreeTypes::BALL_TREE, false); + models[8] = KNNModel(KNNModel::TreeTypes::X_TREE, true); + models[9] = KNNModel(KNNModel::TreeTypes::X_TREE, false); + models[10] = KNNModel(KNNModel::TreeTypes::BALL_TREE, true); + models[11] = KNNModel(KNNModel::TreeTypes::BALL_TREE, false); for (size_t j = 0; j < 2; ++j) { @@ -1059,7 +1063,7 @@ BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) arma::mat baselineDistances; knn.Search(3, baselineNeighbors, baselineDistances); - for (size_t i = 0; i < 10; ++i) + for (size_t i = 0; i < 12; ++i) { // We only have a std::move() constructor... so copy the data. arma::mat referenceCopy(referenceData); diff --git a/src/mlpack/tests/allkrann_search_test.cpp b/src/mlpack/tests/allkrann_search_test.cpp index 0ea62b683a..4faf381a9c 100644 --- a/src/mlpack/tests/allkrann_search_test.cpp +++ b/src/mlpack/tests/allkrann_search_test.cpp @@ -625,7 +625,7 @@ BOOST_AUTO_TEST_CASE(RAModelTest) data::Load("rann_test_q_3_100.csv", queryData, true); // Build all the possible models. - KNNModel models[8]; + KNNModel models[10]; models[0] = KNNModel(KNNModel::TreeTypes::KD_TREE, false); models[1] = KNNModel(KNNModel::TreeTypes::KD_TREE, true); models[2] = KNNModel(KNNModel::TreeTypes::COVER_TREE, false); @@ -634,13 +634,15 @@ BOOST_AUTO_TEST_CASE(RAModelTest) models[5] = KNNModel(KNNModel::TreeTypes::R_TREE, true); models[6] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, false); models[7] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, true); + models[8] = KNNModel(KNNModel::TreeTypes::X_TREE, false); + models[9] = KNNModel(KNNModel::TreeTypes::X_TREE, true); arma::Mat qrRanks; data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. for (size_t j = 0; j < 3; ++j) { - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < 10; ++i) { // We only have std::move() constructors so make a copy of our data. arma::mat referenceCopy(referenceData); diff --git a/src/mlpack/tests/range_search_test.cpp b/src/mlpack/tests/range_search_test.cpp index f7ed67a4b6..84cfed8dfc 100644 --- a/src/mlpack/tests/range_search_test.cpp +++ b/src/mlpack/tests/range_search_test.cpp @@ -1251,7 +1251,7 @@ BOOST_AUTO_TEST_CASE(RSModelTest) arma::mat referenceData = arma::randu(10, 200); // Build all the possible models. - RSModel models[10]; + RSModel models[12]; models[0] = RSModel(RSModel::TreeTypes::KD_TREE, true); models[1] = RSModel(RSModel::TreeTypes::KD_TREE, false); models[2] = RSModel(RSModel::TreeTypes::COVER_TREE, true); @@ -1260,8 +1260,10 @@ BOOST_AUTO_TEST_CASE(RSModelTest) models[5] = RSModel(RSModel::TreeTypes::R_TREE, false); models[6] = RSModel(RSModel::TreeTypes::R_STAR_TREE, true); models[7] = RSModel(RSModel::TreeTypes::R_STAR_TREE, false); - models[8] = RSModel(RSModel::TreeTypes::BALL_TREE, true); - models[9] = RSModel(RSModel::TreeTypes::BALL_TREE, false); + models[8] = RSModel(RSModel::TreeTypes::X_TREE, true); + models[9] = RSModel(RSModel::TreeTypes::X_TREE, false); + models[10] = RSModel(RSModel::TreeTypes::BALL_TREE, true); + models[11] = RSModel(RSModel::TreeTypes::BALL_TREE, false); for (size_t j = 0; j < 2; ++j) { @@ -1275,7 +1277,7 @@ BOOST_AUTO_TEST_CASE(RSModelTest) vector>> baselineSorted; SortResults(baselineNeighbors, baselineDistances, baselineSorted); - for (size_t i = 0; i < 10; ++i) + for (size_t i = 0; i < 12; ++i) { // We only have std::move() constructors, so make a copy of our data. arma::mat referenceCopy(referenceData); @@ -1319,7 +1321,7 @@ BOOST_AUTO_TEST_CASE(RSModelMonochromaticTest) arma::mat referenceData = arma::randu(10, 200); // Build all the possible models. - RSModel models[10]; + RSModel models[12]; models[0] = RSModel(RSModel::TreeTypes::KD_TREE, true); models[1] = RSModel(RSModel::TreeTypes::KD_TREE, false); models[2] = RSModel(RSModel::TreeTypes::COVER_TREE, true); @@ -1328,8 +1330,10 @@ BOOST_AUTO_TEST_CASE(RSModelMonochromaticTest) models[5] = RSModel(RSModel::TreeTypes::R_TREE, false); models[6] = RSModel(RSModel::TreeTypes::R_STAR_TREE, true); models[7] = RSModel(RSModel::TreeTypes::R_STAR_TREE, false); - models[8] = RSModel(RSModel::TreeTypes::BALL_TREE, true); - models[9] = RSModel(RSModel::TreeTypes::BALL_TREE, false); + models[8] = RSModel(RSModel::TreeTypes::X_TREE, true); + models[9] = RSModel(RSModel::TreeTypes::X_TREE, false); + models[10] = RSModel(RSModel::TreeTypes::BALL_TREE, true); + models[11] = RSModel(RSModel::TreeTypes::BALL_TREE, false); for (size_t j = 0; j < 2; ++j) { @@ -1342,7 +1346,7 @@ BOOST_AUTO_TEST_CASE(RSModelMonochromaticTest) vector>> baselineSorted; SortResults(baselineNeighbors, baselineDistances, baselineSorted); - for (size_t i = 0; i < 10; ++i) + for (size_t i = 0; i < 12; ++i) { // We only have std::move() cosntructors, so make a copy of our data. arma::mat referenceCopy(referenceData); From 3c1142afa61c57015b6b247ff8efd31241b9e67e Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Fri, 11 Mar 2016 13:18:50 +0300 Subject: [PATCH 08/17] XTree bugfuxes. Fix a supernode splitting. Fix a supernode creation fault. --- .../core/tree/rectangle_tree/rectangle_tree.hpp | 12 +++++++++++- .../tree/rectangle_tree/rectangle_tree_impl.hpp | 17 ++++++++++++++--- .../tree/rectangle_tree/x_tree_split_impl.hpp | 13 ++++++++----- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp index a66f2523ee..e4d69d3f6d 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp @@ -76,6 +76,9 @@ class RectangleTree } SplitHistoryStruct; private: + //! The max number of child nodes a non-leaf normal node can have. + //! (used in x-trees) + size_t normalNodeMaxNumChildren; //! 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. @@ -173,8 +176,10 @@ class RectangleTree * firstDataIndex) from the parent. * * @param parentNode The parent of the node that is being constructed. + * @param numMaxChildren The max number of child nodes (used in x-trees). */ - explicit RectangleTree(RectangleTree* parentNode); + explicit RectangleTree(RectangleTree* parentNode, + const size_t numMaxChildren = 0); /** * Create a rectangle tree by copying the other tree. Be careful! This can @@ -329,6 +334,11 @@ class RectangleTree //! Modify the minimum leaf size. size_t& MinLeafSize() { return minLeafSize; } + //! Return the maximum number of a normal node's children (used in x-trees). + size_t NormalNodeMaxNumChildren() const { return normalNodeMaxNumChildren; } + //! Modify the maximum number of a normal node's children (used in x-trees). + size_t& NormalNodeMaxNumChildren() { return normalNodeMaxNumChildren; } + //! 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). 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 c95eef6483..8495ba23c5 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -29,6 +29,7 @@ RectangleTree(const MatType& data, const size_t maxNumChildren, const size_t minNumChildren, const size_t firstDataIndex) : + normalNodeMaxNumChildren(maxNumChildren), maxNumChildren(maxNumChildren), minNumChildren(minNumChildren), numChildren(0), @@ -68,6 +69,7 @@ RectangleTree(MatType&& data, const size_t maxNumChildren, const size_t minNumChildren, const size_t firstDataIndex) : + normalNodeMaxNumChildren(maxNumChildren), maxNumChildren(maxNumChildren), minNumChildren(minNumChildren), numChildren(0), @@ -103,8 +105,9 @@ template:: RectangleTree( RectangleTree* - parentNode) : - maxNumChildren(parentNode->MaxNumChildren()), + parentNode,const size_t numMaxChildren) : + normalNodeMaxNumChildren(parentNode->NormalNodeMaxNumChildren()), + maxNumChildren(numMaxChildren > 0 ? numMaxChildren : parentNode->MaxNumChildren()), minNumChildren(parentNode->MinNumChildren()), numChildren(0), children(maxNumChildren + 1), @@ -138,6 +141,7 @@ RectangleTree:: RectangleTree( const RectangleTree& other, const bool deepCopy) : + normalNodeMaxNumChildren(other.NormalNodeMaxNumChildren()), maxNumChildren(other.MaxNumChildren()), minNumChildren(other.MinNumChildren()), numChildren(other.NumChildren()), @@ -800,6 +804,14 @@ void RectangleTree:: { // If there are multiple children, we can't do anything to the root. RectangleTree* child = children[0]; + + // Required for the X tree. + if(child->NumChildren() > maxNumChildren) + { + maxNumChildren = child->MaxNumChildren(); + children.resize(maxNumChildren+1); + } + for (size_t i = 0; i < child->NumChildren(); i++) { children[i] = child->Children()[i]; children[i]->Parent() = this; @@ -815,7 +827,6 @@ void RectangleTree:: } count = child->Count(); - maxNumChildren = child->MaxNumChildren(); // Required for the X tree. child->SoftDelete(); return; } 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 index ae4bad1045..d4973e43ab 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -218,8 +218,8 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) std::sort(sorted.begin(), sorted.end(), structComp); - TreeType* treeOne = new TreeType(tree->Parent()); - TreeType* treeTwo = new TreeType(tree->Parent()); + TreeType* treeOne = new TreeType(tree->Parent(),tree->NormalNodeMaxNumChildren()); + TreeType* treeTwo = new TreeType(tree->Parent(),tree->NormalNodeMaxNumChildren()); // The leaf nodes should never have any overlap introduced by the above method // since a split axis is chosen and then points are assigned based on their @@ -657,8 +657,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) std::sort(sorted.begin(), sorted.end(), structComp); - TreeType* treeOne = new TreeType(tree->Parent()); - TreeType* treeTwo = new TreeType(tree->Parent()); + TreeType* treeOne = new TreeType(tree->Parent(),tree->MaxNumChildren()); + TreeType* treeTwo = new TreeType(tree->Parent(),tree->MaxNumChildren()); // Now as per the X-tree paper, we ensure that this split was good enough. bool useMinOverlapSplit = false; @@ -743,11 +743,14 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) (tree->Parent()->NumChildren() == 1)) { // We make the root a supernode instead. - tree->Parent()->MaxNumChildren() *= 2; + tree->Parent()->MaxNumChildren() = tree->MaxNumChildren() * 2; tree->Parent()->Children().resize(tree->Parent()->MaxNumChildren() + 1); tree->Parent()->NumChildren() = tree->NumChildren(); for (size_t i = 0; i < tree->NumChildren(); i++) + { tree->Parent()->Children()[i] = tree->Children()[i]; + tree->Child(i).Parent() = tree->Parent(); + } delete treeOne; delete treeTwo; From ad97d730a752ec66e4e15c87c356c6490b570bab Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Fri, 11 Mar 2016 14:23:37 +0300 Subject: [PATCH 09/17] Fix trees order. --- src/mlpack/methods/neighbor_search/ns_model.hpp | 4 ++-- src/mlpack/methods/range_search/rs_model.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/neighbor_search/ns_model.hpp b/src/mlpack/methods/neighbor_search/ns_model.hpp index a4613e9a5a..2b1b1d751e 100644 --- a/src/mlpack/methods/neighbor_search/ns_model.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model.hpp @@ -47,8 +47,8 @@ class NSModel COVER_TREE, R_TREE, R_STAR_TREE, - X_TREE, - BALL_TREE + BALL_TREE, + X_TREE }; private: diff --git a/src/mlpack/methods/range_search/rs_model.hpp b/src/mlpack/methods/range_search/rs_model.hpp index b2b809bb26..e88f6eab91 100644 --- a/src/mlpack/methods/range_search/rs_model.hpp +++ b/src/mlpack/methods/range_search/rs_model.hpp @@ -28,8 +28,8 @@ class RSModel COVER_TREE, R_TREE, R_STAR_TREE, - X_TREE, - BALL_TREE + BALL_TREE, + X_TREE }; private: From 121bbafe14eba62873f20271ea59612b7b5bcae9 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Fri, 18 Mar 2016 02:13:23 +0300 Subject: [PATCH 10/17] This commit allows to avoid splitting a node which owns a dataset and has children with the same dataset. --- src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp | 4 ++-- src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 8495ba23c5..b3180ce337 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -154,8 +154,8 @@ RectangleTree( bound(other.bound), splitHistory(other.SplitHistory()), parentDistance(other.ParentDistance()), - dataset(new MatType(*other.dataset)), - ownsDataset(true), + dataset(deepCopy ? new MatType(*other.dataset) : &other.Dataset()), + ownsDataset(deepCopy), points(other.Points()), localDataset(NULL) { 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 index d4973e43ab..21d3da31d9 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -743,7 +743,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) (tree->Parent()->NumChildren() == 1)) { // We make the root a supernode instead. - tree->Parent()->MaxNumChildren() = tree->MaxNumChildren() * 2; + tree->Parent()->MaxNumChildren() = tree->MaxNumChildren() + tree->NormalNodeMaxNumChildren(); tree->Parent()->Children().resize(tree->Parent()->MaxNumChildren() + 1); tree->Parent()->NumChildren() = tree->NumChildren(); for (size_t i = 0; i < tree->NumChildren(); i++) @@ -760,7 +760,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) } // If we don't have to worry about the root, we just enlarge this node. - tree->MaxNumChildren() *= 2; + tree->MaxNumChildren() += tree->NormalNodeMaxNumChildren(); tree->Children().resize(tree->MaxNumChildren() + 1); for (size_t i = 0; i < tree->NumChildren(); i++) tree->Child(i).Parent() = tree; From 1ed8c18dedb54772377c17ff48f2b313792feb0f Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Fri, 18 Mar 2016 02:40:38 +0300 Subject: [PATCH 11/17] Use RTreeDescentHeuristic. Add documentation. --- .../core/tree/rectangle_tree/typedef.hpp | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/mlpack/core/tree/rectangle_tree/typedef.hpp b/src/mlpack/core/tree/rectangle_tree/typedef.hpp index 5007d2b266..9ec09036b2 100644 --- a/src/mlpack/core/tree/rectangle_tree/typedef.hpp +++ b/src/mlpack/core/tree/rectangle_tree/typedef.hpp @@ -68,15 +68,29 @@ using RStarTree = RectangleTree; /** - * X-tree - * (not yet finished) + * The X-tree, a variant of the R tree with supernodes. This template typedef + * satisfies the TreeType policy API. + * + * @code + * @inproceedings{berchtold1996r, + * title = {The X-Tree: An Index Structure for High--Dimensional Data}, + * author = {Berchtold, Stefan and Keim, Daniel A. and Kriegel, Hans-Peter}, + * booktitle = {Proc. 22th Int. Conf. on Very Large Databases (VLDB'96), Bombay, India}, + * editor = {Vijayaraman, T. and Buchmann, Alex and Mohan, C. and Sarda, N.}, + * pages = {28--39}, + * year = {1996}, + * publisher = {Morgan Kaufmann} + * } + * @endcode + * + * @see @ref trees, RTree, RStarTree */ template using XTree = RectangleTree; + RTreeDescentHeuristic>; } // namespace tree } // namespace mlpack From 65df1ea29a700fff54e386acd76eeaa6cb85b0df Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Thu, 7 Apr 2016 18:01:42 +0300 Subject: [PATCH 12/17] Fix trees ordering. --- .../methods/neighbor_search/allkfn_main.cpp | 4 +- .../methods/neighbor_search/allknn_main.cpp | 4 +- .../methods/neighbor_search/ns_model.hpp | 2 +- .../methods/neighbor_search/ns_model_impl.hpp | 72 +++++++++---------- .../range_search/range_search_main.cpp | 4 +- src/mlpack/methods/range_search/rs_model.cpp | 40 +++++------ src/mlpack/methods/range_search/rs_model.hpp | 4 +- .../methods/range_search/rs_model_impl.hpp | 28 ++++---- 8 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/mlpack/methods/neighbor_search/allkfn_main.cpp b/src/mlpack/methods/neighbor_search/allkfn_main.cpp index 975b23f069..3902259244 100644 --- a/src/mlpack/methods/neighbor_search/allkfn_main.cpp +++ b/src/mlpack/methods/neighbor_search/allkfn_main.cpp @@ -158,10 +158,10 @@ int main(int argc, char *argv[]) tree = KFNModel::R_TREE; else if (treeType == "r-star") tree = KFNModel::R_STAR_TREE; - else if (treeType == "x") - tree = KFNModel::X_TREE; else if (treeType == "ball") tree = KFNModel::BALL_TREE; + else if (treeType == "x") + tree = KFNModel::X_TREE; else Log::Fatal << "Unknown tree type '" << treeType << "'; valid choices are " << "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl; diff --git a/src/mlpack/methods/neighbor_search/allknn_main.cpp b/src/mlpack/methods/neighbor_search/allknn_main.cpp index 5440e26454..1bc399632b 100644 --- a/src/mlpack/methods/neighbor_search/allknn_main.cpp +++ b/src/mlpack/methods/neighbor_search/allknn_main.cpp @@ -162,10 +162,10 @@ int main(int argc, char *argv[]) tree = KNNModel::R_TREE; else if (treeType == "r-star") tree = KNNModel::R_STAR_TREE; - else if (treeType == "x") - tree = KNNModel::X_TREE; else if (treeType == "ball") tree = KNNModel::BALL_TREE; + else if (treeType == "x") + tree = KNNModel::X_TREE; else Log::Fatal << "Unknown tree type '" << treeType << "'; valid choices are " << "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl; diff --git a/src/mlpack/methods/neighbor_search/ns_model.hpp b/src/mlpack/methods/neighbor_search/ns_model.hpp index 2b1b1d751e..3de4d12625 100644 --- a/src/mlpack/methods/neighbor_search/ns_model.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model.hpp @@ -75,8 +75,8 @@ class NSModel NSType* coverTreeNS; NSType* rTreeNS; NSType* rStarTreeNS; - NSType* xTreeNS; NSType* ballTreeNS; + NSType* xTreeNS; public: /** diff --git a/src/mlpack/methods/neighbor_search/ns_model_impl.hpp b/src/mlpack/methods/neighbor_search/ns_model_impl.hpp index 8155edad1a..2571967873 100644 --- a/src/mlpack/methods/neighbor_search/ns_model_impl.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model_impl.hpp @@ -28,8 +28,8 @@ NSModel::NSModel(int treeType, bool randomBasis) : coverTreeNS(NULL), rTreeNS(NULL), rStarTreeNS(NULL), - xTreeNS(NULL), - ballTreeNS(NULL) + ballTreeNS(NULL), + xTreeNS(NULL) { // Nothing to do. } @@ -46,10 +46,10 @@ NSModel::~NSModel() delete rTreeNS; if (rStarTreeNS) delete rStarTreeNS; - if (xTreeNS) - delete xTreeNS; if (ballTreeNS) delete ballTreeNS; + if (xTreeNS) + delete xTreeNS; } //! Serialize the kNN model. @@ -73,18 +73,18 @@ void NSModel::Serialize(Archive& ar, delete rTreeNS; if (rStarTreeNS) delete rStarTreeNS; - if (xTreeNS) - delete xTreeNS; if (ballTreeNS) delete ballTreeNS; + if (xTreeNS) + delete xTreeNS; // Set all the pointers to NULL. kdTreeNS = NULL; coverTreeNS = NULL; rTreeNS = NULL; rStarTreeNS = NULL; - xTreeNS = NULL; ballTreeNS = NULL; + xTreeNS = NULL; } // We'll only need to serialize one of the kNN objects, based on the type. @@ -103,12 +103,12 @@ void NSModel::Serialize(Archive& ar, case R_STAR_TREE: ar & data::CreateNVP(rStarTreeNS, name); break; - case X_TREE: - ar & data::CreateNVP(xTreeNS, name); - break; case BALL_TREE: ar & data::CreateNVP(ballTreeNS, name); break; + case X_TREE: + ar & data::CreateNVP(xTreeNS, name); + break; } } @@ -123,10 +123,10 @@ const arma::mat& NSModel::Dataset() const return rTreeNS->ReferenceSet(); else if (rStarTreeNS) return rStarTreeNS->ReferenceSet(); - else if (xTreeNS) - return xTreeNS->ReferenceSet(); else if (ballTreeNS) return ballTreeNS->ReferenceSet(); + else if (xTreeNS) + return xTreeNS->ReferenceSet(); throw std::runtime_error("no neighbor search model initialized"); } @@ -143,10 +143,10 @@ bool NSModel::SingleMode() const return rTreeNS->SingleMode(); else if (rStarTreeNS) return rStarTreeNS->SingleMode(); - else if (xTreeNS) - return xTreeNS->SingleMode(); else if (ballTreeNS) return ballTreeNS->SingleMode(); + else if (xTreeNS) + return xTreeNS->SingleMode(); throw std::runtime_error("no neighbor search model initialized"); } @@ -162,10 +162,10 @@ bool& NSModel::SingleMode() return rTreeNS->SingleMode(); else if (rStarTreeNS) return rStarTreeNS->SingleMode(); - else if (xTreeNS) - return xTreeNS->SingleMode(); else if (ballTreeNS) return ballTreeNS->SingleMode(); + else if (xTreeNS) + return xTreeNS->SingleMode(); throw std::runtime_error("no neighbor search model initialized"); } @@ -181,10 +181,10 @@ bool NSModel::Naive() const return rTreeNS->Naive(); else if (rStarTreeNS) return rStarTreeNS->Naive(); - else if (xTreeNS) - return xTreeNS->Naive(); else if (ballTreeNS) return ballTreeNS->Naive(); + else if (xTreeNS) + return xTreeNS->Naive(); throw std::runtime_error("no neighbor search model initialized"); } @@ -200,10 +200,10 @@ bool& NSModel::Naive() return rTreeNS->Naive(); else if (rStarTreeNS) return rStarTreeNS->Naive(); - else if (xTreeNS) - return xTreeNS->Naive(); else if (ballTreeNS) return ballTreeNS->Naive(); + else if (xTreeNS) + return xTreeNS->Naive(); throw std::runtime_error("no neighbor search model initialized"); } @@ -256,10 +256,10 @@ void NSModel::BuildModel(arma::mat&& referenceSet, delete rTreeNS; if (rStarTreeNS) delete rStarTreeNS; - if (xTreeNS) - delete xTreeNS; if (ballTreeNS) delete ballTreeNS; + if (xTreeNS) + delete xTreeNS; // Do we need to modify the reference set? if (randomBasis) @@ -309,11 +309,6 @@ void NSModel::BuildModel(arma::mat&& referenceSet, rStarTreeNS = new NSType(std::move(referenceSet), naive, singleMode); break; - case X_TREE: - // If necessary, build the X tree. - xTreeNS = new NSType(std::move(referenceSet), naive, - singleMode); - break; case BALL_TREE: // If necessary, build the ball tree. if (naive) @@ -335,6 +330,11 @@ void NSModel::BuildModel(arma::mat&& referenceSet, } break; + case X_TREE: + // If necessary, build the X tree. + xTreeNS = new NSType(std::move(referenceSet), naive, + singleMode); + break; } if (!naive) @@ -408,10 +408,6 @@ void NSModel::Search(arma::mat&& querySet, // No mapping necessary. rStarTreeNS->Search(querySet, k, neighbors, distances); break; - case X_TREE: - // No mapping necessary. - xTreeNS->Search(querySet, k, neighbors, distances); - break; case BALL_TREE: if (!ballTreeNS->Naive() && !ballTreeNS->SingleMode()) { @@ -443,6 +439,10 @@ void NSModel::Search(arma::mat&& querySet, ballTreeNS->Search(querySet, k, neighbors, distances); } + break; + case X_TREE: + // No mapping necessary. + xTreeNS->Search(querySet, k, neighbors, distances); break; } } @@ -475,12 +475,12 @@ void NSModel::Search(const size_t k, case R_STAR_TREE: rStarTreeNS->Search(k, neighbors, distances); break; - case X_TREE: - xTreeNS->Search(k, neighbors, distances); - break; case BALL_TREE: ballTreeNS->Search(k, neighbors, distances); break; + case X_TREE: + xTreeNS->Search(k, neighbors, distances); + break; } } @@ -498,10 +498,10 @@ std::string NSModel::TreeName() const return "R tree"; case R_STAR_TREE: return "R* tree"; - case X_TREE: - return "X tree"; case BALL_TREE: return "ball tree"; + case X_TREE: + return "X tree"; default: return "unknown tree"; } diff --git a/src/mlpack/methods/range_search/range_search_main.cpp b/src/mlpack/methods/range_search/range_search_main.cpp index fe870c442d..48fd2ede30 100644 --- a/src/mlpack/methods/range_search/range_search_main.cpp +++ b/src/mlpack/methods/range_search/range_search_main.cpp @@ -169,10 +169,10 @@ int main(int argc, char *argv[]) tree = RSModel::R_TREE; else if (treeType == "r-star") tree = RSModel::R_STAR_TREE; - else if (treeType == "x") - tree = RSModel::X_TREE; else if (treeType == "ball") tree = RSModel::BALL_TREE; + else if (treeType == "x") + tree = RSModel::X_TREE; else Log::Fatal << "Unknown tree type '" << treeType << "; valid choices are " << "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl; diff --git a/src/mlpack/methods/range_search/rs_model.cpp b/src/mlpack/methods/range_search/rs_model.cpp index 27f05ad741..7ffc97d41e 100644 --- a/src/mlpack/methods/range_search/rs_model.cpp +++ b/src/mlpack/methods/range_search/rs_model.cpp @@ -21,8 +21,8 @@ RSModel::RSModel(int treeType, bool randomBasis) : coverTreeRS(NULL), rTreeRS(NULL), rStarTreeRS(NULL), - xTreeRS(NULL), - ballTreeRS(NULL) + ballTreeRS(NULL), + xTreeRS(NULL) { // Nothing to do. } @@ -96,11 +96,6 @@ void RSModel::BuildModel(arma::mat&& referenceSet, singleMode); break; - case X_TREE: - xTreeRS = new RSType(move(referenceSet), naive, - singleMode); - break; - case BALL_TREE: // If necessary, build the ball tree. if (naive) @@ -122,6 +117,11 @@ void RSModel::BuildModel(arma::mat&& referenceSet, } break; + + case X_TREE: + xTreeRS = new RSType(move(referenceSet), naive, + singleMode); + break; } if (!naive) @@ -196,10 +196,6 @@ void RSModel::Search(arma::mat&& querySet, rStarTreeRS->Search(querySet, range, neighbors, distances); break; - case X_TREE: - xTreeRS->Search(querySet, range, neighbors, distances); - break; - case BALL_TREE: if (!ballTreeRS->Naive() && !ballTreeRS->SingleMode()) { @@ -231,6 +227,10 @@ void RSModel::Search(arma::mat&& querySet, ballTreeRS->Search(querySet, range, neighbors, distances); } break; + + case X_TREE: + xTreeRS->Search(querySet, range, neighbors, distances); + break; } } @@ -266,13 +266,13 @@ void RSModel::Search(const math::Range& range, rStarTreeRS->Search(range, neighbors, distances); break; - case X_TREE: - xTreeRS->Search(range, neighbors, distances); - break; - case BALL_TREE: ballTreeRS->Search(range, neighbors, distances); break; + + case X_TREE: + xTreeRS->Search(range, neighbors, distances); + break; } } @@ -289,10 +289,10 @@ std::string RSModel::TreeName() const return "R tree"; case R_STAR_TREE: return "R* tree"; - case X_TREE: - return "X tree"; case BALL_TREE: return "ball tree"; + case X_TREE: + return "X tree"; default: return "unknown tree"; } @@ -309,15 +309,15 @@ void RSModel::CleanMemory() delete rTreeRS; if (rStarTreeRS) delete rStarTreeRS; - if (xTreeRS) - delete xTreeRS; if (ballTreeRS) delete ballTreeRS; + if (xTreeRS) + delete xTreeRS; kdTreeRS = NULL; coverTreeRS = NULL; rTreeRS = NULL; rStarTreeRS = NULL; - xTreeRS = NULL; ballTreeRS = NULL; + xTreeRS = NULL; } diff --git a/src/mlpack/methods/range_search/rs_model.hpp b/src/mlpack/methods/range_search/rs_model.hpp index e88f6eab91..80d600ea78 100644 --- a/src/mlpack/methods/range_search/rs_model.hpp +++ b/src/mlpack/methods/range_search/rs_model.hpp @@ -56,10 +56,10 @@ class RSModel RSType* rTreeRS; //! R* tree based range search object (NULL if not in use). RSType* rStarTreeRS; - //! X tree based range search object (NULL if not in use). - RSType* xTreeRS; //! Ball tree based range search object (NULL if not in use). RSType* ballTreeRS; + //! X tree based range search object (NULL if not in use). + RSType* xTreeRS; public: /** diff --git a/src/mlpack/methods/range_search/rs_model_impl.hpp b/src/mlpack/methods/range_search/rs_model_impl.hpp index 77a806898d..ed1087ed98 100644 --- a/src/mlpack/methods/range_search/rs_model_impl.hpp +++ b/src/mlpack/methods/range_search/rs_model_impl.hpp @@ -46,13 +46,13 @@ void RSModel::Serialize(Archive& ar, const unsigned int /* version */) ar & CreateNVP(rStarTreeRS, "range_search_model"); break; - case X_TREE: - ar & CreateNVP(xTreeRS, "range_search_model"); - break; - case BALL_TREE: ar & CreateNVP(ballTreeRS, "range_search_model"); break; + + case X_TREE: + ar & CreateNVP(xTreeRS, "range_search_model"); + break; } } @@ -66,10 +66,10 @@ inline const arma::mat& RSModel::Dataset() const return rTreeRS->ReferenceSet(); else if (rStarTreeRS) return rStarTreeRS->ReferenceSet(); - else if (xTreeRS) - return xTreeRS->ReferenceSet(); else if (ballTreeRS) return ballTreeRS->ReferenceSet(); + else if (xTreeRS) + return xTreeRS->ReferenceSet(); throw std::runtime_error("no range search model initialized"); } @@ -84,10 +84,10 @@ inline bool RSModel::SingleMode() const return rTreeRS->SingleMode(); else if (rStarTreeRS) return rStarTreeRS->SingleMode(); - else if (xTreeRS) - return xTreeRS->SingleMode(); else if (ballTreeRS) return ballTreeRS->SingleMode(); + else if (xTreeRS) + return xTreeRS->SingleMode(); throw std::runtime_error("no range search model initialized"); } @@ -102,10 +102,10 @@ inline bool& RSModel::SingleMode() return rTreeRS->SingleMode(); else if (rStarTreeRS) return rStarTreeRS->SingleMode(); - else if (xTreeRS) - return xTreeRS->SingleMode(); else if (ballTreeRS) return ballTreeRS->SingleMode(); + else if (xTreeRS) + return xTreeRS->SingleMode(); throw std::runtime_error("no range search model initialized"); } @@ -120,10 +120,10 @@ inline bool RSModel::Naive() const return rTreeRS->Naive(); else if (rStarTreeRS) return rStarTreeRS->Naive(); - else if (xTreeRS) - return xTreeRS->Naive(); else if (ballTreeRS) return ballTreeRS->Naive(); + else if (xTreeRS) + return xTreeRS->Naive(); throw std::runtime_error("no range search model initialized"); } @@ -138,10 +138,10 @@ inline bool& RSModel::Naive() return rTreeRS->Naive(); else if (rStarTreeRS) return rStarTreeRS->Naive(); - else if (xTreeRS) - return xTreeRS->Naive(); else if (ballTreeRS) return ballTreeRS->Naive(); + else if (xTreeRS) + return xTreeRS->Naive(); throw std::runtime_error("no range search model initialized"); } From 03a34ed2e59c640f29d40483f02d3175f32abe78 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Fri, 22 Apr 2016 15:10:45 +0300 Subject: [PATCH 13/17] Replace static SplitType in the RectangleTree by an instantiated object. --- .../rectangle_tree/dual_tree_traverser.hpp | 2 +- .../dual_tree_traverser_impl.hpp | 4 +- .../tree/rectangle_tree/r_star_tree_split.hpp | 17 +++-- .../rectangle_tree/r_star_tree_split_impl.hpp | 31 ++++++--- .../core/tree/rectangle_tree/r_tree_split.hpp | 27 ++++---- .../tree/rectangle_tree/r_tree_split_impl.hpp | 60 +++++++++------- .../tree/rectangle_tree/rectangle_tree.hpp | 6 +- .../rectangle_tree/rectangle_tree_impl.hpp | 68 ++++++++++--------- .../rectangle_tree/single_tree_traverser.hpp | 2 +- .../single_tree_traverser_impl.hpp | 4 +- .../core/tree/rectangle_tree/traits.hpp | 2 +- .../core/tree/rectangle_tree/x_tree_split.hpp | 17 +++-- .../tree/rectangle_tree/x_tree_split_impl.hpp | 31 ++++++--- 13 files changed, 169 insertions(+), 102 deletions(-) diff --git a/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser.hpp b/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser.hpp index 397a1c24a6..75a05011f2 100644 --- a/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser.hpp +++ b/src/mlpack/core/tree/rectangle_tree/dual_tree_traverser.hpp @@ -19,7 +19,7 @@ namespace tree { template class SplitType, typename DescentType> template class RectangleTree class SplitType, typename DescentType> template RectangleTree:: @@ -35,7 +35,7 @@ DualTreeTraverser::DualTreeTraverser(RuleType& rule) : template class SplitType, typename DescentType> template void RectangleTree:: 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 index 54d1bba1bf..3970f3a68f 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp @@ -18,25 +18,33 @@ namespace tree /** Trees and tree-building procedures. */ { * nodes overflow, we split them, moving up the tree and splitting nodes * as necessary. */ +template class RStarTreeSplit { public: + //! Default constructor + RStarTreeSplit(); + + //! Construct this with specified node. + RStarTreeSplit(TreeType *node); + /** * 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. */ - template - static void SplitLeafNode(TreeType* tree, std::vector& relevels); + void SplitLeafNode(std::vector& relevels); /** * Split a non-leaf node using the "default" algorithm. If this is a root * node, the tree increases in depth. */ - template - static bool SplitNonLeafNode(TreeType* tree, std::vector& relevels); + bool SplitNonLeafNode(std::vector& relevels); private: + //! The node which has to be split. + TreeType *tree; + /** * Class to allow for faster sorting. */ @@ -60,7 +68,6 @@ class RStarTreeSplit /** * Insert a node into another node. */ - template static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode); }; 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 index 9c0e95cc33..a2af8aaf06 100644 --- 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 @@ -15,6 +15,20 @@ namespace mlpack { namespace tree { +template +RStarTreeSplit::RStarTreeSplit() : + tree(NULL) +{ + +} + +template +RStarTreeSplit::RStarTreeSplit(TreeType *node) : + tree(node) +{ + +} + /** * 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 @@ -22,7 +36,7 @@ namespace tree { * new nodes into the tree, spliting the parent if necessary. */ template -void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) +void RStarTreeSplit::SplitLeafNode(std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -41,7 +55,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) tree->Children()[(tree->NumChildren())++] = copy; assert(tree->NumChildren() == 1); - SplitLeafNode(copy, relevels); + copy->SplitNode(relevels); return; } @@ -58,7 +72,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) size_t p = tree->MaxLeafSize() * 0.3; // The paper says this works the best. if (p == 0) { - SplitLeafNode(tree, relevels); + tree->SplitNode(relevels); return; } @@ -251,7 +265,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) // just in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - SplitNonLeafNode(par, relevels); + par->SplitNode(relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren()); assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren()); @@ -269,8 +283,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) * higher up the tree because they were already updated if necessary. */ template -bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree, - std::vector& relevels) +bool RStarTreeSplit::SplitNonLeafNode(std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -288,7 +301,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree, tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - SplitNonLeafNode(copy, relevels); + copy->SplitNode(relevels); return true; } @@ -644,7 +657,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree, assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) { - SplitNonLeafNode(par, relevels); + par->SplitNode(relevels); } // We have to update the children of each of these new nodes so that they @@ -673,7 +686,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree, * numberOfChildren. */ template -void RStarTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode) +void RStarTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode) { destTree->Bound() |= srcNode->Bound(); destTree->Children()[destTree->NumChildren()++] = srcNode; 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 1bf5745cca..8a412adde9 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp @@ -18,42 +18,45 @@ namespace tree /** Trees and tree-building procedures. */ { * nodes overflow, we split them, moving up the tree and splitting nodes * as necessary. */ +template class RTreeSplit { public: + //! Default constructor + RTreeSplit(); + + //! Construct this with specified node. + RTreeSplit(TreeType *node); + /** * Split a leaf node using the "default" algorithm. If necessary, this split * will propagate upwards through the tree. */ - template - static void SplitLeafNode(TreeType* tree, - std::vector& relevels); + void SplitLeafNode(std::vector& relevels); /** * Split a non-leaf node using the "default" algorithm. If this is a root * node, the tree increases in depth. */ - template - static bool SplitNonLeafNode(TreeType* tree, - std::vector& relevels); + bool SplitNonLeafNode(std::vector& relevels); private: + //! The node which has to be split. + TreeType *tree; + /** * Get the seeds for splitting a leaf node. */ - template - static void GetPointSeeds(const TreeType& tree, int& i, int& j); + void GetPointSeeds(int& i, int& j); /** * Get the seeds for splitting a non-leaf node. */ - template - static void GetBoundSeeds(const TreeType& tree, int& i, int& j); + void GetBoundSeeds(int& i, int& j); /** * Assign points to the two new nodes. */ - template static void AssignPointDestNode(TreeType* oldTree, TreeType* treeOne, TreeType* treeTwo, @@ -63,7 +66,6 @@ class RTreeSplit /** * Assign nodes to the two new nodes. */ - template static void AssignNodeDestNode(TreeType* oldTree, TreeType* treeOne, TreeType* treeTwo, @@ -73,7 +75,6 @@ class RTreeSplit /** * Insert a node into another node. */ - template static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode); }; 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 15d70bda09..5bc04612a2 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 @@ -14,6 +14,20 @@ namespace mlpack { namespace tree { +template +RTreeSplit::RTreeSplit() : + tree(NULL) +{ + +} + +template +RTreeSplit::RTreeSplit(TreeType *node) : + tree(node) +{ + +} + /** * 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 @@ -21,7 +35,7 @@ namespace tree { * new nodes into the tree, spliting the parent if necessary. */ template -void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) +void RTreeSplit::SplitLeafNode(std::vector& 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 @@ -35,7 +49,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) tree->NullifyData(); // Because this was a leaf node, numChildren must be 0. tree->Children()[(tree->NumChildren())++] = copy; - SplitLeafNode(copy, relevels); + copy->SplitNode(relevels); return; } @@ -46,7 +60,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) // rectangles, only points. We assume that the tree uses Euclidean Distance. int i = 0; int j = 0; - GetPointSeeds(*tree, i, j); + GetPointSeeds(i, j); TreeType* treeOne = new TreeType(tree->Parent()); TreeType* treeTwo = new TreeType(tree->Parent()); @@ -66,7 +80,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) // just in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - SplitNonLeafNode(par, relevels); + par->SplitNode(relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren()); assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren()); @@ -85,7 +99,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) * higher up the tree because they were already updated if necessary. */ template -bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) +bool RTreeSplit::SplitNonLeafNode(std::vector& 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 @@ -98,13 +112,13 @@ bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) tree->NumChildren() = 0; tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - SplitNonLeafNode(copy, relevels); + copy->SplitNode(relevels); return true; } int i = 0; int j = 0; - GetBoundSeeds(*tree, i, j); + GetBoundSeeds(i, j); assert(i != j); @@ -131,7 +145,7 @@ bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - SplitNonLeafNode(par, relevels); + par->SplitNode(relevels); // We have to update the children of each of these new nodes so that they // record the correct parent. @@ -157,18 +171,18 @@ bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) * The indices of these points will be stored in iRet and jRet. */ template -void RTreeSplit::GetPointSeeds(const TreeType& tree, int& iRet, int& jRet) +void RTreeSplit::GetPointSeeds(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. typename TreeType::ElemType worstPairScore = -1.0; - for (size_t i = 0; i < tree.Count(); i++) + for (size_t i = 0; i < tree->Count(); i++) { - for (size_t j = i + 1; j < tree.Count(); j++) + for (size_t j = i + 1; j < tree->Count(); j++) { const typename TreeType::ElemType score = arma::prod(arma::abs( - tree.LocalDataset().col(i) - tree.LocalDataset().col(j))); + tree->LocalDataset().col(i) - tree->LocalDataset().col(j))); if (score > worstPairScore) { @@ -185,23 +199,23 @@ void RTreeSplit::GetPointSeeds(const TreeType& tree, int& iRet, int& jRet) * indices of the bounds will be stored in iRet and jRet. */ template -void RTreeSplit::GetBoundSeeds(const TreeType& tree, int& iRet, int& jRet) +void RTreeSplit::GetBoundSeeds(int& iRet, int& jRet) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; ElemType worstPairScore = -1.0; - for (size_t i = 0; i < tree.NumChildren(); i++) + for (size_t i = 0; i < tree->NumChildren(); i++) { - for (size_t j = i + 1; j < tree.NumChildren(); j++) + for (size_t j = i + 1; j < tree->NumChildren(); j++) { ElemType score = 1.0; - for (size_t k = 0; k < tree.Bound().Dim(); k++) + for (size_t k = 0; k < tree->Bound().Dim(); k++) { - const ElemType hiMax = std::max(tree.Children()[i]->Bound()[k].Hi(), - tree.Children()[j]->Bound()[k].Hi()); - const ElemType loMin = std::min(tree.Children()[i]->Bound()[k].Lo(), - tree.Children()[j]->Bound()[k].Lo()); + const ElemType hiMax = std::max(tree->Children()[i]->Bound()[k].Hi(), + tree->Children()[j]->Bound()[k].Hi()); + const ElemType loMin = std::min(tree->Children()[i]->Bound()[k].Lo(), + tree->Children()[j]->Bound()[k].Lo()); score *= (hiMax - loMin); } @@ -216,7 +230,7 @@ void RTreeSplit::GetBoundSeeds(const TreeType& tree, int& iRet, int& jRet) } template -void RTreeSplit::AssignPointDestNode(TreeType* oldTree, +void RTreeSplit::AssignPointDestNode(TreeType* oldTree, TreeType* treeOne, TreeType* treeTwo, const int intI, @@ -357,7 +371,7 @@ void RTreeSplit::AssignPointDestNode(TreeType* oldTree, } template -void RTreeSplit::AssignNodeDestNode(TreeType* oldTree, +void RTreeSplit::AssignNodeDestNode(TreeType* oldTree, TreeType* treeOne, TreeType* treeTwo, const int intI, @@ -522,7 +536,7 @@ void RTreeSplit::AssignNodeDestNode(TreeType* oldTree, * numberOfChildren. */ template -void RTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode) +void RTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode) { destTree->Bound() |= srcNode->Bound(); destTree->Children()[destTree->NumChildren()++] = srcNode; diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp index e4d69d3f6d..090a832ed1 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp @@ -35,13 +35,15 @@ namespace tree /** Trees and tree-building procedures. */ { * @tparam DescentType The heuristic to use when descending the tree to insert * points. */ + template class SplitType = RTreeSplit, typename DescentType = RTreeDescentHeuristic> class RectangleTree { + friend class SplitType; // The metric *must* be the euclidean distance. static_assert(boost::is_same::value, "RectangleTree: MetricType must be metric::EuclideanDistance."); @@ -118,6 +120,8 @@ class RectangleTree std::vector points; //! The local dataset MatType* localDataset; + //! The class that performs the split of the node. + SplitType split; public: //! A single traverser for rectangle type trees. See 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 2c747ca5ab..cca78de9d2 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -20,7 +20,7 @@ namespace tree { template class SplitType, typename DescentType> RectangleTree:: RectangleTree(const MatType& data, @@ -50,6 +50,8 @@ RectangleTree(const MatType& data, { stat = StatisticType(*this); + split = SplitType(this); + // For now, just insert the points in order. RectangleTree* root = this; @@ -60,7 +62,7 @@ RectangleTree(const MatType& data, template class SplitType, typename DescentType> RectangleTree:: RectangleTree(MatType&& data, @@ -90,6 +92,8 @@ RectangleTree(MatType&& data, { stat = StatisticType(*this); + split = SplitType(this); + // For now, just insert the points in order. RectangleTree* root = this; @@ -100,7 +104,7 @@ RectangleTree(MatType&& data, template class SplitType, typename DescentType> RectangleTree:: RectangleTree( @@ -126,6 +130,7 @@ RectangleTree( maxLeafSize + 1))) { stat = StatisticType(*this); + split = SplitType(this); } /** @@ -135,7 +140,7 @@ RectangleTree( template class SplitType, typename DescentType> RectangleTree:: RectangleTree( @@ -159,6 +164,7 @@ RectangleTree( points(other.Points()), localDataset(NULL) { + split = SplitType(this); if (deepCopy) { if (numChildren > 0) @@ -187,7 +193,7 @@ RectangleTree( template class SplitType, typename DescentType> template RectangleTree:: @@ -208,7 +214,7 @@ RectangleTree( template class SplitType, typename DescentType> RectangleTree:: ~RectangleTree() @@ -229,7 +235,7 @@ RectangleTree:: template class SplitType, typename DescentType> void RectangleTree:: SoftDelete() @@ -249,7 +255,7 @@ void RectangleTree:: template class SplitType, typename DescentType> void RectangleTree:: NullifyData() @@ -264,7 +270,7 @@ void RectangleTree:: template class SplitType, typename DescentType> void RectangleTree:: InsertPoint(const size_t point) @@ -301,7 +307,7 @@ void RectangleTree:: template class SplitType, typename DescentType> void RectangleTree:: InsertPoint(const size_t point, std::vector& relevels) @@ -336,7 +342,7 @@ void RectangleTree:: template class SplitType, typename DescentType> void RectangleTree:: InsertNode(RectangleTree* node, @@ -365,7 +371,7 @@ void RectangleTree:: template class SplitType, typename DescentType> bool RectangleTree:: DeletePoint(const size_t point) @@ -410,7 +416,7 @@ bool RectangleTree:: template class SplitType, typename DescentType> bool RectangleTree:: DeletePoint(const size_t point, std::vector& relevels) @@ -445,7 +451,7 @@ bool RectangleTree:: template class SplitType, typename DescentType> bool RectangleTree:: RemoveNode(const RectangleTree* node, std::vector& relevels) @@ -474,7 +480,7 @@ bool RectangleTree:: template class SplitType, typename DescentType> size_t RectangleTree::TreeSize() const @@ -489,7 +495,7 @@ size_t RectangleTree class SplitType, typename DescentType> size_t RectangleTree::TreeDepth() const @@ -509,7 +515,7 @@ size_t RectangleTree class SplitType, typename DescentType> inline bool RectangleTree::IsLeaf() const @@ -524,7 +530,7 @@ inline bool RectangleTree class SplitType, typename DescentType> inline typename RectangleTree class SplitType, typename DescentType> inline typename RectangleTree class SplitType, typename DescentType> inline size_t RectangleTree::NumPoints() const @@ -585,7 +591,7 @@ inline size_t RectangleTree class SplitType, typename DescentType> inline size_t RectangleTree::NumDescendants() const @@ -609,7 +615,7 @@ inline size_t RectangleTree class SplitType, typename DescentType> inline size_t RectangleTree::Descendant(const size_t index) const @@ -641,7 +647,7 @@ inline size_t RectangleTree class SplitType, typename DescentType> inline size_t RectangleTree::Point(const size_t index) const @@ -656,7 +662,7 @@ inline size_t RectangleTree class SplitType, typename DescentType> void RectangleTree:: SplitNode(std::vector& relevels) @@ -669,7 +675,7 @@ void RectangleTree:: // 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); + split.SplitLeafNode(relevels); } else { @@ -679,7 +685,7 @@ void RectangleTree:: // 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::SplitNonLeafNode(this, relevels); + split.SplitNonLeafNode(relevels); } } @@ -687,7 +693,7 @@ void RectangleTree:: template class SplitType, typename DescentType> RectangleTree:: RectangleTree() : @@ -715,7 +721,7 @@ RectangleTree() : template class SplitType, typename DescentType> void RectangleTree:: CondenseTree(const arma::vec& point, @@ -844,7 +850,7 @@ void RectangleTree:: template class SplitType, typename DescentType> bool RectangleTree:: ShrinkBoundForPoint(const arma::vec& point) @@ -940,7 +946,7 @@ bool RectangleTree:: template class SplitType, typename DescentType> bool RectangleTree:: ShrinkBoundForBound(const bound::HRectBound& /* b */) @@ -974,7 +980,7 @@ bool RectangleTree:: template class SplitType, typename DescentType> template void RectangleTree:: diff --git a/src/mlpack/core/tree/rectangle_tree/single_tree_traverser.hpp b/src/mlpack/core/tree/rectangle_tree/single_tree_traverser.hpp index 720a06ebea..7c4c938cb0 100644 --- a/src/mlpack/core/tree/rectangle_tree/single_tree_traverser.hpp +++ b/src/mlpack/core/tree/rectangle_tree/single_tree_traverser.hpp @@ -19,7 +19,7 @@ namespace tree { template class SplitType, typename DescentType> template class RectangleTree class SplitType, typename DescentType> template RectangleTree:: @@ -32,7 +32,7 @@ SingleTreeTraverser::SingleTreeTraverser(RuleType& rule) : template class SplitType, typename DescentType> template void RectangleTree:: diff --git a/src/mlpack/core/tree/rectangle_tree/traits.hpp b/src/mlpack/core/tree/rectangle_tree/traits.hpp index 811d9ace16..49b357f1f4 100644 --- a/src/mlpack/core/tree/rectangle_tree/traits.hpp +++ b/src/mlpack/core/tree/rectangle_tree/traits.hpp @@ -21,7 +21,7 @@ namespace tree { template class SplitType, typename DescentType> class TreeTraits> diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp index ef9224c99e..3264353162 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp @@ -28,25 +28,33 @@ const double MAX_OVERLAP = 0.2; * nodes overflow, we split them, moving up the tree and splitting nodes * as necessary. */ +template class XTreeSplit { public: + //! Default constructor + XTreeSplit(); + + //! Construct this with specified node. + XTreeSplit(TreeType *node); + /** * 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. */ - template - static void SplitLeafNode(TreeType* tree, std::vector& relevels); + void SplitLeafNode(std::vector& relevels); /** * Split a non-leaf node using the "default" algorithm. If this is a root * node, the tree increases in depth. */ - template - static bool SplitNonLeafNode(TreeType* tree, std::vector& relevels); + bool SplitNonLeafNode(std::vector& relevels); private: + //! The node which has to be split. + TreeType *tree; + /** * Class to allow for faster sorting. */ @@ -71,7 +79,6 @@ class XTreeSplit /** * Insert a node into another node. */ - template static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode); }; 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 index 21d3da31d9..685b26aec4 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -14,6 +14,21 @@ namespace mlpack { namespace tree { +template +XTreeSplit::XTreeSplit() : + tree(NULL) +{ + +} + +template +XTreeSplit::XTreeSplit(TreeType *node) : + tree(node) +{ + +} + + /** * 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 @@ -21,7 +36,7 @@ namespace tree { * new nodes into the tree, spliting the parent if necessary. */ template -void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) +void XTreeSplit::SplitLeafNode(std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -39,7 +54,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) // Because this was a leaf node, numChildren must be 0. tree->Children()[(tree->NumChildren())++] = copy; assert(tree->NumChildren() == 1); - XTreeSplit::SplitLeafNode(copy, relevels); + copy->SplitNode(relevels); return; } @@ -57,7 +72,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) size_t p = tree->MaxLeafSize() * 0.3; if (p == 0) { - SplitLeafNode(tree, relevels); + tree->SplitNode(relevels); return; } @@ -270,7 +285,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) // in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - SplitNonLeafNode(par, relevels); + par->SplitNode(relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->Parent()->MaxNumChildren()); @@ -292,7 +307,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector& relevels) * higher up the tree because they were already updated if necessary. */ template -bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) +bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -309,7 +324,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) tree->NumChildren() = 0; tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - XTreeSplit::SplitNonLeafNode(copy, relevels); + copy->SplitNode(relevels); return true; } @@ -803,7 +818,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) if (par->NumChildren() == par->MaxNumChildren() + 1) { - SplitNonLeafNode(par, relevels); + par->SplitNode(relevels); } // We have to update the children of each of these new nodes so that they @@ -832,7 +847,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector& relevels) * numberOfChildren. */ template -void XTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode) +void XTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode) { destTree->Bound() |= srcNode->Bound(); destTree->Children()[destTree->NumChildren()] = srcNode; From 6008c15f62263229eec240cec5487fc59062b993 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Fri, 22 Apr 2016 20:21:23 +0300 Subject: [PATCH 14/17] Use the RectangleTree::Split() method instead of the friend class. Move the normalNodeMaxNumChildren to the XTreeSplit. --- .../tree/rectangle_tree/r_star_tree_split.hpp | 8 ++- .../rectangle_tree/r_star_tree_split_impl.hpp | 25 ++++++++-- .../core/tree/rectangle_tree/r_tree_split.hpp | 8 ++- .../tree/rectangle_tree/r_tree_split_impl.hpp | 22 +++++++-- .../tree/rectangle_tree/rectangle_tree.hpp | 14 ++---- .../rectangle_tree/rectangle_tree_impl.hpp | 8 +-- .../core/tree/rectangle_tree/x_tree_split.hpp | 20 +++++++- .../tree/rectangle_tree/x_tree_split_impl.hpp | 49 ++++++++++++++----- 8 files changed, 116 insertions(+), 38 deletions(-) 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 index 3970f3a68f..8ef11ec977 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp @@ -25,9 +25,15 @@ class RStarTreeSplit //! Default constructor RStarTreeSplit(); - //! Construct this with specified node. + //! Construct this with the specified node. RStarTreeSplit(TreeType *node); + //! Construct this with the specified node and the parent of the node. + RStarTreeSplit(TreeType *node,const TreeType *parentNode); + + //! Create a copy of the other.split. + RStarTreeSplit(TreeType *node,const TreeType &other); + /** * Split a leaf node using the algorithm described in "The R*-tree: An * Efficient and Robust Access method for Points and Rectangles." If 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 index a2af8aaf06..41994dbae2 100644 --- 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 @@ -29,6 +29,21 @@ RStarTreeSplit::RStarTreeSplit(TreeType *node) : } +template +RStarTreeSplit::RStarTreeSplit(TreeType *node,const TreeType *) : + tree(node) +{ + +} + +template +RStarTreeSplit::RStarTreeSplit(TreeType *node,const TreeType &) : + tree(node) +{ + +} + + /** * 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 @@ -55,7 +70,7 @@ void RStarTreeSplit::SplitLeafNode(std::vector& relevels) tree->Children()[(tree->NumChildren())++] = copy; assert(tree->NumChildren() == 1); - copy->SplitNode(relevels); + copy->Split().SplitLeafNode(relevels); return; } @@ -72,7 +87,7 @@ void RStarTreeSplit::SplitLeafNode(std::vector& relevels) size_t p = tree->MaxLeafSize() * 0.3; // The paper says this works the best. if (p == 0) { - tree->SplitNode(relevels); + tree->Split().SplitLeafNode(relevels); return; } @@ -265,7 +280,7 @@ void RStarTreeSplit::SplitLeafNode(std::vector& relevels) // just in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->SplitNode(relevels); + par->Split().SplitNonLeafNode(relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren()); assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren()); @@ -301,7 +316,7 @@ bool RStarTreeSplit::SplitNonLeafNode(std::vector& relevels) tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - copy->SplitNode(relevels); + copy->Split().SplitNonLeafNode(relevels); return true; } @@ -657,7 +672,7 @@ bool RStarTreeSplit::SplitNonLeafNode(std::vector& relevels) assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) { - par->SplitNode(relevels); + par->Split().SplitNonLeafNode(relevels); } // We have to update the children of each of these new nodes so that they 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 8a412adde9..c72a2e2567 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp @@ -25,9 +25,15 @@ class RTreeSplit //! Default constructor RTreeSplit(); - //! Construct this with specified node. + //! Construct this with the specified node. RTreeSplit(TreeType *node); + //! Construct this with the specified node and the parent of the node. + RTreeSplit(TreeType *node,const TreeType *parentNode); + + //! Create a copy of the other.split. + RTreeSplit(TreeType *node,const TreeType &other); + /** * Split a leaf node using the "default" algorithm. If necessary, this split * will propagate upwards through the tree. 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 5bc04612a2..6cb925d03d 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 @@ -28,6 +28,20 @@ RTreeSplit::RTreeSplit(TreeType *node) : } +template +RTreeSplit::RTreeSplit(TreeType *node,const TreeType *) : + tree(node) +{ + +} + +template +RTreeSplit::RTreeSplit(TreeType *node,const TreeType &) : + tree(node) +{ + +} + /** * 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 @@ -49,7 +63,7 @@ void RTreeSplit::SplitLeafNode(std::vector& relevels) tree->NullifyData(); // Because this was a leaf node, numChildren must be 0. tree->Children()[(tree->NumChildren())++] = copy; - copy->SplitNode(relevels); + copy->Split().SplitLeafNode(relevels); return; } @@ -80,7 +94,7 @@ void RTreeSplit::SplitLeafNode(std::vector& relevels) // just in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->SplitNode(relevels); + par->Split().SplitNonLeafNode(relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren()); assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren()); @@ -112,7 +126,7 @@ bool RTreeSplit::SplitNonLeafNode(std::vector& relevels) tree->NumChildren() = 0; tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - copy->SplitNode(relevels); + copy->Split().SplitNonLeafNode(relevels); return true; } @@ -145,7 +159,7 @@ bool RTreeSplit::SplitNonLeafNode(std::vector& relevels) assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->SplitNode(relevels); + par->Split().SplitNonLeafNode(relevels); // We have to update the children of each of these new nodes so that they // record the correct parent. diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp index 090a832ed1..8930998017 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp @@ -43,7 +43,6 @@ template class RectangleTree { - friend class SplitType; // The metric *must* be the euclidean distance. static_assert(boost::is_same::value, "RectangleTree: MetricType must be metric::EuclideanDistance."); @@ -78,9 +77,6 @@ class RectangleTree } SplitHistoryStruct; private: - //! The max number of child nodes a non-leaf normal node can have. - //! (used in x-trees) - size_t normalNodeMaxNumChildren; //! 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. @@ -325,6 +321,11 @@ class RectangleTree //! Modify the split history object of this node. SplitHistoryStruct& SplitHistory() { return splitHistory; } + //! Return the split object of this node. + const SplitType& Split() const { return split; } + //! Modify the split object of this node. + SplitType& Split() { return split; } + //! Return whether or not this node is a leaf (true if it has no children). bool IsLeaf() const; @@ -338,11 +339,6 @@ class RectangleTree //! Modify the minimum leaf size. size_t& MinLeafSize() { return minLeafSize; } - //! Return the maximum number of a normal node's children (used in x-trees). - size_t NormalNodeMaxNumChildren() const { return normalNodeMaxNumChildren; } - //! Modify the maximum number of a normal node's children (used in x-trees). - size_t& NormalNodeMaxNumChildren() { return normalNodeMaxNumChildren; } - //! 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). 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 cca78de9d2..57916c8e6c 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -29,7 +29,6 @@ RectangleTree(const MatType& data, const size_t maxNumChildren, const size_t minNumChildren, const size_t firstDataIndex) : - normalNodeMaxNumChildren(maxNumChildren), maxNumChildren(maxNumChildren), minNumChildren(minNumChildren), numChildren(0), @@ -71,7 +70,6 @@ RectangleTree(MatType&& data, const size_t maxNumChildren, const size_t minNumChildren, const size_t firstDataIndex) : - normalNodeMaxNumChildren(maxNumChildren), maxNumChildren(maxNumChildren), minNumChildren(minNumChildren), numChildren(0), @@ -110,7 +108,6 @@ RectangleTree:: RectangleTree( RectangleTree* parentNode,const size_t numMaxChildren) : - normalNodeMaxNumChildren(parentNode->NormalNodeMaxNumChildren()), maxNumChildren(numMaxChildren > 0 ? numMaxChildren : parentNode->MaxNumChildren()), minNumChildren(parentNode->MinNumChildren()), numChildren(0), @@ -130,7 +127,7 @@ RectangleTree( maxLeafSize + 1))) { stat = StatisticType(*this); - split = SplitType(this); + split = SplitType(this,parentNode); } /** @@ -146,7 +143,6 @@ RectangleTree:: RectangleTree( const RectangleTree& other, const bool deepCopy) : - normalNodeMaxNumChildren(other.NormalNodeMaxNumChildren()), maxNumChildren(other.MaxNumChildren()), minNumChildren(other.MinNumChildren()), numChildren(other.NumChildren()), @@ -164,7 +160,7 @@ RectangleTree( points(other.Points()), localDataset(NULL) { - split = SplitType(this); + split = SplitType(this,other); if (deepCopy) { if (numChildren > 0) diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp index 3264353162..884034ce3d 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp @@ -35,9 +35,18 @@ class XTreeSplit //! Default constructor XTreeSplit(); - //! Construct this with specified node. + //! Construct this with the specified node. XTreeSplit(TreeType *node); + //! Construct this with the specified node and the specified normalNodeMaxNumChildren. + XTreeSplit(TreeType *node,const size_t normalNodeMaxNumChildren); + + //! Construct this with the specified node and the parent of the node. + XTreeSplit(TreeType *node,const TreeType *parentNode); + + //! Create a copy of the other.split. + XTreeSplit(TreeType *node,const TreeType &other); + /** * Split a leaf node using the algorithm described in "The R*-tree: An * Efficient and Robust Access method for Points and Rectangles." If @@ -55,6 +64,9 @@ class XTreeSplit //! The node which has to be split. TreeType *tree; + //! The max number of child nodes a non-leaf normal node can have. + size_t normalNodeMaxNumChildren; + /** * Class to allow for faster sorting. */ @@ -80,6 +92,12 @@ class XTreeSplit * Insert a node into another node. */ static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode); + + public: + //! Return the maximum number of a normal node's children. + size_t NormalNodeMaxNumChildren() const { return normalNodeMaxNumChildren; } + //! Modify the maximum number of a normal node's children. + size_t& NormalNodeMaxNumChildren() { return normalNodeMaxNumChildren; } }; } // namespace tree 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 index 685b26aec4..a8f803be9d 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -16,14 +16,41 @@ namespace tree { template XTreeSplit::XTreeSplit() : - tree(NULL) + tree(NULL), + normalNodeMaxNumChildren(0) { } template XTreeSplit::XTreeSplit(TreeType *node) : - tree(node) + tree(node), + normalNodeMaxNumChildren(node->MaxNumChildren()) +{ + +} + + +template +XTreeSplit::XTreeSplit(TreeType *node,const size_t normalNodeMaxNumChildren) : + tree(node), + normalNodeMaxNumChildren(normalNodeMaxNumChildren) +{ + +} + +template +XTreeSplit::XTreeSplit(TreeType *node,const TreeType *parent) : + tree(node), + normalNodeMaxNumChildren(parent->Split().NormalNodeMaxNumChildren()) +{ + +} + +template +XTreeSplit::XTreeSplit(TreeType *node,const TreeType &other) : + tree(node), + normalNodeMaxNumChildren(other.Split().NormalNodeMaxNumChildren()) { } @@ -54,7 +81,7 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) // Because this was a leaf node, numChildren must be 0. tree->Children()[(tree->NumChildren())++] = copy; assert(tree->NumChildren() == 1); - copy->SplitNode(relevels); + copy->Split().SplitLeafNode(relevels); return; } @@ -72,7 +99,7 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) size_t p = tree->MaxLeafSize() * 0.3; if (p == 0) { - tree->SplitNode(relevels); + tree->Split().SplitLeafNode(relevels); return; } @@ -233,8 +260,8 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) std::sort(sorted.begin(), sorted.end(), structComp); - TreeType* treeOne = new TreeType(tree->Parent(),tree->NormalNodeMaxNumChildren()); - TreeType* treeTwo = new TreeType(tree->Parent(),tree->NormalNodeMaxNumChildren()); + TreeType* treeOne = new TreeType(tree->Parent(),NormalNodeMaxNumChildren()); + TreeType* treeTwo = new TreeType(tree->Parent(),NormalNodeMaxNumChildren()); // The leaf nodes should never have any overlap introduced by the above method // since a split axis is chosen and then points are assigned based on their @@ -285,7 +312,7 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) // in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->SplitNode(relevels); + par->Split().SplitNonLeafNode(relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->Parent()->MaxNumChildren()); @@ -324,7 +351,7 @@ bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) tree->NumChildren() = 0; tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - copy->SplitNode(relevels); + copy->Split().SplitNonLeafNode(relevels); return true; } @@ -758,7 +785,7 @@ bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) (tree->Parent()->NumChildren() == 1)) { // We make the root a supernode instead. - tree->Parent()->MaxNumChildren() = tree->MaxNumChildren() + tree->NormalNodeMaxNumChildren(); + tree->Parent()->MaxNumChildren() = tree->MaxNumChildren() + NormalNodeMaxNumChildren(); tree->Parent()->Children().resize(tree->Parent()->MaxNumChildren() + 1); tree->Parent()->NumChildren() = tree->NumChildren(); for (size_t i = 0; i < tree->NumChildren(); i++) @@ -775,7 +802,7 @@ bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) } // If we don't have to worry about the root, we just enlarge this node. - tree->MaxNumChildren() += tree->NormalNodeMaxNumChildren(); + tree->MaxNumChildren() += NormalNodeMaxNumChildren(); tree->Children().resize(tree->MaxNumChildren() + 1); for (size_t i = 0; i < tree->NumChildren(); i++) tree->Child(i).Parent() = tree; @@ -818,7 +845,7 @@ bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) if (par->NumChildren() == par->MaxNumChildren() + 1) { - par->SplitNode(relevels); + par->Split().SplitNonLeafNode(relevels); } // We have to update the children of each of these new nodes so that they From 52423b82b0765abc658c601eb423f1e8852dd260 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Tue, 3 May 2016 19:36:42 +0300 Subject: [PATCH 15/17] Remove a pointer to the node from the SplitType class. --- .../tree/rectangle_tree/r_star_tree_split.hpp | 13 +++----- .../rectangle_tree/r_star_tree_split_impl.hpp | 26 +++++++-------- .../core/tree/rectangle_tree/r_tree_split.hpp | 17 ++++------ .../tree/rectangle_tree/r_tree_split_impl.hpp | 32 ++++++++---------- .../rectangle_tree/rectangle_tree_impl.hpp | 6 ++-- .../core/tree/rectangle_tree/x_tree_split.hpp | 16 +++------ .../tree/rectangle_tree/x_tree_split_impl.hpp | 33 ++++++------------- 7 files changed, 55 insertions(+), 88 deletions(-) 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 index 1b937682b6..908d6c2161 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp @@ -26,31 +26,28 @@ class RStarTreeSplit RStarTreeSplit(); //! Construct this with the specified node. - RStarTreeSplit(TreeType *node); + RStarTreeSplit(const TreeType *node); //! Construct this with the specified node and the parent of the node. - RStarTreeSplit(TreeType *node,const TreeType *parentNode); + RStarTreeSplit(const TreeType *node,const TreeType *parentNode); //! Create a copy of the other.split. - RStarTreeSplit(TreeType *node,const TreeType &other); + RStarTreeSplit(const TreeType &other); /** * 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. */ - void SplitLeafNode(std::vector& relevels); + void SplitLeafNode(TreeType *tree,std::vector& relevels); /** * Split a non-leaf node using the "default" algorithm. If this is a root * node, the tree increases in depth. */ - bool SplitNonLeafNode(std::vector& relevels); + bool SplitNonLeafNode(TreeType *tree,std::vector& relevels); private: - //! The node which has to be split. - TreeType *tree; - /** * Class to allow for faster sorting. */ 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 index 9fda2f53ae..f233ff7494 100644 --- 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 @@ -16,29 +16,25 @@ namespace mlpack { namespace tree { template -RStarTreeSplit::RStarTreeSplit() : - tree(NULL) +RStarTreeSplit::RStarTreeSplit() { } template -RStarTreeSplit::RStarTreeSplit(TreeType *node) : - tree(node) +RStarTreeSplit::RStarTreeSplit(const TreeType *) { } template -RStarTreeSplit::RStarTreeSplit(TreeType *node,const TreeType *) : - tree(node) +RStarTreeSplit::RStarTreeSplit(const TreeType *,const TreeType *) { } template -RStarTreeSplit::RStarTreeSplit(TreeType *node,const TreeType &) : - tree(node) +RStarTreeSplit::RStarTreeSplit(const TreeType &) { } @@ -51,7 +47,7 @@ RStarTreeSplit::RStarTreeSplit(TreeType *node,const TreeType &) : * new nodes into the tree, spliting the parent if necessary. */ template -void RStarTreeSplit::SplitLeafNode(std::vector& relevels) +void RStarTreeSplit::SplitLeafNode(TreeType *tree,std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -70,7 +66,7 @@ void RStarTreeSplit::SplitLeafNode(std::vector& relevels) tree->Children()[(tree->NumChildren())++] = copy; assert(tree->NumChildren() == 1); - copy->Split().SplitLeafNode(relevels); + copy->Split().SplitLeafNode(copy,relevels); return; } @@ -87,7 +83,7 @@ void RStarTreeSplit::SplitLeafNode(std::vector& relevels) size_t p = tree->MaxLeafSize() * 0.3; // The paper says this works the best. if (p == 0) { - tree->Split().SplitLeafNode(relevels); + tree->Split().SplitLeafNode(tree,relevels); return; } @@ -280,7 +276,7 @@ void RStarTreeSplit::SplitLeafNode(std::vector& relevels) // just in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->Split().SplitNonLeafNode(relevels); + par->Split().SplitNonLeafNode(par,relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren()); assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren()); @@ -298,7 +294,7 @@ void RStarTreeSplit::SplitLeafNode(std::vector& relevels) * higher up the tree because they were already updated if necessary. */ template -bool RStarTreeSplit::SplitNonLeafNode(std::vector& relevels) +bool RStarTreeSplit::SplitNonLeafNode(TreeType *tree,std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -316,7 +312,7 @@ bool RStarTreeSplit::SplitNonLeafNode(std::vector& relevels) tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - copy->Split().SplitNonLeafNode(relevels); + copy->Split().SplitNonLeafNode(copy,relevels); return true; } @@ -672,7 +668,7 @@ bool RStarTreeSplit::SplitNonLeafNode(std::vector& relevels) assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) { - par->Split().SplitNonLeafNode(relevels); + par->Split().SplitNonLeafNode(par,relevels); } // We have to update the children of each of these new nodes so that they 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 71e506f0a5..ebb640c1f1 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp @@ -26,39 +26,36 @@ class RTreeSplit RTreeSplit(); //! Construct this with the specified node. - RTreeSplit(TreeType *node); + RTreeSplit(const TreeType *node); //! Construct this with the specified node and the parent of the node. - RTreeSplit(TreeType *node,const TreeType *parentNode); + RTreeSplit(const TreeType *node,const TreeType *parentNode); //! Create a copy of the other.split. - RTreeSplit(TreeType *node,const TreeType &other); + RTreeSplit(const TreeType &other); /** * Split a leaf node using the "default" algorithm. If necessary, this split * will propagate upwards through the tree. */ - void SplitLeafNode(std::vector& relevels); + void SplitLeafNode(TreeType *tree,std::vector& relevels); /** * Split a non-leaf node using the "default" algorithm. If this is a root * node, the tree increases in depth. */ - bool SplitNonLeafNode(std::vector& relevels); + bool SplitNonLeafNode(TreeType *tree,std::vector& relevels); private: - //! The node which has to be split. - TreeType *tree; - /** * Get the seeds for splitting a leaf node. */ - void GetPointSeeds(int& i, int& j); + static void GetPointSeeds(const TreeType *tree,int& i, int& j); /** * Get the seeds for splitting a non-leaf node. */ - void GetBoundSeeds(int& i, int& j); + static void GetBoundSeeds(const TreeType *tree,int& i, int& j); /** * Assign points to the two new nodes. 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 66b208480f..f315e3ca52 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 @@ -15,29 +15,25 @@ namespace mlpack { namespace tree { template -RTreeSplit::RTreeSplit() : - tree(NULL) +RTreeSplit::RTreeSplit() { } template -RTreeSplit::RTreeSplit(TreeType *node) : - tree(node) +RTreeSplit::RTreeSplit(const TreeType *) { } template -RTreeSplit::RTreeSplit(TreeType *node,const TreeType *) : - tree(node) +RTreeSplit::RTreeSplit(const TreeType *,const TreeType *) { } template -RTreeSplit::RTreeSplit(TreeType *node,const TreeType &) : - tree(node) +RTreeSplit::RTreeSplit(const TreeType &) { } @@ -49,7 +45,7 @@ RTreeSplit::RTreeSplit(TreeType *node,const TreeType &) : * new nodes into the tree, spliting the parent if necessary. */ template -void RTreeSplit::SplitLeafNode(std::vector& relevels) +void RTreeSplit::SplitLeafNode(TreeType *tree,std::vector& 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 @@ -63,7 +59,7 @@ void RTreeSplit::SplitLeafNode(std::vector& relevels) tree->NullifyData(); // Because this was a leaf node, numChildren must be 0. tree->Children()[(tree->NumChildren())++] = copy; - copy->Split().SplitLeafNode(relevels); + copy->Split().SplitLeafNode(copy,relevels); return; } @@ -74,7 +70,7 @@ void RTreeSplit::SplitLeafNode(std::vector& relevels) // rectangles, only points. We assume that the tree uses Euclidean Distance. int i = 0; int j = 0; - GetPointSeeds(i, j); + RTreeSplit::GetPointSeeds(tree,i, j); TreeType* treeOne = new TreeType(tree->Parent()); TreeType* treeTwo = new TreeType(tree->Parent()); @@ -94,7 +90,7 @@ void RTreeSplit::SplitLeafNode(std::vector& relevels) // just in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->Split().SplitNonLeafNode(relevels); + par->Split().SplitNonLeafNode(par,relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren()); assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren()); @@ -113,7 +109,7 @@ void RTreeSplit::SplitLeafNode(std::vector& relevels) * higher up the tree because they were already updated if necessary. */ template -bool RTreeSplit::SplitNonLeafNode(std::vector& relevels) +bool RTreeSplit::SplitNonLeafNode(TreeType *tree,std::vector& 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 @@ -126,13 +122,13 @@ bool RTreeSplit::SplitNonLeafNode(std::vector& relevels) tree->NumChildren() = 0; tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - copy->Split().SplitNonLeafNode(relevels); + copy->Split().SplitNonLeafNode(copy,relevels); return true; } int i = 0; int j = 0; - GetBoundSeeds(i, j); + RTreeSplit::GetBoundSeeds(tree,i, j); assert(i != j); @@ -159,7 +155,7 @@ bool RTreeSplit::SplitNonLeafNode(std::vector& relevels) assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->Split().SplitNonLeafNode(relevels); + par->Split().SplitNonLeafNode(par,relevels); // We have to update the children of each of these new nodes so that they // record the correct parent. @@ -185,7 +181,7 @@ bool RTreeSplit::SplitNonLeafNode(std::vector& relevels) * The indices of these points will be stored in iRet and jRet. */ template -void RTreeSplit::GetPointSeeds(int& iRet, int& jRet) +void RTreeSplit::GetPointSeeds(const TreeType *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 @@ -213,7 +209,7 @@ void RTreeSplit::GetPointSeeds(int& iRet, int& jRet) * indices of the bounds will be stored in iRet and jRet. */ template -void RTreeSplit::GetBoundSeeds(int& iRet, int& jRet) +void RTreeSplit::GetBoundSeeds(const TreeType *tree,int& iRet, int& jRet) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; 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 050c4b82f6..4e1526c901 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -160,7 +160,7 @@ RectangleTree( points(other.Points()), localDataset(NULL) { - split = SplitType(this,other); + split = SplitType(other); if (deepCopy) { if (numChildren > 0) @@ -671,7 +671,7 @@ void RectangleTree:: // 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. - split.SplitLeafNode(relevels); + split.SplitLeafNode(this,relevels); } else { @@ -681,7 +681,7 @@ void RectangleTree:: // 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. - split.SplitNonLeafNode(relevels); + split.SplitNonLeafNode(this,relevels); } } diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp index 66eee3fc35..3d112c615d 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp @@ -36,34 +36,28 @@ class XTreeSplit XTreeSplit(); //! Construct this with the specified node. - XTreeSplit(TreeType *node); - - //! Construct this with the specified node and the specified normalNodeMaxNumChildren. - XTreeSplit(TreeType *node,const size_t normalNodeMaxNumChildren); + XTreeSplit(const TreeType *node); //! Construct this with the specified node and the parent of the node. - XTreeSplit(TreeType *node,const TreeType *parentNode); + XTreeSplit(const TreeType *node,const TreeType *parentNode); //! Create a copy of the other.split. - XTreeSplit(TreeType *node,const TreeType &other); + XTreeSplit(const TreeType &other); /** * 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. */ - void SplitLeafNode(std::vector& relevels); + void SplitLeafNode(TreeType *tree,std::vector& relevels); /** * Split a non-leaf node using the "default" algorithm. If this is a root * node, the tree increases in depth. */ - bool SplitNonLeafNode(std::vector& relevels); + bool SplitNonLeafNode(TreeType *tree,std::vector& relevels); private: - //! The node which has to be split. - TreeType *tree; - //! The max number of child nodes a non-leaf normal node can have. size_t normalNodeMaxNumChildren; 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 index 3d99cf0553..b1929d0c67 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -16,40 +16,27 @@ namespace tree { template XTreeSplit::XTreeSplit() : - tree(NULL), normalNodeMaxNumChildren(0) { } template -XTreeSplit::XTreeSplit(TreeType *node) : - tree(node), +XTreeSplit::XTreeSplit(const TreeType *node) : normalNodeMaxNumChildren(node->MaxNumChildren()) { } - template -XTreeSplit::XTreeSplit(TreeType *node,const size_t normalNodeMaxNumChildren) : - tree(node), - normalNodeMaxNumChildren(normalNodeMaxNumChildren) -{ - -} - -template -XTreeSplit::XTreeSplit(TreeType *node,const TreeType *parent) : - tree(node), +XTreeSplit::XTreeSplit(const TreeType *,const TreeType *parent) : normalNodeMaxNumChildren(parent->Split().NormalNodeMaxNumChildren()) { } template -XTreeSplit::XTreeSplit(TreeType *node,const TreeType &other) : - tree(node), +XTreeSplit::XTreeSplit(const TreeType &other) : normalNodeMaxNumChildren(other.Split().NormalNodeMaxNumChildren()) { @@ -63,7 +50,7 @@ XTreeSplit::XTreeSplit(TreeType *node,const TreeType &other) : * new nodes into the tree, spliting the parent if necessary. */ template -void XTreeSplit::SplitLeafNode(std::vector& relevels) +void XTreeSplit::SplitLeafNode(TreeType *tree,std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -81,7 +68,7 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) // Because this was a leaf node, numChildren must be 0. tree->Children()[(tree->NumChildren())++] = copy; assert(tree->NumChildren() == 1); - copy->Split().SplitLeafNode(relevels); + copy->Split().SplitLeafNode(copy,relevels); return; } @@ -99,7 +86,7 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) size_t p = tree->MaxLeafSize() * 0.3; if (p == 0) { - tree->Split().SplitLeafNode(relevels); + tree->Split().SplitLeafNode(tree,relevels); return; } @@ -312,7 +299,7 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) // in case, we use an assert. assert(par->NumChildren() <= par->MaxNumChildren() + 1); if (par->NumChildren() == par->MaxNumChildren() + 1) - par->Split().SplitNonLeafNode(relevels); + par->Split().SplitNonLeafNode(par,relevels); assert(treeOne->Parent()->NumChildren() <= treeOne->Parent()->MaxNumChildren()); @@ -334,7 +321,7 @@ void XTreeSplit::SplitLeafNode(std::vector& relevels) * higher up the tree because they were already updated if necessary. */ template -bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) +bool XTreeSplit::SplitNonLeafNode(TreeType *tree,std::vector& relevels) { // Convenience typedef. typedef typename TreeType::ElemType ElemType; @@ -351,7 +338,7 @@ bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) tree->NumChildren() = 0; tree->NullifyData(); tree->Children()[(tree->NumChildren())++] = copy; - copy->Split().SplitNonLeafNode(relevels); + copy->Split().SplitNonLeafNode(copy,relevels); return true; } @@ -845,7 +832,7 @@ bool XTreeSplit::SplitNonLeafNode(std::vector& relevels) if (par->NumChildren() == par->MaxNumChildren() + 1) { - par->Split().SplitNonLeafNode(relevels); + par->Split().SplitNonLeafNode(par,relevels); } // We have to update the children of each of these new nodes so that they From 4208f38a73cb46f147602064eb13d32fb9aabe24 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Tue, 3 May 2016 20:41:03 +0300 Subject: [PATCH 16/17] Move splitHistory to XTreeSplit. Update serialization of the RectangleTree class. --- .../tree/rectangle_tree/r_star_tree_split.hpp | 7 +++ .../core/tree/rectangle_tree/r_tree_split.hpp | 8 +++ .../tree/rectangle_tree/rectangle_tree.hpp | 30 ----------- .../rectangle_tree/rectangle_tree_impl.hpp | 7 +-- .../core/tree/rectangle_tree/x_tree_split.hpp | 36 +++++++++++++ .../tree/rectangle_tree/x_tree_split_impl.hpp | 50 +++++++++++++------ 6 files changed, 86 insertions(+), 52 deletions(-) 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 index 908d6c2161..e3550ffa0b 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp @@ -72,6 +72,13 @@ class RStarTreeSplit * Insert a node into another node. */ static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode); + + public: + /** + * Serialize the split. + */ + template + void Serialize(Archive &, const unsigned int /* version */) { }; }; } // 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 ebb640c1f1..5312125b79 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp @@ -79,6 +79,14 @@ class RTreeSplit * Insert a node into another node. */ static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode); + + public: + /** + * Serialize the split. + */ + template + void Serialize(Archive &, const unsigned int /* version */) { }; + }; } // namespace tree diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp index 8e762f90d0..8432f44233 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp @@ -53,29 +53,6 @@ class RectangleTree //! The element type held by the matrix type. typedef typename MatType::elem_type ElemType; - /** - * The X tree requires that the tree records it's "split history". To make - * this easy, we use the following structure. - */ - typedef struct SplitHistoryStruct - { - int lastDimension; - std::vector history; - - SplitHistoryStruct(int dim) : lastDimension(0), history(dim) - { - for (int i = 0; i < dim; i++) - history[i] = false; - } - - template - void Serialize(Archive& ar, const unsigned int /* version */) - { - ar & data::CreateNVP(lastDimension, "lastDimension"); - ar & data::CreateNVP(history, "history"); - } - } SplitHistoryStruct; - private: //! The max number of child nodes a non-leaf node can have. size_t maxNumChildren; @@ -103,8 +80,6 @@ class RectangleTree bound::HRectBound bound; //! Any extra data contained in the node. StatisticType stat; - //! A struct to store the "split history" for X trees. - SplitHistoryStruct splitHistory; //! The distance from the centroid of this node to the centroid of the parent. ElemType parentDistance; //! The dataset. @@ -316,11 +291,6 @@ class RectangleTree //! Modify the statistic object for this node. StatisticType& Stat() { return stat; } - //! Return the split history object of this node. - const SplitHistoryStruct& SplitHistory() const { return splitHistory; } - //! Modify the split history object of this node. - SplitHistoryStruct& SplitHistory() { return splitHistory; } - //! Return the split object of this node. const SplitType& Split() const { return split; } //! Modify the split object of this node. 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 4e1526c901..67936491db 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -39,7 +39,6 @@ RectangleTree(const MatType& data, maxLeafSize(maxLeafSize), minLeafSize(minLeafSize), bound(data.n_rows), - splitHistory(bound.Dim()), parentDistance(0), dataset(new MatType(data)), ownsDataset(true), @@ -80,7 +79,6 @@ RectangleTree(MatType&& data, maxLeafSize(maxLeafSize), minLeafSize(minLeafSize), bound(data.n_rows), - splitHistory(bound.Dim()), parentDistance(0), dataset(new MatType(std::move(data))), ownsDataset(true), @@ -118,7 +116,6 @@ RectangleTree( maxLeafSize(parentNode->MaxLeafSize()), minLeafSize(parentNode->MinLeafSize()), bound(parentNode->Bound().Dim()), - splitHistory(bound.Dim()), parentDistance(0), dataset(&parentNode->Dataset()), ownsDataset(false), @@ -153,7 +150,6 @@ RectangleTree( maxLeafSize(other.MaxLeafSize()), minLeafSize(other.MinLeafSize()), bound(other.bound), - splitHistory(other.SplitHistory()), parentDistance(other.ParentDistance()), dataset(deepCopy ? new MatType(*other.dataset) : &other.Dataset()), ownsDataset(deepCopy), @@ -701,7 +697,6 @@ RectangleTree() : count(0), maxLeafSize(0), minLeafSize(0), - splitHistory(0), parentDistance(0.0), dataset(NULL), ownsDataset(false), @@ -1023,7 +1018,6 @@ void RectangleTree:: ar & CreateNVP(minLeafSize, "minLeafSize"); ar & CreateNVP(bound, "bound"); ar & CreateNVP(stat, "stat"); - ar & CreateNVP(splitHistory, "splitHistory"); ar & CreateNVP(parentDistance, "parentDistance"); ar & CreateNVP(dataset, "dataset"); @@ -1033,6 +1027,7 @@ void RectangleTree:: ar & CreateNVP(points, "points"); ar & CreateNVP(localDataset, "localDataset"); + ar & CreateNVP(split, "split"); // Because 'children' holds mlpack types (that have Serialize()), we can't use // the std::vector serialization. diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp index 3d112c615d..8d3e5d80d8 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp @@ -57,9 +57,34 @@ class XTreeSplit */ bool SplitNonLeafNode(TreeType *tree,std::vector& relevels); + /** + * The X tree requires that the tree records it's "split history". To make + * this easy, we use the following structure. + */ + typedef struct SplitHistoryStruct + { + int lastDimension; + std::vector history; + + SplitHistoryStruct(int dim) : lastDimension(0), history(dim) + { + for (int i = 0; i < dim; i++) + history[i] = false; + } + + template + void Serialize(Archive& ar, const unsigned int /* version */) + { + ar & data::CreateNVP(lastDimension, "lastDimension"); + ar & data::CreateNVP(history, "history"); + } + } SplitHistoryStruct; + private: //! The max number of child nodes a non-leaf normal node can have. size_t normalNodeMaxNumChildren; + //! A struct to store the "split history" for X trees. + SplitHistoryStruct splitHistory; /** * Class to allow for faster sorting. @@ -92,6 +117,17 @@ class XTreeSplit size_t NormalNodeMaxNumChildren() const { return normalNodeMaxNumChildren; } //! Modify the maximum number of a normal node's children. size_t& NormalNodeMaxNumChildren() { return normalNodeMaxNumChildren; } + //! Return the split history of the node assosiated with this object. + const SplitHistoryStruct& SplitHistory() const { return splitHistory; } + //! Modify the split history of the node assosiated with this object. + SplitHistoryStruct& SplitHistory() { return splitHistory; } + + + /** + * Serialize the split. + */ + template + void Serialize(Archive& ar, const unsigned int /* version */); }; } // namespace tree 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 index b1929d0c67..1bde106c71 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -16,28 +16,32 @@ namespace tree { template XTreeSplit::XTreeSplit() : - normalNodeMaxNumChildren(0) + normalNodeMaxNumChildren(0), + splitHistory(0) { } template XTreeSplit::XTreeSplit(const TreeType *node) : - normalNodeMaxNumChildren(node->MaxNumChildren()) + normalNodeMaxNumChildren(node->MaxNumChildren()), + splitHistory(node->Bound().Dim()) { } template -XTreeSplit::XTreeSplit(const TreeType *,const TreeType *parent) : - normalNodeMaxNumChildren(parent->Split().NormalNodeMaxNumChildren()) +XTreeSplit::XTreeSplit(const TreeType *node,const TreeType *parent) : + normalNodeMaxNumChildren(parent->Split().NormalNodeMaxNumChildren()), + splitHistory(node->Bound().Dim()) { } template XTreeSplit::XTreeSplit(const TreeType &other) : - normalNodeMaxNumChildren(other.Split().NormalNodeMaxNumChildren()) + normalNodeMaxNumChildren(other.Split().NormalNodeMaxNumChildren()), + splitHistory(other.Split().SplitHistory()) { } @@ -290,10 +294,10 @@ void XTreeSplit::SplitLeafNode(TreeType *tree,std::vector& relev par->Children()[par->NumChildren()++] = treeTwo; // We now update the split history of each new node. - treeOne->SplitHistory().history[bestAxis] = true; - treeOne->SplitHistory().lastDimension = bestAxis; - treeTwo->SplitHistory().history[bestAxis] = true; - treeTwo->SplitHistory().lastDimension = bestAxis; + treeOne->Split().SplitHistory().history[bestAxis] = true; + treeOne->Split().SplitHistory().lastDimension = bestAxis; + treeTwo->Split().SplitHistory().history[bestAxis] = true; + treeTwo->Split().SplitHistory().lastDimension = bestAxis; // We only add one at a time, so we should only need to test for equality just // in case, we use an assert. @@ -353,7 +357,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType *tree,std::vector& re std::vector axes(tree->Bound().Dim()); std::vector dimensionsLastUsed(tree->NumChildren()); for (size_t i = 0; i < tree->NumChildren(); i++) - dimensionsLastUsed[i] = tree->Child(i).SplitHistory().lastDimension; + dimensionsLastUsed[i] = tree->Child(i).Split().SplitHistory().lastDimension; std::sort(dimensionsLastUsed.begin(), dimensionsLastUsed.end()); size_t lastDim = dimensionsLastUsed[dimensionsLastUsed.size()/2]; @@ -364,7 +368,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType *tree,std::vector& re { axes[i] = true; for (size_t j = 0; j < tree->NumChildren(); j++) - axes[i] = axes[i] & tree->Child(j).SplitHistory().history[i]; + axes[i] = axes[i] & tree->Child(j).Split().SplitHistory().history[i]; if (axes[i] == true) { minOverlapSplitDimension = i; @@ -377,7 +381,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType *tree,std::vector& re { axes[i] = true; for (size_t j = 0; j < tree->NumChildren(); j++) - axes[i] = axes[i] & tree->Child(j).SplitHistory().history[i]; + axes[i] = axes[i] & tree->Child(j).Split().SplitHistory().history[i]; if (axes[i] == true) { minOverlapSplitDimension = i; @@ -802,10 +806,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType *tree,std::vector& re } // Update the split history of each child. - treeOne->SplitHistory().history[bestAxis] = true; - treeOne->SplitHistory().lastDimension = bestAxis; - treeTwo->SplitHistory().history[bestAxis] = true; - treeTwo->SplitHistory().lastDimension = bestAxis; + treeOne->Split().SplitHistory().history[bestAxis] = true; + treeOne->Split().SplitHistory().lastDimension = bestAxis; + treeTwo->Split().SplitHistory().history[bestAxis] = true; + treeTwo->Split().SplitHistory().lastDimension = bestAxis; // Remove this node and insert treeOne and treeTwo TreeType* par = tree->Parent(); @@ -868,6 +872,20 @@ void XTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcN destTree->NumChildren()++; } +/** + * Serialize the split. + */ +template +template +void XTreeSplit::Serialize(Archive& ar,const unsigned int /* version */) +{ + using data::CreateNVP; + + ar & CreateNVP(normalNodeMaxNumChildren, "normalNodeMaxNumChildren"); + ar & CreateNVP(splitHistory, "splitHistory"); + +} + } // namespace tree } // namespace mlpack From 019680f96d86eecf70b675a617db23a6eacc5e5a Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Tue, 3 May 2016 23:17:08 +0300 Subject: [PATCH 17/17] Combine SplitType's constructors. --- .../core/tree/rectangle_tree/r_star_tree_split.hpp | 3 --- .../tree/rectangle_tree/r_star_tree_split_impl.hpp | 6 ------ src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp | 3 --- .../core/tree/rectangle_tree/r_tree_split_impl.hpp | 6 ------ .../core/tree/rectangle_tree/rectangle_tree_impl.hpp | 2 +- src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp | 3 --- .../core/tree/rectangle_tree/x_tree_split_impl.hpp | 12 +++--------- 7 files changed, 4 insertions(+), 31 deletions(-) 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 index e3550ffa0b..d17abf64f4 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_star_tree_split.hpp @@ -28,9 +28,6 @@ class RStarTreeSplit //! Construct this with the specified node. RStarTreeSplit(const TreeType *node); - //! Construct this with the specified node and the parent of the node. - RStarTreeSplit(const TreeType *node,const TreeType *parentNode); - //! Create a copy of the other.split. RStarTreeSplit(const TreeType &other); 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 index f233ff7494..49adbe8377 100644 --- 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 @@ -27,12 +27,6 @@ RStarTreeSplit::RStarTreeSplit(const TreeType *) } -template -RStarTreeSplit::RStarTreeSplit(const TreeType *,const TreeType *) -{ - -} - template RStarTreeSplit::RStarTreeSplit(const TreeType &) { 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 5312125b79..a77308a9a7 100644 --- a/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/r_tree_split.hpp @@ -28,9 +28,6 @@ class RTreeSplit //! Construct this with the specified node. RTreeSplit(const TreeType *node); - //! Construct this with the specified node and the parent of the node. - RTreeSplit(const TreeType *node,const TreeType *parentNode); - //! Create a copy of the other.split. RTreeSplit(const TreeType &other); 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 f315e3ca52..442e49f7ed 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 @@ -26,12 +26,6 @@ RTreeSplit::RTreeSplit(const TreeType *) } -template -RTreeSplit::RTreeSplit(const TreeType *,const TreeType *) -{ - -} - template RTreeSplit::RTreeSplit(const TreeType &) { 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 67936491db..8184f89c06 100644 --- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp @@ -124,7 +124,7 @@ RectangleTree( maxLeafSize + 1))) { stat = StatisticType(*this); - split = SplitType(this,parentNode); + split = SplitType(this); } /** diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp index 8d3e5d80d8..7b120a9086 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split.hpp @@ -38,9 +38,6 @@ class XTreeSplit //! Construct this with the specified node. XTreeSplit(const TreeType *node); - //! Construct this with the specified node and the parent of the node. - XTreeSplit(const TreeType *node,const TreeType *parentNode); - //! Create a copy of the other.split. XTreeSplit(const TreeType &other); 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 index 1bde106c71..a619b725a5 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -24,15 +24,9 @@ XTreeSplit::XTreeSplit() : template XTreeSplit::XTreeSplit(const TreeType *node) : - normalNodeMaxNumChildren(node->MaxNumChildren()), - splitHistory(node->Bound().Dim()) -{ - -} - -template -XTreeSplit::XTreeSplit(const TreeType *node,const TreeType *parent) : - normalNodeMaxNumChildren(parent->Split().NormalNodeMaxNumChildren()), + normalNodeMaxNumChildren(node->Parent() ? + node->Parent()->Split().NormalNodeMaxNumChildren() : + node->MaxNumChildren()), splitHistory(node->Bound().Dim()) {