[mlpack-git] master: Fixed copy constructor of RectangleTree and added move constructor. (be94cfe)

gitdub at mlpack.org gitdub at mlpack.org
Fri Aug 19 15:23:22 EDT 2016


Repository : https://github.com/mlpack/mlpack
On branch  : master
Link       : https://github.com/mlpack/mlpack/compare/20f4eacd1b082d04d9aab1fc2f61ef3edaac3f33...5429a59ec38c2b8ebaf27257c74b5e45594976e1

>---------------------------------------------------------------

commit be94cfe400d330f1961540a7773997bc6e4800d7
Author: Mikhail Lozhnikov <lozhnikovma at gmail.com>
Date:   Fri Aug 19 22:22:12 2016 +0300

    Fixed copy constructor of RectangleTree and added move constructor.


>---------------------------------------------------------------

be94cfe400d330f1961540a7773997bc6e4800d7
 .../tree/rectangle_tree/discrete_hilbert_value.hpp | 25 ++++++-
 .../rectangle_tree/discrete_hilbert_value_impl.hpp | 84 ++++++++++++++++++++--
 .../hilbert_r_tree_auxiliary_information.hpp       | 29 +++++++-
 .../hilbert_r_tree_auxiliary_information_impl.hpp  | 23 +++++-
 .../rectangle_tree/hilbert_r_tree_split_impl.hpp   |  7 +-
 .../rectangle_tree/no_auxiliary_information.hpp    | 12 +++-
 .../r_plus_plus_tree_auxiliary_information.hpp     | 21 ++++--
 ...r_plus_plus_tree_auxiliary_information_impl.hpp | 12 +++-
 .../core/tree/rectangle_tree/rectangle_tree.hpp    | 11 ++-
 .../tree/rectangle_tree/rectangle_tree_impl.hpp    | 70 ++++++++++++++++--
 .../x_tree_auxiliary_information.hpp               | 61 ++++++++++++++--
 src/mlpack/tests/rectangle_tree_test.cpp           | 78 ++++++++++++++++++++
 12 files changed, 399 insertions(+), 34 deletions(-)

diff --git a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp
index 3ce0788..a2a12b0 100644
--- a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp
@@ -45,9 +45,21 @@ class DiscreteHilbertValue
   /**
    * Create a Hilbert value object by copying from another one.
    *
-   * @param other The Hilbert value object from which the value will be copied.
+   * @param other The object from which the value will be copied.
+   * @param tree The node that holds the Hilbert value.
+   * @param deepCopy If false, the dataset will not be copied.
    */
-  DiscreteHilbertValue(const DiscreteHilbertValue& other);
+  template<typename TreeType>
+  DiscreteHilbertValue(const DiscreteHilbertValue& other,
+                       TreeType* tree,
+                       bool deepCopy);
+
+  /**
+   * Create a Hilbert value object by moving another one.
+   *
+   * @param other The Hilbert value object from which the value will be moved.
+   */
+  DiscreteHilbertValue(DiscreteHilbertValue&& other);
 
   //! Free memory
   ~DiscreteHilbertValue();
@@ -224,12 +236,21 @@ class DiscreteHilbertValue
   arma::Mat<HilbertElemType>*& LocalHilbertValues()
   { return localHilbertValues; }
 
+  //! Return the ownsLocalHilbertValues variable.
+  bool OwnsLocalHilbertValues() const { return ownsLocalHilbertValues; }
+  //! Modify the ownsLocalHilbertValues variable.
+  bool& OwnsLocalHilbertValues() { return ownsLocalHilbertValues; }
+
   //! Return the cached point (valueToInsert).
   const arma::Col<HilbertElemType>* ValueToInsert() const
   { return valueToInsert; }
   //! Modify the cached point (valueToInsert).
   arma::Col<HilbertElemType>* ValueToInsert() { return valueToInsert; }
 
