/*
 *    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 2 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, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 *    J48Consolidated.java
 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
 *
 */

package weka.classifiers.trees;


import weka.classifiers.RandomizableClassifier;
import weka.classifiers.Sourcable;
import weka.classifiers.trees.j48.*;
import weka.classifiers.trees.j48Consolidated.*;

import weka.core.AdditionalMeasureProducer;
import weka.core.Capabilities;
import weka.core.Drawable;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Matchable;
import weka.core.Option;
import weka.core.OptionHandler;
import weka.core.RevisionUtils;
import weka.core.Summarizable;
import weka.core.TechnicalInformation;
import weka.core.TechnicalInformationHandler;
import weka.core.Utils;
import weka.core.WeightedInstancesHandler;
import weka.core.TechnicalInformation.Field;
import weka.core.TechnicalInformation.Type;

import java.util.Enumeration;
import java.util.Random;
import java.util.Vector;

/**
 <!-- globalinfo-start -->
 * Class for generating a pruned or unpruned J48Consolidated decision tree. For more information, see<br/>
 * <br/>
 * �rboles Consolidados: Construcci�n de un �rbol de clasificaci�n basado en m�ltiples submuestras sin renunciar a la explicaci�n
 * <p/>
 <!-- globalinfo-end -->
 *
 <!-- technical-bibtex-start -->
 * BibTeX:
 * <pre>
 *  AUTHOR, "Jes�s M�P�rez de la Fuente");
 *  YEAR, "2006");
 *  TITLE, "�rboles Consolidados: Construcci�n de un �rbol de clasificaci�n basado en m�ltiples submuestras sin renunciar a la explicaci�n");   
 * </pre>
 * <p/>
 <!-- technical-bibtex-end -->
 *
 <!-- options-start -->
 * Valid options are: <p/>
 * 
 * <pre> -U
 *  Use unpruned tree.</pre>
 * 
 * <pre> -C &lt;pruning confidence&gt;
 *  Set confidence threshold for pruning.
 *  (default 0.25)</pre>
 * 
 * <pre> -M &lt;minimum number of instances&gt;
 *  Set minimum number of instances per leaf.
 *  (default 2)</pre>
 *  
 * <pre> -S
 *  Don't perform subtree raising.</pre>
 * 
 * <pre> -L
 *  Do not clean up after the tree has been built.</pre>
 * 
 * <pre> -A
 *  Laplace smoothing for predicted probabilities.</pre>
 * 
 * <pre> -Q &lt;seed&gt;
 *  Seed for random data shuffling (default 1).</pre>
 * 
 * <pre> -N
 * Number of samples to be generated for use in the construction of the consolidated tree.</pre>
 * 
 * <pre> -R
 * Determines whether or not replacement is used when generating the samples.</pre>
 * 
 * <pre> -B
 * Sample sizes to generate, given in percent (%) compared to the size of the original database or training sample.</pre>
 * 
 <!-- options-end -->
 *
 * @author Fernando Lozano J48Consolidated code - Eibe Frank J48 code (eibe@cs.waikato.ac.nz)
 * @version $Revision: 1.9 $
 */
