001: /*
002: * This program is free software; you can redistribute it and/or modify
003: * it under the terms of the GNU General Public License as published by
004: * the Free Software Foundation; either version 2 of the License, or
005: * (at your option) any later version.
006: *
007: * This program is distributed in the hope that it will be useful,
008: * but WITHOUT ANY WARRANTY; without even the implied warranty of
009: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: * GNU General Public License for more details.
011: *
012: * You should have received a copy of the GNU General Public License
013: * along with this program; if not, write to the Free Software
014: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
015: */
016:
017: /*
018: * EnsembleLibrary.java
019: * Copyright (C) 2006 Robert Jung
020: *
021: */
022:
023: package weka.classifiers;
024:
025: import weka.gui.ensembleLibraryEditor.LibrarySerialization;
026:
027: import java.beans.PropertyChangeListener;
028: import java.beans.PropertyChangeSupport;
029: import java.io.BufferedReader;
030: import java.io.BufferedWriter;
031: import java.io.File;
032: import java.io.FileReader;
033: import java.io.FileWriter;
034: import java.io.InputStream;
035: import java.io.Serializable;
036: import java.io.Writer;
037: import java.util.Iterator;
038: import java.util.TreeSet;
039: import java.util.Vector;
040:
041: import javax.swing.JComponent;
042: import javax.swing.JOptionPane;
043:
044: /**
045: * This class represents a library of classifiers. This class
046: * follows the factory design pattern of creating LibraryModels
047: * when asked. It also has the methods necessary for saving
048: * and loading models from lists.
049: *
050: * @author Robert Jung (mrbobjung@gmail.com)
051: * @version $Revision: 1.1 $
052: */
053: public class EnsembleLibrary implements Serializable {
054:
055: /** for serialization */
056: private static final long serialVersionUID = -7987178904923706760L;
057:
058: /** The default file extension for model list files */
059: public static final String XML_FILE_EXTENSION = ".model.xml";
060:
061: /** The flat file extension for model list files */
062: public static final String FLAT_FILE_EXTENSION = ".mlf";
063:
064: /** the set of classifiers that constitute the library */
065: public TreeSet m_Models;
066:
067: /** A helper class for notifying listeners when the library changes */
068: private transient PropertyChangeSupport m_LibraryPropertySupport = new PropertyChangeSupport(
069: this );
070:
071: /**
072: * Constructor is responsible for initializing the data
073: * structure hoilding all of the models
074: *
075: */
076: public EnsembleLibrary() {
077:
078: m_Models = new TreeSet(new EnsembleLibraryModelComparator());
079: }
080:
081: /**
082: * Returns the number of models in the ensemble library
083: *
084: * @return the number of models
085: */
086: public int size() {
087: if (m_Models != null)
088: return m_Models.size();
089: else
090: return 0;
091: }
092:
093: /**
094: * adds a LibraryModel to the Library
095: *
096: * @param model the model to add
097: */
098: public void addModel(EnsembleLibraryModel model) {
099: m_Models.add(model);
100: if (m_LibraryPropertySupport != null)
101: m_LibraryPropertySupport.firePropertyChange(null, null,
102: null);
103: }
104:
105: /**
106: * adds a LibraryModel to the Library
107: *
108: * @param modelString the model to add
109: */
110: public void addModel(String modelString) {
111: m_Models.add(createModel(modelString));
112: m_LibraryPropertySupport.firePropertyChange(null, null, null);
113: }
114:
115: /**
116: * removes a LibraryModel from the Library
117: *
118: * @param model the model to remove
119: */
120: public void removeModel(EnsembleLibraryModel model) {
121: m_Models.remove(model);
122: m_LibraryPropertySupport.firePropertyChange(null, null, null);
123: }
124:
125: /**
126: * creates a LibraryModel from a string representing the command
127: * line invocation
128: *
129: * @param classifier the classifier to create a model from
130: * @return the generated model
131: */
132: public EnsembleLibraryModel createModel(Classifier classifier) {
133: EnsembleLibraryModel model = new EnsembleLibraryModel(
134: classifier);
135:
136: return model;
137: }
138:
139: /**
140: * This method takes a String argument defining a classifier and
141: * uses it to create a base Classifier.
142: *
143: * @param modelString the classifier string
144: * @return the generated model
145: */
146: public EnsembleLibraryModel createModel(String modelString) {
147:
148: String[] splitString = modelString.split("\\s+");
149: String className = splitString[0];
150:
151: String argString = modelString.replaceAll(splitString[0], "");
152: String[] optionStrings = argString.split("\\s+");
153:
154: EnsembleLibraryModel model = null;
155: try {
156: model = new EnsembleLibraryModel(Classifier.forName(
157: className, optionStrings));
158: } catch (Exception e) {
159: e.printStackTrace();
160: }
161: return model;
162: }
163:
164: /**
165: * getter for the set of models in this library
166: *
167: * @return the current models
168: */
169: public TreeSet getModels() {
170: return m_Models;
171: }
172:
173: /**
174: * setter for the set of models in this library
175: *
176: * @param models the models to use
177: */
178: public void setModels(TreeSet models) {
179: m_Models = models;
180: m_LibraryPropertySupport.firePropertyChange(null, null, null);
181: }
182:
183: /**
184: * removes all models from the current library
185: */
186: public void clearModels() {
187: m_Models.clear();
188: m_LibraryPropertySupport.firePropertyChange(null, null, null);
189: }
190:
191: /**
192: * Loads and returns a library from the specified file
193: *
194: * @param selectedFile the file to load from
195: * @param dialogParent the parent component
196: * @param library will contain the data after loading
197: */
198: public static void loadLibrary(File selectedFile,
199: JComponent dialogParent, EnsembleLibrary library) {
200:
201: try {
202: loadLibrary(selectedFile, library);
203: } catch (Exception ex) {
204: JOptionPane.showMessageDialog(dialogParent,
205: "Error reading file '" + selectedFile.getName()
206: + "':\n" + ex.getMessage(), "Load failed",
207: JOptionPane.ERROR_MESSAGE);
208: System.err.println(ex.getMessage());
209: }
210: }
211:
212: /**
213: * This method takes a model list file and a library object as arguments and
214: * Instantiates all of the models in the library list file. It is assumed
215: * that the passed library was an associated working directory and can take
216: * care of creating the model objects itself.
217: *
218: * @param selectedFile the file to load
219: * @param library the library
220: * @throws Exception if something goes wrong
221: */
222: public static void loadLibrary(File selectedFile,
223: EnsembleLibrary library) throws Exception {
224:
225: //decide what type of model file list we are dealing with and
226: //then load accordingly
227:
228: //deal with XML extension for xml files
229: if (selectedFile.getName().toLowerCase().endsWith(
230: EnsembleLibrary.XML_FILE_EXTENSION)) {
231:
232: LibrarySerialization librarySerialization;
233:
234: Vector classifiers = null;
235:
236: try {
237: librarySerialization = new LibrarySerialization();
238: classifiers = (Vector) librarySerialization
239: .read(selectedFile.getPath());
240: } catch (Exception e) {
241: e.printStackTrace();
242: }
243:
244: //library.setClassifiers(classifiers);
245:
246: for (Iterator it = classifiers.iterator(); it.hasNext();) {
247:
248: EnsembleLibraryModel model = library
249: .createModel((Classifier) it.next());
250: model.testOptions();
251: library.addModel(model);
252: }
253:
254: //deal with MLF extesion for flat files
255: } else if (selectedFile.getName().toLowerCase().endsWith(
256: EnsembleLibrary.FLAT_FILE_EXTENSION)) {
257:
258: BufferedReader reader = null;
259:
260: reader = new BufferedReader(new FileReader(selectedFile));
261:
262: String modelString;
263:
264: while ((modelString = reader.readLine()) != null) {
265:
266: EnsembleLibraryModel model = library
267: .createModel(modelString);
268:
269: if (model != null) {
270: model.testOptions();
271: library.addModel(model);
272: } else {
273: System.err.println("Failed to create model: "
274: + modelString);
275: }
276: }
277:
278: reader.close();
279: }
280: }
281:
282: /**
283: * This method takes an XML input stream and a library object as arguments
284: * and Instantiates all of the models in the stream. It is assumed
285: * that the passed library was an associated working directory and can take
286: * care of creating the model objects itself.
287: *
288: * @param stream the XML stream to load
289: * @param library the library
290: * @throws Exception if something goes wrong
291: */
292: public static void loadLibrary(InputStream stream,
293: EnsembleLibrary library) throws Exception {
294:
295: Vector classifiers = null;
296:
297: try {
298: LibrarySerialization librarySerialization = new LibrarySerialization();
299: classifiers = (Vector) librarySerialization.read(stream);
300: } catch (Exception e) {
301: e.printStackTrace();
302: }
303:
304: for (int i = 0; i < classifiers.size(); i++) {
305: EnsembleLibraryModel model = library
306: .createModel((Classifier) classifiers.get(i));
307: model.testOptions();
308: library.addModel(model);
309: }
310: }
311:
312: /**
313: * Saves the given library in the specified file. This saves only
314: * the specification of the models as a model list.
315: *
316: * @param selectedFile the file to save to
317: * @param library the library to save
318: * @param dialogParent the component parent
319: */
320: public static void saveLibrary(File selectedFile,
321: EnsembleLibrary library, JComponent dialogParent) {
322:
323: //save decide what type of model file list we are dealing with and
324: //then save accordingly
325:
326: //System.out.println("writing to file: "+selectedFile.getPath());
327:
328: //deal with XML extension for xml files
329: if (selectedFile.getName().toLowerCase().endsWith(
330: EnsembleLibrary.XML_FILE_EXTENSION)) {
331:
332: LibrarySerialization librarySerialization;
333:
334: Vector classifiers = new Vector();
335:
336: for (Iterator it = library.getModels().iterator(); it
337: .hasNext();) {
338: EnsembleLibraryModel model = (EnsembleLibraryModel) it
339: .next();
340: classifiers.add(model.getClassifier());
341: }
342:
343: try {
344: librarySerialization = new LibrarySerialization();
345: librarySerialization.write(selectedFile.getPath(),
346: classifiers);
347: } catch (Exception e) {
348: e.printStackTrace();
349: }
350:
351: //deal with MLF extesion for flat files
352: } else if (selectedFile.getName().toLowerCase().endsWith(
353: EnsembleLibrary.FLAT_FILE_EXTENSION)) {
354:
355: Writer writer = null;
356: try {
357: writer = new BufferedWriter(
358: new FileWriter(selectedFile));
359:
360: Iterator it = library.getModels().iterator();
361:
362: while (it.hasNext()) {
363: EnsembleLibraryModel model = (EnsembleLibraryModel) it
364: .next();
365: writer
366: .write(model.getStringRepresentation()
367: + "\n");
368: }
369:
370: writer.close();
371: } catch (Exception ex) {
372: JOptionPane.showMessageDialog(dialogParent,
373: "Error writing file '" + selectedFile.getName()
374: + "':\n" + ex.getMessage(),
375: "Save failed", JOptionPane.ERROR_MESSAGE);
376: System.err.println(ex.getMessage());
377: }
378: }
379: }
380:
381: /**
382: * Adds an object to the list of those that wish to be informed when the
383: * library changes.
384: *
385: * @param listener a new listener to add to the list
386: */
387: public void addPropertyChangeListener(
388: PropertyChangeListener listener) {
389:
390: if (m_LibraryPropertySupport != null) {
391: m_LibraryPropertySupport
392: .addPropertyChangeListener(listener);
393:
394: }
395: }
396: }
|