+  //! Return the ownsValueToInsert variable.
+  bool OwnsValueToInsert() const { return ownsValueToInsert; }
+  //! Modify the ownsValueToInsert variable.
+  bool& OwnsValueToInsert() { return ownsValueToInsert; }
  private:
   //! The number of bits that we can store.
   static constexpr size_t order = sizeof(HilbertElemType) * CHAR_BIT;
diff --git a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp
index 6495927..5c549f8 100644
--- a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp
@@ -60,16 +60,86 @@ DiscreteHilbertValue<TreeElemType>::DiscreteHilbertValue(const TreeType* tree) :
 }
 
 template<typename TreeElemType>
+template<typename TreeType>
 DiscreteHilbertValue<TreeElemType>::
-DiscreteHilbertValue(const DiscreteHilbertValue& other) :
-    localHilbertValues(
-        const_cast<arma::Mat<HilbertElemType>*>(other.LocalHilbertValues())),
+DiscreteHilbertValue(const DiscreteHilbertValue& other,
+                     TreeType* tree,
+                     bool deepCopy) :
+    localHilbertValues(NULL),
     ownsLocalHilbertValues(other.ownsLocalHilbertValues),
     numValues(other.NumValues()),
-    valueToInsert(
-        const_cast<arma::Col<HilbertElemType>*>(other.ValueToInsert())),
-    ownsValueToInsert(false)
-{ }
+    valueToInsert(NULL),
+    ownsValueToInsert(other.ownsValueToInsert)
+{
+  if (deepCopy)
+  {
+    // Only leaf nodes own the localHilbertValues dataset.
+    // Intarmediate nodes store the pointer to the corresponding dataset.
+    if (ownsLocalHilbertValues)
+      localHilbertValues = new arma::Mat<HilbertElemType>(
+          *other.LocalHilbertValues());
+    else
+      localHilbertValues = NULL;
+
+    // Only the root owns ownsValueToInsert. Other nodes the pointer.
+    if (ownsValueToInsert)
+      valueToInsert = new arma::Col<HilbertElemType>(
+          *other.ValueToInsert());
+    else
+    {
+      assert(tree->Parent() != NULL);
+      // Copy the pointer from the parent node.
+      valueToInsert = const_cast<arma::Col<HilbertElemType>*>
+        (tree->Parent()->AuxiliaryInfo().HilbertValue().ValueToInsert());
+    }
+
+    if (tree->NumChildren() == 0)
+    {
+      // We have to update pointers to the localHilbertValues dataset in
+      // intermediate nodes.
+      TreeType* node = tree;
+
+      while (node->Parent() != NULL)
+      {
+        if (node->Parent()->NumChildren() > 1)
+        {
+          const std::vector<TreeType*> parentChildren =
+              node->AuxiliaryInfo().Children(node->Parent());
+          // If node is not the last child of its parent, we shouldn't copy
+          // the localHilbertValues pointer.
+          if (parentChildren[node->Parent()->NumChildren() - 2] == NULL)
+            break;
+        }
+        node->Parent()->AuxiliaryInfo().HilbertValue().LocalHilbertValues() =
+          localHilbertValues;
+        node = node->Parent();
+      }
+    }
+  }
+  else
+  {
+    localHilbertValues = const_cast<arma::Mat<HilbertElemType>*>
+        (other.LocalHilbertValues());
+    valueToInsert = const_cast<arma::Col<HilbertElemType>*>
+        (other.ValueToInsert());
+  }
+}
+
+template<typename TreeElemType>
+DiscreteHilbertValue<TreeElemType>::
+DiscreteHilbertValue(DiscreteHilbertValue&& other) :
+    localHilbertValues(other.localHilbertValues),
+    ownsLocalHilbertValues(other.ownsLocalHilbertValues),
+    numValues(other.numValues),
+    valueToInsert(other.valueToInsert),
+    ownsValueToInsert(other.ownsValueToInsert)
+{
+  other.localHilbertValues = NULL;
+  other.ownsLocalHilbertValues = false;
+  other.numValues = 0;
+  other.valueToInsert = NULL;
+  other.ownsValueToInsert = false;
+}
 
 template<typename TreeElemType>
 template<typename VecType>
