public void recycleGraph( KdTree tree ) { if( tree.root != null ) { // step through the graph and recycle each node open.add(tree.root); while (!open.isEmpty()) { KdTree.Node n = open.remove(open.size() - 1); if (n.left != null) open.add(n.left); if (n.right != null) open.add(n.right); recycle(n); } tree.root = null; } unusedTrees.add(tree); }
/** * Request a leaf node be returned. All data parameters will be automatically assigned appropriate * values for a leaf. */ public KdTree.Node requestNode(P point , int index ) { KdTree.Node n = requestNode(); n.point = point; n.index = index; n.split = -1; return n; }
@Test public void recycleGraph_nullRoot() { KdTreeMemory alg = new KdTreeMemory(); KdTree tree = new KdTree(); tree.root = null; alg.recycleGraph(tree); assertEquals(0,alg.open.size()); assertEquals(1,alg.unusedTrees.size()); assertEquals(0,alg.unusedNodes.size()); }
@Test public void requestNode() { KdTreeMemory alg = new KdTreeMemory(); // Empty unused list KdTree.Node n = alg.requestNode(); assertTrue(n.point == null); assertTrue(n.left == null); assertTrue(n.right == null); // put the node into the unused list alg.unusedNodes.add(n); KdTree.Node m = alg.requestNode(); assertTrue(n==m); }
@Test public void requestTree() { KdTreeMemory alg = new KdTreeMemory(); // Empty unused list KdTree n = alg.requestTree(2); assertTrue(n.root==null); // put it into the unused list and see if it is returned alg.unusedTrees.add(n); KdTree m = alg.requestTree(2); assertTrue(n==m); }
@Test public void recycle() { KdTreeMemory alg = new KdTreeMemory(); KdTree.Node n = new KdTree.Node(); n.point = new double[2]; n.left = n; n.right = n; alg.recycle(n); assertTrue(n.point == null); assertTrue(n.left == null); assertTrue(n.right == null); assertEquals(1,alg.unusedNodes.size()); } @Test
/** * Creates canonical K-D Tree by selecting the maximum variance axis and splitting the points at the median. * */ public KdTreeConstructor( KdTreeDistance<P> distance ) { this(new KdTreeMemory<>(), new AxisSplitterMedian<>(distance, new AxisSplitRuleMax())); }
@Override public void setPoints(List<P> points , boolean trackIndicies ) { if( forest[0] != null ) { for( int i = 0; i < forest.length; i++ ) memory.recycleGraph(forest[i]); } for( int i = 0; i < forest.length; i++ ) forest[i] = constructor.construct(points,trackIndicies); search1.setTrees(forest); searchN.setTrees(forest); }
/** * Creates a new {@link KdTree} from the provided points. * * WARNING: Reference to each point is saved to reduce memory usage.. * * @param points Data points. * @return KdTre */ public KdTree construct(List<P> points , boolean trackIndexes ) { GrowQueue_I32 indexes = null; if( trackIndexes ) { indexes = new GrowQueue_I32(); indexes.resize(points.size()); for (int i = 0; i < indexes.size; i++) { indexes.data[i] = i; } } KdTree tree = memory.requestTree(splitter.getPointLength()); if( points.size() == 1 ) { tree.root = createLeaf(points,indexes); } else if( points.size() > 1 ) { tree.root = computeBranch(points, indexes ); } return tree; }
@Test public void recycleGraph() { KdTreeMemory alg = new KdTreeMemory(); KdTree tree = new KdTree(); tree.root = new KdTree.Node(); tree.root.left = new KdTree.Node(); tree.root.right = new KdTree.Node(); tree.root.left.left = new KdTree.Node(); tree.root.left.right = new KdTree.Node(); alg.recycleGraph(tree); assertEquals(0,alg.open.size()); assertEquals(1,alg.unusedTrees.size()); assertEquals(5,alg.unusedNodes.size()); }
@Test public void requestNode_leaf() { // create a node with values that need to be changed KdTree.Node n = new KdTree.Node(); n.point = new double[2]; n.split = 123; n.index = 3; KdTreeMemory alg = new KdTreeMemory(); alg.unusedNodes.add(n); KdTree.Node m = alg.requestNode(new double[]{1,2},4); assertTrue(m==n); assertTrue(((double[])m.point)[0]==1); assertEquals(m.index,4); assertTrue(m.split==-1); }
/** * Creates canonical K-D Tree by selecting the maximum variance axis and splitting the points at the median. * */ public KdTreeConstructor( KdTreeDistance<P> distance ) { this(new KdTreeMemory<>(), new AxisSplitterMedian<>(distance, new AxisSplitRuleMax())); }
@Override public void setPoints(List<P> points, boolean trackIndicies) { if( tree != null ) memory.recycleGraph(tree); tree = constructor.construct(points,trackIndicies); search.setTree(tree); searchN.setTree(tree); }
/** * Creates a new {@link KdTree} from the provided points. * * WARNING: Reference to each point is saved to reduce memory usage.. * * @param points Data points. * @return KdTre */ public KdTree construct(List<P> points , boolean trackIndexes ) { GrowQueue_I32 indexes = null; if( trackIndexes ) { indexes = new GrowQueue_I32(); indexes.resize(points.size()); for (int i = 0; i < indexes.size; i++) { indexes.data[i] = i; } } KdTree tree = memory.requestTree(splitter.getPointLength()); if( points.size() == 1 ) { tree.root = createLeaf(points,indexes); } else if( points.size() > 1 ) { tree.root = computeBranch(points, indexes ); } return tree; }
/** * Request a leaf node be returned. All data parameters will be automatically assigned appropriate * values for a leaf. */ public KdTree.Node requestNode(P point , int index ) { KdTree.Node n = requestNode(); n.point = point; n.index = index; n.split = -1; return n; }
/** * Makes sure a branch is created correctly given the results from the splitter */ @Test public void computeBranch_dontTrack() { DummySplitter splitter = createSplitter(1,1,false); splitter.splitAxis = 1; splitter.splitPoint = new double[]{2,3}; KdTreeConstructor<double[]> alg = new KdTreeConstructor<>(new KdTreeMemory(),splitter); KdTree.Node n = alg.computeBranch(new ArrayList<>(),null); assertSame(n.point, splitter.splitPoint); assertEquals(n.split, splitter.splitAxis); assertEquals(-2, n.index); // default value in splitter assertTrue(n.left.isLeaf()); assertTrue(n.right.isLeaf()); assertSame(n.left.point, splitter.left.get(0)); assertEquals(-1, n.left.index); assertSame(n.right.point, splitter.right.get(0)); assertEquals(-1, n.right.index); }
@Override public void setPoints(List<P> points , boolean trackIndicies ) { if( forest[0] != null ) { for( int i = 0; i < forest.length; i++ ) memory.recycleGraph(forest[i]); } for( int i = 0; i < forest.length; i++ ) forest[i] = constructor.construct(points,trackIndicies); search1.setTrees(forest); searchN.setTrees(forest); }
public void recycleGraph( KdTree tree ) { if( tree.root != null ) { // step through the graph and recycle each node open.add(tree.root); while (!open.isEmpty()) { KdTree.Node n = open.remove(open.size() - 1); if (n.left != null) open.add(n.left); if (n.right != null) open.add(n.right); recycle(n); } tree.root = null; } unusedTrees.add(tree); }
/** * Convenient function for creating a leaf node */ private KdTree.Node createLeaf(List<P> points , GrowQueue_I32 indexes ) { int index = indexes == null ? -1 : indexes.get(0); return memory.requestNode(points.get(0),index); } }
/** * Basic tests to see if it can handle different sized input lists. */ @Test public void construct() { KdTreeConstructor<double[]> alg = new KdTreeConstructor<>(new KdTreeMemory(),createSplitter(1,1,false)); // test an empty list List<double[]> points = new ArrayList<>(); KdTree tree = alg.construct(points,false); assertEquals(2, tree.N); assertNull(tree.root); // add a point points.add( new double[]{1,2}); tree = alg.construct(points,false); assertEquals(2, tree.N); assertSame(tree.root.point, points.get(0)); assertTrue(tree.root.isLeaf()); // add another point. These input points are ignored by the dummy splitter points.add( new double[]{1,2,4,5}); tree = alg.construct(points,false); assertEquals(2, tree.N); assertTrue(tree.root.left.isLeaf()); assertTrue(tree.root.right.isLeaf()); }