/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* BallTreeConstructor.java
* Copyright (C) 2007-2012 University of Waikato, Hamilton, New Zealand
*/
package weka.core.neighboursearch.balltrees;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Vector;
import weka.core.DistanceFunction;
import weka.core.EuclideanDistance;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Option;
import weka.core.OptionHandler;
import weka.core.RevisionHandler;
import weka.core.RevisionUtils;
import weka.core.Utils;
/**
* Abstract class for constructing a BallTree .
*
* @author Ashraf M. Kibriya (amk14[at-the-rate]cs[dot]waikato[dot]ac[dot]nz)
* @version $Revision: 8034 $
*/
public abstract class BallTreeConstructor
implements OptionHandler, Serializable, RevisionHandler {
/** The maximum number of instances allowed in a leaf. */
protected int m_MaxInstancesInLeaf=40;
/** The maximum relative radius of a leaf node
* (relative to the smallest ball enclosing all the
* data (training) points). */
protected double m_MaxRelLeafRadius=0.001;
/** Should a parent ball completely enclose the balls
* of its two children, or only the points inside
* its children. */
protected boolean m_FullyContainChildBalls = false;
/** The instances on which to build the tree. */
protected Instances m_Instances;
/** The distance function to use to build the tree. */
protected DistanceFunction m_DistanceFunction;
/** The number of internal and leaf nodes in the
* built tree. */
protected int m_NumNodes;
/** The number of leaf nodes in the built tree. */
protected int m_NumLeaves;
/** The depth of the built tree. */
protected int m_MaxDepth;
/** The master index array. */
protected int[] m_InstList;
/**
* Creates a new instance of BallTreeConstructor.
*/
public BallTreeConstructor() {
}
/**
* Builds the ball tree.
* @return The root node of the tree.
* @throws Exception If there is problem building
* the tree.
*/
public abstract BallNode buildTree() throws Exception;
/**
* Adds an instance to the ball tree.
* @param node The root node of the tree.
* @param inst The instance to add to the tree.
* @return The new master index array after
* adding the instance.
* @throws Exception If there is some problem adding
* the given instance to the tree.
*/
public abstract int[] addInstance(BallNode node, Instance inst)
throws Exception;
/**
* Returns the tip text for this property.
*
* @return tip text for this property suitable for
* displaying in the explorer/experimenter gui.
*/
public String maxInstancesInLeafTipText() {
return "The maximum number of instances allowed in a leaf.";
}
/**
* Returns the maximum number of instances allowed in a leaf.
* @return The maximum number of instances allowed in a leaf.
*/
public int getMaxInstancesInLeaf() {
return m_MaxInstancesInLeaf;
}
/**
* Sets the maximum number of instances allowed in a leaf.
* @param num The maximum number of instances allowed in
* a leaf.
* @throws Exception If the num is < 1.
*/
public void setMaxInstancesInLeaf(int num) throws Exception {
if(num<1)
throw new Exception("The maximum number of instances in a leaf must " +
"be >=1.");
m_MaxInstancesInLeaf = num;
}
/**
* Returns the tip text for this property.
*
* @return tip text for this property suitable for
* displaying in the explorer/experimenter gui.
*/
public String maxRelativeLeafRadiusTipText() {
return "The maximum relative radius allowed for a leaf node. " +
"Itis relative to the radius of the smallest ball " +
"enclosing all the data points (that were used to " +
"build the tree). This smallest ball would be the " +
"same as the root node's ball, if ContainChildBalls " +
"property is set to false (default).";
}
/** Returns the maximum relative radius of a leaf node.
* It is relative to the radius of the smallest ball enclosing all
* the data points (that were used to build the tree). This smallest
* ball would be the same as the root node's ball, if
* ContainChildBalls property is set to false (default).
* @return The maximum relative radius allowed for a leaf.
*/
public double getMaxRelativeLeafRadius() {
return m_MaxRelLeafRadius;
}
/** Sets the maximum relative radius, allowed for a leaf node. The
* radius is relative to the radius of the smallest ball enclosing all
* the data points (that were used to build the tree). This smallest
* ball would be the same as the root node's ball, if
* ContainChildBalls property is set to false (default).
* @param radius The maximum relative radius allowed for a leaf.
* @throws Exception If radius is < 0.0.
*/
public void setMaxRelativeLeafRadius(double radius) throws Exception {
if(radius < 0.0)
throw new Exception("The radius for the leaves should be >= 0.0");
m_MaxRelLeafRadius = radius;
}
/**
* Returns the tip text for this property.
*
* @return tip text for this property suitable for
* displaying in the explorer/experimenter gui.
*/
public String containChildBallsTipText() {
return "Whether to contain fully the child balls.";
}
/**
* Gets whether if a parent ball should completely enclose
* its two child balls.
* @return true if parent ball is to enclose its child
* balls.
*/
public boolean getContainChildBalls() {
return m_FullyContainChildBalls;
}
/**
* Sets whether if a parent ball should completely enclose
* its two child balls.
* @param containChildBalls Should be tree if parent ball
* is to enclose its child balls.
*/
public void setContainChildBalls(boolean containChildBalls) {
m_FullyContainChildBalls = containChildBalls;
}
/**
* Sets the instances on which the tree is to be built.
* @param inst The instances on which to build the
* ball tree.
*/
public void setInstances(Instances inst) {
m_Instances = inst;
}
/**
* Sets the master index array that points to
* instances in m_Instances, so that only this array
* is manipulated, and m_Instances is left
* untouched.
* @param instList The master index array.
*/
public void setInstanceList(int[] instList) {
m_InstList = instList;
}
/**
* Sets the distance function to use to build the
* tree.
* @param func The distance function.
*/
public void setEuclideanDistanceFunction(EuclideanDistance func) {
m_DistanceFunction = func;
}
/**
* Returns the number of nodes (internal + leaf)
* in the built tree.
* @return The number of nodes in the tree.
*/
public int getNumNodes() {
return m_NumNodes;
}
/**
* Returns the number of leaves in the built tree.
* @return The number of leaves in the tree.
*/
public int getNumLeaves() {
return m_NumLeaves;
}
/**
* Returns the depth of the built tree.
* @return The depth of the tree.
*/
public int getMaxDepth() {
return m_MaxDepth;
}
/**
* Returns an enumeration describing the available options.
*
* @return an enumeration of all the available options.
*/
public Enumeration listOptions() {
Vector<Option> newVector = new Vector<Option>();
newVector.addElement(new Option(
"\tSet maximum number of instances in a leaf node\n"
+ "\t(default: 40)",
"N", 0, "-N <value>"));
newVector.addElement(new Option(
"\tSet internal nodes' radius to the sum \n"
+ "\tof the child balls radii. So that it \n"
+ "contains the child balls.",
"R", 0, "-R"));
return newVector.elements();
}
/**
* Parses a given list of options.
*
* @param options the list of options as an array of strings
* @throws Exception if an option is not supported
*/
public void setOptions(String[] options)
throws Exception {
String optionString = Utils.getOption('N', options);
if(optionString.length() != 0) {
setMaxInstancesInLeaf(Integer.parseInt(optionString));
}
else {
setMaxInstancesInLeaf(40);
}
setContainChildBalls(Utils.getFlag('R', options));
}
/**
* Gets the current settings.
*
* @return an array of strings suitable for passing to setOptions
*/
public String[] getOptions() {
Vector<String> result;
result = new Vector<String>();
result.add("-N");
result.add("" + getMaxInstancesInLeaf());
if (getContainChildBalls())
result.add("-R");
return result.toArray(new String[result.size()]);
}
/**
* Returns the revision string.
*
* @return the revision
*/
public String getRevision() {
return RevisionUtils.extract("$Revision: 8034 $");
}
}