diff --git a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information.hpp b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information.hpp
index 8c0b4ae..4db0fa6 100644
--- a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information.hpp
@@ -30,11 +30,32 @@ class HilbertRTreeAuxiliaryInformation
   HilbertRTreeAuxiliaryInformation(const TreeType* node);
 
   /**
-   * Create an auxiliary information object by copying from the other node.
+   * Create an auxiliary information object by copying from another object.
    *
-   * @param other The node from which the information will be copied.
+   * @param other Another auxiliary information object from which the
+   *    information will be copied.
+   * @param tree The node that holds the auxiliary information.
+   * @param deepCopy If false, the new object uses the same memory
+   *    (not used here).
    */
   HilbertRTreeAuxiliaryInformation(
+      const HilbertRTreeAuxiliaryInformation& other,
+      TreeType* tree = NULL,
+      bool deepCopy = true);
+
+  /**
+   * Create an auxiliary information object by moving from the other node.
+   *
+   * @param other The object from which the information will be moved.
+   */
+  HilbertRTreeAuxiliaryInformation(HilbertRTreeAuxiliaryInformation&& other);
+
+  /**
+   * Copy the auxiliary information.
+   *
+   * @param other The object from which the information will be moved.
+   */
+  HilbertRTreeAuxiliaryInformation& operator=(
       const HilbertRTreeAuxiliaryInformation& other);
 
   /**
@@ -94,6 +115,10 @@ class HilbertRTreeAuxiliaryInformation
   //! Clear memory.
   void NullifyData();
 
+  //! Return the children vector of the tree.
+  static const std::vector<TreeType*> Children(const TreeType* tree)
+  { return tree->children; }
+
  private:
   //! The largest Hilbert value of a point enclosed by the node.
   HilbertValueType<ElemType> hilbertValue;
diff --git a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information_impl.hpp b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information_impl.hpp
index b27507f..73689bf 100644
--- a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information_impl.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_auxiliary_information_impl.hpp
@@ -30,12 +30,31 @@ template<typename TreeType,
          template<typename> class HilbertValueType>
 HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>::
 HilbertRTreeAuxiliaryInformation(
-    const HilbertRTreeAuxiliaryInformation& other) :
-    hilbertValue(other.HilbertValue())
+    const HilbertRTreeAuxiliaryInformation& other,
+    TreeType* tree,
+    bool deepCopy) :
+    hilbertValue(other.HilbertValue(), tree, deepCopy)
 { }
 
 template<typename TreeType,
          template<typename> class HilbertValueType>
+HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>::
+HilbertRTreeAuxiliaryInformation(HilbertRTreeAuxiliaryInformation&& other) :
+    hilbertValue(std::move(other.hilbertValue))
+{ }
+
+template<typename TreeType,
+         template<typename> class HilbertValueType>
+HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>&
+HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>::operator=(
+    const HilbertRTreeAuxiliaryInformation& other)
+{
+  hilbertValue = other.hilbertValue;
+  return *this;
+}
+
+template<typename TreeType,
+         template<typename> class HilbertValueType>
 bool HilbertRTreeAuxiliaryInformation<TreeType, HilbertValueType>::
 HandlePointInsertion(TreeType* node, const size_t point)
 {
diff --git a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split_impl.hpp b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split_impl.hpp
index 5fa7911..12ba1ae 100644
--- a/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split_impl.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/hilbert_r_tree_split_impl.hpp
@@ -28,6 +28,10 @@ void HilbertRTreeSplit<splitOrder>::SplitLeafNode(TreeType* tree,
   {
     // We actually want to copy this way.  Pointers and everything.
     TreeType* copy = new TreeType(*tree, false);
+    // Only the root node owns this variable.
+    copy->AuxiliaryInfo().HilbertValue().OwnsValueToInsert() = false;
+    // Only leaf nodes own this variable.
+    tree->AuxiliaryInfo().HilbertValue().OwnsLocalHilbertValues() = false;
     copy->Parent() = tree;
     tree->Count() = 0;
     tree->NullifyData();
@@ -89,7 +93,8 @@ SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
   {
     // We actually want to copy this way.  Pointers and everything.
     TreeType* copy = new TreeType(*tree, false);
-
+    // Only the root node owns this variable.
+    copy->AuxiliaryInfo().HilbertValue().OwnsValueToInsert() = false;
     copy->Parent() = tree;
     tree->NumChildren() = 0;
     tree->NullifyData();
diff --git a/src/mlpack/core/tree/rectangle_tree/no_auxiliary_information.hpp b/src/mlpack/core/tree/rectangle_tree/no_auxiliary_information.hpp
index e282a4c..c0772f8 100644
--- a/src/mlpack/core/tree/rectangle_tree/no_auxiliary_information.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/no_auxiliary_information.hpp
@@ -20,7 +20,17 @@ class NoAuxiliaryInformation
   //! Construct the auxiliary information object.
   NoAuxiliaryInformation(const TreeType* /* node */) { };
   //! Construct the auxiliary information object.
