All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ddogleg.nn.alg.KdTreeConstructor Maven / Gradle / Ivy

Go to download

DDogleg Numerics is a high performance Java library for non-linear optimization, robust model fitting, polynomial root finding, sorting, and more.

There is a newer version: 0.23.4
Show newest version
/*
 * 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);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy