Fixed comments.
Removed RecursiveHilbertValue. Added a template parameter splitOrder.
This commit is contained in:
@@ -59,8 +59,6 @@ set(SOURCES
|
||||
rectangle_tree/hilbert_r_tree_split_impl.hpp
|
||||
rectangle_tree/hilbert_r_tree_auxiliary_information.hpp
|
||||
rectangle_tree/hilbert_r_tree_auxiliary_information_impl.hpp
|
||||
rectangle_tree/recursive_hilbert_value.hpp
|
||||
rectangle_tree/recursive_hilbert_value_impl.hpp
|
||||
rectangle_tree/discrete_hilbert_value.hpp
|
||||
rectangle_tree/discrete_hilbert_value_impl.hpp
|
||||
statistic.hpp
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "rectangle_tree/hilbert_r_tree_descent_heuristic.hpp"
|
||||
#include "rectangle_tree/hilbert_r_tree_split.hpp"
|
||||
#include "rectangle_tree/hilbert_r_tree_auxiliary_information.hpp"
|
||||
#include "rectangle_tree/recursive_hilbert_value.hpp"
|
||||
#include "rectangle_tree/discrete_hilbert_value.hpp"
|
||||
#include "rectangle_tree/typedef.hpp"
|
||||
|
||||
|
||||
@@ -139,11 +139,21 @@ class DiscreteHilbertValue
|
||||
*/
|
||||
template<typename TreeType>
|
||||
void Copy(TreeType* dst, TreeType* src);
|
||||
|
||||
|
||||
/**
|
||||
* Copy the local Hilbert value's pointer.
|
||||
* @param val The DiscreteHilbertValue object from which the dataset
|
||||
* will be copied.
|
||||
*/
|
||||
DiscreteHilbertValue& operator = (const DiscreteHilbertValue& val);
|
||||
|
||||
/**
|
||||
* Nullify the localHilbertValues pointer in order to prevent an invalid free.
|
||||
*/
|
||||
void NullifyData();
|
||||
|
||||
/**
|
||||
* Update the largest Hilbert value and the local dataset.
|
||||
* Update the largest Hilbert value and the local Hilbert values of an intermediate node.
|
||||
* The children of the node (or the points that the node contains) should be
|
||||
* arranged according to their Hilbert values.
|
||||
* @param node The node in which the information should be updated.
|
||||
@@ -151,8 +161,16 @@ class DiscreteHilbertValue
|
||||
template<typename TreeType>
|
||||
void UpdateLargestValue(TreeType* node);
|
||||
|
||||
/**
|
||||
* This method updates the largest Hilbert value of a leaf node and
|
||||
* redistributes the Hilbert values of points according to their new position
|
||||
* after the split algorithm.
|
||||
* @param parent The parent of the node that was split.
|
||||
* @param firstSibling The first cooperationg sibling.
|
||||
* @param lastSibling The last cooperating sibling.
|
||||
*/
|
||||
template<typename TreeType>
|
||||
void UpdateHilbertValues(TreeType* parent, size_t firstSibling,
|
||||
void RedistributeHilbertValues(TreeType* parent, size_t firstSibling,
|
||||
size_t lastSibling);
|
||||
|
||||
/**
|
||||
@@ -182,11 +200,12 @@ class DiscreteHilbertValue
|
||||
{ return numValues; }
|
||||
|
||||
//! Return the local dataset
|
||||
const arma::Mat<HilbertElemType>* LocalDataset() const
|
||||
{ return localDataset; }
|
||||
const arma::Mat<HilbertElemType>* LocalHilbertValues() const
|
||||
{ return localHilbertValues; }
|
||||
|
||||
//! Modify the dataset
|
||||
arma::Mat<HilbertElemType>*& LocalDataset() { return localDataset; }
|
||||
arma::Mat<HilbertElemType>*& LocalHilbertValues()
|
||||
{ return localHilbertValues; }
|
||||
|
||||
//! Modify the valueToInsert
|
||||
arma::Col<HilbertElemType>* ValueToInsert() { return valueToInsert; }
|
||||
@@ -198,21 +217,21 @@ class DiscreteHilbertValue
|
||||
private:
|
||||
//! The number of bits that we can store
|
||||
static constexpr size_t order = sizeof(HilbertElemType) * CHAR_BIT;
|
||||
//! The local dataset
|
||||
arma::Mat<HilbertElemType>* localDataset;
|
||||
//! Indicates that the node owns the local dataset
|
||||
bool ownsLocalDataset;
|
||||
//! The number of values in the local dataset
|
||||
//! The local Hilbert values
|
||||
arma::Mat<HilbertElemType>* localHilbertValues;
|
||||
//! Indicates that the node owns the localHilbertValues variable
|
||||
bool ownsLocalHilbertValues;
|
||||
//! The number of values in the localHilbertValues dataset
|
||||
size_t numValues;
|
||||
//! The Hilbert value of the point that is being inserted
|
||||
arma::Col<HilbertElemType>* valueToInsert;
|
||||
//! Indicates that the node owns the valueToInsert
|
||||
bool ownsValueToInsert;
|
||||
|
||||
/**
|
||||
* Returns true if the node has the largest Hilbert value.
|
||||
/** The Hilbert value of the point that is being inserted.
|
||||
* The pointer is the same in all nodes. The value is updated in InsertPoint()
|
||||
* if it is invoked at the root level. This variable helps to avoid
|
||||
* multiple computation of the Hilbert value of a point in the insertion
|
||||
* process.
|
||||
*/
|
||||
bool HasValue() const;
|
||||
arma::Col<HilbertElemType>* valueToInsert;
|
||||
//! Indicates that the node owns the valueToInsert.
|
||||
bool ownsValueToInsert;
|
||||
|
||||
public:
|
||||
template<typename Archive>
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace tree /** Trees and tree-building procedures. */ {
|
||||
|
||||
template<typename TreeElemType>
|
||||
DiscreteHilbertValue<TreeElemType>::DiscreteHilbertValue() :
|
||||
localDataset(NULL),
|
||||
ownsLocalDataset(false),
|
||||
localHilbertValues(NULL),
|
||||
ownsLocalHilbertValues(false),
|
||||
numValues(0),
|
||||
valueToInsert(NULL),
|
||||
ownsValueToInsert(false)
|
||||
@@ -27,8 +27,8 @@ DiscreteHilbertValue<TreeElemType>::DiscreteHilbertValue() :
|
||||
template<typename TreeElemType>
|
||||
DiscreteHilbertValue<TreeElemType>::~DiscreteHilbertValue()
|
||||
{
|
||||
if (ownsLocalDataset)
|
||||
delete localDataset;
|
||||
if (ownsLocalHilbertValues)
|
||||
delete localHilbertValues;
|
||||
if (ownsValueToInsert)
|
||||
delete valueToInsert;
|
||||
}
|
||||
@@ -36,8 +36,8 @@ DiscreteHilbertValue<TreeElemType>::~DiscreteHilbertValue()
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
DiscreteHilbertValue<TreeElemType>::DiscreteHilbertValue(const TreeType* tree) :
|
||||
localDataset(NULL),
|
||||
ownsLocalDataset(false),
|
||||
localHilbertValues(NULL),
|
||||
ownsLocalHilbertValues(false),
|
||||
numValues(0),
|
||||
valueToInsert(tree->Parent() ?
|
||||
tree->Parent()->AuxiliaryInfo().HilbertValue().ValueToInsert() :
|
||||
@@ -46,17 +46,17 @@ DiscreteHilbertValue<TreeElemType>::DiscreteHilbertValue(const TreeType* tree) :
|
||||
{
|
||||
// Calculate the Hilbert value for all points
|
||||
if (!tree->Parent()) // This is the root node
|
||||
ownsLocalDataset = true;
|
||||
ownsLocalHilbertValues = true;
|
||||
else if (tree->Parent()->Children()[0]->IsLeaf())
|
||||
{
|
||||
// This is a leaf node
|
||||
assert(tree->Parent()->NumChildren() > 0);
|
||||
ownsLocalDataset = true;
|
||||
ownsLocalHilbertValues = true;
|
||||
}
|
||||
|
||||
if (ownsLocalDataset)
|
||||
if (ownsLocalHilbertValues)
|
||||
{
|
||||
localDataset = new arma::Mat<HilbertElemType>(tree->Dataset().n_rows,
|
||||
localHilbertValues = new arma::Mat<HilbertElemType>(tree->Dataset().n_rows,
|
||||
tree->MaxLeafSize() + 1);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ DiscreteHilbertValue<TreeElemType>::DiscreteHilbertValue(const TreeType* tree) :
|
||||
template<typename TreeElemType>
|
||||
DiscreteHilbertValue<TreeElemType>::
|
||||
DiscreteHilbertValue(const DiscreteHilbertValue& other) :
|
||||
localDataset(const_cast<arma::Mat<HilbertElemType>*>(other.LocalDataset())),
|
||||
ownsLocalDataset(other.ownsLocalDataset),
|
||||
localHilbertValues(const_cast<arma::Mat<HilbertElemType>*>(other.LocalHilbertValues())),
|
||||
ownsLocalHilbertValues(other.ownsLocalHilbertValues),
|
||||
numValues(other.NumValues()),
|
||||
valueToInsert(const_cast<arma::Col<HilbertElemType>*>(other.ValueToInsert())),
|
||||
ownsValueToInsert(false)
|
||||
@@ -216,15 +216,15 @@ int DiscreteHilbertValue<TreeElemType>::
|
||||
CompareValues(const DiscreteHilbertValue& val1,
|
||||
const DiscreteHilbertValue& val2)
|
||||
{
|
||||
if (val1.HasValue() && !val2.HasValue())
|
||||
if (val1.NumValues() > 0 && val2.NumValues() == 0)
|
||||
return 1;
|
||||
else if (!val1.HasValue() && val2.HasValue())
|
||||
else if (val1.NumValues() == 0 && val2.NumValues() > 0)
|
||||
return -1;
|
||||
else if (!val1.HasValue() && !val2.HasValue())
|
||||
else if (val1.NumValues() == 0 && val2.NumValues() == 0)
|
||||
return 0;
|
||||
|
||||
return CompareValues(val1.LocalDataset()->col(val1.NumValues() - 1),
|
||||
val2.LocalDataset()->col(val2.NumValues() - 1));
|
||||
return CompareValues(val1.LocalHilbertValues()->col(val1.NumValues() - 1),
|
||||
val2.LocalHilbertValues()->col(val2.NumValues() - 1));
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
@@ -242,10 +242,10 @@ CompareWith(const VecType& pt,
|
||||
{
|
||||
arma::Col<HilbertElemType> val = CalculateValue(pt);
|
||||
|
||||
if (!HasValue())
|
||||
if (numValues == 0)
|
||||
return -1;
|
||||
|
||||
return CompareValues(localDataset->col(numValues - 1),val);
|
||||
return CompareValues(localHilbertValues->col(numValues - 1),val);
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
@@ -254,10 +254,10 @@ int DiscreteHilbertValue<TreeElemType>::
|
||||
CompareWithCachedPoint(const VecType& ,
|
||||
typename boost::enable_if<IsVector<VecType>>*) const
|
||||
{
|
||||
if (!HasValue())
|
||||
if (numValues == 0)
|
||||
return -1;
|
||||
|
||||
return CompareValues(localDataset->col(numValues - 1),*valueToInsert);
|
||||
return CompareValues(localHilbertValues->col(numValues - 1),*valueToInsert);
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
@@ -275,13 +275,13 @@ InsertPoint(TreeType *node, const VecType& pt,
|
||||
{
|
||||
// Find an appropriate place
|
||||
for (i = 0; i < numValues; i++)
|
||||
if (CompareValues(localDataset->col(i), *valueToInsert) > 0)
|
||||
if (CompareValues(localHilbertValues->col(i), *valueToInsert) > 0)
|
||||
break;
|
||||
|
||||
for (size_t j = numValues; j > i; j--)
|
||||
localDataset->col(j) = localDataset->col(j-1);
|
||||
localHilbertValues->col(j) = localHilbertValues->col(j-1);
|
||||
|
||||
localDataset->col(i) = *valueToInsert;
|
||||
localHilbertValues->col(i) = *valueToInsert;
|
||||
numValues++;
|
||||
// Propogate changes of the largest Hilbert value downward
|
||||
TreeType* root = node->Parent();
|
||||
@@ -306,7 +306,7 @@ void DiscreteHilbertValue<TreeElemType>::InsertNode(TreeType* node)
|
||||
|
||||
if (CompareWith(node,val) < 0)
|
||||
{
|
||||
localDataset = val.LocalDataset();
|
||||
localHilbertValues = val.LocalHilbertValues();
|
||||
numValues = val.NumValues();
|
||||
}
|
||||
}
|
||||
@@ -319,7 +319,7 @@ DeletePoint(TreeType* node, const size_t localIndex)
|
||||
|
||||
// Delete the Hilbert value from the local dataset
|
||||
for (size_t i = numValues - 1; i > localIndex; i--)
|
||||
localDataset->col(i-1) = localDataset->col(i);
|
||||
localHilbertValues->col(i-1) = localHilbertValues->col(i);
|
||||
|
||||
numValues--;
|
||||
}
|
||||
@@ -331,7 +331,7 @@ RemoveNode(TreeType* node, const size_t nodeIndex)
|
||||
{
|
||||
if (node->NumChildren() <= 1)
|
||||
{
|
||||
localDataset = NULL;
|
||||
localHilbertValues = NULL;
|
||||
numValues = 0;
|
||||
return;
|
||||
}
|
||||
@@ -342,31 +342,32 @@ RemoveNode(TreeType* node, const size_t nodeIndex)
|
||||
if (child->AuxiliaryInfo.HilbertValue().NumValues() != 0)
|
||||
{
|
||||
numValues = child->AuxiliaryInfo.HilbertValue().NumValues();
|
||||
localDataset = child->AuxiliaryInfo.HilbertValue().LocalDataset();
|
||||
localHilbertValues = child->AuxiliaryInfo.HilbertValue().LocalHilbertValues();
|
||||
}
|
||||
else
|
||||
{
|
||||
localDataset = NULL;
|
||||
localHilbertValues = NULL;
|
||||
numValues = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void DiscreteHilbertValue<TreeElemType>::Copy(TreeType* dst, TreeType* src)
|
||||
DiscreteHilbertValue<TreeElemType>& DiscreteHilbertValue<TreeElemType>::
|
||||
operator = (const DiscreteHilbertValue& val)
|
||||
{
|
||||
DiscreteHilbertValue<TreeElemType> &dstVal = dst->AuxiliaryInfo().HilbertValue();
|
||||
DiscreteHilbertValue<TreeElemType> &srcVal = src->AuxiliaryInfo().HilbertValue();
|
||||
localHilbertValues = const_cast<arma::Mat<HilbertElemType>* >
|
||||
(val.LocalHilbertValues());
|
||||
ownsLocalHilbertValues = false;
|
||||
numValues = val.NumValues();
|
||||
|
||||
dst.LocalDataset() = src.LocalDataset();
|
||||
dst.NumValues() = src.NumValues();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
void DiscreteHilbertValue<TreeElemType>::NullifyData()
|
||||
{
|
||||
ownsLocalDataset = false;
|
||||
ownsLocalHilbertValues = false;
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
@@ -376,7 +377,7 @@ void DiscreteHilbertValue<TreeElemType>::UpdateLargestValue(TreeType* node)
|
||||
if (!node->IsLeaf())
|
||||
{
|
||||
// Update the largest Hilbert value
|
||||
localDataset = node->Children()[node->NumChildren()-1]->AuxiliaryInfo().HilbertValue().LocalDataset();
|
||||
localHilbertValues = node->Children()[node->NumChildren()-1]->AuxiliaryInfo().HilbertValue().LocalHilbertValues();
|
||||
numValues = node->Children()[node->NumChildren()-1]->AuxiliaryInfo().HilbertValue().NumValues();
|
||||
}
|
||||
}
|
||||
@@ -384,7 +385,7 @@ void DiscreteHilbertValue<TreeElemType>::UpdateLargestValue(TreeType* node)
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void DiscreteHilbertValue<TreeElemType>::
|
||||
UpdateHilbertValues(TreeType* parent, size_t firstSibling, size_t lastSibling)
|
||||
RedistributeHilbertValues(TreeType* parent, size_t firstSibling, size_t lastSibling)
|
||||
{
|
||||
// We should update the local dataset if points were redistributed
|
||||
|
||||
@@ -394,7 +395,7 @@ UpdateHilbertValues(TreeType* parent, size_t firstSibling, size_t lastSibling)
|
||||
numPoints += parent->Children()[i]->NumPoints();
|
||||
|
||||
// Copy the local datasets
|
||||
arma::Mat<HilbertElemType> tmp(localDataset->n_rows,numPoints);
|
||||
arma::Mat<HilbertElemType> tmp(localHilbertValues->n_rows,numPoints);
|
||||
|
||||
size_t iPoint = 0;
|
||||
for (size_t i = firstSibling; i<= lastSibling; i++)
|
||||
@@ -404,7 +405,7 @@ UpdateHilbertValues(TreeType* parent, size_t firstSibling, size_t lastSibling)
|
||||
|
||||
for (size_t j = 0; j < value.NumValues(); j++)
|
||||
{
|
||||
tmp.col(iPoint) = value.LocalDataset()->col(j);
|
||||
tmp.col(iPoint) = value.LocalHilbertValues()->col(j);
|
||||
iPoint++;
|
||||
}
|
||||
}
|
||||
@@ -420,7 +421,7 @@ UpdateHilbertValues(TreeType* parent, size_t firstSibling, size_t lastSibling)
|
||||
|
||||
for (size_t j = 0; j < parent->Children()[i]->NumPoints(); j++)
|
||||
{
|
||||
value.LocalDataset()->col(j) = tmp.col(iPoint);
|
||||
value.LocalHilbertValues()->col(j) = tmp.col(iPoint);
|
||||
iPoint++;
|
||||
}
|
||||
value.NumValues() = parent->Children()[i]->NumPoints();
|
||||
@@ -430,13 +431,6 @@ UpdateHilbertValues(TreeType* parent, size_t firstSibling, size_t lastSibling)
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename TreeElemType>
|
||||
bool DiscreteHilbertValue<TreeElemType>::HasValue() const
|
||||
{
|
||||
return numValues > 0;
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename Archive>
|
||||
void DiscreteHilbertValue<TreeElemType>::
|
||||
@@ -444,8 +438,8 @@ Serialize(Archive& ar, const unsigned int /* version */)
|
||||
{
|
||||
using data::CreateNVP;
|
||||
|
||||
ar & CreateNVP(localDataset, "localDataset");
|
||||
ar & CreateNVP(ownsLocalDataset, "ownsLocalDataset");
|
||||
ar & CreateNVP(localHilbertValues, "localHilbertValues");
|
||||
ar & CreateNVP(ownsLocalHilbertValues, "ownsLocalHilbertValues");
|
||||
ar & CreateNVP(numValues, "numValues");
|
||||
ar & CreateNVP(valueToInsert, "valueToInsert");
|
||||
ar & CreateNVP(ownsValueToInsert, "ownsValueToInsert");
|
||||
|
||||
@@ -34,9 +34,6 @@ class HilbertRTreeAuxiliaryInformation
|
||||
*/
|
||||
HilbertRTreeAuxiliaryInformation(const HilbertRTreeAuxiliaryInformation& other);
|
||||
|
||||
//! Free memory
|
||||
~HilbertRTreeAuxiliaryInformation();
|
||||
|
||||
/**
|
||||
* The Hilbert R tree requires to insert points according to their
|
||||
* Hilbert value. This method should take care of it.
|
||||
|
||||
@@ -40,14 +40,6 @@ HilbertRTreeAuxiliaryInformation(const HilbertRTreeAuxiliaryInformation& other)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
template<typename TreeType,
|
||||
template<typename> class HilbertValueType>
|
||||
HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>::
|
||||
~HilbertRTreeAuxiliaryInformation()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename TreeType,
|
||||
template<typename> class HilbertValueType>
|
||||
@@ -158,14 +150,6 @@ UpdateAuxiliaryInfo(TreeType* node)
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename TreeType,
|
||||
template<typename> class HilbertValueType>
|
||||
void HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>::
|
||||
Copy(TreeType* dst, TreeType* src)
|
||||
{
|
||||
hilbertValue.Copy(dst,src);
|
||||
}
|
||||
|
||||
template<typename TreeType,
|
||||
template<typename> class HilbertValueType>
|
||||
void HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>::
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace tree /** Trees and tree-building procedures. */ {
|
||||
* The order of the splitting policy. The Hilbert R tree splits a node
|
||||
* on overflow, turnung splitOrder node to (splitOrder+1) nodes.
|
||||
*/
|
||||
constexpr int splitOrder = 2;
|
||||
|
||||
template<size_t splitOrder = 2>
|
||||
class HilbertRTreeSplit
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
namespace mlpack {
|
||||
namespace tree {
|
||||
|
||||
template<size_t splitOrder>
|
||||
template<typename TreeType>
|
||||
void HilbertRTreeSplit::
|
||||
void HilbertRTreeSplit<splitOrder>::
|
||||
SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
|
||||
{
|
||||
// If we are splitting the root node, we need will do things differently so
|
||||
@@ -30,7 +31,7 @@ SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
|
||||
tree->NullifyData();
|
||||
// Because this was a leaf node, numChildren must be 0.
|
||||
tree->Children()[(tree->NumChildren())++] = copy;
|
||||
HilbertRTreeSplit::SplitLeafNode(copy, relevels);
|
||||
SplitLeafNode(copy, relevels);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,12 +73,13 @@ SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
|
||||
RedistributePointsEvenly(parent, firstSibling, lastSibling);
|
||||
|
||||
if (parent->NumChildren() == parent->MaxNumChildren() + 1)
|
||||
HilbertRTreeSplit::SplitNonLeafNode(parent, relevels);
|
||||
SplitNonLeafNode(parent, relevels);
|
||||
|
||||
}
|
||||
|
||||
template<size_t splitOrder>
|
||||
template<typename TreeType>
|
||||
bool HilbertRTreeSplit::
|
||||
bool HilbertRTreeSplit<splitOrder>::
|
||||
SplitNonLeafNode(TreeType* tree,std::vector<bool>& relevels)
|
||||
{
|
||||
// If we are splitting the root node, we need will do things differently so
|
||||
@@ -93,7 +95,7 @@ SplitNonLeafNode(TreeType* tree,std::vector<bool>& relevels)
|
||||
tree->NullifyData();
|
||||
tree->Children()[(tree->NumChildren())++] = copy;
|
||||
|
||||
HilbertRTreeSplit::SplitNonLeafNode(copy, relevels);
|
||||
SplitNonLeafNode(copy, relevels);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -137,12 +139,13 @@ SplitNonLeafNode(TreeType* tree,std::vector<bool>& relevels)
|
||||
RedistributeNodesEvenly(parent, firstSibling, lastSibling);
|
||||
|
||||
if (parent->NumChildren() == parent->MaxNumChildren() + 1)
|
||||
HilbertRTreeSplit::SplitNonLeafNode(parent, relevels);
|
||||
SplitNonLeafNode(parent, relevels);
|
||||
return false;
|
||||
}
|
||||
|
||||
template<size_t splitOrder>
|
||||
template<typename TreeType>
|
||||
bool HilbertRTreeSplit::FindCooperatingSiblings(TreeType *parent, size_t iTree,
|
||||
bool HilbertRTreeSplit<splitOrder>::FindCooperatingSiblings(TreeType *parent, size_t iTree,
|
||||
size_t &firstSibling, size_t &lastSibling)
|
||||
{
|
||||
size_t start = (iTree > splitOrder-1 ? iTree - splitOrder + 1 : 0);
|
||||
@@ -192,8 +195,9 @@ bool HilbertRTreeSplit::FindCooperatingSiblings(TreeType *parent, size_t iTree,
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t splitOrder>
|
||||
template<typename TreeType>
|
||||
void HilbertRTreeSplit::
|
||||
void HilbertRTreeSplit<splitOrder>::
|
||||
RedistributeNodesEvenly(const TreeType *parent,
|
||||
size_t firstSibling, size_t lastSibling)
|
||||
{
|
||||
@@ -254,8 +258,9 @@ RedistributeNodesEvenly(const TreeType *parent,
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t splitOrder>
|
||||
template<typename TreeType>
|
||||
void HilbertRTreeSplit::
|
||||
void HilbertRTreeSplit<splitOrder>::
|
||||
RedistributePointsEvenly(TreeType *parent,
|
||||
size_t firstSibling, size_t lastSibling)
|
||||
{
|
||||
@@ -308,7 +313,7 @@ RedistributePointsEvenly(TreeType *parent,
|
||||
parent->Children()[i]->MaxLeafSize());
|
||||
}
|
||||
// Fix the largest Hilbert values of the siblings.
|
||||
parent->AuxiliaryInfo().HilbertValue().UpdateHilbertValues(parent, firstSibling, lastSibling);
|
||||
parent->AuxiliaryInfo().HilbertValue().RedistributeHilbertValues(parent, firstSibling, lastSibling);
|
||||
|
||||
TreeType* root = parent;
|
||||
|
||||
|
||||
@@ -21,7 +21,12 @@ class NoAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the insertion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the insertion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node in which the point is being inserted.
|
||||
* @param point The global number of the point being inserted.
|
||||
*/
|
||||
bool HandlePointInsertion(TreeType* , const size_t)
|
||||
{
|
||||
@@ -30,7 +35,14 @@ class NoAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the insertion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the insertion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node in which the nodeToInsert is being inserted.
|
||||
* @param nodeToInsert The node being inserted.
|
||||
* @param insertionLevel The level of the tree at which the nodeToInsert
|
||||
* should be inserted.
|
||||
*/
|
||||
bool HandleNodeInsertion(TreeType* , TreeType* ,bool)
|
||||
{
|
||||
@@ -39,7 +51,12 @@ class NoAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the deletion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the deletion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node from which the point is being deleted.
|
||||
* @param localIndex The local index of the point being deleted.
|
||||
*/
|
||||
bool HandlePointDeletion(TreeType* , const size_t)
|
||||
{
|
||||
@@ -48,7 +65,12 @@ class NoAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the deletion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the deletion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node from which the node is being deleted.
|
||||
* @param nodeIndex The local index of the node being deleted.
|
||||
*/
|
||||
bool HandleNodeRemoval(TreeType* , const size_t)
|
||||
{
|
||||
@@ -56,8 +78,10 @@ class NoAuxiliaryInformation
|
||||
}
|
||||
|
||||
/**
|
||||
* Some tree types require to propagate the information downward.
|
||||
* This method should return false if this is not the case.
|
||||
* Some tree types require to propagate the information upward.
|
||||
* This method should return false if this is not the case. If true is
|
||||
* returned, the update will be propogated upward.
|
||||
* @param node The node in which the auxiliary information being update.
|
||||
*/
|
||||
bool UpdateAuxiliaryInfo(TreeType* )
|
||||
{
|
||||
@@ -65,11 +89,8 @@ class NoAuxiliaryInformation
|
||||
}
|
||||
|
||||
/**
|
||||
* Nothing to copy.
|
||||
* Nullify the auxiliary information in order to prevent an invalid free.
|
||||
*/
|
||||
void Copy(TreeType* , TreeType* )
|
||||
{ }
|
||||
|
||||
void NullifyData()
|
||||
{ }
|
||||
|
||||
|
||||
@@ -881,7 +881,7 @@ void RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
|
||||
points[i] = child->Points()[i];
|
||||
}
|
||||
|
||||
auxiliaryInfo.Copy(this,child);
|
||||
auxiliaryInfo = child->AuxiliaryInfo();
|
||||
|
||||
count = child->Count();
|
||||
child->SoftDelete();
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
/**
|
||||
* @file recursive_hilbert_value.hpp
|
||||
* @author Mikhail Lozhnikov
|
||||
*
|
||||
* Defintion of the RecursiveHilbertValue class, a class that measures
|
||||
* ordering of points recursively.
|
||||
*/
|
||||
#ifndef MLPACK_CORE_TREE_RECTANGLE_TREE_RECURSIVE_HILBERT_VALUE_HPP
|
||||
#define MLPACK_CORE_TREE_RECTANGLE_TREE_RECURSIVE_HILBERT_VALUE_HPP
|
||||
|
||||
#include <mlpack/core.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace tree /** Trees and tree-building procedures. */ {
|
||||
|
||||
constexpr int recursionDepth = 500;
|
||||
|
||||
template<typename TreeElemType>
|
||||
class RecursiveHilbertValue
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
RecursiveHilbertValue();
|
||||
|
||||
/**
|
||||
* Construct this for the node tree. If the node is the root this method
|
||||
* computes the Hilbert value for each point in the tree's dataset.
|
||||
* @param node The node that stores this Hilbert value.
|
||||
*/
|
||||
template<typename TreeType>
|
||||
RecursiveHilbertValue(const TreeType* tree);
|
||||
|
||||
/**
|
||||
* Create a Hilbert value object by copying from another one.
|
||||
* @param other The Hilbert value object from which the value will be copied.
|
||||
*/
|
||||
RecursiveHilbertValue(const RecursiveHilbertValue& other);
|
||||
|
||||
~RecursiveHilbertValue();
|
||||
|
||||
//! This struct is designed in order to facilitate the recursion.
|
||||
typedef struct tagCompareStruct
|
||||
{
|
||||
//! Lower bound
|
||||
arma::Col<TreeElemType> Lo;
|
||||
//! High bound
|
||||
arma::Col<TreeElemType> Hi;
|
||||
//! Permutation of axes
|
||||
std::vector<size_t> permutation;
|
||||
//! Indicates that the axis should be inverted
|
||||
std::vector<bool> inversion;
|
||||
//! Indicates that the result should be inverted
|
||||
arma::Col<TreeElemType> center;
|
||||
arma::Col<TreeElemType> vec;
|
||||
std::vector<int> bits;
|
||||
std::vector<int> bits2;
|
||||
bool invertResult;
|
||||
int recursionLevel;
|
||||
|
||||
|
||||
tagCompareStruct(size_t dim) :
|
||||
Lo(dim),
|
||||
Hi(dim),
|
||||
permutation(dim),
|
||||
inversion(dim),
|
||||
center(dim),
|
||||
vec(dim),
|
||||
bits(dim),
|
||||
bits2(dim),
|
||||
invertResult(false),
|
||||
recursionLevel(0)
|
||||
{
|
||||
for (size_t i = 0; i < dim; i++)
|
||||
{
|
||||
Lo[i] = std::numeric_limits<TreeElemType>::lowest();
|
||||
Hi[i] = std::numeric_limits<TreeElemType>::max();
|
||||
permutation[i] = i;
|
||||
inversion[i] = false;
|
||||
}
|
||||
}
|
||||
} CompareStruct;
|
||||
|
||||
/**
|
||||
* Compare two points. It returns 1 if the first point is greater than
|
||||
* the second one, -1 if the first point is less than the second one and
|
||||
* 0 if the Hilbert values of the points are equal.
|
||||
* @param pt1 The first point.
|
||||
* @param pt2 The second point.
|
||||
*/
|
||||
template<typename VecType1, typename VecType2>
|
||||
static int ComparePoints(const VecType1& pt1, const VecType2& pt2,
|
||||
typename boost::enable_if<IsVector<VecType1>>* = 0,
|
||||
typename boost::enable_if<IsVector<VecType2>>* = 0);
|
||||
|
||||
/**
|
||||
* Compare two Hilbert values. It returns 1 if the first value is greater than
|
||||
* the second one, -1 if the first value is less than the second one and
|
||||
* 0 if the values are equal.
|
||||
* @param val1 The first Hilbert value.
|
||||
* @param val2 The second Hilbert value.
|
||||
*/
|
||||
|
||||
static int CompareValues(const RecursiveHilbertValue& val1,
|
||||
const RecursiveHilbertValue& val2);
|
||||
|
||||
/**
|
||||
* Compare the largest Hilbert value of the node with the val value.
|
||||
* It returns 1 if the value of the node is greater than val,
|
||||
* -1 if the value of the node is less than val and
|
||||
* 0 if the values are equal.
|
||||
* @param val The Hilbert value to compare with.
|
||||
*/
|
||||
int CompareWith(const RecursiveHilbertValue& val) const;
|
||||
|
||||
/**
|
||||
* Compare the largest Hilbert value of the node with the Hilbert value
|
||||
* of the point. It returns 1 if the value of the node is greater than
|
||||
* the value of the point, -1 if the value of the node is less than
|
||||
* the value of the point and 0 if the values are equal.
|
||||
* @param point The point to compare with.
|
||||
*/
|
||||
template<typename VecType>
|
||||
int CompareWith(const VecType& point,
|
||||
typename boost::enable_if<IsVector<VecType>>* = 0) const;
|
||||
|
||||
template<typename VecType>
|
||||
int CompareWithCachedPoint(const VecType& point,
|
||||
typename boost::enable_if<IsVector<VecType>>* = 0) const;
|
||||
|
||||
|
||||
/**
|
||||
* Update the largest Hilbert value of the node.
|
||||
* @param node The node in which the point is being inserted.
|
||||
* @param point The number of the point being inserted.
|
||||
*/
|
||||
template<typename TreeType, typename VecType>
|
||||
size_t InsertPoint(TreeType* node, const VecType& point,
|
||||
typename boost::enable_if<IsVector<VecType>>* = 0);
|
||||
|
||||
/**
|
||||
* Update the largest Hilbert value of the node.
|
||||
* @param node The node being inserted.
|
||||
*/
|
||||
template<typename TreeType>
|
||||
void InsertNode(TreeType* node);
|
||||
|
||||
/**
|
||||
* Update the largest Hilbert value of the node.
|
||||
* @param node The node from which another node is being deleted.
|
||||
* @param nodeIndex The number of the node being deleted.
|
||||
*/
|
||||
template<typename TreeType>
|
||||
void DeletePoint(TreeType* node, const size_t localIndex);
|
||||
|
||||
/**
|
||||
* Update the largest Hilbert value of the node.
|
||||
* @param node The node from which another node is being deleted.
|
||||
* @param nodeIndex The number of the node being deleted.
|
||||
*/
|
||||
template<typename TreeType>
|
||||
void RemoveNode(TreeType* node, const size_t nodeIndex);
|
||||
|
||||
|
||||
/**
|
||||
* Copy the largest Hilbert value.
|
||||
* @param dst The node to which the information is being copied.
|
||||
* @param src The node from which the information is being copied.
|
||||
*/
|
||||
template<typename TreeType>
|
||||
void Copy(TreeType* dst, TreeType* src);
|
||||
|
||||
void NullifyData();
|
||||
|
||||
/**
|
||||
* Update the largest Hilbert value.
|
||||
* @param node The node in which the information should be updated.
|
||||
*/
|
||||
template<typename TreeType>
|
||||
void UpdateLargestValue(TreeType* node);
|
||||
|
||||
template<typename TreeType>
|
||||
void UpdateHilbertValues(TreeType* parent, size_t firstSibling,
|
||||
size_t lastSibling);
|
||||
|
||||
//! Return the largest Hilbert value
|
||||
const arma::Col<TreeElemType>* LargestValue() const { return largestValue; }
|
||||
|
||||
//! Modify the largest Hilbert value
|
||||
arma::Col<TreeElemType>*& LargestValue() { return largestValue; }
|
||||
|
||||
private:
|
||||
//! The point that has the largest Hilbert value.
|
||||
arma::Col<TreeElemType>* largestValue;
|
||||
bool ownsLargestValue;
|
||||
bool hasLargestValue;
|
||||
|
||||
/**
|
||||
* Compare two points. It returns 1 if the first point is greater than
|
||||
* the second one, -1 if the first point is less than the second one and
|
||||
* 0 if the Hilbert values of the points are equal.
|
||||
* @param pt1 The first point.
|
||||
* @param pt2 The second point.
|
||||
* @param comp An object of CompareStruct.
|
||||
*/
|
||||
template<typename VecType1, typename VecType2>
|
||||
static int ComparePoints(const VecType1& pt1, const VecType2& pt2,
|
||||
CompareStruct& comp, typename boost::enable_if<IsVector<VecType1>>* = 0,
|
||||
typename boost::enable_if<IsVector<VecType2>>* = 0);
|
||||
public:
|
||||
template<typename Archive>
|
||||
void Serialize(Archive& ar, const unsigned int /* version */);
|
||||
};
|
||||
} // namespace tree
|
||||
} // namespace mlpack
|
||||
|
||||
// Include implementation
|
||||
#include "recursive_hilbert_value_impl.hpp"
|
||||
|
||||
#endif // MLPACK_CORE_TREE_RECTANGLE_TREE_RECURSIVE_HILBERT_VALUE_HPP
|
||||
@@ -1,347 +0,0 @@
|
||||
/**
|
||||
* @file recursive_hilbert_value_impl.hpp
|
||||
* @author Mikhail Lozhnikov
|
||||
*
|
||||
* Implementation of the RecursiveHilbertValue class, a class that measures
|
||||
* ordering of points recursively.
|
||||
*/
|
||||
#ifndef MLPACK_CORE_TREE_RECTANGLE_TREE_RECURSIVE_HILBERT_VALUE_IMPL_HPP
|
||||
#define MLPACK_CORE_TREE_RECTANGLE_TREE_RECURSIVE_HILBERT_VALUE_IMPL_HPP
|
||||
|
||||
namespace mlpack {
|
||||
namespace tree /** Trees and tree-building procedures. */ {
|
||||
|
||||
template<typename TreeElemType>
|
||||
RecursiveHilbertValue<TreeElemType>::RecursiveHilbertValue() :
|
||||
largestValue(NULL),
|
||||
ownsLargestValue(false),
|
||||
hasLargestValue(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
RecursiveHilbertValue<TreeElemType>::
|
||||
RecursiveHilbertValue(const TreeType* tree) :
|
||||
largestValue(NULL),
|
||||
ownsLargestValue(false),
|
||||
hasLargestValue(false)
|
||||
{
|
||||
if (!tree->Parent()) // This is the root node
|
||||
ownsLargestValue = true;
|
||||
else if (tree->Parent()->Children()[0]->IsLeaf())
|
||||
{
|
||||
// This is a leaf node
|
||||
assert(tree->Parent()->NumChildren() > 0);
|
||||
ownsLargestValue = true;
|
||||
}
|
||||
|
||||
if (ownsLargestValue)
|
||||
{
|
||||
largestValue = new arma::Col<TreeElemType>(tree->Dataset().n_rows);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
RecursiveHilbertValue<TreeElemType>::
|
||||
RecursiveHilbertValue(const RecursiveHilbertValue& other) :
|
||||
largestValue(const_cast<arma::Col<TreeElemType>*>(other.LargestValue())),
|
||||
ownsLargestValue(other.ownsLargestValue),
|
||||
hasLargestValue(other.hasLargestValue)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
RecursiveHilbertValue<TreeElemType>::~RecursiveHilbertValue()
|
||||
{
|
||||
if (ownsLargestValue)
|
||||
delete largestValue;
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename VecType1, typename VecType2>
|
||||
int RecursiveHilbertValue<TreeElemType>::
|
||||
ComparePoints(const VecType1& pt1, const VecType2& pt2,
|
||||
typename boost::enable_if<IsVector<VecType1>>*,
|
||||
typename boost::enable_if<IsVector<VecType2>>* )
|
||||
{
|
||||
size_t dim = pt1.n_rows;
|
||||
CompareStruct comp(dim);
|
||||
|
||||
return ComparePoints(pt1, pt2, comp);
|
||||
};
|
||||
|
||||
template<typename TreeElemType>
|
||||
int RecursiveHilbertValue<TreeElemType>::
|
||||
CompareValues(const RecursiveHilbertValue& val1,
|
||||
const RecursiveHilbertValue& val2)
|
||||
{
|
||||
if (!val1.hasLargestValue && val2.hasLargestValue)
|
||||
return -1;
|
||||
else if (val1.hasLargestValue && !val2.hasLargestValue)
|
||||
return 1;
|
||||
else if (!val1.hasLargestValue && !val2.hasLargestValue)
|
||||
return 0;
|
||||
|
||||
return ComparePoints(*val1.LargestValue(),
|
||||
*val2.LargestValue());
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
int RecursiveHilbertValue<TreeElemType>::
|
||||
CompareWith(const RecursiveHilbertValue& val) const
|
||||
{
|
||||
if (!hasLargestValue)
|
||||
return -1;
|
||||
return CompareValues(*this, val);
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename VecType>
|
||||
int RecursiveHilbertValue<TreeElemType>::
|
||||
CompareWith(const VecType& point,
|
||||
typename boost::enable_if<IsVector<VecType>>* ) const
|
||||
{
|
||||
if (!hasLargestValue)
|
||||
return -1;
|
||||
return ComparePoints(*largestValue, point);
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename VecType>
|
||||
int RecursiveHilbertValue<TreeElemType>::
|
||||
CompareWithCachedPoint(const VecType& point,
|
||||
typename boost::enable_if<IsVector<VecType>>* ) const
|
||||
{
|
||||
return CompareWith(point);
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename VecType1, typename VecType2>
|
||||
int RecursiveHilbertValue<TreeElemType>::
|
||||
ComparePoints(const VecType1& pt1, const VecType2& pt2,
|
||||
CompareStruct& comp, typename boost::enable_if<IsVector<VecType1>>*,
|
||||
typename boost::enable_if<IsVector<VecType2>>* )
|
||||
|
||||
{
|
||||
comp.center = comp.Hi * 0.5;
|
||||
comp.vec = comp.Lo * 0.5;
|
||||
|
||||
comp.center += comp.vec;
|
||||
|
||||
// Get bits in order to use the Gray code
|
||||
for (size_t i = 0; i < pt1.n_rows; i++)
|
||||
{
|
||||
size_t j = comp.permutation[i];
|
||||
comp.bits[i] = (pt1(j) > comp.center(j) && !comp.inversion[j]) ||
|
||||
(pt1(j) <= comp.center(j) && !comp.inversion[j]);
|
||||
|
||||
comp.bits2[i] = (pt2(j) > comp.center(j) && !comp.inversion[j]) ||
|
||||
(pt2(j) <= comp.center(j) && !comp.inversion[j]);
|
||||
}
|
||||
|
||||
// Gray encode
|
||||
for (size_t i = 1; i < pt1.n_rows; i++)
|
||||
{
|
||||
comp.bits[i] ^= comp.bits[i-1];
|
||||
comp.bits2[i] ^= comp.bits2[i-1];
|
||||
}
|
||||
|
||||
if (comp.invertResult)
|
||||
{
|
||||
for (size_t i = 0; i < pt1.n_rows; i++)
|
||||
{
|
||||
comp.bits[i] = !comp.bits[i];
|
||||
comp.bits2[i] = !comp.bits2[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pt1.n_rows; i++)
|
||||
{
|
||||
if (comp.bits[i] < comp.bits2[i])
|
||||
return -1;
|
||||
if (comp.bits[i] > comp.bits2[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (comp.recursionLevel >= recursionDepth)
|
||||
return 0;
|
||||
|
||||
comp.recursionLevel++;
|
||||
|
||||
if (comp.bits[pt1.n_rows-1])
|
||||
comp.invertResult = !comp.invertResult;
|
||||
|
||||
// Since the Hilbert curve is continuous we should permutate and intend
|
||||
// coordinate axes depending on the position of the point
|
||||
for (size_t i = 0; i < pt1.n_rows; i++)
|
||||
{
|
||||
size_t j = comp.permutation[i];
|
||||
size_t j0 = comp.permutation[0];
|
||||
if ((pt1(j) > comp.center(j) && !comp.inversion[j]) ||
|
||||
(pt1(j) <= comp.center(j) && !comp.inversion[j]))
|
||||
comp.inversion[j0] = !comp.inversion[j0];
|
||||
else
|
||||
{
|
||||
size_t tmp;
|
||||
tmp = comp.permutation[0];
|
||||
comp.permutation[0] = comp.permutation[i];
|
||||
comp.permutation[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// Choose an appropriate subhypercube
|
||||
for (size_t i = 0; i < pt1.n_rows; i++)
|
||||
{
|
||||
if (pt1(i) > comp.center(i))
|
||||
comp.Lo(i) = comp.center(i);
|
||||
else
|
||||
comp.Hi(i) = comp.center(i);
|
||||
}
|
||||
|
||||
return ComparePoints(pt1, pt2, comp);
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType, typename VecType>
|
||||
size_t RecursiveHilbertValue<TreeElemType>::
|
||||
InsertPoint(TreeType* node, const VecType& point,
|
||||
typename boost::enable_if<IsVector<VecType>>* )
|
||||
{
|
||||
if (node->IsLeaf())
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < node->NumPoints(); i++)
|
||||
if (ComparePoints(node->Dataset().col(node->Point(i)), point) > 0)
|
||||
break;
|
||||
if (i == node->NumPoints())
|
||||
*largestValue = point;
|
||||
|
||||
hasLargestValue = true;
|
||||
|
||||
// Propogate changes of the largest Hilbert value downward
|
||||
TreeType* root = node->Parent();
|
||||
|
||||
while (root != NULL)
|
||||
{
|
||||
root->AuxiliaryInfo().HilbertValue().LargestValue() = largestValue;
|
||||
root->AuxiliaryInfo().HilbertValue().hasLargestValue = true;
|
||||
|
||||
root = root->Parent();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void RecursiveHilbertValue<TreeElemType>::InsertNode(TreeType* node)
|
||||
{
|
||||
if (CompareWith(node->AuxiliaryInfo().HilbertValue()) < 0)
|
||||
{
|
||||
largestValue = node->AuxiliaryInfo().HilbertValue().LargestValue();
|
||||
hasLargestValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void RecursiveHilbertValue<TreeElemType>::
|
||||
DeletePoint(TreeType* node, const size_t localIndex)
|
||||
{
|
||||
if (node->NumPoints() <= 1)
|
||||
{
|
||||
hasLargestValue = false;
|
||||
return;
|
||||
}
|
||||
if (localIndex + 1 == node->NumPoints())
|
||||
*largestValue = node->Dataset()[node->Point(localIndex-1)];
|
||||
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void RecursiveHilbertValue<TreeElemType>::
|
||||
RemoveNode(TreeType* node, const size_t nodeIndex)
|
||||
{
|
||||
if (node->NumChildren() <= 1)
|
||||
{
|
||||
hasLargestValue = false;
|
||||
return;
|
||||
}
|
||||
if (nodeIndex + 1 == node->NumChildren())
|
||||
largestValue = node->Children()[nodeIndex-1]->AuxiliaryInfo.HilbertValue().LargestValue();
|
||||
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void RecursiveHilbertValue<TreeElemType>::Copy(TreeType* dst, TreeType* src)
|
||||
{
|
||||
dst->AuxiliaryInfo().HilbertValue().LargestValue() =
|
||||
src->AuxiliaryInfo().HilbertValue().LargestValue();
|
||||
dst->AuxiliaryInfo().HilbertValue().hasLargestValue =
|
||||
src->AuxiliaryInfo().HilbertValue().hasLargestValue;
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
void RecursiveHilbertValue<TreeElemType>::NullifyData()
|
||||
{
|
||||
ownsLargestValue = false;
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void RecursiveHilbertValue<TreeElemType>::UpdateLargestValue(TreeType* node)
|
||||
{
|
||||
if (!node->IsLeaf())
|
||||
{
|
||||
largestValue = (node->NumChildren() > 0 ?
|
||||
node->Children()[node->NumChildren() - 1]->AuxiliaryInfo().HilbertValue().LargestValue() : NULL);
|
||||
hasLargestValue = (node->NumChildren() > 0 ?
|
||||
node->Children()[node->NumChildren() - 1]->AuxiliaryInfo().HilbertValue().hasLargestValue : false);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename TreeType>
|
||||
void RecursiveHilbertValue<TreeElemType>::
|
||||
UpdateHilbertValues(TreeType* parent, size_t firstSibling, size_t lastSibling)
|
||||
{
|
||||
for (size_t i = firstSibling; i<= lastSibling; i++)
|
||||
{
|
||||
RecursiveHilbertValue<TreeElemType> &value =
|
||||
parent->Children()[i]->AuxiliaryInfo().HilbertValue();
|
||||
|
||||
assert(parent->Children()[i]->NumPoints() > 0);
|
||||
|
||||
TreeType *child = parent->Children()[i];
|
||||
*value.LargestValue() = child->Dataset().col(child->Point(child->NumPoints() - 1));
|
||||
value.hasLargestValue = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename TreeElemType>
|
||||
template<typename Archive>
|
||||
void RecursiveHilbertValue<TreeElemType>::
|
||||
Serialize(Archive& ar, const unsigned int /* version */)
|
||||
{
|
||||
using data::CreateNVP;
|
||||
|
||||
ar & CreateNVP(largestValue, "largestValue");
|
||||
ar & CreateNVP(ownsLargestValue, "ownsLargestValue");
|
||||
ar & CreateNVP(hasLargestValue, "hasLargestValue");
|
||||
}
|
||||
|
||||
} // namespace tree
|
||||
} // namespace mlpack
|
||||
|
||||
#endif //MLPACK_CORE_TREE_RECTANGLE_TREE_RECURSIVE_HILBERT_VALUE_IMPL_HPP
|
||||
@@ -119,26 +119,14 @@ using XTree = RectangleTree<MetricType,
|
||||
* @see @ref trees, RTree, DiscreteHilbertRTree
|
||||
*/
|
||||
template<typename TreeType>
|
||||
using RecursiveHilbertRTreeAuxiliaryInformation =
|
||||
HilbertRTreeAuxiliaryInformation<TreeType,RecursiveHilbertValue>;
|
||||
|
||||
template<typename MetricType, typename StatisticType, typename MatType>
|
||||
using RecursiveHilbertRTree = RectangleTree<MetricType,
|
||||
StatisticType,
|
||||
MatType,
|
||||
HilbertRTreeSplit,
|
||||
HilbertRTreeDescentHeuristic,
|
||||
RecursiveHilbertRTreeAuxiliaryInformation>;
|
||||
|
||||
template<typename TreeType>
|
||||
using DiscreteHilbertRTreeAuxiliaryInformation =
|
||||
HilbertRTreeAuxiliaryInformation<TreeType,DiscreteHilbertValue>;
|
||||
|
||||
template<typename MetricType, typename StatisticType, typename MatType>
|
||||
using DiscreteHilbertRTree = RectangleTree<MetricType,
|
||||
using HilbertRTree = RectangleTree<MetricType,
|
||||
StatisticType,
|
||||
MatType,
|
||||
HilbertRTreeSplit,
|
||||
HilbertRTreeSplit<2>,
|
||||
HilbertRTreeDescentHeuristic,
|
||||
DiscreteHilbertRTreeAuxiliaryInformation>;
|
||||
|
||||
|
||||
@@ -43,7 +43,12 @@ class XTreeAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the insertion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the insertion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node in which the point is being inserted.
|
||||
* @param point The global number of the point being inserted.
|
||||
*/
|
||||
bool HandlePointInsertion(TreeType* , const size_t)
|
||||
{
|
||||
@@ -52,7 +57,14 @@ class XTreeAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the insertion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the insertion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node in which the nodeToInsert is being inserted.
|
||||
* @param nodeToInsert The node being inserted.
|
||||
* @param insertionLevel The level of the tree at which the nodeToInsert
|
||||
* should be inserted.
|
||||
*/
|
||||
bool HandleNodeInsertion(TreeType* , TreeType *,bool)
|
||||
{
|
||||
@@ -61,7 +73,12 @@ class XTreeAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the deletion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the deletion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node from which the point is being deleted.
|
||||
* @param localIndex The local index of the point being deleted.
|
||||
*/
|
||||
bool HandlePointDeletion(TreeType* , const size_t)
|
||||
{
|
||||
@@ -70,7 +87,12 @@ class XTreeAuxiliaryInformation
|
||||
|
||||
/**
|
||||
* Some tree types require to save some properties at the deletion process.
|
||||
* This method should return false if it does not handle the process.
|
||||
* This method allows the auxiliary information the option of manipulating
|
||||
* the tree in order to perform the deletion process. If the auxiliary
|
||||
* information does that, then the method should return true; if the method
|
||||
* returns false the RectangleTree performs its default behavior.
|
||||
* @param node The node from which the node is being deleted.
|
||||
* @param nodeIndex The local index of the node being deleted.
|
||||
*/
|
||||
bool HandleNodeRemoval(TreeType* , const size_t)
|
||||
{
|
||||
@@ -78,8 +100,10 @@ class XTreeAuxiliaryInformation
|
||||
}
|
||||
|
||||
/**
|
||||
* Some tree types require to propagate the information downward.
|
||||
* This method should return false if this is not the case.
|
||||
* Some tree types require to propagate the information upward.
|
||||
* This method should return false if this is not the case. If true is
|
||||
* returned, the update will be propogated upward.
|
||||
* @param node The node in which the auxiliary information being update.
|
||||
*/
|
||||
bool UpdateAuxiliaryInfo(TreeType* )
|
||||
{
|
||||
@@ -87,18 +111,8 @@ class XTreeAuxiliaryInformation
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the auxiliary information from one node to another.
|
||||
* @param dst The node to which the information being copied.
|
||||
* @param src The node from which the information being copied.
|
||||
* Nullify the auxiliary information in order to prevent an invalid free.
|
||||
*/
|
||||
void Copy(TreeType* dst,TreeType* src)
|
||||
{
|
||||
dst->AuxiliaryInfo().NormalNodeMaxNumChildren() =
|
||||
src->AuxiliaryInfo().NormalNodeMaxNumChildren();
|
||||
|
||||
dst->AuxiliaryInfo().SplitHistory() = src->AuxiliaryInfo().SplitHistory();
|
||||
}
|
||||
|
||||
void NullifyData()
|
||||
{ }
|
||||
|
||||
|
||||
@@ -570,7 +570,7 @@ BOOST_AUTO_TEST_CASE(XTreeTraverserTest)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DiscreteHilbertRTreeTraverserTest)
|
||||
BOOST_AUTO_TEST_CASE(HilbertRTreeTraverserTest)
|
||||
{
|
||||
arma::mat dataset;
|
||||
|
||||
@@ -582,14 +582,14 @@ BOOST_AUTO_TEST_CASE(DiscreteHilbertRTreeTraverserTest)
|
||||
arma::Mat<size_t> neighbors2;
|
||||
arma::mat distances2;
|
||||
|
||||
typedef DiscreteHilbertRTree<EuclideanDistance,
|
||||
typedef HilbertRTree<EuclideanDistance,
|
||||
NeighborSearchStat<NearestNeighborSort>,arma::mat> TreeType;
|
||||
TreeType hilbertRTree(dataset, 20, 6, 5, 2, 0);
|
||||
|
||||
// Nearest neighbor search with the Hilbert R tree.
|
||||
|
||||
NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>, arma::mat,
|
||||
DiscreteHilbertRTree > knn1(&hilbertRTree, true);
|
||||
HilbertRTree > knn1(&hilbertRTree, true);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(hilbertRTree.NumDescendants(), numP);
|
||||
|
||||
@@ -611,50 +611,6 @@ BOOST_AUTO_TEST_CASE(DiscreteHilbertRTreeTraverserTest)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
BOOST_AUTO_TEST_CASE(RecursiveHilbertRTreeTraverserTest)
|
||||
{
|
||||
arma::mat dataset;
|
||||
|
||||
const int numP = 1000;
|
||||
|
||||
dataset.randu(8, numP); // 1000 points in 8 dimensions.
|
||||
arma::Mat<size_t> neighbors1;
|
||||
arma::mat distances1;
|
||||
arma::Mat<size_t> neighbors2;
|
||||
arma::mat distances2;
|
||||
|
||||
typedef RecursiveHilbertRTree<EuclideanDistance,
|
||||
NeighborSearchStat<NearestNeighborSort>,arma::mat> TreeType;
|
||||
TreeType hilbertRTree(dataset, 20, 6, 5, 2, 0);
|
||||
|
||||
// Nearest neighbor search with the Hilbert R tree.
|
||||
|
||||
NeighborSearch<NearestNeighborSort, metric::LMetric<2, true>, arma::mat,
|
||||
RecursiveHilbertRTree > knn1(&hilbertRTree, true);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(hilbertRTree.NumDescendants(), numP);
|
||||
|
||||
CheckSync(hilbertRTree);
|
||||
CheckContainment(hilbertRTree);
|
||||
CheckExactContainment(hilbertRTree);
|
||||
CheckHierarchy(hilbertRTree);
|
||||
|
||||
knn1.Search(5, neighbors1, distances1);
|
||||
|
||||
// Nearest neighbor search the naive way.
|
||||
KNN knn2(dataset, true, true);
|
||||
|
||||
knn2.Search(5, neighbors2, distances2);
|
||||
|
||||
for (size_t i = 0; i < neighbors1.size(); i++)
|
||||
{
|
||||
BOOST_REQUIRE_EQUAL(neighbors1[i], neighbors2[i]);
|
||||
BOOST_REQUIRE_EQUAL(distances1[i], distances2[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename TreeType>
|
||||
void CheckHilbertOrdering(TreeType* tree)
|
||||
{
|
||||
@@ -691,12 +647,12 @@ void CheckHilbertOrdering(TreeType* tree)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DiscreteHilbertOrderingTest)
|
||||
BOOST_AUTO_TEST_CASE(HilbertRTreeOrderingTest)
|
||||
{
|
||||
arma::mat dataset;
|
||||
dataset.randu(8, 1000); // 1000 points in 8 dimensions.
|
||||
|
||||
typedef DiscreteHilbertRTree<EuclideanDistance,
|
||||
typedef HilbertRTree<EuclideanDistance,
|
||||
NeighborSearchStat<NearestNeighborSort>,arma::mat> TreeType;
|
||||
TreeType hilbertRTree(dataset, 20, 6, 5, 2, 0);
|
||||
|
||||
@@ -719,7 +675,7 @@ void CheckDiscreteHilbertValueSync(const TreeType* tree)
|
||||
arma::Col<HilbertElemType> pointValue =
|
||||
HilbertValue::CalculateValue(tree->Dataset().col(tree->Points()[i]));
|
||||
|
||||
int equal = HilbertValue::CompareValues(value.LocalDataset()->col(i), pointValue);
|
||||
int equal = HilbertValue::CompareValues(value.LocalHilbertValues()->col(i), pointValue);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(equal, 0);
|
||||
}
|
||||
@@ -734,27 +690,13 @@ BOOST_AUTO_TEST_CASE(DiscreteHilbertValueSyncTest)
|
||||
arma::mat dataset;
|
||||
dataset.randu(8, 1000); // 1000 points in 8 dimensions.
|
||||
|
||||
typedef DiscreteHilbertRTree<EuclideanDistance,
|
||||
typedef HilbertRTree<EuclideanDistance,
|
||||
NeighborSearchStat<NearestNeighborSort>,arma::mat> TreeType;
|
||||
TreeType hilbertRTree(dataset, 20, 6, 5, 2, 0);
|
||||
|
||||
CheckDiscreteHilbertValueSync(&hilbertRTree);
|
||||
}
|
||||
|
||||
/*
|
||||
BOOST_AUTO_TEST_CASE(RecursiveHilbertOrderingTest)
|
||||
{
|
||||
arma::mat dataset;
|
||||
dataset.randu(8, 1000); // 1000 points in 8 dimensions.
|
||||
|
||||
typedef RecursiveHilbertRTree<EuclideanDistance,
|
||||
NeighborSearchStat<NearestNeighborSort>,arma::mat> TreeType;
|
||||
TreeType hilbertRTree(dataset, 20, 6, 5, 2, 0);
|
||||
|
||||
CheckHilbertOrdering(&hilbertRTree);
|
||||
}
|
||||
*/
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DiscreteHilbertValueTest)
|
||||
{
|
||||
arma::vec point01(1);
|
||||
|
||||
Reference in New Issue
Block a user