LearningRateResultProducer.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 23k
Category:

Windows Develop

Development Platform:

Java

  1. /*
  2.  *    This program is free software; you can redistribute it and/or modify
  3.  *    it under the terms of the GNU General Public License as published by
  4.  *    the Free Software Foundation; either version 2 of the License, or
  5.  *    (at your option) any later version.
  6.  *
  7.  *    This program is distributed in the hope that it will be useful,
  8.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *    GNU General Public License for more details.
  11.  *
  12.  *    You should have received a copy of the GNU General Public License
  13.  *    along with this program; if not, write to the Free Software
  14.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  */
  16. /*
  17.  *    LearningRateResultProducer.java
  18.  *    Copyright (C) 1999 Len Trigg
  19.  *
  20.  */
  21. package weka.experiment;
  22. import java.util.Enumeration;
  23. import java.util.Vector;
  24. import weka.core.AdditionalMeasureProducer;
  25. import weka.core.FastVector;
  26. import weka.core.Instances;
  27. import weka.core.Option;
  28. import weka.core.OptionHandler;
  29. import weka.core.Utils;
  30. import java.util.Random;
  31. /**
  32.  * LearningRateResultProducer takes the results from a ResultProducer
  33.  * and submits the average to the result listener. For non-numeric
  34.  * result fields, the first value is used.
  35.  *
  36.  * @author Len Trigg (trigg@cs.waikato.ac.nz)
  37.  * @version $Revision: 1.4 $
  38.  */
  39. public class LearningRateResultProducer 
  40.   implements ResultListener, ResultProducer, OptionHandler,
  41.      AdditionalMeasureProducer {
  42.   /** The dataset of interest */
  43.   protected Instances m_Instances;
  44.   /** The ResultListener to send results to */
  45.   protected ResultListener m_ResultListener = new CSVResultListener();
  46.   /** The ResultProducer used to generate results */
  47.   protected ResultProducer m_ResultProducer
  48.     = new AveragingResultProducer();
  49.   /** The names of any additional measures to look for in SplitEvaluators */
  50.   protected String [] m_AdditionalMeasures = null;
  51.   /** 
  52.    * The minimum number of instances to use. If this is zero, the first
  53.    * step will contain m_StepSize instances 
  54.    */
  55.   protected int m_LowerSize = 0;
  56.   
  57.   /**
  58.    * The maximum number of instances to use. -1 indicates no maximum 
  59.    * (other than the total number of instances)
  60.    */
  61.   protected int m_UpperSize = -1;
  62.   /** The number of instances to add at each step */
  63.   protected int m_StepSize = 10;
  64.   /** The current dataset size during stepping */
  65.   protected int m_CurrentSize = 0;
  66.   /* The name of the key field containing the learning rate step number */
  67.   public static String STEP_FIELD_NAME = "Total_instances";
  68.   /**
  69.    * Returns a string describing this result producer
  70.    * @return a description of the result producer suitable for
  71.    * displaying in the explorer/experimenter gui
  72.    */
  73.   public String globalInfo() {
  74.     return "Tells a sub-ResultProducer to reproduce the current run for "
  75.       +"varying sized subsamples of the dataset. Normally used with "
  76.       +"an AveragingResultProducer and CrossValidationResultProducer "
  77.       +"combo to generate learning curve results.";
  78.   }
  79.   /**
  80.    * Determines if there are any constraints (imposed by the
  81.    * destination) on the result columns to be produced by
  82.    * resultProducers. Null should be returned if there are NO
  83.    * constraints, otherwise a list of column names should be
  84.    * returned as an array of Strings.
  85.    * @param rp the ResultProducer to which the constraints will apply
  86.    * @return an array of column names to which resutltProducer's
  87.    * results will be restricted.
  88.    * @exception Exception if constraints can't be determined
  89.    */
  90.   public String [] determineColumnConstraints(ResultProducer rp) 
  91.     throws Exception {
  92.     return null;
  93.   }
  94.   /**
  95.    * Gets the keys for a specified run number. Different run
  96.    * numbers correspond to different randomizations of the data. Keys
  97.    * produced should be sent to the current ResultListener
  98.    *
  99.    * @param run the run number to get keys for.
  100.    * @exception Exception if a problem occurs while getting the keys
  101.    */
  102.   public void doRunKeys(int run) throws Exception {
  103.     if (m_ResultProducer == null) {
  104.       throw new Exception("No ResultProducer set");
  105.     }
  106.     if (m_ResultListener == null) {
  107.       throw new Exception("No ResultListener set");
  108.     }
  109.     if (m_Instances == null) {
  110.       throw new Exception("No Instances set");
  111.     }
  112.     // Tell the resultproducer to send results to us
  113.     m_ResultProducer.setResultListener(this);
  114.     m_ResultProducer.setInstances(m_Instances);
  115.     // For each subsample size
  116.     if (m_LowerSize == 0) {
  117.       m_CurrentSize = m_StepSize;
  118.     } else {
  119.       m_CurrentSize = m_LowerSize;
  120.     }
  121.     while (m_CurrentSize <= m_Instances.numInstances() &&
  122.            ((m_UpperSize == -1) ||
  123.             (m_CurrentSize <= m_UpperSize))) {
  124.       m_ResultProducer.doRunKeys(run);
  125.       m_CurrentSize += m_StepSize;
  126.     }
  127.   }
  128.   /**
  129.    * Gets the results for a specified run number. Different run
  130.    * numbers correspond to different randomizations of the data. Results
  131.    * produced should be sent to the current ResultListener
  132.    *
  133.    * @param run the run number to get results for.
  134.    * @exception Exception if a problem occurs while getting the results
  135.    */
  136.   public void doRun(int run) throws Exception {
  137.     if (m_ResultProducer == null) {
  138.       throw new Exception("No ResultProducer set");
  139.     }
  140.     if (m_ResultListener == null) {
  141.       throw new Exception("No ResultListener set");
  142.     }
  143.     if (m_Instances == null) {
  144.       throw new Exception("No Instances set");
  145.     }
  146.     // Randomize on a copy of the original dataset
  147.     Instances runInstances = new Instances(m_Instances);
  148.     runInstances.randomize(new Random(run));
  149.     if (runInstances.classAttribute().isNominal()) {
  150.       runInstances.stratify(m_StepSize);
  151.     }
  152.     // Tell the resultproducer to send results to us
  153.     m_ResultProducer.setResultListener(this);
  154.     // For each subsample size
  155.     if (m_LowerSize == 0) {
  156.       m_CurrentSize = m_StepSize;
  157.     } else {
  158.       m_CurrentSize = m_LowerSize;
  159.     }
  160.     while (m_CurrentSize <= m_Instances.numInstances() &&
  161.            ((m_UpperSize == -1) ||
  162.             (m_CurrentSize <= m_UpperSize))) {
  163.       m_ResultProducer.setInstances(new Instances(runInstances, 0, 
  164.                                                   m_CurrentSize));
  165.       m_ResultProducer.doRun(run);
  166.       m_CurrentSize += m_StepSize;
  167.     }
  168.   }
  169.   
  170.   
  171.   /**
  172.    * Prepare for the results to be received.
  173.    *
  174.    * @param rp the ResultProducer that will generate the results
  175.    * @exception Exception if an error occurs during preprocessing.
  176.    */
  177.   public void preProcess(ResultProducer rp) throws Exception {
  178.     if (m_ResultListener == null) {
  179.       throw new Exception("No ResultListener set");
  180.     }
  181.     m_ResultListener.preProcess(this);
  182.   }
  183.   /**
  184.    * Prepare to generate results. The ResultProducer should call
  185.    * preProcess(this) on the ResultListener it is to send results to.
  186.    *
  187.    * @exception Exception if an error occurs during preprocessing.
  188.    */
  189.   public void preProcess() throws Exception {
  190.     
  191.     if (m_ResultProducer == null) {
  192.       throw new Exception("No ResultProducer set");
  193.     }
  194.     // Tell the resultproducer to send results to us
  195.     m_ResultProducer.setResultListener(this);
  196.     m_ResultProducer.preProcess();
  197.   }
  198.   
  199.   /**
  200.    * When this method is called, it indicates that no more results
  201.    * will be sent that need to be grouped together in any way.
  202.    *
  203.    * @param rp the ResultProducer that generated the results
  204.    * @exception Exception if an error occurs
  205.    */
  206.   public void postProcess(ResultProducer rp) throws Exception {
  207.     m_ResultListener.postProcess(this);
  208.   }
  209.   /**
  210.    * When this method is called, it indicates that no more requests to
  211.    * generate results for the current experiment will be sent. The
  212.    * ResultProducer should call preProcess(this) on the
  213.    * ResultListener it is to send results to.
  214.    *
  215.    * @exception Exception if an error occurs
  216.    */
  217.   public void postProcess() throws Exception {
  218.     m_ResultProducer.postProcess();
  219.   }
  220.   
  221.   /**
  222.    * Accepts results from a ResultProducer.
  223.    *
  224.    * @param rp the ResultProducer that generated the results
  225.    * @param key an array of Objects (Strings or Doubles) that uniquely
  226.    * identify a result for a given ResultProducer with given compatibilityState
  227.    * @param result the results stored in an array. The objects stored in
  228.    * the array may be Strings, Doubles, or null (for the missing value).
  229.    * @exception Exception if the result could not be accepted.
  230.    */
  231.   public void acceptResult(ResultProducer rp, Object [] key, Object [] result)
  232.     throws Exception {
  233.     if (m_ResultProducer != rp) {
  234.       throw new Error("Unrecognized ResultProducer sending results!!");
  235.     }
  236.     // Add in current step as key field
  237.     Object [] newKey = new Object [key.length + 1];
  238.     System.arraycopy(key, 0, newKey, 0, key.length);
  239.     newKey[key.length] = new String("" + m_CurrentSize);
  240.     // Pass on to result listener
  241.     m_ResultListener.acceptResult(this, newKey, result);
  242.   }
  243.   /**
  244.    * Determines whether the results for a specified key must be
  245.    * generated.
  246.    *
  247.    * @param rp the ResultProducer wanting to generate the results
  248.    * @param key an array of Objects (Strings or Doubles) that uniquely
  249.    * identify a result for a given ResultProducer with given compatibilityState
  250.    * @return true if the result should be generated
  251.    * @exception Exception if it could not be determined if the result 
  252.    * is needed.
  253.    */
  254.   public boolean isResultRequired(ResultProducer rp, Object [] key) 
  255.     throws Exception {
  256.     if (m_ResultProducer != rp) {
  257.       throw new Error("Unrecognized ResultProducer sending results!!");
  258.     }
  259.     // Add in current step as key field
  260.     Object [] newKey = new Object [key.length + 1];
  261.     System.arraycopy(key, 0, newKey, 0, key.length);
  262.     newKey[key.length] = new String("" + m_CurrentSize);
  263.     // Pass on request to result listener
  264.     return m_ResultListener.isResultRequired(this, newKey);
  265.   }
  266.   /**
  267.    * Gets the names of each of the columns produced for a single run.
  268.    *
  269.    * @return an array containing the name of each column
  270.    * @exception Exception if key names cannot be generated
  271.    */
  272.   public String [] getKeyNames() throws Exception {
  273.     String [] keyNames = m_ResultProducer.getKeyNames();
  274.     String [] newKeyNames = new String [keyNames.length + 1];
  275.     System.arraycopy(keyNames, 0, newKeyNames, 0, keyNames.length);
  276.     // Think of a better name for this key field
  277.     newKeyNames[keyNames.length] = STEP_FIELD_NAME;
  278.     return newKeyNames;
  279.   }
  280.   /**
  281.    * Gets the data types of each of the columns produced for a single run.
  282.    * This method should really be static.
  283.    *
  284.    * @return an array containing objects of the type of each column. The 
  285.    * objects should be Strings, or Doubles.
  286.    * @exception Exception if the key types could not be determined (perhaps
  287.    * because of a problem from a nested sub-resultproducer)
  288.    */
  289.   public Object [] getKeyTypes() throws Exception {
  290.     Object [] keyTypes = m_ResultProducer.getKeyTypes();
  291.     Object [] newKeyTypes = new Object [keyTypes.length + 1];
  292.     System.arraycopy(keyTypes, 0, newKeyTypes, 0, keyTypes.length);
  293.     newKeyTypes[keyTypes.length] = "";
  294.     return newKeyTypes;
  295.   }
  296.   /**
  297.    * Gets the names of each of the columns produced for a single run.
  298.    * A new result field is added for the number of results used to
  299.    * produce each average.
  300.    * If only averages are being produced the names are not altered, if
  301.    * standard deviations are produced then "Dev_" and "Avg_" are prepended
  302.    * to each result deviation and average field respectively.
  303.    *
  304.    * @return an array containing the name of each column
  305.    * @exception Exception if the result names could not be determined (perhaps
  306.    * because of a problem from a nested sub-resultproducer)
  307.    */
  308.   public String [] getResultNames() throws Exception {
  309.     return m_ResultProducer.getResultNames();
  310.   }
  311.   /**
  312.    * Gets the data types of each of the columns produced for a single run.
  313.    *
  314.    * @return an array containing objects of the type of each column. The 
  315.    * objects should be Strings, or Doubles.
  316.    * @exception Exception if the result types could not be determined (perhaps
  317.    * because of a problem from a nested sub-resultproducer)
  318.    */
  319.   public Object [] getResultTypes() throws Exception {
  320.     return m_ResultProducer.getResultTypes();
  321.   }
  322.   /**
  323.    * Gets a description of the internal settings of the result
  324.    * producer, sufficient for distinguishing a ResultProducer
  325.    * instance from another with different settings (ignoring
  326.    * those settings set through this interface). For example,
  327.    * a cross-validation ResultProducer may have a setting for the
  328.    * number of folds. For a given state, the results produced should
  329.    * be compatible. Typically if a ResultProducer is an OptionHandler,
  330.    * this string will represent the command line arguments required
  331.    * to set the ResultProducer to that state.
  332.    *
  333.    * @return the description of the ResultProducer state, or null
  334.    * if no state is defined
  335.    */
  336.   public String getCompatibilityState() {
  337.     String result = " ";
  338.     // + "-F " + Utils.quote(getKeyFieldName())
  339.     // + " -X " + getStepSize() + " ";
  340.     if (m_ResultProducer == null) {
  341.       result += "<null ResultProducer>";
  342.     } else {
  343.       result += "-W " + m_ResultProducer.getClass().getName();
  344.     }
  345.     result  += " -- " + m_ResultProducer.getCompatibilityState();
  346.     return result.trim();
  347.   }
  348.   /**
  349.    * Returns an enumeration describing the available options.
  350.    *
  351.    * @return an enumeration of all the available options
  352.    */
  353.   public Enumeration listOptions() {
  354.     Vector newVector = new Vector(2);
  355.     newVector.addElement(new Option(
  356.      "tThe number of steps in the learning rate curve.n"
  357.       +"t(default 10)", 
  358.      "X", 1, 
  359.      "-X <num steps>"));
  360.     newVector.addElement(new Option(
  361.      "tThe full class name of a ResultProducer.n"
  362.       +"teg: weka.experiment.CrossValidationResultProducer", 
  363.      "W", 1, 
  364.      "-W <class name>"));
  365.     if ((m_ResultProducer != null) &&
  366. (m_ResultProducer instanceof OptionHandler)) {
  367.       newVector.addElement(new Option(
  368.      "",
  369.      "", 0, "nOptions specific to result producer "
  370.      + m_ResultProducer.getClass().getName() + ":"));
  371.       Enumeration enum = ((OptionHandler)m_ResultProducer).listOptions();
  372.       while (enum.hasMoreElements()) {
  373. newVector.addElement(enum.nextElement());
  374.       }
  375.     }
  376.     return newVector.elements();
  377.   }
  378.   /**
  379.    * Parses a given list of options. Valid options are:<p>
  380.    *
  381.    * -L num <br>
  382.    * The lowest number of instances to use. (default 0 = stepsize) <p>
  383.    *
  384.    * -U num <br>
  385.    * The upper number of instances to use. (default -1 = no limit) <p>
  386.    *
  387.    * -S num <br>
  388.    * The number of instances to add at each step. (default 10) <p>
  389.    *
  390.    * -W classname <br>
  391.    * Specify the full class name of the result producer. <p>
  392.    *
  393.    * All option after -- will be passed to the result producer.
  394.    *
  395.    * @param options the list of options as an array of strings
  396.    * @exception Exception if an option is not supported
  397.    */
  398.   public void setOptions(String[] options) throws Exception {
  399.     
  400.     String stepSize = Utils.getOption('S', options);
  401.     if (stepSize.length() != 0) {
  402.       setStepSize(Integer.parseInt(stepSize));
  403.     } else {
  404.       setStepSize(10);
  405.     }
  406.     String lowerSize = Utils.getOption('L', options);
  407.     if (lowerSize.length() != 0) {
  408.       setLowerSize(Integer.parseInt(lowerSize));
  409.     } else {
  410.       setLowerSize(0);
  411.     }
  412.     
  413.     String upperSize = Utils.getOption('U', options);
  414.     if (upperSize.length() != 0) {
  415.       setUpperSize(Integer.parseInt(upperSize));
  416.     } else {
  417.       setUpperSize(-1);
  418.     }
  419.     String rpName = Utils.getOption('W', options);
  420.     if (rpName.length() == 0) {
  421.       throw new Exception("A ResultProducer must be specified with"
  422.   + " the -W option.");
  423.     }
  424.     // Do it first without options, so if an exception is thrown during
  425.     // the option setting, listOptions will contain options for the actual
  426.     // RP.
  427.     setResultProducer((ResultProducer)Utils.forName(
  428.       ResultProducer.class,
  429.       rpName,
  430.       null));
  431.     if (getResultProducer() instanceof OptionHandler) {
  432.       ((OptionHandler) getResultProducer())
  433. .setOptions(Utils.partitionOptions(options));
  434.     }
  435.   }
  436.   /**
  437.    * Gets the current settings of the result producer.
  438.    *
  439.    * @return an array of strings suitable for passing to setOptions
  440.    */
  441.   public String [] getOptions() {
  442.     String [] seOptions = new String [0];
  443.     if ((m_ResultProducer != null) && 
  444. (m_ResultProducer instanceof OptionHandler)) {
  445.       seOptions = ((OptionHandler)m_ResultProducer).getOptions();
  446.     }
  447.     
  448.     String [] options = new String [seOptions.length + 9];
  449.     int current = 0;
  450.     options[current++] = "-S";
  451.     options[current++] = "" + getStepSize();
  452.     options[current++] = "-L";
  453.     options[current++] = "" + getLowerSize();
  454.     options[current++] = "-U";
  455.     options[current++] = "" + getUpperSize();
  456.     if (getResultProducer() != null) {
  457.       options[current++] = "-W";
  458.       options[current++] = getResultProducer().getClass().getName();
  459.     }
  460.     options[current++] = "--";
  461.     System.arraycopy(seOptions, 0, options, current, 
  462.      seOptions.length);
  463.     current += seOptions.length;
  464.     while (current < options.length) {
  465.       options[current++] = "";
  466.     }
  467.     return options;
  468.   }
  469.   /**
  470.    * Set a list of method names for additional measures to look for
  471.    * in SplitEvaluators. This could contain many measures (of which only a
  472.    * subset may be produceable by the current resultProducer) if an experiment
  473.    * is the type that iterates over a set of properties.
  474.    * @param additionalMeasures an array of measure names, null if none
  475.    */
  476.   public void setAdditionalMeasures(String [] additionalMeasures) {
  477.     m_AdditionalMeasures = additionalMeasures;
  478.     if (m_ResultProducer != null) {
  479.       System.err.println("LearningRateResultProducer: setting additional "
  480.  +"measures for "
  481.  +"ResultProducer");
  482.       m_ResultProducer.setAdditionalMeasures(m_AdditionalMeasures);
  483.     }
  484.   }
  485.   /**
  486.    * Returns an enumeration of any additional measure names that might be
  487.    * in the result producer
  488.    * @return an enumeration of the measure names
  489.    */
  490.   public Enumeration enumerateMeasures() {
  491.     Vector newVector = new Vector();
  492.     if (m_ResultProducer instanceof AdditionalMeasureProducer) {
  493.       Enumeration en = ((AdditionalMeasureProducer)m_ResultProducer).
  494. enumerateMeasures();
  495.       while (en.hasMoreElements()) {
  496. String mname = (String)en.nextElement();
  497. newVector.addElement(mname);
  498.       }
  499.     }
  500.     return newVector.elements();
  501.   }
  502.   /**
  503.    * Returns the value of the named measure
  504.    * @param measureName the name of the measure to query for its value
  505.    * @return the value of the named measure
  506.    * @exception IllegalArgumentException if the named measure is not supported
  507.    */
  508.   public double getMeasure(String additionalMeasureName) {
  509.     if (m_ResultProducer instanceof AdditionalMeasureProducer) {
  510.       return ((AdditionalMeasureProducer)m_ResultProducer).
  511. getMeasure(additionalMeasureName);
  512.     } else {
  513.       throw new IllegalArgumentException("LearningRateResultProducer: "
  514.   +"Can't return value for : "+additionalMeasureName
  515.   +". "+m_ResultProducer.getClass().getName()+" "
  516.   +"is not an AdditionalMeasureProducer");
  517.     }
  518.   }
  519.   /**
  520.    * Sets the dataset that results will be obtained for.
  521.    *
  522.    * @param instances a value of type 'Instances'.
  523.    */
  524.   public void setInstances(Instances instances) {
  525.     
  526.     m_Instances = instances;
  527.   }
  528.   /**
  529.    * Returns the tip text for this property
  530.    * @return tip text for this property suitable for
  531.    * displaying in the explorer/experimenter gui
  532.    */
  533.   public String lowerSizeTipText() {
  534.     return "Set the minmum number of instances in a dataset. Setting zero "
  535.       + "here will actually use <stepSize> number of instances at the first "
  536.       + "step (since it makes no sense to use zero instances :-))";
  537.   }
  538.   /**
  539.    * Get the value of LowerSize.
  540.    *
  541.    * @return Value of LowerSize.
  542.    */
  543.   public int getLowerSize() {
  544.     
  545.     return m_LowerSize;
  546.   }
  547.   
  548.   /**
  549.    * Set the value of LowerSize.
  550.    *
  551.    * @param newLowerSize Value to assign to
  552.    * LowerSize.
  553.    */
  554.   public void setLowerSize(int newLowerSize) {
  555.     
  556.     m_LowerSize = newLowerSize;
  557.   }
  558.   /**
  559.    * Returns the tip text for this property
  560.    * @return tip text for this property suitable for
  561.    * displaying in the explorer/experimenter gui
  562.    */
  563.   public String upperSizeTipText() {
  564.     return "Set the maximum number of instances in a dataset. Setting -1 "
  565.       + "sets no upper limit (other than the total number of instances "
  566.       + "in the full dataset)";
  567.   }
  568.   /**
  569.    * Get the value of UpperSize.
  570.    *
  571.    * @return Value of UpperSize.
  572.    */
  573.   public int getUpperSize() {
  574.     
  575.     return m_UpperSize;
  576.   }
  577.   
  578.   /**
  579.    * Set the value of UpperSize.
  580.    *
  581.    * @param newUpperSize Value to assign to
  582.    * UpperSize.
  583.    */
  584.   public void setUpperSize(int newUpperSize) {
  585.     
  586.     m_UpperSize = newUpperSize;
  587.   }
  588.   /**
  589.    * Returns the tip text for this property
  590.    * @return tip text for this property suitable for
  591.    * displaying in the explorer/experimenter gui
  592.    */
  593.   public String stepSizeTipText() {
  594.     return "Set the number of instances to add at each step.";
  595.   }
  596.   /**
  597.    * Get the value of StepSize.
  598.    *
  599.    * @return Value of StepSize.
  600.    */
  601.   public int getStepSize() {
  602.     
  603.     return m_StepSize;
  604.   }
  605.   
  606.   /**
  607.    * Set the value of StepSize.
  608.    *
  609.    * @param newStepSize Value to assign to
  610.    * StepSize.
  611.    */
  612.   public void setStepSize(int newStepSize) {
  613.     
  614.     m_StepSize = newStepSize;
  615.   }
  616.   /**
  617.    * Sets the object to send results of each run to.
  618.    *
  619.    * @param listener a value of type 'ResultListener'
  620.    */
  621.   public void setResultListener(ResultListener listener) {
  622.     m_ResultListener = listener;
  623.   }
  624.   
  625.   /**
  626.    * Returns the tip text for this property
  627.    * @return tip text for this property suitable for
  628.    * displaying in the explorer/experimenter gui
  629.    */
  630.   public String resultProducerTipText() {
  631.     return "Set the resultProducer for which learning rate results should be "
  632.       + "generated.";
  633.   }
  634.   /**
  635.    * Get the ResultProducer.
  636.    *
  637.    * @return the ResultProducer.
  638.    */
  639.   public ResultProducer getResultProducer() {
  640.     
  641.     return m_ResultProducer;
  642.   }
  643.   
  644.   /**
  645.    * Set the ResultProducer.
  646.    *
  647.    * @param newResultProducer new ResultProducer to use.
  648.    */
  649.   public void setResultProducer(ResultProducer newResultProducer) {
  650.     m_ResultProducer = newResultProducer;
  651.     m_ResultProducer.setResultListener(this);
  652.   }
  653.   /**
  654.    * Gets a text descrption of the result producer.
  655.    *
  656.    * @return a text description of the result producer.
  657.    */
  658.   public String toString() {
  659.     String result = "LearningRateResultProducer: ";
  660.     result += getCompatibilityState();
  661.     if (m_Instances == null) {
  662.       result += ": <null Instances>";
  663.     } else {
  664.       result += ": " + Utils.backQuoteChars(m_Instances.relationName());
  665.     }
  666.     return result;
  667.   }
  668. } // LearningRateResultProducer