-  NoAuxiliaryInformation(const TreeType& /* node */) { };
+  NoAuxiliaryInformation(const NoAuxiliaryInformation& /* other */,
+                         TreeType* /* tree */,
+                         bool /* deepCopy */ = true) { };
+  //! Construct the auxiliary information object.
+  NoAuxiliaryInformation(NoAuxiliaryInformation&& /* other */) { };
+
+  //! Copy the auxiliary information object.
+  NoAuxiliaryInformation& operator=(const NoAuxiliaryInformation& /* other */)
+  {
+    return *this;
+  }
 
   /**
    * Some tree types require to save some properties at the insertion process.
diff --git a/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information.hpp b/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information.hpp
index aebd98f..768c870 100644
--- a/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information.hpp
@@ -35,13 +35,26 @@ class RPlusPlusTreeAuxiliaryInformation
   RPlusPlusTreeAuxiliaryInformation(const TreeType* /* node */);
 
   /**
-   * Create an auxiliary information object by copying from another node.
+   * Create an auxiliary information object by copying from another object.
    *
-   * @param other The auxiliary information object from which the information
-   * will be copied.
+   * @param other Another auxiliary information object from which the
+   *    information will be copied.
+   * @param tree The node that holds the auxiliary information.
+   * @param deepCopy If false, the new object uses the same memory
+   *    (not used here).
    */
   RPlusPlusTreeAuxiliaryInformation(
-      const RPlusPlusTreeAuxiliaryInformation& other);
+      const RPlusPlusTreeAuxiliaryInformation& other,
+      TreeType* tree,
+      bool /* deepCopy */ = true);
+
+  /**
+   * Create an auxiliary information object by moving from another node.
+   *
+   * @param other The auxiliary information object from which the information
+   * will be moved.
+   */
+  RPlusPlusTreeAuxiliaryInformation(RPlusPlusTreeAuxiliaryInformation&& other);
 
   /**
    * Some tree types require to save some properties at the insertion process.
diff --git a/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information_impl.hpp b/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information_impl.hpp
index 534ad9a..3494494 100644
--- a/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information_impl.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/r_plus_plus_tree_auxiliary_information_impl.hpp
@@ -41,13 +41,23 @@ RPlusPlusTreeAuxiliaryInformation(const TreeType* tree) :
 template<typename TreeType>
 RPlusPlusTreeAuxiliaryInformation<TreeType>::
 RPlusPlusTreeAuxiliaryInformation(
-    const RPlusPlusTreeAuxiliaryInformation& other) :
+    const RPlusPlusTreeAuxiliaryInformation& other,
+    TreeType* /* tree */,
+    bool /* deepCopy */) :
     outerBound(other.OuterBound())
 {
 
 }
 
 template<typename TreeType>
