source: branches/MetisMQI/src/main/java/weka/classifiers/scripting/JythonClassifier.java

Last change on this file was 29, checked in by gnappo, 14 years ago

Taggata versione per la demo e aggiunto branch.

File size: 10.9 KB
RevLine 
[29]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/*
18 *    JythonClassifier.java
19 *    Copyright (C) 2007 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.classifiers.scripting;
24
25import weka.classifiers.Classifier;
26import weka.classifiers.AbstractClassifier;
27import weka.core.Capabilities;
28import weka.core.Instance;
29import weka.core.Instances;
30import weka.core.Option;
31import weka.core.RevisionUtils;
32import weka.core.Utils;
33import weka.core.OptionHandler;
34import weka.core.scripting.Jython;
35
36import java.io.File;
37import java.util.Enumeration;
38import java.util.Vector;
39
40/**
41 <!-- globalinfo-start -->
42 * A wrapper class for Jython code. Even though the classifier is serializable, the trained classifier cannot be stored persistently. I.e., one cannot store a model file and re-load it at a later point in time again to make predictions.
43 * <p/>
44 <!-- globalinfo-end -->
45 *
46 <!-- options-start -->
47 * Valid options are: <p/>
48 *
49 * <pre> -J &lt;filename&gt;
50 *  The Jython module to load (full path)
51 *  Options after '--' will be passed on to the Jython module.</pre>
52 *
53 * <pre> -P &lt;directory[,directory,...]&gt;
54 *  The paths to add to 'sys.path' (comma-separated list).</pre>
55 *
56 * <pre> -D
57 *  If set, classifier is run in debug mode and
58 *  may output additional info to the console</pre>
59 *
60 <!-- options-end -->
61 *
62 * Options after "--" will be passed onto the Jython module.
63 * <p/>
64 * Partially based on <a href="http://wiki.python.org/jython/JythonMonthly/Articles/September2006/1" target="_blank">this</a>
65 * code.
66 *
67 * @author FracPete (fracpete at waikato dot ac dot nz)
68 * @version $Revision: 5987 $
69 */
70public class JythonClassifier 
71  extends AbstractClassifier {
72
73  /** for serialization. */
74  private static final long serialVersionUID = -9078371491735496175L;
75 
76  /** the Jython module. */
77  protected File m_JythonModule = new File(System.getProperty("user.dir"));
78
79  /** the options for the Jython module. */
80  protected String[] m_JythonOptions = new String[0];
81
82  /** additional paths for the Jython module (will be added to "sys.path"). */
83  protected File[] m_JythonPaths = new File[0];
84
85  /** the loaded Jython object. */
86  transient protected Classifier m_JythonObject = null;
87
88  /**
89   * default constructor.
90   */
91  public JythonClassifier() {
92    super();
93  }
94 
95  /**
96   * Returns a string describing classifier.
97   *
98   * @return            a description suitable for
99   *                    displaying in the explorer/experimenter gui
100   */
101  public String globalInfo() {
102    return 
103        "A wrapper class for Jython code. Even though the classifier is "
104      + "serializable, the trained classifier cannot be stored persistently. "
105      + "I.e., one cannot store a model file and re-load it at a later point "
106      + "in time again to make predictions.";
107  }
108
109  /**
110   * Returns an enumeration describing the available options.
111   *
112   * @return            an enumeration of all the available options.
113   */
114  public Enumeration listOptions() {
115    Vector result = new Vector();
116
117    result.addElement(new Option(
118        "\tThe Jython module to load (full path)\n"
119        + "\tOptions after '--' will be passed on to the Jython module.",
120        "J", 1, "-J <filename>"));
121
122    result.addElement(new Option(
123        "\tThe paths to add to 'sys.path' (comma-separated list).",
124        "P", 1, "-P <directory[,directory,...]>"));
125
126    Enumeration en = super.listOptions();
127    while (en.hasMoreElements())
128      result.addElement(en.nextElement());
129
130    return result.elements();
131  }
132
133  /**
134   * Parses a given list of options.
135   *
136   * @param options     the list of options as an array of strings
137   * @throws Exception  if an option is not supported
138   */
139  public void setOptions(String[] options) throws Exception {
140    String              tmpStr;
141
142    m_JythonOptions = new String[0];
143
144    setJythonPaths(Utils.getOption('P', options));
145
146    tmpStr = Utils.getOption('J', options);
147    if (tmpStr.length() != 0)
148      setJythonModule(new File(tmpStr));
149    else
150      setJythonModule(new File(System.getProperty("user.dir")));
151
152    setJythonOptions(Utils.joinOptions(Utils.partitionOptions(options).clone()));
153
154    super.setOptions(options);
155  }
156
157  /**
158   * Gets the current settings of the Classifier.
159   *
160   * @return            an array of strings suitable for passing to
161   *                    setOptions
162   */
163  public String[] getOptions() {
164    Vector<String>      result;
165    String[]            options;
166    int                 i;
167
168    result = new Vector<String>();
169
170    if (getJythonPaths().length() > 0) {
171      result.add("-P");
172      result.add("" + getJythonPaths());
173    }
174
175    result.add("-J");
176    result.add("" + getJythonModule().getAbsolutePath());
177
178    options = super.getOptions();
179    for (i = 0; i < options.length; i++)
180      result.add(options[i]);
181
182    if (m_JythonOptions.length > 0) {
183      options = m_JythonOptions;
184      result.add("--");
185      for (i = 0; i < options.length; i++)
186        result.add(options[i]);
187    }
188
189    return result.toArray(new String[result.size()]);
190  }
191
192  /**
193   * Returns the tip text for this property.
194   *
195   * @return            tip text for this property suitable for
196   *                    displaying in the explorer/experimenter gui
197   */
198  public String jythonModuleTipText() {
199    return "The Jython module to load and execute.";
200  }
201
202  /**
203   * Sets the Jython module.
204   *
205   * @param value       the Jython module
206   */
207  public void setJythonModule(File value) {
208    m_JythonModule = value;
209    initJythonObject();
210  }
211
212  /**
213   * Gets the Jython module.
214   *
215   * @return            the Jython module
216   */
217  public File getJythonModule() {
218    return m_JythonModule;
219  }
220
221  /**
222   * Returns the tip text for this property.
223   *
224   * @return            tip text for this property suitable for
225   *                    displaying in the explorer/experimenter gui
226   */
227  public String jythonOptionsTipText() {
228    return "The options for the Jython module.";
229  }
230
231  /**
232   * Sets the Jython module options.
233   *
234   * @param value       the options
235   */
236  public void setJythonOptions(String value) {
237    try {
238      m_JythonOptions = Utils.splitOptions(value).clone();
239      initJythonObject();
240    }
241    catch (Exception e) {
242      m_JythonOptions = new String[0];
243      e.printStackTrace();
244    }
245  }
246
247  /**
248   * Gets the Jython module options.
249   *
250   * @return            the options
251   */
252  public String getJythonOptions() {
253    return Utils.joinOptions(m_JythonOptions);
254  }
255
256  /**
257   * Returns the tip text for this property.
258   *
259   * @return            tip text for this property suitable for
260   *                    displaying in the explorer/experimenter gui
261   */
262  public String jythonPathsTipText() {
263    return "Comma-separated list of additional paths that get added to 'sys.path'.";
264  }
265
266  /**
267   * Sets the additional Jython paths.
268   *
269   * @param value       the paths (comma-separated list)
270   */
271  public void setJythonPaths(String value) {
272    String[]    paths;
273    int         i;
274
275    if (value.length() == 0) {
276      m_JythonPaths = new File[0];
277    }
278    else {
279      paths = value.split(",");
280      m_JythonPaths = new File[paths.length];
281      for (i = 0; i < m_JythonPaths.length; i++)
282        m_JythonPaths[i] = new File(paths[i]);
283    }
284  }
285
286  /**
287   * Gets the additional Jython paths.
288   *
289   * @return            the paths
290   */
291  public String getJythonPaths() {
292    String      result;
293    int         i;
294
295    result = "";
296
297    for (i = 0; i < m_JythonPaths.length; i++) {
298      if (i > 0)
299        result += ",";
300      result += m_JythonPaths[i].getAbsolutePath();
301    }
302
303    return result;
304  }
305
306  /**
307   * Returns default capabilities of the classifier.
308   *
309   * @return            the capabilities of this classifier
310   */
311  public Capabilities getCapabilities() {
312    Capabilities        result;
313
314    if (m_JythonObject == null) {
315      result = new Capabilities(this);
316      result.disableAll();
317    } else {
318      result = m_JythonObject.getCapabilities();
319    }
320
321    result.enableAllAttributeDependencies();
322    result.enableAllClassDependencies();
323
324    return result;
325  }
326
327  /**
328   * tries to initialize the python object and set its options.
329   */
330  protected void initJythonObject() {
331    try {
332      if (m_JythonModule.isFile())
333        m_JythonObject = (Classifier) Jython.newInstance(m_JythonModule, Classifier.class, m_JythonPaths);
334      else
335        m_JythonObject = null;
336     
337      if (m_JythonObject != null)
338        ((OptionHandler)m_JythonObject).setOptions(m_JythonOptions.clone());
339    }
340    catch (Exception e) {
341      m_JythonObject = null;
342      e.printStackTrace();
343    }
344  }
345
346  /**
347   * Generates the classifier.
348   *
349   * @param instances   set of instances serving as training data
350   * @throws Exception  if the classifier has not been generated successfully
351   */
352  public void buildClassifier(Instances instances) throws Exception {
353    if (!Jython.isPresent())
354      throw new Exception("Jython classes not in CLASSPATH!");
355
356    // try loading the module
357    initJythonObject();
358
359    // build the model
360    if (m_JythonObject != null)
361      m_JythonObject.buildClassifier(instances);
362    else
363      System.err.println("buildClassifier: No Jython object present!");
364  }
365
366  /**
367   * Classifies a given instance.
368   *
369   * @param instance    the instance to be classified
370   * @return            index of the predicted class
371   * @throws Exception  if an error occurred during the prediction
372   */
373  public double classifyInstance(Instance instance) throws Exception {
374    if (m_JythonObject != null)
375      return m_JythonObject.classifyInstance(instance);
376    else
377      return Utils.missingValue();
378  }
379
380  /**
381   * Calculates the class membership probabilities for the given test instance.
382   *
383   * @param instance    the instance to be classified
384   * @return            predicted class probability distribution
385   * @throws Exception  if class is numeric
386   */
387  public double[] distributionForInstance(Instance instance) throws Exception {
388    if (m_JythonObject != null)
389      return m_JythonObject.distributionForInstance(instance);
390    else
391      return new double[instance.numClasses()];
392  }
393
394  /**
395   * Returns a description of the classifier.
396   *
397   * @return            a description of the classifier as a string.
398   */
399  public String toString() {
400    if (m_JythonObject != null)
401      return m_JythonObject.toString();
402    else
403      return "No Jython module loaded.";
404  }
405 
406  /**
407   * Returns the revision string.
408   *
409   * @return            the revision
410   */
411  public String getRevision() {
412    return RevisionUtils.extract("$Revision: 5987 $");
413  }
414
415  /**
416   * Main method for testing this class.
417   *
418   * @param args        the options
419   */
420  public static void main(String [] args) {
421    runClassifier(new JythonClassifier(), args);
422  }
423}
Note: See TracBrowser for help on using the repository browser.