public Queue<List<Double>> findNeighbors(int k, List<Double> point) { Queue<List<Double>> pointsN = getPointsQueue(point); Queue<BallNode> ballsQueueQ = getBallsQueue(point); ballsQueueQ.add(root); while (!ballsQueueQ.isEmpty()) { BallNode ballS = ballsQueueQ.poll(); if (pointsN.size() >= k) { if (ballS.distanceTo(point) > distance(pointsN.peek(), point)) { return pointsN; } } if (ballS.isLeaf()) { for (List<Double> p : ballS.points.getData()) { pointsN.add(p); } while (pointsN.size() > k) { pointsN.poll(); } } else { ballsQueueQ.add(ballS.left); ballsQueueQ.add(ballS.right); } } return pointsN; }
/** * Builds a ball tree middle out. * * @return The root node of the tree. * @throws Exception If there is problem building the tree. */ public BallNode buildTree() throws Exception { m_NumNodes = m_MaxDepth = m_NumLeaves = 0; if (rootRadius == -1) { rootRadius = BallNode.calcRadius( m_InstList, m_Instances, BallNode.calcCentroidPivot(m_InstList, m_Instances), m_DistanceFunction); } BallNode root = buildTreeMiddleOut(0, m_Instances.numInstances() - 1); return root; }
/** * Applies the middle out build procedure to the leaves of the tree. The leaf nodes should be the * ones that were created by createAnchorsHierarchy(). The process continues recursively for the * leaves created for each leaf of the given tree until for some leaf node <= m_MaxInstancesInLeaf * instances remain in the leaf. * * @param node The root of the tree. * @throws Exception If there is some problem in building the tree leaves. */ protected void buildLeavesMiddleOut(BallNode node) throws Exception { if (node.m_Left != null && node.m_Right != null) { // if an internal node buildLeavesMiddleOut(node.m_Left); buildLeavesMiddleOut(node.m_Right); } else if (node.m_Left != null || node.m_Right != null) { throw new Exception("Invalid leaf assignment. Please check code"); } else { // if node is a leaf BallNode n2 = buildTreeMiddleOut(node.m_Start, node.m_End); if (n2.m_Left != null && n2.m_Right != null) { node.m_Left = n2.m_Left; node.m_Right = n2.m_Right; buildLeavesMiddleOut(node); // the stopping condition in buildTreeMiddleOut will stop the recursion, // where it won't split a node at all, and we won't recurse here. } else if (n2.m_Left != null || n2.m_Right != null) throw new Exception("Invalid leaf assignment. Please check code"); } }
/** * Makes BallTreeNodes out of TempNodes. * * @param node The root TempNode * @param startidx The start of the portion of master index array the TempNodes are made from. * @param endidx The end of the portion of master index array the TempNodes are made from. * @param depth The depth in the tree where this root TempNode is made (needed when leaves of a * tree deeper down are built middle out). * @return The root BallTreeNode. */ protected BallNode makeBallTreeNodes(TempNode node, int startidx, int endidx, int depth) { BallNode ball = null; if (node.left != null && node.right != null) { // make an internal node ball = new BallNode(startidx, endidx, m_NumNodes, node.anchor, node.radius); m_NumNodes += 1; ball.m_Left = makeBallTreeNodes( node.left, startidx, startidx + node.left.points.length() - 1, depth + 1); ball.m_Right = makeBallTreeNodes(node.right, startidx + node.left.points.length(), endidx, depth + 1); m_MaxDepth++; } else { // make a leaf node ball = new BallNode(startidx, endidx, m_NumNodes, node.anchor, node.radius); m_NumNodes += 1; m_NumLeaves += 1; } return ball; }
/** * Builds a ball tree middle out from the portion of the master index array given by supplied * start and end index. * * @param startIdx The start of the portion in master index array. * @param endIdx the end of the portion in master index array. * @return The root node of the built tree. * @throws Exception If there is some problem building the tree. */ protected BallNode buildTreeMiddleOut(int startIdx, int endIdx) throws Exception { Instance pivot; double radius; Vector<TempNode> anchors; int numInsts = endIdx - startIdx + 1; int numAnchors = (int) Math.round(Math.sqrt(numInsts)); // create anchor's hierarchy if (numAnchors > 1) { pivot = BallNode.calcCentroidPivot(startIdx, endIdx, m_InstList, m_Instances); radius = BallNode.calcRadius(startIdx, endIdx, m_InstList, m_Instances, pivot, m_DistanceFunction); if (numInsts <= m_MaxInstancesInLeaf || (rootRadius == 0 ? true : radius / rootRadius < m_MaxRelLeafRadius)) { // just make a leaf don't make anchors hierarchy BallNode node = new BallNode(startIdx, endIdx, m_NumNodes, pivot, radius); return node; } anchors = new Vector<TempNode>(numAnchors); createAnchorsHierarchy(anchors, numAnchors, startIdx, endIdx); BallNode node = mergeNodes(anchors, startIdx, endIdx); buildLeavesMiddleOut(node); return node; } // end anchors hierarchy else { BallNode node = new BallNode( startIdx, endIdx, m_NumNodes, (pivot = BallNode.calcCentroidPivot(startIdx, endIdx, m_InstList, m_Instances)), BallNode.calcRadius( startIdx, endIdx, m_InstList, m_Instances, pivot, m_DistanceFunction)); return node; } }
/** * Returns an anchor point which is furthest from the mean point for a given set of points * (instances) (The anchor instance is chosen from the given set of points). * * @param startIdx The start index of the points for which anchor point is required. * @param endIdx The end index of the points for which anchor point is required. * @return The furthest point/instance from the mean of given set of points. */ protected TempNode getFurthestFromMeanAnchor(int startIdx, int endIdx) { TempNode anchor = new TempNode(); Instance centroid = BallNode.calcCentroidPivot(startIdx, endIdx, m_InstList, m_Instances); Instance temp; double tmpr; anchor.radius = Double.NEGATIVE_INFINITY; for (int i = startIdx; i <= endIdx; i++) { temp = m_Instances.instance(m_InstList[i]); tmpr = m_DistanceFunction.distance(centroid, temp); if (tmpr > anchor.radius) { anchor.idx = m_InstList[i]; anchor.anchor = temp; anchor.radius = tmpr; } } setPoints(anchor, startIdx, endIdx, m_InstList); return anchor; }
public BallTree(Matrix points, int k) { root = BallNode.buildBallNode(points, k); }