+RPlusPlusTreeAuxiliaryInformation<TreeType>::
+RPlusPlusTreeAuxiliaryInformation(RPlusPlusTreeAuxiliaryInformation&& other) :
+    outerBound(std::move(other.outerBound))
+{
+
+}
+
+template<typename TreeType>
 bool RPlusPlusTreeAuxiliaryInformation<TreeType>::HandlePointInsertion(
     TreeType* /* node */, const size_t /* point */)
 {
diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp
index c694337..57e80f2 100644
--- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree.hpp
@@ -168,7 +168,16 @@ class RectangleTree
    * @param other The tree to be copied.
    * @param deepCopy If false, the children are not recursively copied.
    */
-  RectangleTree(const RectangleTree& other, const bool deepCopy = true);
+  RectangleTree(const RectangleTree& other,
+                const bool deepCopy = true,
+                RectangleTree* newParent = NULL);
+
+  /**
+   * Create a rectangle tree by moving the other tree.
+   *
+   * @param other The tree to be copied.
+   */
+  RectangleTree(RectangleTree&& other);
 
   /**
    * Construct the tree from a boost::serialization archive.
diff --git a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp
index 81842ac..6c553ec 100644
--- a/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp
@@ -143,12 +143,13 @@ RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
               AuxiliaryInformationType>::
 RectangleTree(
     const RectangleTree& other,
-    const bool deepCopy) :
+    const bool deepCopy,
+    RectangleTree* newParent) :
     maxNumChildren(other.MaxNumChildren()),
     minNumChildren(other.MinNumChildren()),
     numChildren(other.NumChildren()),
-    children(maxNumChildren + 1),
-    parent(other.Parent()),
+    children(maxNumChildren + 1, NULL),
+    parent(deepCopy ? newParent : other.Parent()),
     begin(other.Begin()),
     count(other.Count()),
     numDescendants(other.numDescendants),
@@ -156,23 +157,78 @@ RectangleTree(
     minLeafSize(other.MinLeafSize()),
     bound(other.bound),
     parentDistance(other.ParentDistance()),
-    dataset(deepCopy ? new MatType(*other.dataset) : &other.Dataset()),
-    ownsDataset(deepCopy),
+    dataset(deepCopy ?
+        (parent ? parent->dataset : new MatType(*other.dataset)) :
+        &other.Dataset()),
+    ownsDataset(deepCopy && (!parent)),
     points(other.points),
-    auxiliaryInfo(other.auxiliaryInfo)
+    auxiliaryInfo(other.auxiliaryInfo, this, deepCopy)
 {
   if (deepCopy)
   {
     if (numChildren > 0)
     {
       for (size_t i = 0; i < numChildren; i++)
-        children[i] = new RectangleTree(other.Child(i));
+        children[i] = new RectangleTree(other.Child(i), true, this);
     }
   }
   else
     children = other.children;
 }
 
+template<typename MetricType,
+         typename StatisticType,
+         typename MatType,
+         typename SplitType,
+         typename DescentType,
+         template<typename> class AuxiliaryInformationType>
+RectangleTree<MetricType, StatisticType, MatType, SplitType, DescentType,
+              AuxiliaryInformationType>::
+RectangleTree(RectangleTree&& other) :
+    maxNumChildren(other.MaxNumChildren()),
+    minNumChildren(other.MinNumChildren()),
+    numChildren(other.NumChildren()),
+    children(std::move(other.children)),
+    parent(other.Parent()),
+    begin(other.Begin()),
+    count(other.Count()),
+    numDescendants(other.numDescendants),
+    maxLeafSize(other.MaxLeafSize()),
+    minLeafSize(other.MinLeafSize()),
+    bound(std::move(other.bound)),
+    parentDistance(other.ParentDistance()),
+    dataset(other.dataset),
+    ownsDataset(other.ownsDataset),
+    points(std::move(other.points)),
+    auxiliaryInfo(std::move(other.auxiliaryInfo))
+{
+  if (parent)
+  {
+    size_t iChild = 0;
+    while (parent->children[iChild] != (&other))
+      iChild++;
+    assert(iChild < numChildren);
+    parent->children[iChild] = this;
+  }
+  if (!IsLeaf())
+  {
+    for (size_t i = 0; i < numChildren; i++)
+      children[i]->parent = this;
+  }
+  other.maxNumChildren = 0;
+  other.minNumChildren = 0;
+  other.numChildren = 0;
+  other.parent = NULL;
+  other.begin = 0;
+  other.count = 0;
+  other.numDescendants = 0;
+  other.maxLeafSize = 0;
+  other.minLeafSize = 0;
+  other.parentDistance = 0;
+  other.dataset = NULL;
+  other.ownsDataset = false;
+}
+
 /**
  * Construct the tree from a boost::serialization archive.
  */
diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_auxiliary_information.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_auxiliary_information.hpp
index f8a553f..ed4a317 100644
--- a/src/mlpack/core/tree/rectangle_tree/x_tree_auxiliary_information.hpp
+++ b/src/mlpack/core/tree/rectangle_tree/x_tree_auxiliary_information.hpp
@@ -38,17 +38,47 @@ class XTreeAuxiliaryInformation
   { };
 
   /**
-   * Create an auxiliary information object by copying from the other node.
+   * Create an auxiliary information object by copying from another object.
    *
-   * @param other The node from which the information will be copied.
+   * @param other Another auxiliary information object from which the
+   *    information will be copied.
+   * @param tree The node that holds the auxiliary information.
+   * @param deepCopy If false, the new object uses the same memory
+   *    (not used here).
    */
-  XTreeAuxiliaryInformation(const TreeType& other) :
-      normalNodeMaxNumChildren(
-          other.AuxiliaryInfo().NormalNodeMaxNumChildren()),
-      splitHistory(other.AuxiliaryInfo().SplitHistory())
+  XTreeAuxiliaryInformation(const XTreeAuxiliaryInformation& other,
+                            TreeType* /* tree */ = NULL,
+                            bool /* deepCopy */ = true) :
+      normalNodeMaxNumChildren(other.NormalNodeMaxNumChildren()),
+      splitHistory(other.SplitHistory())
   { };
 
   /**
+   * Copy the auxiliary information object.
+   *
+   * @param other The node from which the information will be copied.
+   */
+  XTreeAuxiliaryInformation& operator=(const XTreeAuxiliaryInformation& other)
+  {
+    normalNodeMaxNumChildren = other.NormalNodeMaxNumChildren();
+    splitHistory = other.SplitHistory();
+
+    return *this;
+  }
+
+  /**
+   * Create an auxiliary information object by moving from the other node.
+   *
+   * @param other The object from which the information will be moved.
+   */
+  XTreeAuxiliaryInformation(XTreeAuxiliaryInformation&& other) :
+      normalNodeMaxNumChildren(other.NormalNodeMaxNumChildren()),
+      splitHistory(std::move(other.splitHistory))
+  {
+    other.normalNodeMaxNumChildren = 0;
+  };
+
+  /**
    * Some tree types require to save some properties at the insertion process.
    * This method allows the auxiliary information the option of manipulating the
    * tree in order to perform the insertion process. If the auxiliary
@@ -142,6 +172,25 @@ class XTreeAuxiliaryInformation
         history[i] = false;
     }
 
+    SplitHistoryStruct(const SplitHistoryStruct& other) :
+        lastDimension(other.lastDimension),
+        history(other.history)
+    { }
+
+    SplitHistoryStruct& operator=(const SplitHistoryStruct& other)
+    {
+      lastDimension = other.lastDimension;
+      history = other.history;
+      return *this;
+    }
+
+    SplitHistoryStruct(SplitHistoryStruct&& other) :
+        lastDimension(other.lastDimension),
+        history(std::move(other.history))
+    {
+      other.lastDimension = 0;
+    }
+
     template<typename Archive>
     void Serialize(Archive& ar, const unsigned int /* version */)
     {
diff --git a/src/mlpack/tests/rectangle_tree_test.cpp b/src/mlpack/tests/rectangle_tree_test.cpp
index 80e6fc7..c8b99a2 100644
--- a/src/mlpack/tests/rectangle_tree_test.cpp
+++ b/src/mlpack/tests/rectangle_tree_test.cpp
@@ -865,6 +865,83 @@ BOOST_AUTO_TEST_CASE(DiscreteHilbertValueTest)
 }
 
 template<typename TreeType>
