View Javadoc

1   /**
2    * Copyright 2005 Steve Molloy
3    * 
4    * This file is part of OV4J.
5    * 
6    * OV4J is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
7    * published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
8    * 
9    * OV4J is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
10   * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11   * 
12   * You should have received a copy of the GNU General Public License along with OV4J; if not, write to the Free Software
13   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
14   * 
15   */
16  package org.ov4j.comp;
17  
18  import java.util.Arrays;
19  import java.util.logging.Level;
20  import java.util.logging.Logger;
21  
22  /**
23   * Base class for comparing objects.
24   * 
25   * @author smolloy
26   * 
27   */
28  public abstract class ComparisonResult<T> {
29  	/**
30  	 * Logger for this class
31  	 */
32  	private static final Logger	logger	= Logger.getLogger(ComparisonResult.class.getName());
33  
34  	/**
35  	 * Find class to use to compare instances of the given object.
36  	 * 
37  	 * @param o
38  	 *            Object to be compared.
39  	 * @return Class to use for comparing the object.
40  	 * @throws ClassNotFoundException
41  	 */
42  	public static <C, T extends ComparisonResult<C>> Class<T> findComparisonResultClass(final C o)
43  		throws ClassNotFoundException {
44  		if (ComparisonResult.logger.isLoggable(Level.FINER)) {
45  			ComparisonResult.logger.entering("ComparisonResult", "findComparisonResultClass(C=" + o + ")", "start");
46  		}
47  
48  		Class<T> compClass = null;
49  		if (o != null) {
50  			if (o instanceof String) {
51  				compClass = (Class<T>) Class.forName("org.ov4j.comp.StringComparisonResult");
52  			} else if (o instanceof Number) {
53  				compClass = (Class<T>) Class.forName("org.ov4j.comp.NumericComparisonResult");
54  			} else {
55  				String compClassName = o.getClass().getName() + "ComparisonResult";
56  				compClassName = compClassName.replaceAll("\\.data", ".comp");
57  				try {
58  					compClass = (Class<T>) Class.forName(compClassName);
59  				} catch (final ClassNotFoundException e) {
60  					if (ComparisonResult.logger.isLoggable(Level.FINE)) {
61  						ComparisonResult.logger.logp(Level.FINE, "ComparisonResult", "findComparisonResultClass(C=" + o
62  							+ ")", "Exception caught", e);
63  					}
64  
65  					compClass = (Class<T>) Class.forName("org.ov4j.comp.DefaultComparisonResult");
66  				}
67  			}
68  		}
69  
70  		if (ComparisonResult.logger.isLoggable(Level.FINER)) {
71  			ComparisonResult.logger.exiting("ComparisonResult", "findComparisonResultClass(C=" + o + ")",
72  				"end - return value=" + compClass);
73  		}
74  		return compClass;
75  	}
76  
77  	/** Original object. */
78  	private T						original;
79  
80  	/** Compared object. */
81  	private T						changed;
82  
83  	/** Array of false negatives, not found in compared object. */
84  	private Object[]				falseNegatives;
85  
86  	/** Array of false positives, which should not have been found in compared object. */
87  	private Object[]				falsePositives;
88  
89  	/** Array of matches, each match holding more information. */
90  	private ComparisonResult<?>[]	matches;
91  
92  	/** Precision, how much of the compared object is found in the original. */
93  	private double					precision;
94  
95  	/** Recall, how much of the original object is found in the compared one. */
96  	private double					recall;
97  
98  	/**
99  	 * Constructor.
100 	 */
101 	public ComparisonResult() {
102 	}
103 
104 	/**
105 	 * Perform metric computation.
106 	 * 
107 	 */
108 	public abstract void compute();
109 
110 	/**
111 	 * Perform fast computation, only setting precision to 1.0 to indicate that both items are the same or to anything
112 	 * else otherwise.
113 	 * 
114 	 */
115 	public abstract void fastCompute();
116 
117 	/**
118 	 * @return Returns the compared object.
119 	 */
120 	public T getChanged() {
121 		return changed;
122 	}
123 
124 	/**
125 	 * @return Returns the falseNegatives.
126 	 */
127 	public Object[] getFalseNegatives() {
128 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
129 			ComparisonResult.logger.entering("ComparisonResult", "getFalseNegatives()", "start");
130 		}
131 
132 		if (falseNegatives == null) {
133 			if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
134 				ComparisonResult.logger
135 					.exiting("ComparisonResult", "getFalseNegatives()", "end - return value=" + null);
136 			}
137 			return null;
138 		}
139 		final Object[] fn = new Object[falseNegatives.length];
140 		System.arraycopy(falseNegatives, 0, fn, 0, fn.length);
141 
142 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
143 			ComparisonResult.logger.exiting("ComparisonResult", "getFalseNegatives()", "end - return value="
144 				+ Arrays.toString(fn));
145 		}
146 		return fn;
147 	}
148 
149 	/**
150 	 * @return Returns the falsePositives.
151 	 */
152 	public Object[] getFalsePositives() {
153 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
154 			ComparisonResult.logger.entering("ComparisonResult", "getFalsePositives()", "start");
155 		}
156 
157 		if (falsePositives == null) {
158 			if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
159 				ComparisonResult.logger
160 					.exiting("ComparisonResult", "getFalsePositives()", "end - return value=" + null);
161 			}
162 			return null;
163 		}
164 		final Object[] fp = new Object[falsePositives.length];
165 		System.arraycopy(falsePositives, 0, fp, 0, fp.length);
166 
167 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
168 			ComparisonResult.logger.exiting("ComparisonResult", "getFalsePositives()", "end - return value="
169 				+ Arrays.toString(fp));
170 		}
171 		return fp;
172 	}
173 
174 	/**
175 	 * @return Returns the matches.
176 	 */
177 	public ComparisonResult<?>[] getMatches() {
178 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
179 			ComparisonResult.logger.entering("ComparisonResult", "getMatches()", "start");
180 		}
181 
182 		if (matches == null) {
183 			if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
184 				ComparisonResult.logger.exiting("ComparisonResult", "getMatches()", "end - return value=" + null);
185 			}
186 			return null;
187 		}
188 		final ComparisonResult<?>[] m = new ComparisonResult[matches.length];
189 		System.arraycopy(matches, 0, m, 0, m.length);
190 
191 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
192 			ComparisonResult.logger.exiting("ComparisonResult", "getMatches()", "end - return value="
193 				+ Arrays.toString(m));
194 		}
195 		return m;
196 	}
197 
198 	/**
199 	 * @return Returns the original.
200 	 */
201 	public T getOriginal() {
202 		return original;
203 	}
204 
205 	/**
206 	 * @return Returns the precision.
207 	 */
208 	public double getPrecision() {
209 		return precision;
210 	}
211 
212 	/**
213 	 * @return Returns the recall.
214 	 */
215 	public double getRecall() {
216 		return recall;
217 	}
218 
219 	/**
220 	 * @return
221 	 */
222 	public int numFalseNegatives() {
223 		return (falseNegatives == null) ? 0 : falseNegatives.length;
224 	}
225 
226 	/**
227 	 * @return
228 	 */
229 	public int numFalsePositives() {
230 		return (falsePositives == null) ? 0 : falsePositives.length;
231 	}
232 
233 	/**
234 	 * @return
235 	 */
236 	public int numMatches() {
237 		return (matches == null) ? 0 : matches.length;
238 	}
239 
240 	/**
241 	 * @param changed
242 	 *            The compared object to set.
243 	 */
244 	public void setChanged(final T changed) {
245 		this.changed = changed;
246 	}
247 
248 	/**
249 	 * @param falseNegatives
250 	 *            The falseNegatives to set.
251 	 */
252 	public void setFalseNegatives(final Object[] falseNegatives) {
253 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
254 			ComparisonResult.logger.entering("ComparisonResult", "setFalseNegatives(Object[]="
255 				+ Arrays.toString(falseNegatives) + ")", "start");
256 		}
257 
258 		if (falseNegatives == null) {
259 			this.falseNegatives = null;
260 		} else {
261 			this.falseNegatives = new Object[falseNegatives.length];
262 			System.arraycopy(falseNegatives, 0, this.falseNegatives, 0, falseNegatives.length);
263 		}
264 
265 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
266 			ComparisonResult.logger.exiting("ComparisonResult", "setFalseNegatives(Object[]="
267 				+ Arrays.toString(falseNegatives) + ")", "end");
268 		}
269 	}
270 
271 	/**
272 	 * @param falsePositives
273 	 *            The falsePositives to set.
274 	 */
275 	public void setFalsePositives(final Object[] falsePositives) {
276 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
277 			ComparisonResult.logger.entering("ComparisonResult", "setFalsePositives(Object[]="
278 				+ Arrays.toString(falsePositives) + ")", "start");
279 		}
280 
281 		if (falsePositives == null) {
282 			this.falsePositives = null;
283 		} else {
284 			this.falsePositives = new Object[falsePositives.length];
285 			System.arraycopy(falsePositives, 0, this.falsePositives, 0, falsePositives.length);
286 		}
287 
288 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
289 			ComparisonResult.logger.exiting("ComparisonResult", "setFalsePositives(Object[]="
290 				+ Arrays.toString(falsePositives) + ")", "end");
291 		}
292 	}
293 
294 	/**
295 	 * @param matches
296 	 *            The matches to set.
297 	 */
298 	public void setMatches(final ComparisonResult<?>[] matches) {
299 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
300 			ComparisonResult.logger.entering("ComparisonResult", "setMatches(ComparisonResult<T>[]="
301 				+ Arrays.toString(matches) + ")", "start");
302 		}
303 
304 		if (matches == null) {
305 			this.matches = null;
306 		} else {
307 			this.matches = new ComparisonResult[matches.length];
308 			System.arraycopy(matches, 0, this.matches, 0, matches.length);
309 		}
310 
311 		if (ComparisonResult.logger.isLoggable(Level.FINEST)) {
312 			ComparisonResult.logger.exiting("ComparisonResult", "setMatches(ComparisonResult<T>[]="
313 				+ Arrays.toString(matches) + ")", "end");
314 		}
315 	}
316 
317 	/**
318 	 * @param original
319 	 *            The original to set.
320 	 */
321 	public void setOriginal(final T original) {
322 		this.original = original;
323 	}
324 
325 	/**
326 	 * @param precision
327 	 *            The precision to set.
328 	 */
329 	public void setPrecision(final double precision) {
330 		this.precision = precision;
331 	}
332 
333 	/**
334 	 * @param recall
335 	 *            The recall to set.
336 	 */
337 	public void setRecall(final double recall) {
338 		this.recall = recall;
339 	}
340 }