public class J48Consolidated 
	extends RandomizableClassifier 
	implements OptionHandler, Drawable, Matchable, Sourcable, 
			   WeightedInstancesHandler, Summarizable, AdditionalMeasureProducer, 
			   TechnicalInformationHandler {

	/** for serialization */
	static final long serialVersionUID = -217733168393644444L;

	/** The decision tree */
	private ClassifierTree m_root;

	/** Unpruned tree? */
	private boolean m_unpruned = false;

	/** Confidence level */
	private float m_CF = 0.25f;

	/** Minimum number of instances */
	private int m_minNumObj = 2;

	/** Determines whether probabilities are smoothed using
      Laplace correction when predictions are generated */
	private boolean m_useLaplace = false;

	/** Use reduced error pruning? */
	private boolean m_reducedErrorPruning = false;

	/** Subtree raising to be performed? */
	private boolean m_subtreeRaising = true;

	/** Cleanup after the tree has been built. */
	private boolean m_noCleanup = false;

	/** Random number seed for reduced-error pruning. */
	private int m_Seed = 1;

	/** Number of samples to be generated for use in the construction of the consolidated tree.**/
	private int m_numberSamples=5; 

	/**Determines whether or not replacement is used when generating the samples.**/
	private boolean m_replacement=true;

	/**Sample sizes to generate, given in percent (%) compared to the size of the original database or training sample.**/
	private double m_bagSizePercent=100;


	/**
	 * Returns a string describing classifier
	 * @return a description suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String globalInfo() {

		return  "Class for generating a pruned or unpruned J48Consolidated decision tree. For more "
				+ "information, see\n\n"
				+ getTechnicalInformation().toString();
	}

	/**
	 * Returns an instance of a TechnicalInformation object, containing 
	 * detailed information about the technical background of this class,
	 * e.g., paper reference or book this class is based on.
	 * 
	 * @return the technical information about this class
	 */
	public TechnicalInformation getTechnicalInformation() {
		TechnicalInformation 	result;

		result = new TechnicalInformation(Type.PHDTHESIS);
		result.setValue(Field.AUTHOR, "Jes�s M�P�rez de la Fuente");
		result.setValue(Field.YEAR, "2006");
		result.setValue(Field.TITLE, "�rboles Consolidados: Construcci�n de un �rbol de clasificaci�n basado en m�ltiples submuestras sin renunciar a la explicaci�n");
		result.setValue(Field.ADDRESS, "Donostia");

		return result;
	}

	/**
	 * Returns default capabilities of the classifier.
	 *
	 * @return      the capabilities of this classifier
	 */
	public Capabilities getCapabilities() {
		Capabilities      result;

		try {
			result = new C45PruneableClassifierTree(null, !m_unpruned, m_CF, m_subtreeRaising, !m_noCleanup).getCapabilities();
		}
		catch (Exception e) {
			result = new Capabilities(this);
		}

		result.setOwner(this);

		return result;
	}


	private void printGenerateSamples(Instances[] data){

		for(int i=0; i<data.length; i++){
			System.out.println("====SAMPLE BD=="+i+"==");
			System.out.println(data[i]);
			System.out.println(" ");
		}
	}

	/**
	 * Generates the classifier.
	 *
	 * @param instances the data to train the classifier with
	 * @throws Exception if classifier can't be built successfully
	 */
	public void buildClassifier(Instances instances) 
			throws Exception {

		ModelSelection modSelection;
		modSelection = new C45ConsolidatedModelSelection(m_minNumObj, instances);
		m_root = new C45ConsolidatedPruneableClassifierTree(modSelection, !m_unpruned,
				m_CF, m_subtreeRaising, !m_noCleanup);

		// remove instances with missing class before generate samples
		instances = new Instances(instances);
		instances.deleteWithMissingClass();

		//Generate as many samples as the number of samples with the given instances
		Instances[] samplesVector = generateSamples(instances);   

		//	    printGenerateSamples(samplesVector);

		((C45ConsolidatedPruneableClassifierTree)m_root).buildClassifier(instances, samplesVector);

		((C45ModelSelection) modSelection).cleanup();
	}


	/**
	 * Generate as many samples as the number of samples with the given instances
	 * @param instances
	 * @return Instances[] an array of samples
	 * @throws Exception 
	 */

	private Instances[] generateSamples(Instances instances) throws Exception {

		// can classifier tree handle the data?
		getCapabilities().testWithFail(instances);

		// remove instances with missing class
		instances = new Instances(instances);
		instances.deleteWithMissingClass();


		Instances newSample;

		//Generate an array of samples with the given number of Samples.
		Instances[] instancesSamples = new Instances[m_numberSamples];


		for(int k=0; k<m_numberSamples; k++){
			m_Seed=k+m_Seed;
			Random random = new Random(m_Seed);
			newSample = new Instances(instances);
			newSample.randomize(random);

			if(m_replacement){
				Instances auxInstance = new Instances(newSample.resample(random));
				auxInstance.randomize(random);
				newSample = auxInstance;
			}


			//Generating different types of samples

			newSample.randomize(random);
			double bagSize =  newSample.numInstances()* m_bagSizePercent /100;
			int bagSizeInt = (int) bagSize;
			Instances newBagData = new Instances(newSample, 0,bagSizeInt);



			instancesSamples[k]= newBagData;

		}
		return instancesSamples;
	}


	/**
	 * Classifies an instance.
	 *
	 * @param instance the instance to classify
	 * @return the classification for the instance
	 * @throws Exception if instance can't be classified successfully
	 */
	public double classifyInstance(Instance instance) throws Exception {

		return m_root.classifyInstance(instance);
	}

	/** 
	 * Returns class probabilities for an instance.
	 *
	 * @param instance the instance to calculate the class probabilities for
	 * @return the class probabilities
	 * @throws Exception if distribution can't be computed successfully
	 */
	public final double [] distributionForInstance(Instance instance) 
			throws Exception {

		return m_root.distributionForInstance(instance, m_useLaplace);
	}

	/**
	 *  Returns the type of graph this classifier
	 *  represents.
	 *  @return Drawable.TREE
	 */   
	public int graphType() {
		return Drawable.TREE;
	}

	/**
	 * Returns graph describing the tree.
	 *
	 * @return the graph describing the tree
	 * @throws Exception if graph can't be computed
	 */
	public String graph() throws Exception {

		return m_root.graph();
	}

	/**
	 * Returns tree in prefix order.
	 *
	 * @return the tree in prefix order
	 * @throws Exception if something goes wrong
	 */
	public String prefix() throws Exception {

		return m_root.prefix();
	}


	/**
	 * Returns tree as an if-then statement.
	 *
	 * @param className the name of the Java class 
	 * @return the tree as a Java if-then type statement
	 * @throws Exception if something goes wrong
	 */
	public String toSource(String className) throws Exception {

		StringBuffer [] source = m_root.toSource(className);
		return 
				"class " + className + " {\n\n"
				+"  public static double classify(Object[] i)\n"
				+"    throws Exception {\n\n"
				+"    double p = Double.NaN;\n"
				+ source[0]  // Assignment code
						+"    return p;\n"
						+"  }\n"
						+ source[1]  // Support code
								+"}\n";
	}

	/**
	 * Returns an enumeration describing the available options.
	 *
	 * Valid options are: <p>
	 *
	 * -U <br>
	 * Use unpruned tree.<p>
	 *
	 * -C confidence <br>
	 * Set confidence threshold for pruning. (Default: 0.25) <p>
	 *
	 * -M number <br>
	 * Set minimum number of instances per leaf. (Default: 2) <p>
	 *
	 * -N <br>
	 * Number of samples to be generated for use in the construction of the consolidated tree. <p>
	 * 
	 * -R <br>
	 * Determines whether or not replacement is used when generating the samples.<p>
	 * 
	 * -B <br>
	 * Sample sizes to generate, given in percent (%) compared to the size of the original database or training sample.<p>
	 * 
	 *
	 * -S <br>
	 * Don't perform subtree raising. <p>
	 *
	 * -L <br>
	 * Do not clean up after the tree has been built.
	 *
	 * -A <br>
	 * If set, Laplace smoothing is used for predicted probabilites. <p>
	 *
	 * -Q <br>
	 * The seed for reduced-error pruning. <p>
	 *
	 * @return an enumeration of all the available options.
	 */
	public Enumeration listOptions() {

		Vector newVector = new Vector(9);

		newVector.
		addElement(new Option("\tUse unpruned tree.",
				"U", 0, "-U"));
		newVector.
		addElement(new Option("\tSet confidence threshold for pruning.\n" +
				"\t(default 0.25)",
				"C", 1, "-C <pruning confidence>"));
		newVector.
		addElement(new Option("\tSet minimum number of instances per leaf.\n" +
				"\t(default 2)",
				"M", 1, "-M <minimum number of instances>"));

		newVector.
		addElement(new Option("\tDon't perform subtree raising.",
				"S", 0, "-S"));
		newVector.
		addElement(new Option("\tDo not clean up after the tree has been built.",
				"L", 0, "-L"));
		newVector.
		addElement(new Option("\tLaplace smoothing for predicted probabilities.",
				"A", 0, "-A"));
		newVector.
		addElement(new Option("\tSeed for random data shuffling (default 1).",
				"Q", 1, "-Q <seed>"));
		newVector.
		addElement(new Option("\tNumber of samples to be generated for use in the construction of the consolidated tree.",
				"N", 1, "-N <Number of samples>"));

		newVector.
		addElement(new Option("\tUse replacement ",
				"R", 0, "-R"));

		newVector.
		addElement(new Option("\tSample sizes to generate, given in percent (%) compared to the size of the original database or training sample.",
				"B", 1, "-B <Sample size to generate (%)>"));

		return newVector.elements();
	}

	/**
	 * Parses a given list of options.
	 * 
   <!-- options-start -->
	 * Valid options are: <p/>
	 * 
	 * <pre> -U
	 *  Use unpruned tree.</pre>
	 * 
	 * <pre> -C &lt;pruning confidence&gt;
	 *  Set confidence threshold for pruning.
	 *  (default 0.25)</pre>
	 * 
	 * <pre> -M &lt;minimum number of instances&gt;
	 *  Set minimum number of instances per leaf.
	 *  (default 2)</pre>
	 * 
	 * <pre> -N
	 * Number of samples to be generated for use in the construction of the consolidated tree.</pre>
	 * 
	 * <pre> -R
	 * Determines whether or not replacement is used when generating the samples.</pre>
	 * 
	 * <pre> -B
	 * Sample sizes to generate, given in percent (%) compared to the size of the original database or training sample.</pre>
	 * 
	 * 
	 * <pre> -S
	 *  Don't perform subtree raising.</pre>
	 * 
	 * <pre> -L
	 *  Do not clean up after the tree has been built.</pre>
	 * 
	 * <pre> -A
	 *  Laplace smoothing for predicted probabilities.</pre>
	 * 
	 * <pre> -Q &lt;seed&gt;
	 *  Seed for random data shuffling (default 1).</pre>
	 * 
   <!-- options-end -->
	 *
	 * @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 {

		// Other options

		String numberSamplesString = Utils.getOption('N', options);
		if (numberSamplesString.length() != 0) {
			m_numberSamples = Integer.parseInt(numberSamplesString);
		} else {
			m_numberSamples = 5;
		}

		String bagSizePercentString = Utils.getOption('B', options);
		if (bagSizePercentString.length() != 0) {
			m_bagSizePercent = Double.parseDouble(bagSizePercentString);
		} else {
			m_bagSizePercent = 100;
		}


		String minNumString = Utils.getOption('M', options);
		if (minNumString.length() != 0) {
			m_minNumObj = Integer.parseInt(minNumString);
		} else {
			m_minNumObj = 2;
		}

		m_useLaplace = Utils.getFlag('A', options);

		m_replacement = Utils.getFlag('R', options);

		// Pruning options
		m_unpruned = Utils.getFlag('U', options);
		m_subtreeRaising = !Utils.getFlag('S', options);
		m_noCleanup = Utils.getFlag('L', options);
		if ((m_unpruned) && (!m_subtreeRaising)) {
			throw new Exception("Subtree raising doesn't need to be unset for unpruned tree!");
		}

		if ((m_unpruned) && (m_reducedErrorPruning)) {
			throw new Exception("Unpruned tree and reduced error pruning can't be selected " +
					"simultaneously!");
		}
		String confidenceString = Utils.getOption('C', options);
		if (confidenceString.length() != 0) {
			if (m_reducedErrorPruning) {
				throw new Exception("Setting the confidence doesn't make sense " +
						"for reduced error pruning.");
			} else if (m_unpruned) {
				throw new Exception("Doesn't make sense to change confidence for unpruned "
						+"tree!");
			} else {
				m_CF = (new Float(confidenceString)).floatValue();
				if ((m_CF <= 0) || (m_CF >= 1)) {
					throw new Exception("Confidence has to be greater than zero and smaller " +
							"than one!");
				}
			}
		} else {
			m_CF = 0.25f;
		}


		String seedString = Utils.getOption('Q', options);
		if (seedString.length() != 0) {
			m_Seed = Integer.parseInt(seedString);
		} else {
			m_Seed = 1;
		}
	}

	/**
	 * Gets the current settings of the Classifier.
	 *
	 * @return an array of strings suitable for passing to setOptions
	 */
	public String [] getOptions() {

		String [] options = new String [15];
		int current = 0;

		if (m_noCleanup) {
			options[current++] = "-L";
		}
		if (m_unpruned) {
			options[current++] = "-U";
		} else {
			if (!m_subtreeRaising) {
				options[current++] = "-S";
			}
			if (m_reducedErrorPruning) {


				options[current++] = "-Q"; options[current++] = "" + m_Seed;
			} else {
				options[current++] = "-C"; options[current++] = "" + m_CF;
			}
		}


		options[current++] = "-M"; options[current++] = "" + m_minNumObj;
		options[current++] = "-N"; options[current++] = "" + m_numberSamples;
		options[current++] = "-B"; options[current++] = "" + m_bagSizePercent;
		if (m_useLaplace) {
			options[current++] = "-A";
		}
		if (m_replacement) {
			options[current++] = "-R";
		}

		while (current < options.length) {
			options[current++] = "";
		}
		return options;
	}

	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String seedTipText() {
		return "The seed used for randomizing the data " +
				"when reduced-error pruning is used.";
	}

	/**
	 * Get the value of Seed.
	 *
	 * @return Value of Seed.
	 */
	public int getSeed() {

		return m_Seed;
	}

	/**
	 * Set the value of Seed.
	 *
	 * @param newSeed Value to assign to Seed.
	 */
	public void setSeed(int newSeed) {

		m_Seed = newSeed;
	}

	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String useLaplaceTipText() {
		return "Whether counts at leaves are smoothed based on Laplace.";
	}

	/**
	 * Get the value of useLaplace.
	 *
	 * @return Value of useLaplace.
	 */
	public boolean getUseLaplace() {

		return m_useLaplace;
	}

	/**
	 * Set the value of useLaplace.
	 *
	 * @param newuseLaplace Value to assign to useLaplace.
	 */
	public void setUseLaplace(boolean newuseLaplace) {

		m_useLaplace = newuseLaplace;
	}

	/**
	 * Returns a description of the classifier.
	 * 
	 * @return a description of the classifier
	 */
	public String toString() {

		if (m_root == null) {
			return "No classifier built";
		}
		if (m_unpruned)
			return "J48Consolidated unpruned tree\n------------------\n" + m_root.toString();
		else
			return "J48Consolidated pruned tree\n------------------\n" + m_root.toString();
	}

	/**
	 * Returns a superconcise version of the model
	 * 
	 * @return a summary of the model
	 */
	public String toSummaryString() {

		return "Number of leaves: " + m_root.numLeaves() + "\n"
				+ "Size of the tree: " + m_root.numNodes() + "\n";
	}

	/**
	 * Returns the size of the tree
	 * @return the size of the tree
	 */
	public double measureTreeSize() {
		return m_root.numNodes();
	}

	/**
	 * Returns the number of leaves
	 * @return the number of leaves
	 */
	public double measureNumLeaves() {
		return m_root.numLeaves();
	}

	/**
	 * Returns the number of rules (same as number of leaves)
	 * @return the number of rules
	 */
	public double measureNumRules() {
		return m_root.numLeaves();
	}

	/**
	 * Returns an enumeration of the additional measure names
	 * @return an enumeration of the measure names
	 */
	public Enumeration enumerateMeasures() {
		Vector newVector = new Vector(3);
		newVector.addElement("measureTreeSize");
		newVector.addElement("measureNumLeaves");
		newVector.addElement("measureNumRules");
		return newVector.elements();
	}

	/**
	 * Returns the value of the named measure
	 * @param additionalMeasureName the name of the measure to query for its value
	 * @return the value of the named measure
	 * @throws IllegalArgumentException if the named measure is not supported
	 */
	public double getMeasure(String additionalMeasureName) {
		if (additionalMeasureName.compareToIgnoreCase("measureNumRules") == 0) {
			return measureNumRules();
		} else if (additionalMeasureName.compareToIgnoreCase("measureTreeSize") == 0) {
			return measureTreeSize();
		} else if (additionalMeasureName.compareToIgnoreCase("measureNumLeaves") == 0) {
			return measureNumLeaves();
		} else {
			throw new IllegalArgumentException(additionalMeasureName 
					+ " not supported (j48)");
		}
	}


	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String replacementTipText() {
		return "Whether replacement is performed.";
	}

	/**
	 * Get the value of replacement
	 *
	 * @return Value of replacement
	 */
	public boolean getReplacement() {

		return m_replacement;
	}

	/**
	 * Set the value of replacement.
	 * @param v  Value to assign to replacement.
	 */
	public void setReplacement(boolean v) {

		m_replacement = v;
	}

	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String numberSamplesTipText() {
		return "Number of samples to be generated for use in the CTC";
	}

	/**
	 * Get the value of numberSamples.
	 *
	 * @return Value of numberSamples.
	 */
	public int getNumberSamples() {

		return m_numberSamples;
	}

	/**
	 * Set the value of minNumObj.
	 *
	 * @param v  Value to assign to minNumObj.
	 */
	public void setNumberSamples(int v) {

		m_numberSamples = v;
	}




	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String bagSizePercentTipText() {
		return "Sample sizes to generate, given in percent (%)";
	}

	/**
	 * Get the value of bagSizePercent.
	 *
	 * @return Value of bagSizePercent.
	 */
	public double getbagSizePercent() {

		return m_bagSizePercent;
	}

	/**
	 * Set the value of minNumObj.
	 *
	 * @param v  Value to assign to minNumObj.
	 */
	public void setBagSizePercent(double v) {

		m_bagSizePercent = v;
	}



	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String unprunedTipText() {
		return "Whether pruning is performed.";
	}

	/**
	 * Get the value of unpruned.
	 *
	 * @return Value of unpruned.
	 */
	public boolean getUnpruned() {

		return m_unpruned;
	}

	/**
	 * Set the value of unpruned. Turns reduced-error pruning
	 * off if set.
	 * @param v  Value to assign to unpruned.
	 */
	public void setUnpruned(boolean v) {

		if (v) {
			m_reducedErrorPruning = false;
		}
		m_unpruned = v;
	}

	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String confidenceFactorTipText() {
		return "The confidence factor used for pruning (smaller values incur "
				+ "more pruning).";
	}

	/**
	 * Get the value of CF.
	 *
	 * @return Value of CF.
	 */
	public float getConfidenceFactor() {

		return m_CF;
	}

	/**
	 * Set the value of CF.
	 *
	 * @param v  Value to assign to CF.
	 */
	public void setConfidenceFactor(float v) {

		m_CF = v;
	}

	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String minNumObjTipText() {
		return "The minimum number of instances per leaf.";
	}

	/**
	 * Get the value of minNumObj.
	 *
	 * @return Value of minNumObj.
	 */
	public int getMinNumObj() {

		return m_minNumObj;
	}

	/**
	 * Set the value of minNumObj.
	 *
	 * @param v  Value to assign to minNumObj.
	 */
	public void setMinNumObj(int v) {

		m_minNumObj = v;
	}




	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String subtreeRaisingTipText() {
		return "Whether to consider the subtree raising operation when pruning.";
	}

	/**
	 * Get the value of subtreeRaising.
	 *
	 * @return Value of subtreeRaising.
	 */
	public boolean getSubtreeRaising() {

		return m_subtreeRaising;
	}

	/**
	 * Set the value of subtreeRaising.
	 *
	 * @param v  Value to assign to subtreeRaising.
	 */
	public void setSubtreeRaising(boolean v) {

		m_subtreeRaising = v;
	}

	/**
	 * Returns the tip text for this property
	 * @return tip text for this property suitable for
	 * displaying in the explorer/experimenter gui
	 */
	public String saveInstanceDataTipText() {
		return "Whether to save the training data for visualization.";
	}

	/**
	 * Check whether instance data is to be saved.
	 *
	 * @return true if instance data is saved
	 */
	public boolean getSaveInstanceData() {

		return m_noCleanup;
	}

	/**
	 * Set whether instance data is to be saved.
	 * @param v true if instance data is to be saved
	 */
	public void setSaveInstanceData(boolean v) {

		m_noCleanup = v;
	}

	/**
	 * Returns the revision string.
	 * 
	 * @return		the revision
	 */
	public String getRevision() {
		return RevisionUtils.extract("$Revision: 1.9 $");
	}

	/**
	 * Main method for testing this class
	 *
	 * @param argv the commandline options
	 */
	public static void main(String [] argv){
		runClassifier(new J48Consolidated(), argv);
	}
}
