Source code: marf/Classification/Classification.java
1 package marf.Classification;
2
3 import marf.MARF;
4 import marf.FeatureExtraction.IFeatureExtraction;
5 import marf.Storage.ResultSet;
6 import marf.Storage.StorageException;
7 import marf.Storage.StorageManager;
8 import marf.Storage.TrainingSet;
9 import marf.util.Debug;
10
11 import java.util.Vector;
12
13
14 /**
15 * <p>Abstract Classification Module.
16 * A generic implementation of the IClassification interface.
17 * The derivatives must inherit from this module, and if they cannot,
18 * they should implement IClassification themselves.
19 * </p>
20 *
21 * <p>$Id: Classification.java,v 1.39 2005/08/05 22:19:47 mokhov Exp $</p>
22 *
23 * @author Serguei Mokhov
24 * @version $Revision: 1.39 $
25 * @since 0.0.1
26 */
27 public abstract class Classification
28 extends StorageManager
29 implements IClassification
30 {
31 /* Data Members */
32
33 /**
34 * Reference to the enclosed FeatureExtraction object.
35 */
36 protected IFeatureExtraction oFeatureExtraction = null;
37
38 /**
39 * TrainingSet Container.
40 */
41 protected TrainingSet oTrainingSet = null;
42
43 /**
44 * Classification result set. May contain
45 * one or more results (in case of similarity).
46 *
47 * @since 0.3.0.2
48 */
49 protected ResultSet oResultSet = new ResultSet();
50
51 /* Constructors */
52
53 /**
54 * Generic Classification Constructor.
55 * @param poFeatureExtraction FeatureExtraction module reference
56 */
57 protected Classification(IFeatureExtraction poFeatureExtraction)
58 {
59 // TODO: null validation?
60 this.oFeatureExtraction = poFeatureExtraction;
61
62 // See if there is a request for dump format
63 if(MARF.getModuleParams() != null)
64 {
65 Vector oParams = MARF.getModuleParams().getClassificationParams();
66
67 // TODO: Must be validated of what's coming in
68 if(oParams != null && oParams.size() > 0)
69 this.iCurrentDumpMode = ((Integer)oParams.elementAt(0)).intValue();
70 }
71 }
72
73 /* Classification API */
74
75 /**
76 * Generic training routine for building/updating
77 * mean vectors in the training set.
78 * Can be overridden, and if the overriding classifier is using
79 * <code>TrainingSet</code>, it should call <code>super.train();</code>
80 *
81 * @return <code>true</code> if training was successful
82 * (i.e. mean vector was updated); <code>false</code> otherwise
83 * @throws ClassificationException if there was a problem while training
84 * @see TrainingSet
85 */
86 public boolean train()
87 throws ClassificationException
88 {
89 // For exception handling
90 String strPhase = "[start]";
91
92 /*
93 * It is important to use saveTrainingSet() and loadTrainingSet()
94 * throughout this method, as the dump() and restore() may easily
95 * (and likely) to be overridden by the derivatives.
96 */
97 try
98 {
99 if(this.oTrainingSet != null)
100 {
101 // Wrong global cluster loaded, reload the correct one.
102 if
103 (
104 (this.oTrainingSet.getPreprocessingMethod() != MARF.getPreprocessingMethod())
105 ||
106 (this.oTrainingSet.getFeatureExtractionMethod() != MARF.getFeatureExtractionMethod())
107 )
108 {
109 strPhase = "[dumping previous cluster]";
110
111 saveTrainingSet();
112 this.oTrainingSet = null;
113 }
114 }
115
116 strPhase = "[restoring training set]";
117 loadTrainingSet();
118
119 // Add the new feature vector.
120 strPhase = "[adding feature vector]";
121
122 boolean bVectorAdded = this.oTrainingSet.addFeatureVector
123 (
124 this.oFeatureExtraction.getFeaturesArray(),
125 MARF.getSampleFile(),
126 MARF.getCurrentSubject(),
127 MARF.getPreprocessingMethod(),
128 MARF.getFeatureExtractionMethod()
129 );
130
131 // No point of doing I/O if we didn't add anything.
132 if(bVectorAdded)
133 {
134 strPhase = "[dumping updated training set]";
135 saveTrainingSet();
136 }
137
138 return true;
139 }
140 catch(NullPointerException e)
141 {
142 throw new ClassificationException
143 (
144 "NullPointerException in Classification.train(): oTrainingSet = " + this.oTrainingSet +
145 ", oFeatureExtraction = " + this.oFeatureExtraction +
146 ", FeaturesArray = " + this.oFeatureExtraction.getFeaturesArray() +
147 ", phase: " + strPhase
148 );
149 }
150 catch(Exception e)
151 {
152 throw new ClassificationException("Phase: " + strPhase, e);
153 }
154 }
155
156 /* From Storage Manager */
157
158 /**
159 * Generic implementation of dump() to dump the TrainingSet.
160 * @since 0.2.0
161 * @throws StorageException if there's a problem saving training set to disk
162 */
163 public void dump()
164 throws StorageException
165 {
166 saveTrainingSet();
167 }
168
169 /**
170 * Generic implementation of restore() for TrainingSet.
171 * @since 0.2.0
172 * @throws StorageException if there is a problem loading the training set from disk
173 */
174 public void restore()
175 throws StorageException
176 {
177 loadTrainingSet();
178 }
179
180 /**
181 * Saves TrainingSet to a file. Called by <code>dump()</code>.
182 * @since 0.2.0
183 * @throws StorageException if there's a problem saving training set to disk
184 * @see #dump()
185 * @see TrainingSet
186 */
187 private final void saveTrainingSet()
188 throws StorageException
189 {
190 try
191 {
192 // Dump stuff is there's anything to dump
193 if(this.oTrainingSet != null)
194 {
195 this.oTrainingSet.setDumpMode(this.iCurrentDumpMode);
196 this.oTrainingSet.setFilename(getTrainingSetFilename());
197 this.oTrainingSet.dump();
198 }
199
200 // TODO: if TrainingSet is null
201 else
202 {
203 // [SM, 2003-05-02] Should here be something? Like a debug() call or
204 // more severe things?
205 Debug.debug
206 (
207 "WARNING: Classification.saveTrainingSet() -- TrainingSet is null.\n" +
208 " No TrainingSet is saved."
209 );
210 }
211 }
212 catch(Exception e)
213 {
214 throw new StorageException(e);
215 }
216 }
217
218 /**
219 * Loads TrainingSet from a file. Called by <code>restore()</code>.
220 * @since 0.2.0
221 * @throws StorageException if there is a problem loading the training set from disk
222 */
223 private final void loadTrainingSet()
224 throws StorageException
225 {
226 try
227 {
228 if(this.oTrainingSet == null)
229 {
230 this.oTrainingSet = new TrainingSet();
231 this.oTrainingSet.setDumpMode(this.iCurrentDumpMode);
232 this.oTrainingSet.setFilename(getTrainingSetFilename());
233 this.oTrainingSet.restore();
234 }
235
236 //TODO: if TrainingSet is not null
237 else
238 {
239 // [SM, 2003-05-02] Should here be something? Like a debug() call or
240 // more severe things?
241 Debug.debug
242 (
243 "WARNING: Classification.loadTrainingSet() -- TrainingSet is not null.\n" +
244 " No TrainingSet is loaded."
245 );
246 }
247 }
248 catch(Exception e)
249 {
250 throw new StorageException(e);
251 }
252 }
253
254 /**
255 * Retrieves the enclosed result set.
256 * @return the enclosed ResultSet object
257 * @since 0.3.0.2
258 */
259 public ResultSet getResultSet()
260 {
261 return this.oResultSet;
262 }
263
264 /**
265 * Constructs a global cluster file name for the TrainingSet.
266 *
267 * <p>Filename is constructed using fully-qualified class of
268 * either TrainingSet or a classifier name with global
269 * clustering info such as preprocessing and feature
270 * extraction methods, so that ony that cluster can be reloaded
271 * after.</p>
272 *
273 * May be overridden by the drivatives when necessary.
274 *
275 * @return String, filename
276 * @since 0.2.0
277 */
278 protected String getTrainingSetFilename()
279 {
280 return
281 // Fully-qualified class name
282 this.oTrainingSet.getClass().getName() + "." +
283
284 // Global cluster: <PR>.<FE>.<FVS>
285 // For the same FE method we may have different feature vector sizes
286 MARF.getPreprocessingMethod() + "." +
287 MARF.getFeatureExtractionMethod() + "." +
288 this.oFeatureExtraction.getFeaturesArray().length + "." +
289
290 // Extension depending on the dump type
291 getDefaultExtension();
292 }
293
294 /**
295 * Retrieves the features source.
296 * @return returns the FeatureExtraction reference
297 * @since 0.3.0.4
298 */
299 public IFeatureExtraction getFeatureExtraction()
300 {
301 return this.oFeatureExtraction;
302 }
303
304 /**
305 * Allows setting the features surce.
306 * @param poFeatureExtraction the FeatureExtraction object to set
307 * @since 0.3.0.4
308 */
309 public void setFeatureExtraction(IFeatureExtraction poFeatureExtraction)
310 {
311 this.oFeatureExtraction = poFeatureExtraction;
312 }
313
314 /**
315 * Retrieves class' revision.
316 * @return revision string
317 * @since 0.3.0.2
318 */
319 public static String getMARFSourceCodeRevision()
320 {
321 return "$Revision: 1.39 $";
322 }
323 }
324
325 // EOF