Merge pull request #556 from lozhnikov/master

Bugfix #350 and some fixes in RStarTreeSplit and XTreeSplit
This commit is contained in:
Ryan Curtin
2016-05-04 11:04:51 -04:00
30 changed files with 597 additions and 282 deletions
@@ -19,7 +19,7 @@ namespace tree {
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename RuleType>
class RectangleTree<MetricType, StatisticType, MatType, SplitType,
@@ -20,7 +20,7 @@ namespace tree {
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename RuleType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
@@ -35,7 +35,7 @@ DualTreeTraverser<RuleType>::DualTreeTraverser(RuleType& rule) :
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename RuleType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
@@ -18,23 +18,31 @@ namespace tree /** Trees and tree-building procedures. */ {
* nodes overflow, we split them, moving up the tree and splitting nodes
* as necessary.
*/
template <typename TreeType>
class RStarTreeSplit
{
public:
//! Default constructor
RStarTreeSplit();
//! Construct this with the specified node.
RStarTreeSplit(const TreeType *node);
//! Create a copy of the other.split.
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.
*/
template<typename TreeType>
static void SplitLeafNode(TreeType* tree, std::vector<bool>& relevels);
void SplitLeafNode(TreeType *tree,std::vector<bool>& relevels);
/**
* Split a non-leaf node using the "default" algorithm. If this is a root
* node, the tree increases in depth.
*/
template<typename TreeType>
static bool SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels);
bool SplitNonLeafNode(TreeType *tree,std::vector<bool>& relevels);
private:
/**
@@ -60,8 +68,14 @@ class RStarTreeSplit
/**
* Insert a node into another node.
*/
template<typename TreeType>
static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode);
public:
/**
* Serialize the split.
*/
template<typename Archive>
void Serialize(Archive &, const unsigned int /* version */) { };
};
} // namespace tree
@@ -15,6 +15,25 @@
namespace mlpack {
namespace tree {
template<typename TreeType>
RStarTreeSplit<TreeType>::RStarTreeSplit()
{
}
template<typename TreeType>
RStarTreeSplit<TreeType>::RStarTreeSplit(const TreeType *)
{
}
template<typename TreeType>
RStarTreeSplit<TreeType>::RStarTreeSplit(const TreeType &)
{
}
/**
* 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 +41,7 @@ namespace tree {
* new nodes into the tree, spliting the parent if necessary.
*/
template<typename TreeType>
void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
void RStarTreeSplit<TreeType>::SplitLeafNode(TreeType *tree,std::vector<bool>& relevels)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
@@ -41,7 +60,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
tree->Children()[(tree->NumChildren())++] = copy;
assert(tree->NumChildren() == 1);
SplitLeafNode(copy, relevels);
copy->Split().SplitLeafNode(copy,relevels);
return;
}
@@ -58,7 +77,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
size_t p = tree->MaxLeafSize() * 0.3; // The paper says this works the best.
if (p == 0)
{
SplitLeafNode(tree, relevels);
tree->Split().SplitLeafNode(tree,relevels);
return;
}
@@ -95,7 +114,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
int bestAreaIndexOnBestAxis = 0;
bool tiedOnOverlap = false;
int bestAxis = 0;
ElemType bestAxisScore = DBL_MAX;
ElemType bestAxisScore = std::numeric_limits<ElemType>::max();
for (size_t j = 0; j < tree->Bound().Dim(); j++)
{
@@ -251,7 +270,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
// just in case, we use an assert.
assert(par->NumChildren() <= par->MaxNumChildren() + 1);
if (par->NumChildren() == par->MaxNumChildren() + 1)
SplitNonLeafNode(par, relevels);
par->Split().SplitNonLeafNode(par,relevels);
assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren());
assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren());
@@ -269,8 +288,7 @@ void RStarTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
* higher up the tree because they were already updated if necessary.
*/
template<typename TreeType>
bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree,
std::vector<bool>& relevels)
bool RStarTreeSplit<TreeType>::SplitNonLeafNode(TreeType *tree,std::vector<bool>& relevels)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
@@ -288,7 +306,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree,
tree->NullifyData();
tree->Children()[(tree->NumChildren())++] = copy;
SplitNonLeafNode(copy, relevels);
copy->Split().SplitNonLeafNode(copy,relevels);
return true;
}
@@ -359,7 +377,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree,
bool tiedOnOverlap = false;
bool lowIsBest = true;
int bestAxis = 0;
ElemType bestAxisScore = DBL_MAX;
ElemType bestAxisScore = std::numeric_limits<ElemType>::max();
for (size_t j = 0; j < tree->Bound().Dim(); j++)
{
ElemType axisScore = 0.0;
@@ -450,8 +468,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 +583,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++)
{
@@ -644,7 +662,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree,
assert(par->NumChildren() <= par->MaxNumChildren() + 1);
if (par->NumChildren() == par->MaxNumChildren() + 1)
{
SplitNonLeafNode(par, relevels);
par->Split().SplitNonLeafNode(par,relevels);
}
// We have to update the children of each of these new nodes so that they
@@ -673,7 +691,7 @@ bool RStarTreeSplit::SplitNonLeafNode(TreeType* tree,
* numberOfChildren.
*/
template<typename TreeType>
void RStarTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode)
void RStarTreeSplit<TreeType>::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode)
{
destTree->Bound() |= srcNode->Bound();
destTree->Children()[destTree->NumChildren()++] = srcNode;
@@ -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<ElemType>::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<ElemType>::max();
int bestIndex = 0;
ElemType bestVol = 0.0;
@@ -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<typename TreeType>
class RTreeSplit
{
public:
//! Default constructor
RTreeSplit();
//! Construct this with the specified node.
RTreeSplit(const TreeType *node);
//! Create a copy of the other.split.
RTreeSplit(const TreeType &other);
/**
* Split a leaf node using the "default" algorithm. If necessary, this split
* will propagate upwards through the tree.
*/
template<typename TreeType>
static void SplitLeafNode(TreeType* tree,
std::vector<bool>& relevels);
void SplitLeafNode(TreeType *tree,std::vector<bool>& relevels);
/**
* Split a non-leaf node using the "default" algorithm. If this is a root
* node, the tree increases in depth.
*/
template<typename TreeType>
static bool SplitNonLeafNode(TreeType* tree,
std::vector<bool>& relevels);
bool SplitNonLeafNode(TreeType *tree,std::vector<bool>& relevels);
private:
/**
* Get the seeds for splitting a leaf node.
*/
template<typename TreeType>
static void GetPointSeeds(const TreeType& tree, int& i, int& j);
static void GetPointSeeds(const TreeType *tree,int& i, int& j);
/**
* Get the seeds for splitting a non-leaf node.
*/
template<typename TreeType>
static void GetBoundSeeds(const TreeType& tree, int& i, int& j);
static void GetBoundSeeds(const TreeType *tree,int& i, int& j);
/**
* Assign points to the two new nodes.
*/
template<typename TreeType>
static void AssignPointDestNode(TreeType* oldTree,
TreeType* treeOne,
TreeType* treeTwo,
@@ -63,7 +66,6 @@ class RTreeSplit
/**
* Assign nodes to the two new nodes.
*/
template<typename TreeType>
static void AssignNodeDestNode(TreeType* oldTree,
TreeType* treeOne,
TreeType* treeTwo,
@@ -73,8 +75,15 @@ class RTreeSplit
/**
* Insert a node into another node.
*/
template<typename TreeType>
static void InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode);
public:
/**
* Serialize the split.
*/
template<typename Archive>
void Serialize(Archive &, const unsigned int /* version */) { };
};
} // namespace tree
@@ -14,6 +14,24 @@
namespace mlpack {
namespace tree {
template<typename TreeType>
RTreeSplit<TreeType>::RTreeSplit()
{
}
template<typename TreeType>
RTreeSplit<TreeType>::RTreeSplit(const TreeType *)
{
}
template<typename TreeType>
RTreeSplit<TreeType>::RTreeSplit(const TreeType &)
{
}
/**
* 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 +39,7 @@ namespace tree {
* new nodes into the tree, spliting the parent if necessary.
*/
template<typename TreeType>
void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
void RTreeSplit<TreeType>::SplitLeafNode(TreeType *tree,std::vector<bool>& relevels)
{
// If we are splitting the root node, we need will do things differently so
// that the constructor and other methods don't confuse the end user by giving
@@ -35,7 +53,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
tree->NullifyData();
// Because this was a leaf node, numChildren must be 0.
tree->Children()[(tree->NumChildren())++] = copy;
SplitLeafNode(copy, relevels);
copy->Split().SplitLeafNode(copy,relevels);
return;
}
@@ -46,7 +64,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
// rectangles, only points. We assume that the tree uses Euclidean Distance.
int i = 0;
int j = 0;
GetPointSeeds(*tree, i, j);
RTreeSplit<TreeType>::GetPointSeeds(tree,i, j);
TreeType* treeOne = new TreeType(tree->Parent());
TreeType* treeTwo = new TreeType(tree->Parent());
@@ -66,7 +84,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
// just in case, we use an assert.
assert(par->NumChildren() <= par->MaxNumChildren() + 1);
if (par->NumChildren() == par->MaxNumChildren() + 1)
SplitNonLeafNode(par, relevels);
par->Split().SplitNonLeafNode(par,relevels);
assert(treeOne->Parent()->NumChildren() <= treeOne->MaxNumChildren());
assert(treeOne->Parent()->NumChildren() >= treeOne->MinNumChildren());
@@ -85,7 +103,7 @@ void RTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
* higher up the tree because they were already updated if necessary.
*/
template<typename TreeType>
bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
bool RTreeSplit<TreeType>::SplitNonLeafNode(TreeType *tree,std::vector<bool>& relevels)
{
// If we are splitting the root node, we need will do things differently so
// that the constructor and other methods don't confuse the end user by giving
@@ -98,13 +116,13 @@ bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
tree->NumChildren() = 0;
tree->NullifyData();
tree->Children()[(tree->NumChildren())++] = copy;
SplitNonLeafNode(copy, relevels);
copy->Split().SplitNonLeafNode(copy,relevels);
return true;
}
int i = 0;
int j = 0;
GetBoundSeeds(*tree, i, j);
RTreeSplit<TreeType>::GetBoundSeeds(tree,i, j);
assert(i != j);
@@ -131,7 +149,7 @@ bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
assert(par->NumChildren() <= par->MaxNumChildren() + 1);
if (par->NumChildren() == par->MaxNumChildren() + 1)
SplitNonLeafNode(par, 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.
@@ -157,18 +175,18 @@ bool RTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
* The indices of these points will be stored in iRet and jRet.
*/
template<typename TreeType>
void RTreeSplit::GetPointSeeds(const TreeType& tree, int& iRet, int& jRet)
void RTreeSplit<TreeType>::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
// 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 +203,23 @@ void RTreeSplit::GetPointSeeds(const TreeType& tree, int& iRet, int& jRet)
* indices of the bounds will be stored in iRet and jRet.
*/
template<typename TreeType>
void RTreeSplit::GetBoundSeeds(const TreeType& tree, int& iRet, int& jRet)
void RTreeSplit<TreeType>::GetBoundSeeds(const TreeType *tree,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 +234,7 @@ void RTreeSplit::GetBoundSeeds(const TreeType& tree, int& iRet, int& jRet)
}
template<typename TreeType>
void RTreeSplit::AssignPointDestNode(TreeType* oldTree,
void RTreeSplit<TreeType>::AssignPointDestNode(TreeType* oldTree,
TreeType* treeOne,
TreeType* treeTwo,
const int intI,
@@ -270,7 +288,7 @@ void RTreeSplit::AssignPointDestNode(TreeType* oldTree,
std::min(numAssignedOne, numAssignedTwo)))
{
int bestIndex = 0;
ElemType bestScore = DBL_MAX;
ElemType bestScore = std::numeric_limits<ElemType>::max();
int bestRect = 1;
// Calculate the increase in volume for assigning this point to each
@@ -357,7 +375,7 @@ void RTreeSplit::AssignPointDestNode(TreeType* oldTree,
}
template<typename TreeType>
void RTreeSplit::AssignNodeDestNode(TreeType* oldTree,
void RTreeSplit<TreeType>::AssignNodeDestNode(TreeType* oldTree,
TreeType* treeOne,
TreeType* treeTwo,
const int intI,
@@ -414,7 +432,7 @@ void RTreeSplit::AssignNodeDestNode(TreeType* oldTree,
std::min(numAssignTreeOne, numAssignTreeTwo)))
{
int bestIndex = 0;
ElemType bestScore = DBL_MAX;
ElemType bestScore = std::numeric_limits<ElemType>::max();
int bestRect = 0;
// Calculate the increase in volume for assigning this node to each of the
@@ -522,7 +540,7 @@ void RTreeSplit::AssignNodeDestNode(TreeType* oldTree,
* numberOfChildren.
*/
template<typename TreeType>
void RTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode)
void RTreeSplit<TreeType>::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode)
{
destTree->Bound() |= srcNode->Bound();
destTree->Children()[destTree->NumChildren()++] = srcNode;
@@ -35,10 +35,11 @@ namespace tree /** Trees and tree-building procedures. */ {
* @tparam DescentType The heuristic to use when descending the tree to insert
* points.
*/
template<typename MetricType = metric::EuclideanDistance,
typename StatisticType = EmptyStatistic,
typename MatType = arma::mat,
typename SplitType = RTreeSplit,
template<typename> class SplitType = RTreeSplit,
typename DescentType = RTreeDescentHeuristic>
class RectangleTree
{
@@ -52,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<bool> history;
SplitHistoryStruct(int dim) : lastDimension(0), history(dim)
{
for (int i = 0; i < dim; i++)
history[i] = false;
}
template<typename Archive>
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;
@@ -102,8 +80,6 @@ class RectangleTree
bound::HRectBound<metric::EuclideanDistance, ElemType> 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.
@@ -115,6 +91,8 @@ class RectangleTree
std::vector<size_t> points;
//! The local dataset
MatType* localDataset;
//! The class that performs the split of the node.
SplitType<RectangleTree> split;
public:
//! A single traverser for rectangle type trees. See
@@ -173,8 +151,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
@@ -311,10 +291,10 @@ 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<RectangleTree>& Split() const { return split; }
//! Modify the split object of this node.
SplitType<RectangleTree>& Split() { return split; }
//! Return whether or not this node is a leaf (true if it has no children).
bool IsLeaf() const;
@@ -20,7 +20,7 @@ namespace tree {
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
RectangleTree(const MatType& data,
@@ -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),
@@ -49,6 +48,8 @@ RectangleTree(const MatType& data,
{
stat = StatisticType(*this);
split = SplitType<RectangleTree>(this);
// For now, just insert the points in order.
RectangleTree* root = this;
@@ -59,7 +60,7 @@ RectangleTree(const MatType& data,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
RectangleTree(MatType&& data,
@@ -78,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),
@@ -88,6 +88,8 @@ RectangleTree(MatType&& data,
{
stat = StatisticType(*this);
split = SplitType<RectangleTree>(this);
// For now, just insert the points in order.
RectangleTree* root = this;
@@ -98,13 +100,13 @@ RectangleTree(MatType&& data,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
RectangleTree(
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>*
parentNode) :
maxNumChildren(parentNode->MaxNumChildren()),
parentNode,const size_t numMaxChildren) :
maxNumChildren(numMaxChildren > 0 ? numMaxChildren : parentNode->MaxNumChildren()),
minNumChildren(parentNode->MinNumChildren()),
numChildren(0),
children(maxNumChildren + 1),
@@ -114,7 +116,6 @@ RectangleTree(
maxLeafSize(parentNode->MaxLeafSize()),
minLeafSize(parentNode->MinLeafSize()),
bound(parentNode->Bound().Dim()),
splitHistory(bound.Dim()),
parentDistance(0),
dataset(&parentNode->Dataset()),
ownsDataset(false),
@@ -123,6 +124,7 @@ RectangleTree(
maxLeafSize + 1)))
{
stat = StatisticType(*this);
split = SplitType<RectangleTree>(this);
}
/**
@@ -132,7 +134,7 @@ RectangleTree(
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
RectangleTree(
@@ -148,13 +150,13 @@ RectangleTree(
maxLeafSize(other.MaxLeafSize()),
minLeafSize(other.MinLeafSize()),
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)
{
split = SplitType<RectangleTree>(other);
if (deepCopy)
{
if (numChildren > 0)
@@ -183,7 +185,7 @@ RectangleTree(
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename Archive>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
@@ -204,7 +206,7 @@ RectangleTree(
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
~RectangleTree()
@@ -225,7 +227,7 @@ RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
SoftDelete()
@@ -245,7 +247,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
NullifyData()
@@ -260,7 +262,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
InsertPoint(const size_t point)
@@ -297,7 +299,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
InsertPoint(const size_t point, std::vector<bool>& relevels)
@@ -332,7 +334,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
InsertNode(RectangleTree* node,
@@ -361,7 +363,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
DeletePoint(const size_t point)
@@ -406,7 +408,7 @@ bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
DeletePoint(const size_t point, std::vector<bool>& relevels)
@@ -441,7 +443,7 @@ bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
RemoveNode(const RectangleTree* node, std::vector<bool>& relevels)
@@ -470,7 +472,7 @@ bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>::TreeSize() const
@@ -485,7 +487,7 @@ size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>::TreeDepth() const
@@ -505,7 +507,7 @@ size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
inline bool RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>::IsLeaf() const
@@ -520,7 +522,7 @@ inline bool RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
inline
typename RectangleTree<MetricType, StatisticType, MatType, SplitType,
@@ -545,7 +547,7 @@ RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
inline
typename RectangleTree<MetricType, StatisticType, MatType, SplitType,
@@ -564,7 +566,7 @@ RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>::NumPoints() const
@@ -581,7 +583,7 @@ inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>::NumDescendants() const
@@ -605,7 +607,7 @@ inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>::Descendant(const size_t index) const
@@ -637,7 +639,7 @@ inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>::Point(const size_t index) const
@@ -652,7 +654,7 @@ inline size_t RectangleTree<MetricType, StatisticType, MatType, SplitType,
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
SplitNode(std::vector<bool>& relevels)
@@ -665,7 +667,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
// 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(this,relevels);
}
else
{
@@ -675,7 +677,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
// 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(this,relevels);
}
}
@@ -683,7 +685,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
RectangleTree() :
@@ -695,7 +697,6 @@ RectangleTree() :
count(0),
maxLeafSize(0),
minLeafSize(0),
splitHistory(0),
parentDistance(0.0),
dataset(NULL),
ownsDataset(false),
@@ -711,7 +712,7 @@ RectangleTree() :
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
CondenseTree(const arma::vec& point,
@@ -799,6 +800,14 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
{
// 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;
@@ -814,7 +823,6 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
}
count = child->Count();
maxNumChildren = child->MaxNumChildren(); // Required for the X tree.
child->SoftDelete();
return;
}
@@ -833,7 +841,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
ShrinkBoundForPoint(const arma::vec& point)
@@ -929,7 +937,7 @@ bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
ShrinkBoundForBound(const bound::HRectBound<MetricType>& /* b */)
@@ -963,7 +971,7 @@ bool RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename Archive>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
@@ -1010,7 +1018,6 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
ar & CreateNVP(minLeafSize, "minLeafSize");
ar & CreateNVP(bound, "bound");
ar & CreateNVP(stat, "stat");
ar & CreateNVP(splitHistory, "splitHistory");
ar & CreateNVP(parentDistance, "parentDistance");
ar & CreateNVP(dataset, "dataset");
@@ -1020,6 +1027,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
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.
@@ -19,7 +19,7 @@ namespace tree {
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename RuleType>
class RectangleTree<MetricType, StatisticType, MatType, SplitType,
@@ -20,7 +20,7 @@ namespace tree {
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename RuleType>
RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
@@ -32,7 +32,7 @@ SingleTreeTraverser<RuleType>::SingleTreeTraverser(RuleType& rule) :
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
template<typename RuleType>
void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType>::
@@ -21,7 +21,7 @@ namespace tree {
template<typename MetricType,
typename StatisticType,
typename MatType,
typename SplitType,
template<typename> class SplitType,
typename DescentType>
class TreeTraits<RectangleTree<MetricType, StatisticType, MatType, SplitType,
DescentType>>
@@ -68,15 +68,29 @@ using RStarTree = RectangleTree<MetricType,
RStarTreeDescentHeuristic>;
/**
* 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<typename MetricType, typename StatisticType, typename MatType>
//using XTree = RectangleTree<MetricType,
// StatisticType,
// MatType,
// XTreeSplit,
// XTreeDescentHeuristic>;
template<typename MetricType, typename StatisticType, typename MatType>
using XTree = RectangleTree<MetricType,
StatisticType,
MatType,
XTreeSplit,
RTreeDescentHeuristic>;
} // namespace tree
} // namespace mlpack
@@ -28,39 +28,78 @@ const double MAX_OVERLAP = 0.2;
* nodes overflow, we split them, moving up the tree and splitting nodes
* as necessary.
*/
template<typename TreeType>
class XTreeSplit
{
public:
//! Default constructor
XTreeSplit();
//! Construct this with the specified node.
XTreeSplit(const TreeType *node);
//! Create a copy of the other.split.
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.
*/
template<typename TreeType>
static void SplitLeafNode(TreeType* tree, std::vector<bool>& relevels);
void SplitLeafNode(TreeType *tree,std::vector<bool>& relevels);
/**
* Split a non-leaf node using the "default" algorithm. If this is a root
* node, the tree increases in depth.
*/
template<typename TreeType>
static bool SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels);
bool SplitNonLeafNode(TreeType *tree,std::vector<bool>& 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<bool> history;
SplitHistoryStruct(int dim) : lastDimension(0), history(dim)
{
for (int i = 0; i < dim; i++)
history[i] = false;
}
template<typename Archive>
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.
*/
template<typename ElemType>
class sortStruct
{
public:
double d;
ElemType d;
int n;
};
/**
* Comparator for sorting with sortStruct.
*/
static bool structComp(const sortStruct& s1, const sortStruct& s2)
template<typename ElemType>
static bool structComp(const sortStruct<ElemType>& s1,
const sortStruct<ElemType>& s2)
{
return s1.d < s2.d;
}
@@ -68,8 +107,24 @@ class XTreeSplit
/**
* Insert a node into another node.
*/
template<typename TreeType>
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; }
//! 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<typename Archive>
void Serialize(Archive& ar, const unsigned int /* version */);
};
} // namespace tree
@@ -14,6 +14,33 @@
namespace mlpack {
namespace tree {
template<typename TreeType>
XTreeSplit<TreeType>::XTreeSplit() :
normalNodeMaxNumChildren(0),
splitHistory(0)
{
}
template<typename TreeType>
XTreeSplit<TreeType>::XTreeSplit(const TreeType *node) :
normalNodeMaxNumChildren(node->Parent() ?
node->Parent()->Split().NormalNodeMaxNumChildren() :
node->MaxNumChildren()),
splitHistory(node->Bound().Dim())
{
}
template<typename TreeType>
XTreeSplit<TreeType>::XTreeSplit(const TreeType &other) :
normalNodeMaxNumChildren(other.Split().NormalNodeMaxNumChildren()),
splitHistory(other.Split().SplitHistory())
{
}
/**
* 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,8 +48,11 @@ namespace tree {
* new nodes into the tree, spliting the parent if necessary.
*/
template<typename TreeType>
void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
void XTreeSplit<TreeType>::SplitLeafNode(TreeType *tree,std::vector<bool>& 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.
@@ -36,7 +66,7 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& 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->Split().SplitLeafNode(copy,relevels);
return;
}
@@ -54,21 +84,21 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
size_t p = tree->MaxLeafSize() * 0.3;
if (p == 0)
{
SplitLeafNode(tree, relevels);
tree->Split().SplitLeafNode(tree,relevels);
return;
}
std::vector<sortStruct> sorted(tree->Count());
arma::vec center;
std::vector<sortStruct<ElemType>> sorted(tree->Count());
arma::Col<ElemType> center;
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;
}
std::sort(sorted.begin(), sorted.end(), structComp);
std::sort(sorted.begin(), sorted.end(), structComp<ElemType>);
std::vector<int> pointIndices(p);
for (size_t i = 0; i < p; i++)
{
@@ -103,25 +133,25 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
int bestAreaIndexOnBestAxis = 0;
bool tiedOnOverlap = false;
int bestAxis = 0;
double bestAxisScore = DBL_MAX;
ElemType bestAxisScore = std::numeric_limits<ElemType>::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<sortStruct> sorted(tree->Count());
std::vector<sortStruct<ElemType>> 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<ElemType>);
// We'll store each of the three scores for each distribution.
std::vector<double> areas(tree->MaxLeafSize() -
std::vector<ElemType> areas(tree->MaxLeafSize() -
2 * tree->MinLeafSize() + 2);
std::vector<double> margins(tree->MaxLeafSize() -
std::vector<ElemType> margins(tree->MaxLeafSize() -
2 * tree->MinLeafSize() + 2);
std::vector<double> overlapedAreas(tree->MaxLeafSize() -
std::vector<ElemType> overlapedAreas(tree->MaxLeafSize() -
2 * tree->MinLeafSize() + 2);
for (size_t i = 0; i < areas.size(); i++)
{
@@ -137,10 +167,10 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
size_t cutOff = tree->MinLeafSize() + i;
// We'll calculate the max and min in each dimension by hand to save time.
std::vector<double> maxG1(tree->Bound().Dim());
std::vector<double> minG1(maxG1.size());
std::vector<double> maxG2(maxG1.size());
std::vector<double> minG2(maxG1.size());
std::vector<ElemType> maxG1(tree->Bound().Dim());
std::vector<ElemType> minG1(maxG1.size());
std::vector<ElemType> maxG2(maxG1.size());
std::vector<ElemType> 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 +196,8 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& 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,17 +236,17 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
}
}
std::vector<sortStruct> sorted(tree->Count());
std::vector<sortStruct<ElemType>> 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<ElemType>);
TreeType* treeOne = new TreeType(tree->Parent());
TreeType* treeTwo = new TreeType(tree->Parent());
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
@@ -258,16 +288,16 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
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.
assert(par->NumChildren() <= par->MaxNumChildren() + 1);
if (par->NumChildren() == par->MaxNumChildren() + 1)
SplitNonLeafNode(par, relevels);
par->Split().SplitNonLeafNode(par,relevels);
assert(treeOne->Parent()->NumChildren() <=
treeOne->Parent()->MaxNumChildren());
@@ -289,8 +319,11 @@ void XTreeSplit::SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
* higher up the tree because they were already updated if necessary.
*/
template<typename TreeType>
bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
bool XTreeSplit<TreeType>::SplitNonLeafNode(TreeType *tree,std::vector<bool>& 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.
@@ -303,7 +336,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
tree->NumChildren() = 0;
tree->NullifyData();
tree->Children()[(tree->NumChildren())++] = copy;
XTreeSplit::SplitNonLeafNode(copy, relevels);
copy->Split().SplitNonLeafNode(copy,relevels);
return true;
}
@@ -318,7 +351,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
std::vector<bool> axes(tree->Bound().Dim());
std::vector<int> 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];
@@ -329,7 +362,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
{
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;
@@ -342,7 +375,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
{
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;
@@ -352,8 +385,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
}
bool minOverlapSplitUsesHi = false;
double bestScoreMinOverlapSplit = DBL_MAX;
double areaOfBestMinOverlapSplit = 0;
ElemType bestScoreMinOverlapSplit = std::numeric_limits<ElemType>::max();
ElemType areaOfBestMinOverlapSplit = 0;
int bestIndexMinOverlapSplit = 0;
int bestOverlapIndexOnBestAxis = 0;
@@ -361,32 +394,32 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& 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 = std::numeric_limits<ElemType>::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<sortStruct> sorted(tree->NumChildren());
std::vector<sortStruct<ElemType>> 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<ElemType>);
// We'll store each of the three scores for each distribution.
std::vector<double> areas(tree->MaxNumChildren() -
std::vector<ElemType> areas(tree->MaxNumChildren() -
2 * tree->MinNumChildren() + 2);
std::vector<double> margins(tree->MaxNumChildren() -
std::vector<ElemType> margins(tree->MaxNumChildren() -
2 * tree->MinNumChildren() + 2);
std::vector<double> overlapedAreas(tree->MaxNumChildren() -
std::vector<ElemType> overlapedAreas(tree->MaxNumChildren() -
2 * tree->MinNumChildren() + 2);
for (size_t i = 0; i < areas.size(); i++)
{
@@ -403,10 +436,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
size_t cutOff = tree->MinNumChildren() + i;
// We'll calculate the max and min in each dimension by hand to save time.
std::vector<double> maxG1(tree->Bound().Dim());
std::vector<double> minG1(maxG1.size());
std::vector<double> maxG2(maxG1.size());
std::vector<double> minG2(maxG1.size());
std::vector<ElemType> maxG1(tree->Bound().Dim());
std::vector<ElemType> minG1(maxG1.size());
std::vector<ElemType> maxG2(maxG1.size());
std::vector<ElemType> 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 +467,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& 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];
@@ -453,8 +486,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& 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])
@@ -498,24 +533,24 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& 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<sortStruct> sorted(tree->NumChildren());
std::vector<sortStruct<ElemType>> 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<ElemType>);
// We'll store each of the three scores for each distribution.
std::vector<double> areas(tree->MaxNumChildren() -
std::vector<ElemType> areas(tree->MaxNumChildren() -
2 * tree->MinNumChildren() + 2);
std::vector<double> margins(tree->MaxNumChildren() -
std::vector<ElemType> margins(tree->MaxNumChildren() -
2 * tree->MinNumChildren() + 2);
std::vector<double> overlapedAreas(tree->MaxNumChildren() -
std::vector<ElemType> overlapedAreas(tree->MaxNumChildren() -
2 * tree->MinNumChildren() + 2);
for (size_t i = 0; i < areas.size(); i++)
{
@@ -532,10 +567,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
size_t cutOff = tree->MinNumChildren() + i;
// We'll calculate the max and min in each dimension by hand to save time.
std::vector<double> maxG1(tree->Bound().Dim());
std::vector<double> minG1(maxG1.size());
std::vector<double> maxG2(maxG1.size());
std::vector<double> minG2(maxG1.size());
std::vector<ElemType> maxG1(tree->Bound().Dim());
std::vector<ElemType> minG1(maxG1.size());
std::vector<ElemType> maxG2(maxG1.size());
std::vector<ElemType> minG2(maxG1.size());
for (size_t k = 0; k < tree->Bound().Dim(); k++)
{
minG1[k] = tree->Children()[sorted[0].n]->Bound()[k].Lo();
@@ -563,8 +598,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& 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];
@@ -584,8 +619,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& 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])
@@ -627,7 +664,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
}
}
std::vector<sortStruct> sorted(tree->NumChildren());
std::vector<sortStruct<ElemType>> sorted(tree->NumChildren());
if (lowIsBest)
{
for (size_t i = 0; i < sorted.size(); i++)
@@ -645,10 +682,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
}
}
std::sort(sorted.begin(), sorted.end(), structComp);
std::sort(sorted.begin(), sorted.end(), structComp<ElemType>);
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;
@@ -692,7 +729,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
if ((minOverlapSplitDimension != tree->Bound().Dim()) &&
(bestScoreMinOverlapSplit / areaOfBestMinOverlapSplit < MAX_OVERLAP))
{
std::vector<sortStruct> sorted2(tree->NumChildren());
std::vector<sortStruct<ElemType>> sorted2(tree->NumChildren());
if (minOverlapSplitUsesHi)
{
for (size_t i = 0; i < sorted2.size(); i++)
@@ -709,7 +746,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
sorted2[i].n = i;
}
}
std::sort(sorted2.begin(), sorted2.end(), structComp);
std::sort(sorted2.begin(), sorted2.end(), structComp<ElemType>);
for (size_t i = 0; i < tree->NumChildren(); i++)
{
if (i < bestIndexMinOverlapSplit + tree->MinNumChildren())
@@ -733,11 +770,14 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
(tree->Parent()->NumChildren() == 1))
{
// We make the root a supernode instead.
tree->Parent()->MaxNumChildren() *= 2;
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++)
{
tree->Parent()->Children()[i] = tree->Children()[i];
tree->Child(i).Parent() = tree->Parent();
}
delete treeOne;
delete treeTwo;
@@ -747,7 +787,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
}
// If we don't have to worry about the root, we just enlarge this node.
tree->MaxNumChildren() *= 2;
tree->MaxNumChildren() += NormalNodeMaxNumChildren();
tree->Children().resize(tree->MaxNumChildren() + 1);
for (size_t i = 0; i < tree->NumChildren(); i++)
tree->Child(i).Parent() = tree;
@@ -760,10 +800,10 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
}
// 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();
@@ -790,7 +830,7 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
if (par->NumChildren() == par->MaxNumChildren() + 1)
{
SplitNonLeafNode(par, relevels);
par->Split().SplitNonLeafNode(par,relevels);
}
// We have to update the children of each of these new nodes so that they
@@ -819,13 +859,27 @@ bool XTreeSplit::SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
* numberOfChildren.
*/
template<typename TreeType>
void XTreeSplit::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode)
void XTreeSplit<TreeType>::InsertNodeIntoTree(TreeType* destTree, TreeType* srcNode)
{
destTree->Bound() |= srcNode->Bound();
destTree->Children().push_back(srcNode);
destTree->Children()[destTree->NumChildren()] = srcNode;
destTree->NumChildren()++;
}
/**
* Serialize the split.
*/
template<typename TreeType>
template<typename Archive>
void XTreeSplit<TreeType>::Serialize(Archive& ar,const unsigned int /* version */)
{
using data::CreateNVP;
ar & CreateNVP(normalNodeMaxNumChildren, "normalNodeMaxNumChildren");
ar & CreateNVP(splitHistory, "splitHistory");
}
} // namespace tree
} // namespace mlpack
@@ -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");
@@ -160,9 +160,11 @@ int main(int argc, char *argv[])
tree = KFNModel::R_STAR_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', and 'ball'." << endl;
<< "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl;
kfn.TreeType() = tree;
kfn.RandomBasis() = randomBasis;
@@ -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 "
@@ -164,9 +164,11 @@ int main(int argc, char *argv[])
tree = KNNModel::R_STAR_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', and 'ball'." << endl;
<< "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl;
knn.TreeType() = tree;
knn.RandomBasis() = randomBasis;
@@ -47,7 +47,8 @@ class NSModel
COVER_TREE,
R_TREE,
R_STAR_TREE,
BALL_TREE
BALL_TREE,
X_TREE
};
private:
@@ -75,6 +76,7 @@ class NSModel
NSType<tree::RTree>* rTreeNS;
NSType<tree::RStarTree>* rStarTreeNS;
NSType<tree::BallTree>* ballTreeNS;
NSType<tree::XTree>* xTreeNS;
public:
/**
@@ -28,7 +28,8 @@ NSModel<SortPolicy>::NSModel(int treeType, bool randomBasis) :
coverTreeNS(NULL),
rTreeNS(NULL),
rStarTreeNS(NULL),
ballTreeNS(NULL)
ballTreeNS(NULL),
xTreeNS(NULL)
{
// Nothing to do.
}
@@ -47,6 +48,8 @@ NSModel<SortPolicy>::~NSModel()
delete rStarTreeNS;
if (ballTreeNS)
delete ballTreeNS;
if (xTreeNS)
delete xTreeNS;
}
//! Serialize the kNN model.
@@ -72,12 +75,16 @@ void NSModel<SortPolicy>::Serialize(Archive& ar,
delete rStarTreeNS;
if (ballTreeNS)
delete ballTreeNS;
if (xTreeNS)
delete xTreeNS;
// Set all the pointers to NULL.
kdTreeNS = NULL;
coverTreeNS = NULL;
rTreeNS = NULL;
rStarTreeNS = NULL;
ballTreeNS = NULL;
xTreeNS = NULL;
}
// We'll only need to serialize one of the kNN objects, based on the type.
@@ -99,6 +106,9 @@ void NSModel<SortPolicy>::Serialize(Archive& ar,
case BALL_TREE:
ar & data::CreateNVP(ballTreeNS, name);
break;
case X_TREE:
ar & data::CreateNVP(xTreeNS, name);
break;
}
}
@@ -115,6 +125,8 @@ const arma::mat& NSModel<SortPolicy>::Dataset() const
return rStarTreeNS->ReferenceSet();
else if (ballTreeNS)
return ballTreeNS->ReferenceSet();
else if (xTreeNS)
return xTreeNS->ReferenceSet();
throw std::runtime_error("no neighbor search model initialized");
}
@@ -133,6 +145,8 @@ bool NSModel<SortPolicy>::SingleMode() const
return rStarTreeNS->SingleMode();
else if (ballTreeNS)
return ballTreeNS->SingleMode();
else if (xTreeNS)
return xTreeNS->SingleMode();
throw std::runtime_error("no neighbor search model initialized");
}
@@ -150,6 +164,8 @@ bool& NSModel<SortPolicy>::SingleMode()
return rStarTreeNS->SingleMode();
else if (ballTreeNS)
return ballTreeNS->SingleMode();
else if (xTreeNS)
return xTreeNS->SingleMode();
throw std::runtime_error("no neighbor search model initialized");
}
@@ -167,6 +183,8 @@ bool NSModel<SortPolicy>::Naive() const
return rStarTreeNS->Naive();
else if (ballTreeNS)
return ballTreeNS->Naive();
else if (xTreeNS)
return xTreeNS->Naive();
throw std::runtime_error("no neighbor search model initialized");
}
@@ -184,6 +202,8 @@ bool& NSModel<SortPolicy>::Naive()
return rStarTreeNS->Naive();
else if (ballTreeNS)
return ballTreeNS->Naive();
else if (xTreeNS)
return xTreeNS->Naive();
throw std::runtime_error("no neighbor search model initialized");
}
@@ -238,6 +258,8 @@ void NSModel<SortPolicy>::BuildModel(arma::mat&& referenceSet,
delete rStarTreeNS;
if (ballTreeNS)
delete ballTreeNS;
if (xTreeNS)
delete xTreeNS;
// Do we need to modify the reference set?
if (randomBasis)
@@ -308,6 +330,11 @@ void NSModel<SortPolicy>::BuildModel(arma::mat&& referenceSet,
}
break;
case X_TREE:
// If necessary, build the X tree.
xTreeNS = new NSType<tree::XTree>(std::move(referenceSet), naive,
singleMode);
break;
}
if (!naive)
@@ -412,6 +439,10 @@ void NSModel<SortPolicy>::Search(arma::mat&& querySet,
ballTreeNS->Search(querySet, k, neighbors, distances);
}
break;
case X_TREE:
// No mapping necessary.
xTreeNS->Search(querySet, k, neighbors, distances);
break;
}
}
@@ -447,6 +478,9 @@ void NSModel<SortPolicy>::Search(const size_t k,
case BALL_TREE:
ballTreeNS->Search(k, neighbors, distances);
break;
case X_TREE:
xTreeNS->Search(k, neighbors, distances);
break;
}
}
@@ -466,6 +500,8 @@ std::string NSModel<SortPolicy>::TreeName() const
return "R* tree";
case BALL_TREE:
return "ball tree";
case X_TREE:
return "X tree";
default:
return "unknown tree";
}
@@ -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");
@@ -171,9 +171,11 @@ int main(int argc, char *argv[])
tree = RSModel::R_STAR_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', and 'ball'." << endl;
<< "'kd', 'cover', 'r', 'r-star', 'x' and 'ball'." << endl;
rs.TreeType() = tree;
rs.RandomBasis() = randomBasis;
+20 -1
View File
@@ -21,7 +21,8 @@ RSModel::RSModel(int treeType, bool randomBasis) :
coverTreeRS(NULL),
rTreeRS(NULL),
rStarTreeRS(NULL),
ballTreeRS(NULL)
ballTreeRS(NULL),
xTreeRS(NULL)
{
// Nothing to do.
}
@@ -116,6 +117,11 @@ void RSModel::BuildModel(arma::mat&& referenceSet,
}
break;
case X_TREE:
xTreeRS = new RSType<tree::XTree>(move(referenceSet), naive,
singleMode);
break;
}
if (!naive)
@@ -221,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;
}
}
@@ -259,6 +269,10 @@ void RSModel::Search(const math::Range& range,
case BALL_TREE:
ballTreeRS->Search(range, neighbors, distances);
break;
case X_TREE:
xTreeRS->Search(range, neighbors, distances);
break;
}
}
@@ -277,6 +291,8 @@ std::string RSModel::TreeName() const
return "R* tree";
case BALL_TREE:
return "ball tree";
case X_TREE:
return "X tree";
default:
return "unknown tree";
}
@@ -295,10 +311,13 @@ void RSModel::CleanMemory()
delete rStarTreeRS;
if (ballTreeRS)
delete ballTreeRS;
if (xTreeRS)
delete xTreeRS;
kdTreeRS = NULL;
coverTreeRS = NULL;
rTreeRS = NULL;
rStarTreeRS = NULL;
ballTreeRS = NULL;
xTreeRS = NULL;
}
+4 -1
View File
@@ -28,7 +28,8 @@ class RSModel
COVER_TREE,
R_TREE,
R_STAR_TREE,
BALL_TREE
BALL_TREE,
X_TREE
};
private:
@@ -57,6 +58,8 @@ class RSModel
RSType<tree::RStarTree>* rStarTreeRS;
//! Ball tree based range search object (NULL if not in use).
RSType<tree::BallTree>* ballTreeRS;
//! X tree based range search object (NULL if not in use).
RSType<tree::XTree>* xTreeRS;
public:
/**
@@ -49,6 +49,10 @@ void RSModel::Serialize(Archive& ar, const unsigned int /* version */)
case BALL_TREE:
ar & CreateNVP(ballTreeRS, "range_search_model");
break;
case X_TREE:
ar & CreateNVP(xTreeRS, "range_search_model");
break;
}
}
@@ -64,6 +68,8 @@ inline const arma::mat& RSModel::Dataset() const
return rStarTreeRS->ReferenceSet();
else if (ballTreeRS)
return ballTreeRS->ReferenceSet();
else if (xTreeRS)
return xTreeRS->ReferenceSet();
throw std::runtime_error("no range search model initialized");
}
@@ -80,6 +86,8 @@ inline bool RSModel::SingleMode() const
return rStarTreeRS->SingleMode();
else if (ballTreeRS)
return ballTreeRS->SingleMode();
else if (xTreeRS)
return xTreeRS->SingleMode();
throw std::runtime_error("no range search model initialized");
}
@@ -96,6 +104,8 @@ inline bool& RSModel::SingleMode()
return rStarTreeRS->SingleMode();
else if (ballTreeRS)
return ballTreeRS->SingleMode();
else if (xTreeRS)
return xTreeRS->SingleMode();
throw std::runtime_error("no range search model initialized");
}
@@ -112,6 +122,8 @@ inline bool RSModel::Naive() const
return rStarTreeRS->Naive();
else if (ballTreeRS)
return ballTreeRS->Naive();
else if (xTreeRS)
return xTreeRS->Naive();
throw std::runtime_error("no range search model initialized");
}
@@ -128,6 +140,8 @@ inline bool& RSModel::Naive()
return rStarTreeRS->Naive();
else if (ballTreeRS)
return ballTreeRS->Naive();
else if (xTreeRS)
return xTreeRS->Naive();
throw std::runtime_error("no range search model initialized");
}
+4 -2
View File
@@ -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;
+4 -1
View File
@@ -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<tree::RTree>* rTreeRA;
//! Non-NULL if the R* tree is used.
RAType<tree::RStarTree>* rStarTreeRA;
//! Non-NULL if the X tree is used.
RAType<tree::XTree>* xTreeRA;
public:
/**
+55 -1
View File
@@ -21,7 +21,8 @@ RAModel<SortPolicy>::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<SortPolicy>::~RAModel()
delete rTreeRA;
if (rStarTreeRA)
delete rStarTreeRA;
if (xTreeRA)
delete xTreeRA;
}
template<typename SortPolicy>
@@ -59,12 +62,15 @@ void RAModel<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::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<SortPolicy>::BuildModel(arma::mat&& referenceSet,
rStarTreeRA = new RAType<tree::RStarTree>(std::move(referenceSet), naive,
singleMode);
break;
case X_TREE:
xTreeRA = new RAType<tree::XTree>(std::move(referenceSet), naive,
singleMode);
break;
}
if (!naive)
@@ -500,6 +545,10 @@ void RAModel<SortPolicy>::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<SortPolicy>::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<SortPolicy>::TreeName() const
return "R tree";
case R_STAR_TREE:
return "R* tree";
case X_TREE:
return "X tree";
default:
return "unknown tree";
}
+4 -2
View File
@@ -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<size_t> 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);
+12 -8
View File
@@ -975,7 +975,7 @@ BOOST_AUTO_TEST_CASE(KNNModelTest)
arma::mat referenceData = arma::randu<arma::mat>(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<arma::mat>(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);
+12 -8
View File
@@ -1251,7 +1251,7 @@ BOOST_AUTO_TEST_CASE(RSModelTest)
arma::mat referenceData = arma::randu<arma::mat>(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<vector<pair<double, size_t>>> 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<arma::mat>(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<vector<pair<double, size_t>>> 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);
+7 -11
View File
@@ -571,7 +571,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;
@@ -584,23 +584,19 @@ BOOST_AUTO_TEST_CASE(XTreeTraverserTest)
arma::Mat<size_t> neighbors2;
arma::mat distances2;
typedef RectangleTree<
XTreeSplit<RStarTreeDescentHeuristic,
NeighborSearchStat<NearestNeighborSort>,
arma::mat>,
RStarTreeDescentHeuristic,
NeighborSearchStat<NearestNeighborSort>,
typedef XTree<EuclideanDistance, NeighborSearchStat<NearestNeighborSort>,
arma::mat> TreeType;
TreeType xTree(dataset, 20, 6, 5, 2, 0);
// Nearest neighbor search with the X tree.
NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>, TreeType>
knn1(&xTree, dataset, true);
NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>, arma::mat, XTree >
knn1(&xTree, true);
BOOST_REQUIRE_EQUAL(xTree.NumDescendants(), numP);
CheckSync(xTree);
//CheckContainment(xTree);
CheckContainment(xTree);
CheckExactContainment(xTree);
CheckHierarchy(xTree);
@@ -617,7 +613,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.