+void CheckHilbertValue(const TreeType& tree)
+{
+  typedef DiscreteHilbertValue<typename TreeType::ElemType>
+      HilbertValue;
+
+  const HilbertValue& value = tree.AuxiliaryInfo().HilbertValue();
+
+  if (tree.IsLeaf())
+  {
+    BOOST_REQUIRE_EQUAL(value.OwnsLocalHilbertValues(), true);
+    return;
+  }
+
+  for (size_t i = 0; i < tree.NumChildren(); i++)
+  {
+    const HilbertValue& childValue =
+        tree.Child(i).AuxiliaryInfo().HilbertValue();
+    BOOST_REQUIRE_EQUAL(value.ValueToInsert(), childValue.ValueToInsert());
+  }
+
+  const HilbertValue& childValue =
+      tree.Child(tree.NumChildren() - 1).AuxiliaryInfo().HilbertValue();
+  BOOST_REQUIRE_EQUAL(value.LocalHilbertValues(),
+      childValue.LocalHilbertValues());
+
+  if (!tree.Parent())
+    BOOST_REQUIRE_EQUAL(value.OwnsValueToInsert(), true);
+  else
+    BOOST_REQUIRE_EQUAL(value.OwnsValueToInsert(), false);
+
+  BOOST_REQUIRE_EQUAL(value.OwnsLocalHilbertValues(), false);
+
+  for (size_t i = 0; i < tree.NumChildren(); i++)
+    CheckHilbertValue(tree.Child(i));
+}
+
+BOOST_AUTO_TEST_CASE(HilbertRTeeCopyConstructorTest)
+{
+  typedef HilbertRTree<EuclideanDistance,
+      NeighborSearchStat<NearestNeighborSort>, arma::mat> TreeType;
+
+  arma::mat dataset;
+  dataset.randu(8, 1000); // 1000 points in 8 dimensions.
+
+  TreeType tree(dataset, 20, 6, 5, 2, 0);
+  TreeType copy(tree);
+
+  CheckHilbertValue(copy);
+  CheckDiscreteHilbertValueSync(copy);
+  CheckHilbertOrdering(copy);
+  CheckContainment(copy);
+  CheckExactContainment(copy);
+  CheckHierarchy(copy);
+  CheckNumDescendants(copy);
+}
+
+BOOST_AUTO_TEST_CASE(HilbertRTeeMoveConstructorTest)
+{
+  typedef HilbertRTree<EuclideanDistance,
+      NeighborSearchStat<NearestNeighborSort>, arma::mat> TreeType;
+
+  arma::mat dataset;
+  dataset.randu(8, 1000); // 1000 points in 8 dimensions.
+
+  TreeType tree(dataset, 20, 6, 5, 2, 0);
+  TreeType copy(std::move(tree));
+
+  CheckHilbertValue(copy);
+  CheckDiscreteHilbertValueSync(copy);
+  CheckHilbertOrdering(copy);
+  CheckContainment(copy);
+  CheckExactContainment(copy);
+  CheckHierarchy(copy);
+  CheckNumDescendants(copy);
+}
+
+template<typename TreeType>
 void CheckOverlap(const TreeType& tree)
 {
   bool success = true;
@@ -893,6 +970,7 @@ void CheckOverlap(const TreeType& tree)
     CheckOverlap(tree.Child(i));
 }
 
+
 BOOST_AUTO_TEST_CASE(RPlusTreeOverlapTest)
 {
   arma::mat dataset;




More information about the mlpack-git mailing list