Package weka.associations

Source Code of weka.associations.Tertius

/*
*    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.
*/

/*
*    Tertius.java
*    Copyright (C) 2003 Peter A. Flach, Nicolas Lachiche
*
*    Thanks to Amelie Deltour for porting the original C code to Java
*    and integrating it into Weka.
*/

package weka.associations;

import weka.associations.tertius.AttributeValueLiteral;
import weka.associations.tertius.IndividualInstances;
import weka.associations.tertius.IndividualLiteral;
import weka.associations.tertius.Literal;
import weka.associations.tertius.Predicate;
import weka.associations.tertius.Rule;
import weka.associations.tertius.SimpleLinkedList;
import weka.core.Attribute;
import weka.core.Capabilities;
import weka.core.Instances;
import weka.core.Option;
import weka.core.OptionHandler;
import weka.core.RevisionUtils;
import weka.core.SelectedTag;
import weka.core.Tag;
import weka.core.TechnicalInformation;
import weka.core.TechnicalInformationHandler;
import weka.core.Utils;
import weka.core.Capabilities.Capability;
import weka.core.TechnicalInformation.Field;
import weka.core.TechnicalInformation.Type;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Label;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

/**
<!-- globalinfo-start -->
* Finds rules according to confirmation measure (Tertius-type algorithm).<br/>
* <br/>
* For more information see:<br/>
* <br/>
* P. A. Flach, N. Lachiche (1999). Confirmation-Guided Discovery of first-order rules with Tertius. Machine Learning. 42:61-95.
* <p/>
<!-- globalinfo-end -->
*
<!-- technical-bibtex-start -->
* BibTeX:
* <pre>
* &#64;article{Flach1999,
*    author = {P. A. Flach and N. Lachiche},
*    journal = {Machine Learning},
*    pages = {61-95},
*    title = {Confirmation-Guided Discovery of first-order rules with Tertius},
*    volume = {42},
*    year = {1999}
* }
* </pre>
* <p/>
<!-- technical-bibtex-end -->
*
<!-- options-start -->
* Valid options are: <p/>
*
* <pre> -K &lt;number of values in result&gt;
*  Set maximum number of confirmation  values in the result. (default: 10)</pre>
*
* <pre> -F &lt;frequency threshold&gt;
*  Set frequency threshold for pruning. (default: 0)</pre>
*
* <pre> -C &lt;confirmation threshold&gt;
*  Set confirmation threshold. (default: 0)</pre>
*
* <pre> -N &lt;noise threshold&gt;
*  Set noise threshold : maximum frequency of counter-examples.
*  0 gives only satisfied rules. (default: 1)</pre>
*
* <pre> -R
*  Allow attributes to be repeated in a same rule.</pre>
*
* <pre> -L &lt;number of literals&gt;
*  Set maximum number of literals in a rule. (default: 4)</pre>
*
* <pre> -G &lt;0=no negation | 1=body | 2=head | 3=body and head&gt;
*  Set the negations in the rule. (default: 0)</pre>
*
* <pre> -S
*  Consider only classification rules.</pre>
*
* <pre> -c &lt;class index&gt;
*  Set index of class attribute. (default: last).</pre>
*
* <pre> -H
*  Consider only horn clauses.</pre>
*
* <pre> -E
*  Keep equivalent rules.</pre>
*
* <pre> -M
*  Keep same clauses.</pre>
*
* <pre> -T
*  Keep subsumed rules.</pre>
*
* <pre> -I &lt;0=always match | 1=never match | 2=significant&gt;
*  Set the way to handle missing values. (default: 0)</pre>
*
* <pre> -O
*  Use ROC analysis. </pre>
*
* <pre> -p &lt;name of file&gt;
*  Set the file containing the parts of the individual for individual-based learning.</pre>
*
* <pre> -P &lt;0=no output | 1=on stdout | 2=in separate window&gt;
*  Set output of current values. (default: 0)</pre>
*
<!-- options-end -->
*
* @author <a href="mailto:adeltour@netcourrier.com">Amelie Deltour</a>
* @version $Revision: 1.10 $
*/

