/* * 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. */ /* * EnsembleLibraryModel.java * Copyright (C) 2006 Robert Jung * */ package weka.classifiers; import weka.core.OptionHandler; import weka.core.RevisionHandler; import weka.core.RevisionUtils; import weka.core.Utils; import weka.gui.GenericObjectEditor; import java.beans.*; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * This class is a light wrapper that is meant to represent a * classifier in a classifier library. This simple base class * is intended only to store the class type and the parameters * for a specific "type" of classifier. You will need to * extend this class to add functionality specific to models * that have been trained on data (as we have for Ensemble Selection) * * @author Robert Jung (mrbobjung@gmail.com) * @version $Revision: 6041 $ */ public class EnsembleLibraryModel implements Serializable, RevisionHandler { /** this stores the class of the classifier */ //private Class m_ModelClass; /** * This is the serialVersionUID that SHOULD stay the same * so that future modified versions of this class will be * backwards compatible with older model versions. */ private static final long serialVersionUID = 7932816660173443200L; /** this is an array of options*/ protected Classifier m_Classifier; /** the description of this classifier*/ protected String m_DescriptionText; /** this is also saved separately */ protected String m_ErrorText; /** a boolean variable tracking whether or not this classifier was * able to be built successfully with the given set of options*/ protected boolean m_OptionsWereValid; /** this is stores redundantly to speed up the many operations that frequently need to get the model string representations (like JList renderers) */ protected String m_StringRepresentation; /** * Default Constructor */ public EnsembleLibraryModel() { super(); } /** * Initializes the class with the given classifier. * * @param classifier the classifier to use */ public EnsembleLibraryModel(Classifier classifier) { m_Classifier = classifier; //this may seem redundant and stupid, but it really is a good idea //to cache the stringRepresentation to minimize the amount of work //that needs to be done when these Models are rendered m_StringRepresentation = toString(); updateDescriptionText(); } /** * This method will attempt to instantiate this classifier with the given * options. If an exception is thrown from the setOptions method of the * classifier then the resulting exception text will be saved in the * description text string. */ public void testOptions() { Classifier testClassifier = null; try { testClassifier = ((Classifier) m_Classifier.getClass().newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } setOptionsWereValid(true); setErrorText(null); updateDescriptionText(); try { ((OptionHandler)testClassifier).setOptions(((OptionHandler)m_Classifier).getOptions()); } catch (Exception e) { setOptionsWereValid(false); setErrorText(e.getMessage()); } updateDescriptionText(); } /** * Returns the base classifier this library model represents. * * @return the base classifier */ public Classifier getClassifier() { return m_Classifier; } /** * getter for the string representation * * @return the string representation */ public String getStringRepresentation() { return m_StringRepresentation; } /** * setter for the description text * * @param descriptionText the description */ public void setDescriptionText(String descriptionText) { m_DescriptionText = descriptionText; } /** * getter for the string representation * * @return the description */ public String getDescriptionText() { return m_DescriptionText; } /** * setter for the error text * * @param errorText the error text */ public void setErrorText(String errorText) { this.m_ErrorText = errorText; } /** * getter for the error text * * @return the error text */ public String getErrorText() { return m_ErrorText; } /** * setter for the optionsWereValid member variable * * @param optionsWereValid if true, the options were valid */ public void setOptionsWereValid(boolean optionsWereValid) { this.m_OptionsWereValid = optionsWereValid; } /** * getter for the optionsWereValid member variable * * @return true if the options were valid */ public boolean getOptionsWereValid() { return m_OptionsWereValid; } /** * This method converts the current set of arguments and the * class name to a string value representing the command line * invocation * * @return a string representation of classname and options */ public String toString() { String str = m_Classifier.getClass().getName(); str += " " + Utils.joinOptions(((OptionHandler) m_Classifier).getOptions()); return str; } /** * getter for the modelClass * * @return the model class */ public Class getModelClass() { return m_Classifier.getClass(); } /** * getter for the classifier options * * @return the classifier options */ public String[] getOptions() { return ((OptionHandler)m_Classifier).getOptions(); } /** * Custom serialization method * * @param stream the stream to write the object to * @throws IOException if something goes wrong IO-wise */ private void writeObject(ObjectOutputStream stream) throws IOException { //stream.defaultWriteObject(); //stream.writeObject(b); //serialize the LibraryModel fields stream.writeObject(m_Classifier); stream.writeObject(m_DescriptionText); stream.writeObject(m_ErrorText); stream.writeObject(new Boolean(m_OptionsWereValid)); stream.writeObject(m_StringRepresentation); } /** * Custom serialization method * * @param stream the stream to write to * @throws IOException if something goes wrong IO-wise * @throws ClassNotFoundException if class couldn't be found */ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { m_Classifier = (Classifier) stream.readObject(); m_DescriptionText = (String) stream.readObject(); m_ErrorText = (String) stream.readObject(); m_OptionsWereValid = ((Boolean) stream.readObject()).booleanValue(); m_StringRepresentation = (String) stream.readObject(); } /** * This method loops through all of the properties of a classifier to * build the html toolTipText that will show all of the property values * for this model. * * Note that this code is copied+adapted from the PropertySheetPanel * class. */ public void updateDescriptionText() { String toolTipText = new String("<html>"); if (!m_OptionsWereValid) { toolTipText += "<font COLOR=\"#FF0000\">" + "<b>Invalid Model:</b><br>" + m_ErrorText + "<br></font>"; } toolTipText += "<TABLE>"; PropertyDescriptor properties[] = null; MethodDescriptor methods[] = null; try { BeanInfo bi = Introspector.getBeanInfo(m_Classifier.getClass()); properties = bi.getPropertyDescriptors(); methods = bi.getMethodDescriptors(); } catch (IntrospectionException ex) { System.err.println("LibraryModel: Couldn't introspect"); return; } for (int i = 0; i < properties.length; i++) { if (properties[i].isHidden() || properties[i].isExpert()) { continue; } String name = properties[i].getDisplayName(); Class type = properties[i].getPropertyType(); Method getter = properties[i].getReadMethod(); Method setter = properties[i].getWriteMethod(); // Only display read/write properties. if (getter == null || setter == null) { continue; } try { Object args[] = {}; Object value = getter.invoke(m_Classifier, args); PropertyEditor editor = null; Class pec = properties[i].getPropertyEditorClass(); if (pec != null) { try { editor = (PropertyEditor) pec.newInstance(); } catch (Exception ex) { // Drop through. } } if (editor == null) { editor = PropertyEditorManager.findEditor(type); } //editors[i] = editor; // If we can't edit this component, skip it. if (editor == null) { continue; } if (editor instanceof GenericObjectEditor) { ((GenericObjectEditor) editor).setClassType(type); } // Don't try to set null values: if (value == null) { continue; } toolTipText += "<TR><TD>" + name + "</TD><TD>" + value.toString() + "</TD></TR>"; } catch (InvocationTargetException ex) { System.err.println("Skipping property " + name + " ; exception on target: " + ex.getTargetException()); ex.getTargetException().printStackTrace(); continue; } catch (Exception ex) { System.err.println("Skipping property " + name + " ; exception: " + ex); ex.printStackTrace(); continue; } } toolTipText += "</TABLE>"; toolTipText += "</html>"; m_DescriptionText = toolTipText; } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 6041 $"); } }