org.ddogleg.nn.alg.KdTreeConstructor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ddogleg Show documentation
Show all versions of ddogleg Show documentation
DDogleg Numerics is a high performance Java library for non-linear optimization, robust model fitting, polynomial root finding, sorting, and more.
/*
* Copyright (c) 2012-2013, Peter Abeles. All Rights Reserved.
*
* This file is part of DDogleg (http://ddogleg.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ddogleg.nn.alg;
import java.util.ArrayList;
import java.util.List;
/**
* Creates a new {@link KdTree KD-Tree} from a list of points and (optional) associated data. Which axis is used
* to split the data and how to split the data is determined by the {@link AxisSplitter} passed in.
*
* A child node can be null if it is a leaf and there was no data in that direction.
*
* WARNING: A reference to the input points is saved. Do not modify the input until the K-D Tree is no longer needed.
* This reduced memory overhead significantly.
*
* @author Peter Abeles
*/
public class KdTreeConstructor {
// Number of elements/axes in each data point
private int N;
// selects which axis to split along and divides the set of points
AxisSplitter splitter;
// Used to recycles memory and avoid GC calls
KdTreeMemory memory;
/**
* Constructor which allows for maximum configurable.
*
* @param memory Used to recycle data
* @param N Number of elements/axes in each data point
*/
public KdTreeConstructor( KdTreeMemory memory , int N , AxisSplitter splitter ) {
this.memory = memory;
this.N = N;
this.splitter = splitter;
splitter.setDimension(N);
}
/**
* Creates canonical K-D Tree by selecting the maximum variance axis and splitting the points at the median.
*
* @param N N Number of elements/axes in each data point
*/
public KdTreeConstructor( int N ) {
this(new KdTreeMemory(), N, new AxisSplitterMedian(new AxisSplitRuleMax()));
}
/**
* Creates a new {@link KdTree} from the provided points.
*
* WARNING: Reference to each point is saved to reduce memory usage..
*
* @param points Data points.
* @param data (Optional) Data associated to each point. Can be null.
* @return KdTre
*/
public KdTree construct( List points ,
List data )
{
KdTree tree = memory.requestTree();
tree.N = N;
if( points.size() == 1 ) {
tree.root = createLeaf(points,data);
} else if( points.size() > 1 ) {
tree.root = computeBranch(points, data );
}
return tree;
}
/**
* Given the data inside this particular node, select a point for the node and
* compute the node's children
*
* @return The node associated with this region
*/
protected KdTree.Node computeBranch(List points, List data ) {
// declare storage for the split data
List left = new ArrayList(points.size()/2);
List right = new ArrayList(points.size()/2);
List leftData,rightData;
if( data == null ) {
leftData = null; rightData = null;
} else {
leftData = new ArrayList(points.size()/2);
rightData = new ArrayList(points.size()/2);
}
// perform the splitting
splitter.splitData(points,data,left,leftData,right,rightData);
// save the results into the current node and its children
KdTree.Node node = memory.requestNode();
node.split = splitter.getSplitAxis();
node.point = splitter.getSplitPoint();
node.data = splitter.getSplitData();
// Compute the left and right children
node.left = computeChild(left,leftData);
// free memory
left = null; leftData = null;
node.right = computeChild(right,rightData);
return node;
}
/**
* Creates a child by checking to see if it is a leaf or branch.
*/
protected KdTree.Node computeChild( List points , List data )
{
if( points.size() == 0 )
return null;
if( points.size() == 1 ) {
return createLeaf(points,data);
} else {
return computeBranch(points,data);
}
}
/**
* Convenient function for creating a leaf node
*/
private KdTree.Node createLeaf( List points , List data ) {
D d = data == null ? null : data.get(0);
return memory.requestNode(points.get(0),d);
}
}