public class Tertius
  extends AbstractAssociator
  implements OptionHandler, Runnable, TechnicalInformationHandler {

  /** for serialization */
  static final long serialVersionUID = 5556726848380738179L;
 
  /** The results. */
  private SimpleLinkedList m_results;

  /** Number of hypotheses considered. */
  private int m_hypotheses;

  /** Number of hypotheses explored. */
  private int m_explored;

  /** Time needed for the search. */
  private Date m_time;

  /** Field to output the current values. */
  private TextField m_valuesText;

  /** Instances used for the search. */
  private Instances m_instances;

  /** Predicates used in the rules. */
  private ArrayList m_predicates;

  /** Status of the search. */
  private int m_status;
  /** Status of the search: normal */
  private static final int NORMAL = 0;
  /** Status of the search: memory problem */
  private static final int MEMORY = 1;
  /** Status of the search: user interruption */
  private static final int STOP = 2;
 
  /* Pruning options. */

  /** Number of best confirmation values to search. */
  private int m_best;

  /** Frequency threshold for the body and the negation of the head. */
  private double m_frequencyThreshold;

  /** Confirmation threshold for the rules. */
  private double m_confirmationThreshold;

  /** Maximal number of counter-instances. */
  private double m_noiseThreshold;

  /* Search space & language bias options. */

  /** Repeat attributes ? */
  private boolean m_repeat;

  /** Number of literals in a rule. */
  private int m_numLiterals;

  /** Type of negation: none */
  private static final int NONE = 0;
  /** Type of negation: body */
  private static final int BODY = 1;
  /** Type of negation: head */
  private static final int HEAD = 2;
  /** Type of negation: all */
  private static final int ALL = 3;
  /** Types of negation. */
  private static final Tag [] TAGS_NEGATION = {
    new Tag(NONE, "None"),
    new Tag(BODY, "Body"),
    new Tag(HEAD, "Head"),
    new Tag(ALL, "Both")
      };

  /** Type of negation used in the rules. */
  private int m_negation;

  /** Classification bias. */
  private boolean m_classification;

  /** Index of class attribute. */
  private int m_classIndex;

  /** Horn clauses bias. */
  private boolean m_horn;

  /* Subsumption tests options. */

  /** Perform test on equivalent rules ? */
  private boolean m_equivalent;

  /** Perform test on same clauses ? */
  private boolean m_sameClause;
 
  /** Perform subsumption test ? */
  private boolean m_subsumption;

  /** Way of handling missing values: min counterinstances */
  public static final int EXPLICIT = 0;
  /** Way of handling missing values: max counterinstances */
  public static final int IMPLICIT = 1;
  /** Way of handling missing values: missing as a particular value */
  public static final int SIGNIFICANT = 2;
  /** Ways of handling missing values.  */
  private static final Tag [] TAGS_MISSING = {
    new Tag(EXPLICIT, "Matches all"),
    new Tag(IMPLICIT, "Matches none"),
    new Tag(SIGNIFICANT, "Significant")
      };

  /** Way of handling missing values in the search. */
  private int m_missing;

  /** Perform ROC analysis ? */
  private boolean m_roc;

  /** Name of the file containing the parts for individual-based learning. */
  private String m_partsString;
 
  /** Part instances for individual-based learning. */
  private Instances m_parts;

  /** Type of values output: No */
  private static final int NO = 0;
  /** Type of values output: stdout */
  private static final int OUT = 1;
  /** Type of values output: Window */
  private static final int WINDOW = 2;
  /** Types of values output. */
  private static final Tag [] TAGS_VALUES = {
    new Tag(NO, "No"),
    new Tag(OUT, "stdout"),
    new Tag(WINDOW, "Window")
      };

  /** Type of values output. */
  private int m_printValues;

  /**
   * Constructor that sets the options to the default values.
   */
  public Tertius() {

    resetOptions();
  }

  /**
   * Returns a string describing this associator.
   *
   * @return A description of the evaluator suitable for
   * displaying in the explorer/experimenter gui.
   */
  public String globalInfo() {
    return
        "Finds rules according to confirmation measure (Tertius-type "
      + "algorithm).\n\n"
      + "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.ARTICLE);
    result.setValue(Field.AUTHOR, "P. A. Flach and N. Lachiche");
    result.setValue(Field.YEAR, "1999");
    result.setValue(Field.TITLE, "Confirmation-Guided Discovery of first-order rules with Tertius");
    result.setValue(Field.JOURNAL, "Machine Learning");
    result.setValue(Field.VOLUME, "42");
    result.setValue(Field.PAGES, "61-95");
   
    return result;
  }

  /**
   * Resets the options to the default values.
   */
  public void resetOptions() {

    /* Pruning options. */
    m_best = 10;
    m_frequencyThreshold = 0;
    m_confirmationThreshold = 0;
    m_noiseThreshold = 1;

    /* Search space & language bias options. */
    m_repeat = false;
    m_numLiterals = 4;
    m_negation = NONE;
    m_classification = false;
    m_classIndex = 0;
    m_horn = false;

    /* Subsumption tests options. */
    m_equivalent = true;
    m_sameClause = true;
    m_subsumption = true;

    /* Missing values. */
    m_missing = EXPLICIT;

    /* ROC analysis. */
    m_roc = false;

    /* Individual-based learning. */
    m_partsString = "";
    m_parts = null;

    /* Values output. */
    m_printValues = NO;
  }

  /**
   * Returns an enumeration describing the available options.
   *
   * @return An enumeration of all the available options.
   */
  public Enumeration listOptions() {
   
    Vector newVector = new Vector(17);

    /* Pruning options. */
    newVector.addElement(new Option("\tSet maximum number of confirmation  "
            + "values in the result. (default: 10)",
            "K", 1, "-K <number of values in result>"));
    newVector.addElement(new Option("\tSet frequency threshold for pruning. "
            + "(default: 0)",
            "F", 1, "-F <frequency threshold>"));
    newVector.addElement(new Option("\tSet confirmation threshold. "
            + "(default: 0)",
            "C", 1, "-C <confirmation threshold>"));
    newVector.addElement(new Option("\tSet noise threshold : maximum frequency "
            + "of counter-examples.\n\t0 gives only "
            + "satisfied rules. (default: 1)",
            "N", 1, "-N <noise threshold>"));

    /* Search space & language bias options. */
    newVector.addElement(new Option("\tAllow attributes to be repeated in a "
            + "same rule.",
            "R", 0, "-R"));
    newVector.addElement(new Option("\tSet maximum number of literals in a "
            + "rule. (default: 4)",
            "L", 1, "-L <number of literals>"));
    newVector.addElement(new Option("\tSet the negations in the rule. "
            + "(default: 0)",
            "G", 1, "-G <0=no negation | "
            + "1=body | "
            + "2=head | "
            + "3=body and head>"));
    newVector.addElement(new Option("\tConsider only classification rules.",
            "S", 0, "-S"));
    newVector.addElement(new Option("\tSet index of class attribute. "
            + "(default: last).",
            "c", 1, "-c <class index>"));
    newVector.addElement(new Option("\tConsider only horn clauses.",
            "H", 0, "-H"));

    /* Subsumption tests options. */
    newVector.addElement(new Option("\tKeep equivalent rules.",
            "E", 0, "-E"));
    newVector.addElement(new Option("\tKeep same clauses.",
            "M", 0, "-M"));
    newVector.addElement(new Option("\tKeep subsumed rules.",
            "T", 0, "-T"));

    /* Missing values options. */
    newVector.addElement(new Option("\tSet the way to handle missing values. "
            + "(default: 0)",
            "I", 1, "-I <0=always match | "
            + "1=never match | "
            + "2=significant>"));

    /* ROC analysis. */
    newVector.addElement(new Option("\tUse ROC analysis. ",
            "O", 0, "-O"));

    /* Individual-based learning. */
    newVector.addElement(new Option("\tSet the file containing the parts of "
            + "the individual for individual-based "
            + "learning.",
            "p", 1, "-p <name of file>"));

    /* Values output. */
    newVector.addElement(new Option("\tSet output of current values. "
            + "(default: 0)",
            "P", 1, "-P <0=no output | "
            + "1=on stdout | "
            + "2=in separate window>"));
   
    return newVector.elements();
  }
 
  /**
   * Parses a given list of options. <p/>
   *
   <!-- options-start -->
   * Valid options are: <p/>
   *
   * <pre> -K &lt;number of values in result&gt;
   *  Set maximum number of confirmation  values in the result. (default: 10)</pre>
   *
   * <pre> -F &lt;frequency threshold&gt;
   *  Set frequency threshold for pruning. (default: 0)</pre>
   *
   * <pre> -C &lt;confirmation threshold&gt;
   *  Set confirmation threshold. (default: 0)</pre>
   *
   * <pre> -N &lt;noise threshold&gt;
   *  Set noise threshold : maximum frequency of counter-examples.
   *  0 gives only satisfied rules. (default: 1)</pre>
   *
   * <pre> -R
   *  Allow attributes to be repeated in a same rule.</pre>
   *
   * <pre> -L &lt;number of literals&gt;
   *  Set maximum number of literals in a rule. (default: 4)</pre>
   *
   * <pre> -G &lt;0=no negation | 1=body | 2=head | 3=body and head&gt;
   *  Set the negations in the rule. (default: 0)</pre>
   *
   * <pre> -S
   *  Consider only classification rules.</pre>
   *
   * <pre> -c &lt;class index&gt;
   *  Set index of class attribute. (default: last).</pre>
   *
   * <pre> -H
   *  Consider only horn clauses.</pre>
   *
   * <pre> -E
   *  Keep equivalent rules.</pre>
   *
   * <pre> -M
   *  Keep same clauses.</pre>
   *
   * <pre> -T
   *  Keep subsumed rules.</pre>
   *
   * <pre> -I &lt;0=always match | 1=never match | 2=significant&gt;
   *  Set the way to handle missing values. (default: 0)</pre>
   *
   * <pre> -O
   *  Use ROC analysis. </pre>
   *
   * <pre> -p &lt;name of file&gt;
   *  Set the file containing the parts of the individual for individual-based learning.</pre>
   *
   * <pre> -P &lt;0=no output | 1=on stdout | 2=in separate window&gt;
   *  Set output of current values. (default: 0)</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 {
   
    resetOptions();
   
    /* Pruning options. */
    String bestString = Utils.getOption('K', options);
    if (bestString.length() != 0) {
      try {
  m_best = Integer.parseInt(bestString);
      } catch (Exception e) {
  throw new Exception("Invalid value for -K option: "
          + e.getMessage() + ".");
      }
      if (m_best < 1) {
  throw new Exception("Number of confirmation values has to be "
          + "greater than one!");
      }
    }
    String frequencyThresholdString = Utils.getOption('F', options);
    if (frequencyThresholdString.length() != 0) {
      try
  m_frequencyThreshold
    = (new Double(frequencyThresholdString)).doubleValue();
      } catch (Exception e) {
  throw new Exception("Invalid value for -F option: "
          + e.getMessage() + ".");
      }
      if (m_frequencyThreshold < 0 || m_frequencyThreshold > 1) {
  throw new Exception("Frequency threshold has to be between "
          + "zero and one!");
      }
    }
    String confirmationThresholdString = Utils.getOption('C', options);
    if (confirmationThresholdString.length() != 0) {
      try {
  m_confirmationThreshold
    = (new Double(confirmationThresholdString)).doubleValue();
      } catch (Exception e) {
  throw new Exception("Invalid value for -C option: "
          + e.getMessage() + ".");
      }
      if (m_confirmationThreshold < 0 || m_confirmationThreshold > 1) {
  throw new Exception("Confirmation threshold has to be between "
          + "zero and one!");
      }
      if (bestString.length() != 0) {
  throw new Exception("Specifying both a number of confirmation "
          + "values and a confirmation threshold "
          + "doesn't make sense!");
      }
      if (m_confirmationThreshold != 0) {
  m_best = 0;
      }
    }
    String noiseThresholdString = Utils.getOption('N', options);
    if (noiseThresholdString.length() != 0) {
      try {
  m_noiseThreshold = (new Double(noiseThresholdString)).doubleValue();
      } catch (Exception e) {
  throw new Exception("Invalid value for -N option: "
          + e.getMessage() + ".");
      }
      if (m_noiseThreshold < 0 || m_noiseThreshold > 1) {
  throw new Exception("Noise threshold has to be between "
          + "zero and one!");
      }
    }

    /* Search space and language bias options. */
    m_repeat = Utils.getFlag('R', options);
    String numLiteralsString = Utils.getOption('L', options);
    if (numLiteralsString.length() != 0) {
      try {
  m_numLiterals = Integer.parseInt(numLiteralsString);
      } catch (Exception e) {
  throw new Exception("Invalid value for -L option: "
          + e.getMessage() + ".");
      }
      if (m_numLiterals < 1) {
  throw new Exception("Number of literals has to be "
          + "greater than one!");
      }
    }
    String negationString = Utils.getOption('G', options);
    if (negationString.length() != 0) {
      SelectedTag selected;
      int tag;
      try {
  tag = Integer.parseInt(negationString);
      } catch (Exception e) {
  throw new Exception("Invalid value for -G option: "
          + e.getMessage() + ".");
      }
      try {
  selected = new SelectedTag(tag, TAGS_NEGATION);
      } catch (Exception e) {
  throw new Exception("Value for -G option has to be "
          + "between zero and three!");
      }
      setNegation(selected);
    }
    m_classification = Utils.getFlag('S', options);
    String classIndexString = Utils.getOption('c', options);
    if (classIndexString.length() != 0) {
      try {
  m_classIndex = Integer.parseInt(classIndexString);
      } catch (Exception e) {
  throw new Exception("Invalid value for -c option: "
          + e.getMessage() + ".");
      }
    }
    m_horn = Utils.getFlag('H', options);
    if (m_horn && (m_negation != NONE)) {
      throw new Exception("Considering horn clauses doesn't make sense "
        + "if negation allowed!");
    }
   
    /* Subsumption tests options. */
    m_equivalent = !(Utils.getFlag('E', options));
    m_sameClause = !(Utils.getFlag('M', options));
    m_subsumption = !(Utils.getFlag('T', options));

    /* Missing values options. */
    String missingString = Utils.getOption('I', options);
    if (missingString.length() != 0) {
      SelectedTag selected;
      int tag;
      try {
  tag = Integer.parseInt(missingString);
      } catch (Exception e) {
  throw new Exception("Invalid value for -I option: "
          + e.getMessage() + ".");
      }
      try {
  selected = new SelectedTag(tag, TAGS_MISSING);
      } catch (Exception e) {
  throw new Exception("Value for -I option has to be "
          + "between zero and two!");
      }
      setMissingValues(selected);
    }

    /* ROC analysis. */
    m_roc = Utils.getFlag('O', options);


    /* Individual-based learning. */
    m_partsString = Utils.getOption('p', options);
    if (m_partsString.length() != 0) {
      Reader reader;
      try {
  reader = new BufferedReader(new FileReader(m_partsString));
      } catch (Exception e) {
  throw new Exception("Can't open file " + e.getMessage() + ".");
      }
      m_parts = new Instances(reader)
    }

    /* Values output. */
    String printValuesString = Utils.getOption('P', options);
    if (printValuesString.length() != 0) {
      SelectedTag selected;
      int tag;
      try {
  tag = Integer.parseInt(printValuesString);
      } catch (Exception e) {
  throw new Exception("Invalid value for -P option: "
          + e.getMessage() + ".");
      }
      try {
  selected = new SelectedTag(tag, TAGS_VALUES);
      } catch (Exception e) {
  throw new Exception("Value for -P option has to be "
          + "between zero and two!");
      }
      setValuesOutput(selected);
    }
  }

  /**
   * Gets the current settings of the Tertius object.
   *
   * @return An array of strings suitable for passing to setOptions.
   */
  public String [] getOptions() {
    Vector      result;

    result = new Vector();

    /* Pruning options. */
    if (m_best > 0) {
      result.add("-K");
      result.add("" + m_best);
    }
   
    result.add("-F");
    result.add("" + m_frequencyThreshold);
   
    if (m_confirmationThreshold > 0) {
      result.add("-C");
      result.add("" + m_confirmationThreshold);
    }
   
    result.add("-N");
    result.add("" + m_noiseThreshold);
   
    /* Search space and language bias options. */
    if (m_repeat)
      result.add("-R");
   
    result.add("-L");
    result.add("" + m_numLiterals);
   
    result.add("-G");
    result.add("" + m_negation);
   
    if (m_classification)
      result.add("-S");
     
    result.add("-c");
    result.add("" + m_classIndex);
   
    if (m_horn)
      result.add("-H");

    /* Subsumption tests options. */
    if (!m_equivalent)
      result.add("-E");
   
    if (!m_sameClause)
      result.add("-M");
   
    if (!m_subsumption)
      result.add("-T");

    /* Missing values options. */
    result.add("-I");
    result.add("" + m_missing);

    /* ROC analysis. */
    if (m_roc)
      result.add("-O");

    /* Individual-based learning. */
    result.add("-p");
    result.add("" + m_partsString);

    /* Values output. */
    result.add("-P");
    result.add("" + m_printValues);

    return (String[]) result.toArray(new String[result.size()]);   
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String confirmationValuesTipText() {

    return "Number of best confirmation values to find.";
  }

  /**
   * Get the value of confirmationValues.
   *
   * @return Value of confirmationValues.
   */
  public int getConfirmationValues() {

    return m_best;
  }

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

    m_best = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String frequencyThresholdTipText() {
   
    return "Minimum proportion of instances satisfying head and body of rules";
  }

  /**
   * Get the value of frequencyThreshold.
   *
   * @return Value of frequencyThreshold.
   */
  public double getFrequencyThreshold() {
   
    return m_frequencyThreshold;
  }

  /**
   * Set the value of frequencyThreshold.
   *
   * @param v  Value to assign to frequencyThreshold.
   */
  public void setFrequencyThreshold(double v) {
   
    m_frequencyThreshold = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String confirmationThresholdTipText() {
   
    return "Minimum confirmation of the rules.";
  }

  /**
   * Get the value of confirmationThreshold.
   *
   * @return Value of confirmationThreshold.
   */
  public double getConfirmationThreshold() {
   
    return m_confirmationThreshold;
  }

  /**
   * Set the value of confirmationThreshold.
   *
   * @param v  Value to assign to confirmationThreshold.
   */
  public void setConfirmationThreshold(double v) {
   
    m_confirmationThreshold = v;
    if (v != 0) {
      m_best = 0;
    }
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String noiseThresholdTipText() {
   
    return "Maximum proportion of counter-instances of rules. "
      + "If set to 0, only satisfied rules will be given.";
  }

  /**
   * Get the value of noiseThreshold.
   *
   * @return Value of noiseThreshold.
   */
  public double getNoiseThreshold() {
   
    return m_noiseThreshold;
  }

  /**
   * Set the value of noiseThreshold.
   *
   * @param v  Value to assign to noiseThreshold.
   */
  public void setNoiseThreshold(double v) {
   
    m_noiseThreshold = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String repeatLiteralsTipText() {

    return "Repeated attributes allowed.";
  }

  /**
   * Get the value of repeatLiterals.
   *
   * @return Value of repeatLiterals.
   */
  public boolean getRepeatLiterals() {
   
    return m_repeat;
  }

  /**
   * Set the value of repeatLiterals.
   *
   * @param v  Value to assign to repeatLiterals.
   */
  public void setRepeatLiterals(boolean v) {
   
    m_repeat = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String numberLiteralsTipText() {
   
    return "Maximum number of literals in a rule.";
  }

  /**
   * Get the value of numberLiterals.
   *
   * @return Value of numberLiterals.
   */
  public int getNumberLiterals() {

    return m_numLiterals;
  }

  /**
   * Set the value of numberLiterals.
   *
   * @param v  Value to assign to numberLiterals.
   */
  public void setNumberLiterals(int v) {
   
    m_numLiterals = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String negationTipText() {
   
    return "Set the type of negation allowed in the rule. "
      + "Negation can be allowed in the body, in the head, in both "
      + "or in none.";
  }

  /**
   * Get the value of negation.
   *
   * @return Value of negation.
   */
  public SelectedTag getNegation() {
   
    return new SelectedTag(m_negation, TAGS_NEGATION);
  }

  /**
   * Set the value of negation.
   *
   * @param v  Value to assign to negation.
   */
  public void setNegation(SelectedTag v) {
   
    if (v.getTags() == TAGS_NEGATION) {
      m_negation = v.getSelectedTag().getID();
    }
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String classificationTipText() {
   
    return "Find only rules with the class in the head.";
  }

  /**
   * Get the value of classification.
   *
   * @return Value of classification.
   */
  public boolean getClassification() {

    return m_classification;
  }

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

    m_classification = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String classIndexTipText() {

    return "Index of the class attribute. If set to 0, the class will be the last attribute.";
  }

  /**
   * Get the value of classIndex.
   *
   * @return Value of classIndex.
   */
  public int getClassIndex() {

    return m_classIndex;
  }

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

    m_classIndex = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String hornClausesTipText() {
   
    return "Find rules with a single conclusion literal only.";
  }

  /**
   * Get the value of hornClauses.
   *
   * @return Value of hornClauses.
   */
  public boolean getHornClauses() {

    return m_horn;
  }

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

    m_horn = v;
  }
 
  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String equivalentTipText() {
   
    return "Keep equivalent rules. "
      + "A rule r2 is equivalent to a rule r1 if the body of r2 is the "
      + "negation of the head of r1, and the head of r2 is the "
      + "negation of the body of r1.";
  }

  /**
   * Get the value of equivalent.
   *
   * @return Value of equivalent.
   */
  public boolean disabled_getEquivalent() {
   
    return !m_equivalent;
  }

  /**
   * Set the value of equivalent.
   *
   * @param v  Value to assign to equivalent.
   */
  public void disabled_setEquivalent(boolean v) {
   
    m_equivalent = !v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String sameClauseTipText() {

    return "Keep rules corresponding to the same clauses. "
      + "If set to false, only the rule with the best confirmation "
      + "value and rules with a lower number of counter-instances "
      + "will be kept.";
  }

  /**
   * Get the value of sameClause.
   *
   * @return Value of sameClause.
   */
  public boolean disabled_getSameClause() {

    return !m_sameClause;
  }

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

    m_sameClause = !v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String subsumptionTipText() {

    return "Keep subsumed rules. "
      + "If set to false, subsumed rules will only be kept if they "
      + "have a better confirmation or a lower number of counter-instances.";
  }

  /**
   * Get the value of subsumption.
   *
   * @return Value of subsumption.
   */
  public boolean disabled_getSubsumption() {

    return !m_subsumption;
  }

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

    m_subsumption = !v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String missingValuesTipText() {
   
    return "Set the way to handle missing values. "
      + "Missing values can be set to match any value, or never match values "
      + "or to be significant and possibly appear in rules.";
  }

  /**
   * Get the value of missingValues.
   *
   * @return Value of missingValues.
   */
  public SelectedTag getMissingValues() {
   
    return new SelectedTag(m_missing, TAGS_MISSING);
  }

  /**
   * Set the value of missingValues.
   *
   * @param v  Value to assign to missingValues.
   */
  public void setMissingValues(SelectedTag v) {
   
    if (v.getTags() == TAGS_MISSING) {
      m_missing = v.getSelectedTag().getID();
    }
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String rocAnalysisTipText() {
   
    return "Return TP-rate and FP-rate for each rule found.";
  }

  /**
   * Get the value of rocAnalysis.
   *
   * @return Value of rocAnalysis.
   */
  public boolean getRocAnalysis() {

    return m_roc;
  }

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

    m_roc = v;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String partFileTipText() {
   
    return "Set file containing the parts of the individual "
      + "for individual-based learning.";
  }

  /**
   * Get the value of partFile.
   *
   * @return Value of partFile.
   */
  public File disabled_getPartFile() {

    return new File(m_partsString);
  }

  /**
   * Set the value of partFile.
   *
   * @param v  Value to assign to partFile.
   * @throws Exception if file cannot be opened
   */
  public void disabled_setPartFile(File v) throws Exception {

    m_partsString = v.getAbsolutePath();
    if (m_partsString.length() != 0) {
      Reader reader;
      try {
  reader = new BufferedReader(new FileReader(m_partsString));
      } catch (Exception e) {
  throw new Exception("Can't open file " + e.getMessage() + ".");
      }
      m_parts = new Instances(reader)
    }
  }

  /**
   * Returns the tip text for this property.
   *
   * @return Tip text for this property suitable for
   * displaying in the explorer/experimenter GUI.
   */
  public String valuesOutputTipText() {
   
    return "Give visual feedback during the search. "
      + "The current best and worst values can be output either to stdout or to a separate window.";
  }

  /**
   * Get the value of valuesOutput.
   *
   * @return Value of valuesOutput.
   */
  public SelectedTag getValuesOutput() {
   
    return new SelectedTag(m_printValues, TAGS_VALUES);
  }

  /**
   * Set the value of valuesOutput.
   *
   * @param v  Value to assign to valuesOutput.
   */
  public void setValuesOutput(SelectedTag v) {
   
    if (v.getTags() == TAGS_VALUES) {
      m_printValues = v.getSelectedTag().getID();
    }
  }

  /**
   * Build the predicate corresponding to an attribute.
   *
   * @param instances The instances this predicates comes from.
   * @param attr The attribute this predicate corresponds to.
   * @param isClass Saying if the attribute is the class attribute.
   * @return The corresponding Predicate.
   * @throws Exception if the predicate could not be build
   * (the attribute is numeric).
   */
  private Predicate buildPredicate(Instances instances,
           Attribute attr, boolean isClass)
    throws Exception {

    Predicate predicate; /* The result. */
    Literal lit;
    Literal negation;
    boolean missingValues; /* Missing values for this attribute ? */
    boolean individual = (m_parts != null); /* Individual-based learning ? */
    int type = (instances == m_parts)
      ? IndividualLiteral.PART_PROPERTY
      : IndividualLiteral.INDIVIDUAL_PROPERTY; /* Type of property. */

    if (attr.isNumeric()) {
      throw new Exception("Can't handle numeric attributes!");
    }
 
    missingValues = instances.attributeStats(attr.index()).missingCount > 0;

    /* Build predicate. */
    if (individual) {
      predicate = new Predicate(instances.relationName() + "." + attr.name(),
        attr.index(), isClass);
    } else {
      predicate = new Predicate(attr.name(), attr.index(), isClass);
    }
 
    if (attr.numValues() == 2
  && (!missingValues || m_missing == EXPLICIT)) {
      /* Case of two values.
       * If there are missing values, this case is treated like other cases.
       */
      if (individual) {
  lit = new IndividualLiteral(predicate, attr.value(0), 0,
            Literal.POS, m_missing, type);
  negation = new IndividualLiteral(predicate, attr.value(1), 1,
           Literal.POS, m_missing, type);
      } else {
  lit = new AttributeValueLiteral(predicate, attr.value(0), 0,
          Literal.POS, m_missing);
  negation = new AttributeValueLiteral(predicate, attr.value(1), 1,
               Literal.POS, m_missing);
      }
      lit.setNegation(negation);
      negation.setNegation(lit);
      predicate.addLiteral(lit);     
    } else {
      /* Case of several values. */
      for (int i = 0; i < attr.numValues(); i++) {
  if (individual) {
    lit = new IndividualLiteral(predicate, attr.value(i), i,
              Literal.POS, m_missing, type);
  } else {
    lit = new AttributeValueLiteral(predicate, attr.value(i), i,
            Literal.POS, m_missing);
  }
  if (m_negation != NONE) {
    if (individual) {
      negation = new IndividualLiteral(predicate, attr.value(i), i,
               Literal.NEG, m_missing, type);
    } else {
      negation = new AttributeValueLiteral(predicate, attr.value(i), i,
             Literal.NEG, m_missing);
    }
    lit.setNegation(negation);
    negation.setNegation(lit);
  }
  predicate.addLiteral(lit);
      }

      /* One more value if missing is significant. */
      if (missingValues && m_missing == SIGNIFICANT) {
  if (individual) {
    lit = new IndividualLiteral(predicate, "?", -1,
              Literal.POS, m_missing, type);
  } else {
    lit = new AttributeValueLiteral(predicate, "?", -1,
            Literal.POS, m_missing);
  }
  if (m_negation != NONE) {
    if (individual) {
      negation = new IndividualLiteral(predicate, "?", -1,
               Literal.NEG, m_missing, type);
    } else {
      negation = new AttributeValueLiteral(predicate, "?", -1,
             Literal.NEG, m_missing);
    }
    lit.setNegation(negation);
    negation.setNegation(lit);
  }
  predicate.addLiteral(lit);
      }
    }
    return predicate;
  }
  
  /**
   * Build the predicates to use in the rules.
   *
   * @return the predicates
   * @throws Exception If the predicates could not be built
   * (numeric attribute).
   */
  private ArrayList buildPredicates() throws Exception {

    ArrayList predicates = new ArrayList(); /* The result. */
    Predicate predicate;
    Attribute attr;
    Enumeration attributes = m_instances.enumerateAttributes();
    boolean individual = (m_parts != null); /* Individual-based learning ? */

    /* Attributes. */
    while (attributes.hasMoreElements()) {
      attr = (Attribute) attributes.nextElement();
      /* Identifiers do not appear in rules in individual-based learning. */
      if (!(individual && attr.name().equals("id"))) {
  predicate = buildPredicate(m_instances, attr, false);
  predicates.add(predicate);
      }
    }
    /* Class attribute. */
    attr = m_instances.classAttribute();
    /* Identifiers do not appear in rules. */
    if (!(individual && attr.name().equals("id"))) {
      predicate = buildPredicate(m_instances, attr, true);
      predicates.add(predicate);
    }

    /* Attributes of the parts in individual-based learning. */
    if (individual) {
      attributes = m_parts.enumerateAttributes();
      while (attributes.hasMoreElements()) {
  attr = (Attribute) attributes.nextElement();
  /* Identifiers do not appear in rules. */
  if (!attr.name().equals("id")) {
    predicate = buildPredicate(m_parts, attr, false);
    predicates.add(predicate);
  }
      }
    }
 
    return predicates;
  }

  /**
   * Count the number of distinct confirmation values in the results.
   *
   * @return Number of confirmation values in the results.
   */
  private int numValuesInResult() {

    int result = 0;
    SimpleLinkedList.LinkedListIterator iter = m_results.iterator();
    Rule current;
    Rule next;
    if (!iter.hasNext()) {
      return result;
    } else {
      current = (Rule) iter.next();
      while (iter.hasNext()) {
  next = (Rule) iter.next();
  if (current.getConfirmation() > next.getConfirmation()) {
    result++;
  }
  current = next;
      }
      return result + 1;
    }
  }

  /**
   * Test if it is worth refining a rule.
   *
   * @param rule The rule to consider.
   * @return True if the rule can be refined, false otherwise.
   */
  private boolean canRefine(Rule rule) {
    if (rule.isEmpty()) {
      return true;
    }
    if (m_best != 0) {
      if (numValuesInResult() < m_best) {
  return true;
      }
      Rule worstResult = (Rule) m_results.getLast();
      if (rule.getOptimistic() >= worstResult.getConfirmation()) {
  return true;
      }
      return false;
    } else {
      return true;
    }
  }

  /**
   * Test if it is worth calculating the optimistic estimate of a rule.
   *
   * @param rule The rule to consider.
   * @return True if the optimistic estimate can be calculated, false otherwise.
   */
  private boolean canCalculateOptimistic(Rule rule) {
    if (rule.hasTrueBody() || rule.hasFalseHead()) {
      return false;
    }
    if (!rule.overFrequencyThreshold(m_frequencyThreshold)) {
      return false;
    }
    return true;
  }

  /**
   * Test if a rule can be explored (if it is interesting for the results
   * or for refining).
   *
   * @param rule The rule to consider.
   * @return True if the rule can be explored, false otherwise.
   */
  private boolean canExplore(Rule rule) {
    if (rule.getOptimistic() < m_confirmationThreshold) {
      return false;
    }
    if (m_best != 0) {
      if (numValuesInResult() < m_best) {
  return true;
     
      Rule worstResult = (Rule) m_results.getLast();
      if (rule.getOptimistic() >= worstResult.getConfirmation()) {
  return true;
      }
      return false;     
    } else {
      return true;
    }
  }   

  /**
   * Test if a rule can be stored in the agenda.
   *
   * @param rule The rule to consider.
   * @return True if the rule can be stored, false otherwise.
   */
  private boolean canStoreInNodes(Rule rule) {
    if (rule.getObservedNumber() == 0) {
      return false;
    }
    return true;
  }

  /**
   * Test if it is worth calculating the confirmation of a rule.
   *
   * @param rule The rule to consider.
   * @return True if the confirmation can be calculated, false otherwise.
   */
  private boolean canCalculateConfirmation(Rule rule) {
    if (rule.getObservedFrequency() > m_noiseThreshold) {
      return false;
    }
    return true;
  }

  /**
   * Test if a rule can be added to the results.
   *
   * @param rule The rule to consider.
   * @return True if the rule can be stored, false otherwise.
   */
  private boolean canStoreInResults(Rule rule) {
    if (rule.getConfirmation() < m_confirmationThreshold) {
      return false;
    }
    if (m_best != 0) {
      if (numValuesInResult() < m_best) {
  return true;
      }
      Rule worstResult = (Rule) m_results.getLast();
      if (rule.getConfirmation() >= worstResult.getConfirmation()) {
  return true;
      }
      return false;   
    } else {
      return true;
    }
  }

  /**
   * Add a rule in the appropriate place in the list of the results,
   * according to the confirmation and
   * number of counter-instances of the rule. <p>
   * Subsumption tests are performed and the rule may not be added. <p>
   * Previous results may also be removed because of sumption.
   */
  private void addResult(Rule rule) {

    Rule current;
    boolean added = false;

    /* Iterate the list until we find the right place. */
    SimpleLinkedList.LinkedListIterator iter = m_results.iterator();
    while (iter.hasNext()) {
      current = (Rule) iter.next();
      if (Rule.confirmationThenObservedComparator.compare(current, rule) > 0) {
  iter.addBefore(rule);
  added = true;
  break;
      }
      /* Subsumption tests to see if the rule can be added. */
      if ((m_subsumption || m_sameClause || m_equivalent)
    && current.subsumes(rule)) {
  if (current.numLiterals() == rule.numLiterals()) {
    if (current.equivalentTo(rule)) {
      /* Equivalent rules. */
      if (m_equivalent) {
        return;
      }
    } else {
      /* Same clauses. */
      if (m_sameClause
    && Rule.confirmationComparator.compare(current, rule) < 0) {
        return;
      }
    }
  } else {
    /* Subsumption. */
    if (m_subsumption
        && Rule.observedComparator.compare(current, rule) <= 0) { 
      return;
    }
  }
      }
    }

    if (added == false) {
      /* The rule must be added in the end of the results. */
      m_results.add(rule);
    }

    /* Iterate the results with a lower confirmation
     *  to see if some of them must be removed. */
    SimpleLinkedList.LinkedListInverseIterator inverse
      = m_results.inverseIterator();
    while (inverse.hasPrevious()) {
      current = (Rule) inverse.previous();
      if (Rule.confirmationThenObservedComparator.compare(current, rule) < 0) {
  break;
      }
      if (current != rule && rule.subsumes(current)) {
  if (current.numLiterals() == rule.numLiterals()) {
    if (!current.equivalentTo(rule)) {
      /* Same clauses. */
      if (m_sameClause
    && Rule.confirmationComparator.compare(current, rule) > 0) {
        inverse.remove();
      }
    }
  } else {
    /* Subsumption. */
    if (m_subsumption
        && Rule.observedComparator.compare(rule, current) <= 0) { 
      inverse.remove();
    }
  } 
      }
    }

    /* Remove the rules with the worst confirmation value
     * if there are too many results. */
    if (m_best != 0 && numValuesInResult() > m_best) {
      Rule worstRule = (Rule) m_results.getLast();
      inverse = m_results.inverseIterator();
      while (inverse.hasPrevious()) {
  current = (Rule) inverse.previous();
  if (Rule.confirmationComparator.compare(current, worstRule) < 0) {
    break;
  }
  inverse.remove();
      }
    }

    /* Print the new current values. */
    printValues();
  }

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

    // attributes
    result.enable(Capability.NOMINAL_ATTRIBUTES);
    result.enable(Capability.MISSING_VALUES);

    // class
    result.enable(Capability.NOMINAL_CLASS);
    result.enable(Capability.MISSING_CLASS_VALUES);
   
    return result;
  }
 
  /**
   * Method that launches the search to find the rules with the highest
   * confirmation.
   *
   * @param instances The instances to be used for generating the rules.
   * @throws Exception if rules can't be built successfully.
   */
  public void buildAssociations(Instances instances) throws Exception {

    Frame valuesFrame = null; /* Frame to display the current values. */

    /* Initialization of the search. */
    if (m_parts == null) {
      m_instances = new Instances(instances);
    } else {
      m_instances = new IndividualInstances(new Instances(instances), m_parts);
    }   
    m_results = new SimpleLinkedList();
    m_hypotheses = 0;
    m_explored = 0;
    m_status = NORMAL;

    if (m_classIndex == -1)
      m_instances.setClassIndex(m_instances.numAttributes()-1);    
    else if (m_classIndex < m_instances.numAttributes() && m_classIndex >= 0)
      m_instances.setClassIndex(m_classIndex);
    else
      throw new Exception("Invalid class index.");
   
    // can associator handle the data?
    getCapabilities().testWithFail(m_instances);
   
    /* Initialization of the window for current values. */
    if (m_printValues == WINDOW) {
      m_valuesText = new TextField(37);
      m_valuesText.setEditable(false);
      m_valuesText.setFont(new Font("Monospaced", Font.PLAIN, 12));   
      Label valuesLabel = new Label("Best and worst current values:");
      Button stop = new Button("Stop search");
      stop.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      /* Signal the interruption to the search. */
      m_status = STOP;
    }
  });
      valuesFrame = new Frame("Tertius status");
      valuesFrame.setResizable(false);
      valuesFrame.add(m_valuesText, BorderLayout.CENTER);
      valuesFrame.add(stop, BorderLayout.SOUTH);
      valuesFrame.add(valuesLabel, BorderLayout.NORTH);
      valuesFrame.pack();
      valuesFrame.setVisible(true);
    } else if (m_printValues == OUT) {
      System.out.println("Best and worst current values:");
    }
     
    Date start = new Date();

    /* Build the predicates and launch the search. */
    m_predicates = buildPredicates();
    beginSearch();   

    Date end = new Date();

    if (m_printValues == WINDOW) {
      valuesFrame.dispose();
    }

    m_time = new Date(end.getTime() - start.getTime());
  }

  /**
   * Run the search.
   */
  public void run() {
    try {
      search();
    } catch (OutOfMemoryError e) {
      /* Garbage collect what can be collected to be able to continue. */
      System.gc();
      m_status = MEMORY;
    }
    endSearch();
  }

  /**
   * Begin the search by starting a new thread.
   */
  private synchronized void beginSearch() throws Exception {
    /* This method must be synchronized to be able to
     * call the wait() method. */
    Thread search = new Thread(this);
    search.start();
    try {
      /* Wait for the end of the thread. */
      wait();
    } catch (InterruptedException e) {
      /* Signal the interruption to the search. */
      m_status = STOP;
    }
  }

  /**
   * End the search by notifying to the waiting thread that it is finished.
   */
  private synchronized void endSearch() {
    /* This method must be synchronized to be able to
     * call the notify() method. */
    notify();
  }

  /**
   * Search in the space of hypotheses the rules that have the highest
   * confirmation.
   * The search starts with the empty rule, other rules are generated by
   * refinement.
   */
  public void search() {

    SimpleLinkedList nodes = new SimpleLinkedList(); /* The agenda. */
    Rule currentNode;
    SimpleLinkedList children;
    SimpleLinkedList.LinkedListIterator iter;
    Rule child;
    boolean negBody = (m_negation == BODY || m_negation == ALL);
    boolean negHead = (m_negation == HEAD || m_negation == ALL);

    /* Start with the empty rule. */
      nodes.add(new Rule(m_repeat, m_numLiterals, negBody, negHead,
       m_classification, m_horn));
   
    /* Print the current values. */
    printValues();

    /* Explore the rules in the agenda. */
    while (m_status != STOP && !nodes.isEmpty()) {
      currentNode = (Rule) nodes.removeFirst();
      if (canRefine(currentNode)) {
  children = currentNode.refine(m_predicates);
  iter = children.iterator();
  /* Calculate the optimistic estimate of the children and
   * consider them for adding to the agenda and to the results. */
  while (iter.hasNext()) {
    m_hypotheses++;
    child = (Rule) iter.next();
    child.upDate(m_instances);
    if (canCalculateOptimistic(child)) {
      child.calculateOptimistic();
      if (canExplore(child)) {
        m_explored++;
        if (canStoreInNodes(child)) {
        } else {
    iter.remove();
        }
        if (canCalculateConfirmation(child)) {
    child.calculateConfirmation();
    if (canStoreInResults(child)) {
      addResult(child);
    }   
        }
      } else {
        iter.remove();
      }
    } else {
      iter.remove();
    }
  }
  /* Since the agenda is already sorted it is more efficient
   * to sort the children only and then merge. */
  children.sort(Rule.optimisticThenObservedComparator);
  nodes.merge(children, Rule.optimisticThenObservedComparator);
      } else {
  /* The agenda being sorted, it is not worth considering the following
   * nodes. */
  break;
      }
    }
  }

  /**
   * returns the results
   *
   * @return    the results
   */
  public SimpleLinkedList getResults() {
    return m_results;
  }

  /**
   * Print the current best and worst values.
   */
  private void printValues() {

    if (m_printValues == NO) {
      return;
    } else {
      if (m_results.isEmpty()) {
  if (m_printValues == OUT) {
    System.out.print("0.000000 0.000000 - 0.000000 0.000000");
  } else { //m_printValues == WINDOW
    m_valuesText.setText("0.000000 0.000000 - 0.000000 0.000000");
  }
      } else {
  Rule best = (Rule) m_results.getFirst();
  Rule worst = (Rule) m_results.getLast();
  String values = best.valuesToString() + " - " + worst.valuesToString();
  if (m_printValues == OUT) {
    System.out.print("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
         + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
    System.out.print(values);
  } else { //m_printValues == WINDOW
    m_valuesText.setText(values);
  }
      }
    }
  }

  /**
   * Outputs the best rules found with their confirmation value and number
   * of counter-instances.
   * Also gives the number of hypotheses considered and explored, and the
   * time needed.
   */
  public String toString() {

    StringBuffer text = new StringBuffer();
    SimpleLinkedList.LinkedListIterator iter = m_results.iterator();
    int size = m_results.size();
    int i = 0;

    text.append("\nTertius\n=======\n\n");

    while (iter.hasNext()) {
      Rule current = (Rule) iter.next();
      text.append(Utils.doubleToString((double) i + 1,
               (int) (Math.log(size)
                / Math.log(10) + 1),
               0)
      + ". ");
      text.append("/* ");
      if (m_roc) {
  text.append(current.rocToString());
      } else {
  text.append(current.valuesToString());
      }
      text.append(" */ ");
      text.append(current.toString());
      text.append("\n");
      i++;
    }
    text.append("\nNumber of hypotheses considered: " + m_hypotheses);
    text.append("\nNumber of hypotheses explored: " + m_explored);

    if (m_status == MEMORY) {
      text.append("\n\nNot enough memory to continue the search");
    } else if (m_status == STOP) {
      text.append("\n\nSearch interrupted");
    }

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

  /**
   * Main method.
   *
   * @param args the commandline parameters
   */
  public static void main(String [] args) {
    runAssociator(new Tertius(), args);
  }
}
TOP

Related Classes of weka.associations.Tertius

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.