source: src/main/java/weka/gui/beans/Clusterer.java @ 22

Last change on this file since 22 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 25.5 KB
Line 
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 *    Clusterer.java
19 *    Copyright (C) 2004 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.beans;
24
25import weka.clusterers.EM;
26import weka.core.Instances;
27import weka.core.OptionHandler;
28import weka.core.Utils;
29import weka.filters.Filter;
30import weka.filters.unsupervised.attribute.Remove;
31import weka.gui.Logger;
32import weka.gui.ExtensionFileFilter;
33
34import java.awt.BorderLayout;
35import java.beans.EventSetDescriptor;
36import java.io.*;
37import java.util.Enumeration;
38import java.util.Hashtable;
39import java.util.Vector;
40
41import javax.swing.JPanel;
42import javax.swing.JOptionPane;
43import javax.swing.JFileChooser;
44
45import javax.swing.JPanel;
46
47/**
48 * Bean that wraps around weka.clusterers
49 *
50 * @author <a href="mailto:mutter@cs.waikato.ac.nz">Stefan Mutter</a>
51 * @version $Revision: 5247 $
52 * @see JPanel
53 * @see BeanCommon
54 * @see Visible
55 * @see WekaWrapper
56 * @see Serializable
57 * @see UserRequestAcceptor
58 * @see TrainingSetListener
59 * @see TestSetListener
60 */
61public class Clusterer
62  extends JPanel
63  implements BeanCommon, Visible, WekaWrapper, EventConstraints, 
64             UserRequestAcceptor, TrainingSetListener, 
65             TestSetListener, ConfigurationProducer {
66
67  /** for serialization */
68  private static final long serialVersionUID = 7729795159836843810L;
69
70  protected BeanVisual m_visual = 
71    new BeanVisual("Clusterer",
72                   BeanVisual.ICON_PATH+"EM.gif",
73                   BeanVisual.ICON_PATH+"EM_animated.gif");
74
75  private static int IDLE = 0;
76  private static int BUILDING_MODEL = 1;
77  private static int CLUSTERING = 2;
78
79  private int m_state = IDLE;
80
81  private Thread m_buildThread = null;
82
83  /**
84   * Global info for the wrapped classifier (if it exists).
85   */
86  protected String m_globalInfo;
87
88  /**
89   * Objects talking to us
90   */
91  private Hashtable m_listenees = new Hashtable();
92
93  /**
94   * Objects listening for batch clusterer events
95   */
96  private Vector m_batchClustererListeners = new Vector();
97
98
99  /**
100   * Objects listening for graph events
101   */
102  private Vector m_graphListeners = new Vector();
103
104  /**
105   * Objects listening for text events
106   */
107  private Vector m_textListeners = new Vector();
108
109  /**
110   * Holds training instances for batch training.
111   */
112  private Instances m_trainingSet;
113  private transient Instances m_testingSet;
114  private weka.clusterers.Clusterer m_Clusterer = new EM();
115 
116
117  private transient Logger m_log = null;
118
119  private Double m_dummy = new Double(0.0);
120
121  private transient JFileChooser m_fileChooser = null;
122
123  /**
124   * Global info (if it exists) for the wrapped classifier
125   *
126   * @return the global info
127   */
128  public String globalInfo() {
129    return m_globalInfo;
130  }
131
132  /**
133   * Creates a new <code>Clusterer</code> instance.
134   */
135  public Clusterer() {
136    setLayout(new BorderLayout());
137    add(m_visual, BorderLayout.CENTER);
138    setClusterer(m_Clusterer);
139  }
140
141  /**
142   * Set a custom (descriptive) name for this bean
143   *
144   * @param name the name to use
145   */
146  public void setCustomName(String name) {
147    m_visual.setText(name);
148  }
149
150  /**
151   * Get the custom (descriptive) name for this bean (if one has been set)
152   *
153   * @return the custom name (or the default name)
154   */
155  public String getCustomName() {
156    return m_visual.getText();
157  }
158
159  /**
160   * Set the clusterer for this wrapper
161   *
162   * @param c a <code>weka.clusterers.Clusterer</code> value
163   */
164  public void setClusterer(weka.clusterers.Clusterer c) {
165    boolean loadImages = true;
166    if (c.getClass().getName().
167        compareTo(m_Clusterer.getClass().getName()) == 0) {
168      loadImages = false;
169    } else {
170      // clusterer has changed so any batch training status is now
171      // invalid
172      m_trainingSet = null;
173    }
174    m_Clusterer = c;
175    String clustererName = c.getClass().toString();
176    clustererName = clustererName.substring(clustererName.
177                                              lastIndexOf('.')+1, 
178                                              clustererName.length());
179    if (loadImages) {
180      if (!m_visual.loadIcons(BeanVisual.ICON_PATH+clustererName+".gif",
181                       BeanVisual.ICON_PATH+clustererName+"_animated.gif")) {
182        useDefaultVisual();
183      }
184    }
185    m_visual.setText(clustererName);
186
187    // get global info
188    m_globalInfo = KnowledgeFlowApp.getGlobalInfo(m_Clusterer);
189  }
190
191
192  /**
193   * Returns true if this clusterer has an incoming connection that is
194   * a batch set of instances
195   *
196   * @return a <code>boolean</code> value
197   */
198  public boolean hasIncomingBatchInstances() {
199    if (m_listenees.size() == 0) {
200      return false;
201    }
202    if (m_listenees.containsKey("trainingSet") ||
203        m_listenees.containsKey("testSet") ||
204        m_listenees.containsKey("dataSet")) {
205      return true;
206    }
207    return false;
208  }
209
210  /**
211   * Get the clusterer currently set for this wrapper
212   *
213   * @return a <code>weka.clusterers.Clusterer</code> value
214   */
215  public weka.clusterers.Clusterer getClusterer() {
216    return m_Clusterer;
217  }
218
219  /**
220   * Sets the algorithm (clusterer) for this bean
221   *
222   * @param algorithm an <code>Object</code> value
223   * @exception IllegalArgumentException if an error occurs
224   */
225  public void setWrappedAlgorithm(Object algorithm) 
226    {
227
228    if (!(algorithm instanceof weka.clusterers.Clusterer)) { 
229      throw new IllegalArgumentException(algorithm.getClass()+" : incorrect "
230                                         +"type of algorithm (Clusterer)");
231    }
232    setClusterer((weka.clusterers.Clusterer)algorithm);
233  }
234
235  /**
236   * Returns the wrapped clusterer
237   *
238   * @return an <code>Object</code> value
239   */
240  public Object getWrappedAlgorithm() {
241    return getClusterer();
242  }
243
244
245  /**
246   * Accepts a training set and builds batch clusterer
247   *
248   * @param e a <code>TrainingSetEvent</code> value
249   */
250  public void acceptTrainingSet(final TrainingSetEvent e) {
251    if (e.isStructureOnly()) {
252      // no need to build a clusterer, instead just generate a dummy
253      // BatchClustererEvent in order to pass on instance structure to
254      // any listeners
255      BatchClustererEvent ce = 
256        new BatchClustererEvent(this, m_Clusterer, 
257                                 new DataSetEvent(this, e.getTrainingSet()),
258                                 e.getSetNumber(), e.getMaxSetNumber(),1);
259
260      notifyBatchClustererListeners(ce);
261      return;
262    }
263    if (m_buildThread == null) {
264      try {
265        if (m_state == IDLE) {
266          synchronized (this) {
267            m_state = BUILDING_MODEL;
268          }
269          m_trainingSet = e.getTrainingSet();
270//        final String oldText = m_visual.getText();
271          m_buildThread = new Thread() {
272              public void run() {
273                try {
274                  if (m_trainingSet != null) { 
275                    m_visual.setAnimated();
276//                  m_visual.setText("Building clusters...");
277                    if (m_log != null) {
278                      m_log.statusMessage(statusMessagePrefix() 
279                          + "Building clusters...");
280                    }
281                    buildClusterer();
282                    if(m_batchClustererListeners.size() > 0){
283                        BatchClustererEvent ce = 
284                            new BatchClustererEvent(this, m_Clusterer, 
285                                 new DataSetEvent(this, e.getTrainingSet()),
286                                 e.getSetNumber(), e.getMaxSetNumber(),1);
287                        notifyBatchClustererListeners(ce);
288                    }
289                    if (m_Clusterer instanceof weka.core.Drawable && 
290                        m_graphListeners.size() > 0) {
291                      String grphString = 
292                        ((weka.core.Drawable)m_Clusterer).graph();
293                      int grphType = ((weka.core.Drawable)m_Clusterer).graphType();
294                      String grphTitle = m_Clusterer.getClass().getName();
295                      grphTitle = grphTitle.substring(grphTitle.
296                                                      lastIndexOf('.')+1, 
297                                                      grphTitle.length());
298                      grphTitle = "Set " + e.getSetNumber() + " ("
299                        +e.getTrainingSet().relationName() + ") "
300                        +grphTitle;
301                     
302                      GraphEvent ge = new GraphEvent(Clusterer.this, 
303                                                     grphString, 
304                                                     grphTitle,
305                                                     grphType);
306                      notifyGraphListeners(ge);
307                    }
308
309                    if (m_textListeners.size() > 0) {
310                      String modelString = m_Clusterer.toString();
311                      String titleString = m_Clusterer.getClass().getName();
312                     
313                      titleString = titleString.
314                        substring(titleString.lastIndexOf('.') + 1,
315                                  titleString.length());
316                      modelString = "=== Clusterer model ===\n\n" +
317                        "Scheme:   " +titleString+"\n" +
318                        "Relation: "  + m_trainingSet.relationName() + 
319                        ((e.getMaxSetNumber() > 1) 
320                         ? "\nTraining Fold: "+e.getSetNumber()
321                         :"")
322                        + "\n\n"
323                        + modelString;
324                      titleString = "Model: " + titleString;
325
326                      TextEvent nt = new TextEvent(Clusterer.this,
327                                                   modelString,
328                                                   titleString);
329                      notifyTextListeners(nt);
330                    }
331                  }
332                } catch (Exception ex) {
333                  Clusterer.this.stop(); // stop processing
334                  if (m_log != null) {
335                    m_log.statusMessage(statusMessagePrefix()
336                        + "ERROR (See log for details");
337                    m_log.logMessage("[Clusterer] " + statusMessagePrefix()
338                        + " problem training clusterer. " + ex.getMessage());
339                  }
340                  ex.printStackTrace();
341                } finally {
342//                m_visual.setText(oldText);
343                  m_visual.setStatic();
344                  m_state = IDLE;
345                  if (isInterrupted()) {
346                    // prevent any clusterer events from being fired
347                    m_trainingSet = null;
348                    if (m_log != null) {
349                      m_log.logMessage("[Clusterer]" + statusMessagePrefix() 
350                          + " Build clusterer interrupted!");
351                      m_log.statusMessage(statusMessagePrefix() 
352                          + "INTERRUPTED");
353                    }
354                  } else {
355                    // save header
356                    m_trainingSet = new Instances(m_trainingSet, 0);
357                    if (m_log != null) {
358                      m_log.statusMessage(statusMessagePrefix() + "Finished.");
359                    }
360                  }
361                  block(false);
362                }
363              } 
364            };
365          m_buildThread.setPriority(Thread.MIN_PRIORITY);
366          m_buildThread.start();
367          // make sure the thread is still running before we block
368          //      if (m_buildThread.isAlive()) {
369          block(true);
370            //    }
371          m_buildThread = null;
372          m_state = IDLE;
373        }
374      } catch (Exception ex) {
375        ex.printStackTrace();
376      }
377    }
378  }
379
380  /**
381   * Accepts a test set for a batch trained clusterer
382   *
383   * @param e a <code>TestSetEvent</code> value
384   */
385  public void acceptTestSet(TestSetEvent e) {
386
387    if (m_trainingSet != null) {
388      try {
389        if (m_state == IDLE) {
390          synchronized(this) {
391            m_state = CLUSTERING;
392          }
393          m_testingSet = e.getTestSet();
394          if (m_trainingSet.equalHeaders(m_testingSet)) {
395            BatchClustererEvent ce = 
396              new BatchClustererEvent(this, m_Clusterer, 
397                                       new DataSetEvent(this, e.getTestSet()),
398                                  e.getSetNumber(), e.getMaxSetNumber(),0);
399
400            notifyBatchClustererListeners(ce);
401           
402          }
403          m_state = IDLE;
404        }
405      } catch (Exception ex) {
406        stop(); // stop any processing
407        if (m_log != null) {
408          m_log.statusMessage(statusMessagePrefix()
409              + "ERROR (see log for details");
410          m_log.logMessage("[Clusterer] " + statusMessagePrefix()
411              + " problem during testing. " + ex.getMessage());
412        }
413        ex.printStackTrace();
414      }
415    }
416  }
417
418/**
419   * Builds the clusters
420   */
421  private void buildClusterer() throws Exception {
422      if(m_trainingSet.classIndex() < 0) 
423        m_Clusterer.buildClusterer(m_trainingSet);
424      else{ //class based evaluation if class attribute is set
425        Remove removeClass = new Remove();
426        removeClass.setAttributeIndices(""+(m_trainingSet.classIndex()+1));
427        removeClass.setInvertSelection(false);
428        removeClass.setInputFormat(m_trainingSet);
429        Instances clusterTrain = Filter.useFilter(m_trainingSet, removeClass);
430        m_Clusterer.buildClusterer(clusterTrain);
431      }
432  }
433
434  /**
435   * Sets the visual appearance of this wrapper bean
436   *
437   * @param newVisual a <code>BeanVisual</code> value
438   */
439  public void setVisual(BeanVisual newVisual) {
440    m_visual = newVisual;
441  }
442
443  /**
444   * Gets the visual appearance of this wrapper bean
445   */
446  public BeanVisual getVisual() {
447    return m_visual;
448  }
449
450  /**
451   * Use the default visual appearance for this bean
452   */
453  public void useDefaultVisual() {
454    m_visual.loadIcons(BeanVisual.ICON_PATH+"DefaultClusterer.gif",
455                       BeanVisual.ICON_PATH+"DefaultClusterer_animated.gif");
456  }
457
458  /**
459   * Add a batch clusterer listener
460   *
461   * @param cl a <code>BatchClustererListener</code> value
462   */
463  public synchronized void 
464    addBatchClustererListener(BatchClustererListener cl) {
465    m_batchClustererListeners.addElement(cl);
466  }
467
468  /**
469   * Remove a batch clusterer listener
470   *
471   * @param cl a <code>BatchClustererListener</code> value
472   */
473  public synchronized void 
474    removeBatchClustererListener(BatchClustererListener cl) {
475    m_batchClustererListeners.remove(cl);
476  }
477
478  /**
479   * Notify all batch clusterer listeners of a batch clusterer event
480   *
481   * @param ce a <code>BatchClustererEvent</code> value
482   */
483  private void notifyBatchClustererListeners(BatchClustererEvent ce) {
484    Vector l;
485    synchronized (this) {
486      l = (Vector)m_batchClustererListeners.clone();
487    }
488    if (l.size() > 0) {
489      for(int i = 0; i < l.size(); i++) {
490        ((BatchClustererListener)l.elementAt(i)).acceptClusterer(ce);
491      }
492    }
493  }
494
495  /**
496   * Add a graph listener
497   *
498   * @param cl a <code>GraphListener</code> value
499   */
500  public synchronized void addGraphListener(GraphListener cl) {
501    m_graphListeners.addElement(cl);
502  }
503
504  /**
505   * Remove a graph listener
506   *
507   * @param cl a <code>GraphListener</code> value
508   */
509  public synchronized void removeGraphListener(GraphListener cl) {
510    m_graphListeners.remove(cl);
511  }
512
513  /**
514   * Notify all graph listeners of a graph event
515   *
516   * @param ge a <code>GraphEvent</code> value
517   */
518  private void notifyGraphListeners(GraphEvent ge) {
519    Vector l;
520    synchronized (this) {
521      l = (Vector)m_graphListeners.clone();
522    }
523    if (l.size() > 0) {
524      for(int i = 0; i < l.size(); i++) {
525        ((GraphListener)l.elementAt(i)).acceptGraph(ge);
526      }
527    }
528  }
529
530  /**
531   * Add a text listener
532   *
533   * @param cl a <code>TextListener</code> value
534   */
535  public synchronized void addTextListener(TextListener cl) {
536    m_textListeners.addElement(cl);
537  }
538
539  /**
540   * Remove a text listener
541   *
542   * @param cl a <code>TextListener</code> value
543   */
544  public synchronized void removeTextListener(TextListener cl) {
545    m_textListeners.remove(cl);
546  }
547
548  /**
549   * Notify all text listeners of a text event
550   *
551   * @param ge a <code>TextEvent</code> value
552   */
553  private void notifyTextListeners(TextEvent ge) {
554    Vector l;
555    synchronized (this) {
556      l = (Vector)m_textListeners.clone();
557    }
558    if (l.size() > 0) {
559      for(int i = 0; i < l.size(); i++) {
560        ((TextListener)l.elementAt(i)).acceptText(ge);
561      }
562    }
563  }
564 
565  /**
566   * We don't have to keep track of configuration listeners (see the
567   * documentation for ConfigurationListener/ConfigurationEvent).
568   *
569   * @param cl a ConfigurationListener.
570   */
571  public synchronized void addConfigurationListener(ConfigurationListener cl) {
572   
573  }
574 
575  /**
576   * We don't have to keep track of configuration listeners (see the
577   * documentation for ConfigurationListener/ConfigurationEvent).
578   *
579   * @param cl a ConfigurationListener.
580   */
581  public synchronized void removeConfigurationListener(ConfigurationListener cl) {
582   
583  }
584
585
586  /**
587   * Returns true if, at this time,
588   * the object will accept a connection with respect to the named event
589   *
590   * @param eventName the event
591   * @return true if the object will accept a connection
592   */
593  public boolean connectionAllowed(String eventName) {
594    /*    if (eventName.compareTo("instance") == 0) {
595      if (!(m_Clusterer instanceof weka.classifiers.UpdateableClassifier)) {
596        return false;
597      }
598      } */
599    if (m_listenees.containsKey(eventName)) {
600      return false;
601    }
602    return true;
603  }
604
605  /**
606   * Returns true if, at this time,
607   * the object will accept a connection according to the supplied
608   * EventSetDescriptor
609   *
610   * @param esd the EventSetDescriptor
611   * @return true if the object will accept a connection
612   */
613  public boolean connectionAllowed(EventSetDescriptor esd) {
614    return connectionAllowed(esd.getName());
615  }
616
617  /**
618   * Notify this object that it has been registered as a listener with
619   * a source with respect to the named event
620   *
621   * @param eventName the event
622   * @param source the source with which this object has been registered as
623   * a listener
624   */
625  public synchronized void connectionNotification(String eventName,
626                                                  Object source) {
627
628    if (connectionAllowed(eventName)) {
629      m_listenees.put(eventName, source);
630      /*      if (eventName.compareTo("instance") == 0) {
631        startIncrementalHandler();
632        } */
633    }
634  }
635
636  /**
637   * Notify this object that it has been deregistered as a listener with
638   * a source with respect to the supplied event name
639   *
640   * @param eventName the event
641   * @param source the source with which this object has been registered as
642   * a listener
643   */
644  public synchronized void disconnectionNotification(String eventName,
645                                                     Object source) {
646    m_listenees.remove(eventName);
647  }
648
649  /**
650   * Function used to stop code that calls acceptTrainingSet. This is
651   * needed as clusterer construction is performed inside a separate
652   * thread of execution.
653   *
654   * @param tf a <code>boolean</code> value
655   */
656  private synchronized void block(boolean tf) {
657
658    if (tf) {
659      try {
660          // only block if thread is still doing something useful!
661        if (m_buildThread.isAlive() && m_state != IDLE) {
662          wait();
663          }
664      } catch (InterruptedException ex) {
665      }
666    } else {
667      notifyAll();
668    }
669  }
670
671  /**
672   * Returns true if. at this time, the bean is busy with some
673   * (i.e. perhaps a worker thread is performing some calculation).
674   *
675   * @return true if the bean is busy.
676   */
677  public boolean isBusy() {
678    return (m_buildThread != null);
679  }
680 
681  /**
682   * Stop any clusterer action
683   */
684  public void stop() {
685    // tell all listenees (upstream beans) to stop
686    Enumeration en = m_listenees.keys();
687    while (en.hasMoreElements()) {
688      Object tempO = m_listenees.get(en.nextElement());
689      if (tempO instanceof BeanCommon) {
690        ((BeanCommon)tempO).stop();
691      }
692    }
693
694    // stop the build thread
695    if (m_buildThread != null) {
696      m_buildThread.interrupt();
697      m_buildThread.stop();
698      m_buildThread = null;
699      m_visual.setStatic();
700    }
701  }
702
703  /**
704   * Set a logger
705   *
706   * @param logger a <code>Logger</code> value
707   */
708  public void setLog(Logger logger) {
709    m_log = logger;
710  }
711
712  public void saveModel() {
713    try {
714      if (m_fileChooser == null) {
715        // i.e. after de-serialization
716        m_fileChooser = 
717          new JFileChooser(new File(System.getProperty("user.dir")));
718        ExtensionFileFilter ef = new ExtensionFileFilter("model", "Serialized weka clusterer");
719      m_fileChooser.setFileFilter(ef);
720      }
721      int returnVal = m_fileChooser.showSaveDialog(this);
722      if (returnVal == JFileChooser.APPROVE_OPTION) {
723        File saveTo = m_fileChooser.getSelectedFile();
724        String fn = saveTo.getAbsolutePath();
725        if (!fn.endsWith(".model")) {
726          fn += ".model";
727          saveTo = new File(fn);
728        }
729        ObjectOutputStream os = 
730          new ObjectOutputStream(new BufferedOutputStream(
731                                                          new FileOutputStream(saveTo)));
732        os.writeObject(m_Clusterer);
733        if (m_trainingSet != null) {
734          Instances header = new Instances(m_trainingSet, 0);
735          os.writeObject(header);
736        }
737        os.close();
738        if (m_log != null) {
739          m_log.logMessage("[Clusterer] Saved clusterer " + getCustomName());
740        }
741      }
742    } catch (Exception ex) {
743      JOptionPane.showMessageDialog(Clusterer.this,
744                                    "Problem saving clusterer.\n",
745                                    "Save Model",
746                                    JOptionPane.ERROR_MESSAGE);
747      if (m_log != null) {
748        m_log.logMessage("[Clusterer] Problem saving clusterer. " 
749            + getCustomName() + ex.getMessage());
750      }
751    }
752  }
753
754  public void loadModel() {
755    try {
756      if (m_fileChooser == null) {
757        // i.e. after de-serialization
758        m_fileChooser = 
759          new JFileChooser(new File(System.getProperty("user.dir")));
760        ExtensionFileFilter ef = new ExtensionFileFilter("model", "Serialized weka clusterer");
761        m_fileChooser.setFileFilter(ef);
762      }
763      int returnVal = m_fileChooser.showOpenDialog(this);
764      if (returnVal == JFileChooser.APPROVE_OPTION) {
765        File loadFrom = m_fileChooser.getSelectedFile();
766        ObjectInputStream is = 
767          new ObjectInputStream(new BufferedInputStream(
768                                new FileInputStream(loadFrom)));
769        // try and read the model
770        weka.clusterers.Clusterer temp = (weka.clusterers.Clusterer)is.readObject();
771
772        // Update name and icon
773        setClusterer(temp);
774       
775        // try and read the header (if present)
776        try {
777          m_trainingSet = (Instances)is.readObject();
778        } catch (Exception ex) {
779          // quietly ignore
780        }
781        is.close();
782        if (m_log != null) {
783          m_log.logMessage("[Clusterer] Loaded clusterer: "
784                           + m_Clusterer.getClass().toString());
785        }
786      }
787    } catch (Exception ex) {
788      JOptionPane.showMessageDialog(Clusterer.this,
789                                    "Problem loading classifier.\n",
790                                    "Load Model",
791                                    JOptionPane.ERROR_MESSAGE);
792      if (m_log != null) {
793        m_log.logMessage("[Clusterer] Problem loading classifier. " 
794            + ex.getMessage());
795      }
796    }
797  }
798
799  /**
800   * Return an enumeration of requests that can be made by the user
801   *
802   * @return an <code>Enumeration</code> value
803   */
804  public Enumeration enumerateRequests() {
805    Vector newVector = new Vector(0);
806    if (m_buildThread != null) {
807      newVector.addElement("Stop");
808    }
809
810    if (m_buildThread == null &&
811        m_Clusterer != null) {
812      newVector.addElement("Save model");
813    }
814
815    if (m_buildThread == null) {
816      newVector.addElement("Load model");
817    }
818   
819    return newVector.elements();
820  }
821
822  /**
823   * Perform a particular request
824   *
825   * @param request the request to perform
826   * @exception IllegalArgumentException if an error occurs
827   */
828  public void performRequest(String request) {
829    if (request.compareTo("Stop") == 0) {
830      stop();
831    }  else if (request.compareTo("Save model") == 0) {
832      saveModel();
833    } else if (request.compareTo("Load model") == 0) {
834      loadModel();
835    } else {
836      throw new IllegalArgumentException(request
837                                         + " not supported (Clusterer)");
838    }
839  }
840
841  /**
842   * Returns true, if at the current time, the event described by the
843   * supplied event descriptor could be generated.
844   *
845   * @param esd an <code>EventSetDescriptor</code> value
846   * @return a <code>boolean</code> value
847   */
848  public boolean eventGeneratable(EventSetDescriptor esd) {
849    String eventName = esd.getName();
850    return eventGeneratable(eventName);
851  }
852
853  /**
854   * Returns true, if at the current time, the named event could
855   * be generated. Assumes that the supplied event name is
856   * an event that could be generated by this bean
857   *
858   * @param eventName the name of the event in question
859   * @return true if the named event could be generated at this point in
860   * time
861   */
862  public boolean eventGeneratable(String eventName) {
863    if (eventName.compareTo("graph") == 0) {
864      // can't generate a GraphEvent if clusterer is not drawable
865      if (!(m_Clusterer instanceof weka.core.Drawable)) {
866        return false;
867      }
868      // need to have a training set before the clusterer
869      // can generate a graph!
870      if (!m_listenees.containsKey("trainingSet")) {
871        return false;
872      }
873      // Source needs to be able to generate a trainingSet
874      // before we can generate a graph
875      Object source = m_listenees.get("trainingSet");
876       if (source instanceof EventConstraints) {
877        if (!((EventConstraints)source).eventGeneratable("trainingSet")) {
878          return false;
879        }
880      }
881    }
882
883    if (eventName.compareTo("batchClusterer") == 0) {
884      if (!m_listenees.containsKey("trainingSet")) {
885        return false;
886      }
887     
888      Object source = m_listenees.get("trainingSet");
889      if (source != null && source instanceof EventConstraints) {
890        if (!((EventConstraints)source).eventGeneratable("trainingSet")) {
891          return false;
892        }
893      }
894    }
895
896    if (eventName.compareTo("text") == 0) {
897      if (!m_listenees.containsKey("trainingSet")){ 
898        return false;
899      }
900      Object source = m_listenees.get("trainingSet");
901      if (source != null && source instanceof EventConstraints) {
902        if (!((EventConstraints)source).eventGeneratable("trainingSet")) {
903          return false;
904        }
905      }
906    }
907
908    if (eventName.compareTo("batchClassifier") == 0)
909        return false;
910    if (eventName.compareTo("incrementalClassifier") == 0)
911        return false;
912   
913    return true;
914  }
915 
916  private String statusMessagePrefix() {
917    return getCustomName() + "$" + hashCode() + "|"
918    + ((m_Clusterer instanceof OptionHandler &&
919        Utils.joinOptions(((OptionHandler)m_Clusterer).getOptions()).length() > 0)
920        ? Utils.joinOptions(((OptionHandler)m_Clusterer).getOptions()) + "|"
921            : "");
922  }
923}
Note: See TracBrowser for help on using the repository browser.