SpillTree<MetricType, StatisticType, MatType, HyperplaneType, SplitType>:: SpillTree(const SpillTree& other) : left(NULL), right(NULL), parent(other.parent), count(other.count), pointsIndex(NULL), overlappingNode(other.overlappingNode), hyperplane(other.hyperplane), bound(other.bound), stat(other.stat), parentDistance(other.parentDistance), furthestDescendantDistance(other.furthestDescendantDistance), // Copy matrix, but only if we are the root and the other tree has its own // copy of the dataset. dataset((other.parent == NULL && other.localDataset) ? new MatType(*other.dataset) : other.dataset), localDataset(other.parent == NULL && other.localDataset) { // Create left and right children (if any). if (other.Left()) { left = new SpillTree(*other.Left()); left->Parent() = this; // Set parent to this, not other tree. } if (other.Right()) { right = new SpillTree(*other.Right()); right->Parent() = this; // Set parent to this, not other tree. } // If vector of indexes, copy it. if (other.pointsIndex) pointsIndex = new arma::Col<size_t>(*other.pointsIndex); // Propagate matrix, but only if we are the root. if (parent == NULL && localDataset) { std::queue<SpillTree*> queue; if (left) queue.push(left); if (right) queue.push(right); while (!queue.empty()) { SpillTree* node = queue.front(); queue.pop(); node->dataset = dataset; if (node->left) queue.push(node->left); if (node->right) queue.push(node->right); } } }
void SpillTree<MetricType, StatisticType, MatType, HyperplaneType, SplitType>:: Serialize(Archive& ar, const unsigned int /* version */) { using data::CreateNVP; // If we're loading, and we have children, they need to be deleted. if (Archive::is_loading::value) { if (left) delete left; if (right) delete right; if (!parent && localDataset) delete dataset; } ar & CreateNVP(parent, "parent"); ar & CreateNVP(count, "count"); ar & CreateNVP(pointsIndex, "pointsIndex"); ar & CreateNVP(overlappingNode, "overlappingNode"); ar & CreateNVP(hyperplane, "hyperplane"); ar & CreateNVP(bound, "bound"); ar & CreateNVP(stat, "statistic"); ar & CreateNVP(parentDistance, "parentDistance"); ar & CreateNVP(furthestDescendantDistance, "furthestDescendantDistance"); ar & CreateNVP(dataset, "dataset"); if (Archive::is_loading::value && parent == NULL) localDataset = true; // Save children last; otherwise boost::serialization gets confused. ar & CreateNVP(left, "left"); ar & CreateNVP(right, "right"); // Due to quirks of boost::serialization, if a tree is saved as an object and // not a pointer, the first level of the tree will be duplicated on load. // Therefore, if we are the root of the tree, then we need to make sure our // children's parent links are correct, and delete the duplicated node if // necessary. if (Archive::is_loading::value) { // Get parents of left and right children, or, NULL, if they don't exist. SpillTree* leftParent = left ? left->Parent() : NULL; SpillTree* rightParent = right ? right->Parent() : NULL; // Reassign parent links if necessary. if (left && left->Parent() != this) left->Parent() = this; if (right && right->Parent() != this) right->Parent() = this; // Do we need to delete the left parent? if (leftParent != NULL && leftParent != this) { // Sever the duplicate parent's children. Ensure we don't delete the // dataset, by faking the duplicated parent's parent (that is, we need to // set the parent to something non-NULL; 'this' works). leftParent->Parent() = this; leftParent->Left() = NULL; leftParent->Right() = NULL; delete leftParent; } // Do we need to delete the right parent? if (rightParent != NULL && rightParent != this && rightParent != leftParent) { // Sever the duplicate parent's children, in the same way as above. rightParent->Parent() = this; rightParent->Left() = NULL; rightParent->Right() = NULL; delete rightParent; } } }
void SpillTree<MetricType, StatisticType, MatType, HyperplaneType, SplitType>:: SpillSingleTreeTraverser<RuleType, Defeatist>::Traverse( const size_t queryIndex, SpillTree<MetricType, StatisticType, MatType, HyperplaneType, SplitType>& referenceNode) { // If we are a leaf, run the base case as necessary. if (referenceNode.IsLeaf()) { for (size_t i = 0; i < referenceNode.NumPoints(); ++i) rule.BaseCase(queryIndex, referenceNode.Point(i)); } else { if (Defeatist && referenceNode.Overlap()) { // If referenceNode is a overlapping node we do defeatist search. size_t bestChild = rule.GetBestChild(queryIndex, referenceNode); Traverse(queryIndex, referenceNode.Child(bestChild)); ++numPrunes; } else { // If either score is DBL_MAX, we do not recurse into that node. double leftScore = rule.Score(queryIndex, *referenceNode.Left()); double rightScore = rule.Score(queryIndex, *referenceNode.Right()); if (leftScore < rightScore) { // Recurse to the left. Traverse(queryIndex, *referenceNode.Left()); // Is it still valid to recurse to the right? rightScore = rule.Rescore(queryIndex, *referenceNode.Right(), rightScore); if (rightScore != DBL_MAX) Traverse(queryIndex, *referenceNode.Right()); // Recurse to the right. else ++numPrunes; } else if (rightScore < leftScore) { // Recurse to the right. Traverse(queryIndex, *referenceNode.Right()); // Is it still valid to recurse to the left? leftScore = rule.Rescore(queryIndex, *referenceNode.Left(), leftScore); if (leftScore != DBL_MAX) Traverse(queryIndex, *referenceNode.Left()); // Recurse to the left. else ++numPrunes; } else // leftScore is equal to rightScore. { if (leftScore == DBL_MAX) { numPrunes += 2; // Pruned both left and right. } else { // Choose the left first. Traverse(queryIndex, *referenceNode.Left()); // Is it still valid to recurse to the right? rightScore = rule.Rescore(queryIndex, *referenceNode.Right(), rightScore); if (rightScore != DBL_MAX) Traverse(queryIndex, *referenceNode.Right()); else ++numPrunes; } } } } }