Coverage Report - weka.classifiers.CheckSource
 
Classes in this File Line Coverage Branch Coverage Complexity
CheckSource
0%
0/122
0%
0/60
3.714
 
 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 3 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, see <http://www.gnu.org/licenses/>.
 14  
  */
 15  
 
 16  
 /*
 17  
  * CheckSource.java
 18  
  * Copyright (C) 2007-2012 University of Waikato, Hamilton, New Zealand
 19  
  */
 20  
 
 21  
 package weka.classifiers;
 22  
 
 23  
 import java.io.File;
 24  
 import java.util.Enumeration;
 25  
 import java.util.Vector;
 26  
 
 27  
 import weka.core.Instances;
 28  
 import weka.core.Option;
 29  
 import weka.core.OptionHandler;
 30  
 import weka.core.RevisionHandler;
 31  
 import weka.core.RevisionUtils;
 32  
 import weka.core.Utils;
 33  
 import weka.core.converters.ConverterUtils.DataSource;
 34  
 
 35  
 /**
 36  
  * A simple class for checking the source generated from Classifiers
 37  
  * implementing the <code>weka.classifiers.Sourcable</code> interface.
 38  
  * It takes a classifier, the classname of the generated source
 39  
  * and the dataset the source was generated with as parameters and tests
 40  
  * the output of the built classifier against the output of the generated
 41  
  * source. Use option '-h' to display all available commandline options.
 42  
  *
 43  
  <!-- options-start -->
 44  
  * Valid options are: <p/>
 45  
  *
 46  
  * <pre> -W &lt;classname and options&gt;
 47  
  *  The classifier (incl. options) that was used to generate
 48  
  *  the source code.</pre>
 49  
  *
 50  
  * <pre> -S &lt;classname&gt;
 51  
  *  The classname of the generated source code.</pre>
 52  
  *
 53  
  * <pre> -t &lt;file&gt;
 54  
  *  The training set with which the source code was generated.</pre>
 55  
  *
 56  
  * <pre> -c &lt;index&gt;
 57  
  *  The class index of the training set. 'first' and 'last' are
 58  
  *  valid indices.
 59  
  *  (default: last)</pre>
 60  
  *
 61  
  <!-- options-end -->
 62  
  *
 63  
  * Options after -- are passed to the designated classifier (specified with -W).
 64  
  *
 65  
  * @author  fracpete (fracpete at waikato dot ac dot nz)
 66  
  * @version $Revision: 8034 $
 67  
  * @see     weka.classifiers.Sourcable
 68  
  */
 69  0
 public class CheckSource
 70  
   implements OptionHandler, RevisionHandler {
 71  
 
 72  
   /** the classifier used for generating the source code */
 73  0
   protected Classifier m_Classifier = null;
 74  
 
 75  
   /** the generated source code */
 76  0
   protected Classifier m_SourceCode = null;
 77  
 
 78  
   /** the dataset to use for testing */
 79  0
   protected File m_Dataset = null;
 80  
 
 81  
   /** the class index */
 82  0
   protected int m_ClassIndex = -1;
 83  
 
 84  
   /**
 85  
    * Returns an enumeration describing the available options.
 86  
    *
 87  
    * @return an enumeration of all the available options.
 88  
    */
 89  
   public Enumeration listOptions() {
 90  0
     Vector result = new Vector();
 91  
 
 92  0
     result.addElement(new Option(
 93  
         "\tThe classifier (incl. options) that was used to generate\n"
 94  
         + "\tthe source code.",
 95  
         "W", 1, "-W <classname and options>"));
 96  
 
 97  0
     result.addElement(new Option(
 98  
         "\tThe classname of the generated source code.",
 99  
         "S", 1, "-S <classname>"));
 100  
 
 101  0
     result.addElement(new Option(
 102  
         "\tThe training set with which the source code was generated.",
 103  
         "t", 1, "-t <file>"));
 104  
 
 105  0
     result.addElement(new Option(
 106  
         "\tThe class index of the training set. 'first' and 'last' are\n"
 107  
         + "\tvalid indices.\n"
 108  
         + "\t(default: last)",
 109  
         "c", 1, "-c <index>"));
 110  
 
 111  0
     return result.elements();
 112  
   }
 113  
 
 114  
   /**
 115  
    * Parses a given list of options. <p/>
 116  
    *
 117  
    <!-- options-start -->
 118  
    * Valid options are: <p/>
 119  
    *
 120  
    * <pre> -W &lt;classname and options&gt;
 121  
    *  The classifier (incl. options) that was used to generate
 122  
    *  the source code.</pre>
 123  
    *
 124  
    * <pre> -S &lt;classname&gt;
 125  
    *  The classname of the generated source code.</pre>
 126  
    *
 127  
    * <pre> -t &lt;file&gt;
 128  
    *  The training set with which the source code was generated.</pre>
 129  
    *
 130  
    * <pre> -c &lt;index&gt;
 131  
    *  The class index of the training set. 'first' and 'last' are
 132  
    *  valid indices.
 133  
    *  (default: last)</pre>
 134  
    *
 135  
    <!-- options-end -->
 136  
    *
 137  
    * Options after -- are passed to the designated classifier (specified with
 138  
    * -W).
 139  
    *
 140  
    * @param options the list of options as an array of strings
 141  
    * @throws Exception if an option is not supported
 142  
    */
 143  
   public void setOptions(String[] options) throws Exception {
 144  
     String      tmpStr;
 145  
     String[]    spec;
 146  
     String      classname;
 147  
 
 148  0
     tmpStr = Utils.getOption('W', options);
 149  0
     if (tmpStr.length() > 0) {
 150  0
       spec = Utils.splitOptions(tmpStr);
 151  0
       if (spec.length == 0)
 152  0
         throw new IllegalArgumentException("Invalid classifier specification string");
 153  0
       classname = spec[0];
 154  0
       spec[0]   = "";
 155  0
       setClassifier((Classifier) Utils.forName(Classifier.class, classname, spec));
 156  
     }
 157  
     else {
 158  0
       throw new Exception("No classifier (classname + options) provided!");
 159  
     }
 160  
 
 161  0
     tmpStr = Utils.getOption('S', options);
 162  0
     if (tmpStr.length() > 0) {
 163  0
       spec = Utils.splitOptions(tmpStr);
 164  0
       if (spec.length != 1)
 165  0
         throw new IllegalArgumentException("Invalid source code specification string");
 166  0
       classname = spec[0];
 167  0
       spec[0]   = "";
 168  0
       setSourceCode((Classifier) Utils.forName(Classifier.class, classname, spec));
 169  
     }
 170  
     else {
 171  0
       throw new Exception("No source code (classname) provided!");
 172  
     }
 173  
 
 174  0
     tmpStr = Utils.getOption('t', options);
 175  0
     if (tmpStr.length() != 0)
 176  0
       setDataset(new File(tmpStr));
 177  
     else
 178  0
       throw new Exception("No dataset provided!");
 179  
 
 180  0
     tmpStr = Utils.getOption('c', options);
 181  0
     if (tmpStr.length() != 0) {
 182  0
       if (tmpStr.equals("first"))
 183  0
         setClassIndex(0);
 184  0
       else if (tmpStr.equals("last"))
 185  0
         setClassIndex(-1);
 186  
       else
 187  0
         setClassIndex(Integer.parseInt(tmpStr) - 1);
 188  
     }
 189  
     else {
 190  0
       setClassIndex(-1);
 191  
     }
 192  0
   }
 193  
 
 194  
   /**
 195  
    * Gets the current settings of the Classifier.
 196  
    *
 197  
    * @return an array of strings suitable for passing to setOptions
 198  
    */
 199  
   public String[] getOptions() {
 200  
     Vector<String>      result;
 201  
 
 202  0
     result  = new Vector<String>();
 203  
 
 204  0
     if (getClassifier() != null) {
 205  0
       result.add("-W");
 206  0
       result.add(getClassifier().getClass().getName() + " "
 207  
           + Utils.joinOptions(((OptionHandler) getClassifier()).getOptions()));
 208  
     }
 209  
 
 210  0
     if (getSourceCode() != null) {
 211  0
       result.add("-S");
 212  0
       result.add(getSourceCode().getClass().getName());
 213  
     }
 214  
 
 215  0
     if (getDataset() != null) {
 216  0
       result.add("-t");
 217  0
       result.add(m_Dataset.getAbsolutePath());
 218  
     }
 219  
 
 220  0
     result.add("-c");
 221  0
     if (getClassIndex() == -1)
 222  0
       result.add("last");
 223  0
     else if (getClassIndex() == 0)
 224  0
       result.add("first");
 225  
     else
 226  0
       result.add("" + (getClassIndex() + 1));
 227  
 
 228  0
     return result.toArray(new String[result.size()]);
 229  
   }
 230  
 
 231  
   /**
 232  
    * Sets the classifier to use for the comparison.
 233  
    *
 234  
    * @param value       the classifier to use
 235  
    */
 236  
   public void setClassifier(Classifier value) {
 237  0
     m_Classifier = value;
 238  0
   }
 239  
 
 240  
   /**
 241  
    * Gets the classifier being used for the tests, can be null.
 242  
    *
 243  
    * @return            the currently set classifier
 244  
    */
 245  
   public Classifier getClassifier() {
 246  0
     return m_Classifier;
 247  
   }
 248  
 
 249  
   /**
 250  
    * Sets the class to test.
 251  
    *
 252  
    * @param value       the class to test
 253  
    */
 254  
   public void setSourceCode(Classifier value) {
 255  0
     m_SourceCode = value;
 256  0
   }
 257  
 
 258  
   /**
 259  
    * Gets the class to test.
 260  
    *
 261  
    * @return            the currently set class, can be null.
 262  
    */
 263  
   public Classifier getSourceCode() {
 264  0
     return m_SourceCode;
 265  
   }
 266  
 
 267  
   /**
 268  
    * Sets the dataset to use for testing.
 269  
    *
 270  
    * @param value       the dataset to use.
 271  
    */
 272  
   public void setDataset(File value) {
 273  0
     if (!value.exists())
 274  0
       throw new IllegalArgumentException(
 275  
           "Dataset '" + value.getAbsolutePath() + "' does not exist!");
 276  
     else
 277  0
       m_Dataset = value;
 278  0
   }
 279  
 
 280  
   /**
 281  
    * Gets the dataset to use for testing, can be null.
 282  
    *
 283  
    * @return            the dataset to use.
 284  
    */
 285  
   public File getDataset() {
 286  0
     return m_Dataset;
 287  
   }
 288  
 
 289  
   /**
 290  
    * Sets the class index of the dataset.
 291  
    *
 292  
    * @param value       the class index of the dataset.
 293  
    */
 294  
   public void setClassIndex(int value) {
 295  0
     m_ClassIndex = value;
 296  0
   }
 297  
 
 298  
   /**
 299  
    * Gets the class index of the dataset.
 300  
    *
 301  
    * @return            the current class index.
 302  
    */
 303  
   public int getClassIndex() {
 304  0
     return m_ClassIndex;
 305  
   }
 306  
 
 307  
   /**
 308  
    * performs the comparison test
 309  
    *
 310  
    * @return            true if tests were successful
 311  
    * @throws Exception  if tests fail
 312  
    */
 313  
   public boolean execute() throws Exception {
 314  
     boolean     result;
 315  
     Classifier  cls;
 316  
     Classifier  code;
 317  
     int         i;
 318  
     Instances   data;
 319  
     DataSource  source;
 320  
     boolean     numeric;
 321  
     boolean     different;
 322  
     double      predClassifier;
 323  
     double      predSource;
 324  
 
 325  0
     result = true;
 326  
 
 327  
     // a few checks
 328  0
     if (getClassifier() == null)
 329  0
       throw new Exception("No classifier set!");
 330  0
     if (getSourceCode() == null)
 331  0
       throw new Exception("No source code set!");
 332  0
     if (getDataset() == null)
 333  0
       throw new Exception("No dataset set!");
 334  0
     if (!getDataset().exists())
 335  0
       throw new Exception(
 336  
           "Dataset '" + getDataset().getAbsolutePath() + "' does not exist!");
 337  
 
 338  
     // load data
 339  0
     source = new DataSource(getDataset().getAbsolutePath());
 340  0
     data   = source.getDataSet();
 341  0
     if (getClassIndex() == -1)
 342  0
       data.setClassIndex(data.numAttributes() - 1);
 343  
     else
 344  0
       data.setClassIndex(getClassIndex());
 345  0
     numeric = data.classAttribute().isNumeric();
 346  
 
 347  
     // build classifier
 348  0
     cls = AbstractClassifier.makeCopy(getClassifier());
 349  0
     cls.buildClassifier(data);
 350  
 
 351  0
     code = getSourceCode();
 352  
 
 353  
     // compare predictions
 354  0
     for (i = 0; i < data.numInstances(); i++) {
 355  
       // perform predictions
 356  0
       predClassifier = cls.classifyInstance(data.instance(i));
 357  0
       predSource     = code.classifyInstance(data.instance(i));
 358  
 
 359  
       // compare both results
 360  0
       if (Double.isNaN(predClassifier) && Double.isNaN(predSource)) {
 361  0
         different = false;
 362  
       }
 363  
       else {
 364  0
         if (numeric)
 365  0
           different = !Utils.eq(predClassifier, predSource);
 366  
         else
 367  0
           different = ((int) predClassifier != (int) predSource);
 368  
       }
 369  
 
 370  0
       if (different) {
 371  0
         result = false;
 372  0
         if (numeric)
 373  0
           System.out.println(
 374  
               (i+1) + ". instance (Classifier/Source code): "
 375  
               + predClassifier + " != " + predSource);
 376  
         else
 377  0
           System.out.println(
 378  
               (i+1) + ". instance (Classifier/Source code): "
 379  
               + data.classAttribute().value((int) predClassifier)
 380  
               + " != " + data.classAttribute().value((int) predSource));
 381  
       }
 382  
     }
 383  
 
 384  0
     return result;
 385  
   }
 386  
 
 387  
   /**
 388  
    * Returns the revision string.
 389  
    *
 390  
    * @return                the revision
 391  
    */
 392  
   public String getRevision() {
 393  0
     return RevisionUtils.extract("$Revision: 8034 $");
 394  
   }
 395  
 
 396  
   /**
 397  
    * Executes the tests, use "-h" to list the commandline options.
 398  
    *
 399  
    * @param args        the commandline parameters
 400  
    * @throws Exception  if something goes wrong
 401  
    */
 402  
   public static void main(String[] args) throws Exception{
 403  
     CheckSource         check;
 404  
     StringBuffer        text;
 405  
     Enumeration         enm;
 406  
 
 407  0
     check = new CheckSource();
 408  0
     if (Utils.getFlag('h', args)) {
 409  0
       text = new StringBuffer();
 410  0
       text.append("\nHelp requested:\n\n");
 411  0
       enm = check.listOptions();
 412  0
       while (enm.hasMoreElements()) {
 413  0
         Option option = (Option) enm.nextElement();
 414  0
         text.append(option.synopsis() + "\n");
 415  0
         text.append(option.description() + "\n");
 416  0
       }
 417  0
       System.out.println("\n" + text + "\n");
 418  
     }
 419  
     else {
 420  0
       check.setOptions(args);
 421  0
       if (check.execute())
 422  0
         System.out.println("Tests OK!");
 423  
       else
 424  0
         System.out.println("Tests failed!");
 425  
     }
 426  0
   }
 427  
 }