/** * Splits a node into two based on the midpoint value of the dimension in which the node's * rectangle is widest. If after splitting one side is empty then it is slided towards the * non-empty side until there is at least one point on the empty side. The two nodes created after * the whole splitting are correctly initialised. And, node.left and node.right are set * appropriately. * * @param node The node to split. * @param numNodesCreated The number of nodes that so far have been created for the tree, so that * the newly created nodes are assigned correct/meaningful node numbers/ids. * @param nodeRanges The attributes' range for the points inside the node that is to be split. * @param universe The attributes' range for the whole point-space. * @throws Exception If there is some problem in splitting the given node. */ public void splitNode( KDTreeNode node, int numNodesCreated, double[][] nodeRanges, double[][] universe) throws Exception { correctlyInitialized(); if (node.m_NodesRectBounds == null) { node.m_NodesRectBounds = new double[2][node.m_NodeRanges.length]; for (int i = 0; i < node.m_NodeRanges.length; i++) { node.m_NodesRectBounds[MIN][i] = node.m_NodeRanges[i][MIN]; node.m_NodesRectBounds[MAX][i] = node.m_NodeRanges[i][MAX]; } } // finding widest side of the hyper rectangle double maxRectWidth = Double.NEGATIVE_INFINITY, maxPtWidth = Double.NEGATIVE_INFINITY, tempval; int splitDim = -1, classIdx = m_Instances.classIndex(); for (int i = 0; i < node.m_NodesRectBounds[0].length; i++) { if (i == classIdx) continue; tempval = node.m_NodesRectBounds[MAX][i] - node.m_NodesRectBounds[MIN][i]; if (m_NormalizeNodeWidth) { tempval = tempval / universe[i][WIDTH]; } if (tempval > maxRectWidth && node.m_NodeRanges[i][WIDTH] > 0.0) maxRectWidth = tempval; } for (int i = 0; i < node.m_NodesRectBounds[0].length; i++) { if (i == classIdx) continue; tempval = node.m_NodesRectBounds[MAX][i] - node.m_NodesRectBounds[MIN][i]; if (m_NormalizeNodeWidth) { tempval = tempval / universe[i][WIDTH]; } if (tempval >= maxRectWidth * (1 - ERR) && node.m_NodeRanges[i][WIDTH] > 0.0) { if (node.m_NodeRanges[i][WIDTH] > maxPtWidth) { maxPtWidth = node.m_NodeRanges[i][WIDTH]; if (m_NormalizeNodeWidth) maxPtWidth = maxPtWidth / universe[i][WIDTH]; splitDim = i; } } } double splitVal = node.m_NodesRectBounds[MIN][splitDim] + (node.m_NodesRectBounds[MAX][splitDim] - node.m_NodesRectBounds[MIN][splitDim]) * 0.5; // might want to try to slide it further to contain more than one point on // the // side that is resulting empty if (splitVal < node.m_NodeRanges[splitDim][MIN]) splitVal = node.m_NodeRanges[splitDim][MIN]; else if (splitVal >= node.m_NodeRanges[splitDim][MAX]) splitVal = node.m_NodeRanges[splitDim][MAX] - node.m_NodeRanges[splitDim][WIDTH] * 0.001; int rightStart = rearrangePoints(m_InstList, node.m_Start, node.m_End, splitDim, splitVal); if (rightStart == node.m_Start || rightStart > node.m_End) { if (rightStart == node.m_Start) throw new Exception( "Left child is empty in node " + node.m_NodeNumber + ". Not possible with " + "SlidingMidPointofWidestSide splitting method. Please " + "check code."); else throw new Exception( "Right child is empty in node " + node.m_NodeNumber + ". Not possible with " + "SlidingMidPointofWidestSide splitting method. Please " + "check code."); } node.m_SplitDim = splitDim; node.m_SplitValue = splitVal; double[][] widths = new double[2][node.m_NodesRectBounds[0].length]; System.arraycopy( node.m_NodesRectBounds[MIN], 0, widths[MIN], 0, node.m_NodesRectBounds[MIN].length); System.arraycopy( node.m_NodesRectBounds[MAX], 0, widths[MAX], 0, node.m_NodesRectBounds[MAX].length); widths[MAX][splitDim] = splitVal; node.m_Left = new KDTreeNode( numNodesCreated + 1, node.m_Start, rightStart - 1, m_EuclideanDistance.initializeRanges(m_InstList, node.m_Start, rightStart - 1), widths); widths = new double[2][node.m_NodesRectBounds[0].length]; System.arraycopy( node.m_NodesRectBounds[MIN], 0, widths[MIN], 0, node.m_NodesRectBounds[MIN].length); System.arraycopy( node.m_NodesRectBounds[MAX], 0, widths[MAX], 0, node.m_NodesRectBounds[MAX].length); widths[MIN][splitDim] = splitVal; node.m_Right = new KDTreeNode( numNodesCreated + 2, rightStart, node.m_End, m_EuclideanDistance.initializeRanges(m_InstList, rightStart, node.m_End), widths); }