package ie.dcu.eval; import ie.dcu.matrix.ByteMatrix; import java.util.*; /** * Abstract class to make implementing evaluators easier. Subclasses should set * the values of name, description and vendor in the constructor, and add all * the measures that will be computed. The subclasses implementation of the run * method should call {@link #setResult(String, double)} for all the measures computed. * * @author Kevin McGuinness */ public abstract class AbstractEvaluator implements Evaluator { /** * Map will contain the results of the evaluation. */ private final Map results; /** * Name of the evaluator, should be set by subclass on construction. */ protected String name; /** * Description of the evaluator, should be set by subclass on construction. */ protected String description; /** * Vendor of the evaluator, should be set by subclass on construction. */ protected String vendor; /** * Cached names of the measures; */ private transient String[] measures; /** * Constructor. */ public AbstractEvaluator() { // Use a tree-map as we expect only a small number of measures results = new TreeMap(); } /** * Default implementation returns the name field. */ public String getName() { return name; } /** * Default implementation returns the description field. */ public String getDescription() { return description; } /** * Default implementation returns the vendor field. */ public String getVendor() { return vendor; } public String[] getMeasures() { if (measures == null) { Set keySet = results.keySet(); measures = keySet.toArray(new String[keySet.size()]); } return measures; } public double getMeasure(String name) throws IllegalStateException, IllegalArgumentException { Double measure = results.get(name); if (measure == null) { if (results.containsKey(name)) { // Measure not computed by run method throw new IllegalStateException(); } // Unknown measure name throw new IllegalArgumentException(name + " is not a valid measure"); } return measure; } /** * Add a measure that the evaluator will compute. Subclasses should add all * their measures using this method in their constructor. * * @param name * The name of the measure. */ protected void addMeasure(String name) { // Add measure with null value results.put(name, null); // Invalidate cache measures = null; } /** * Set the value of a measure resulting from running the evaluator. This * method should be called at the end of run to set the results of the * evaluation. * * @param name * The name of the measure. * @param value * The computed value. * @throws IllegalArgumentException * If the name of the measure has not been added with * {@link #addMeasure(String)} */ protected void setResult(String name, double value) throws IllegalArgumentException { // Ensure we're a real measure if (!results.containsKey(name)) { throw new IllegalArgumentException(); } results.put(name, value); } /** * Checks if the two masks are non-null and the have the same dimensions. If * they do not, an IllegalArgumentException is thrown. Method is provided to * let subclasses easily validate parameters to run(). * * @param a * The first segmentation mask * @param b * The second segmentation mask * @throws IllegalArgumentException * If either mask is null or they have different * dimensions. */ protected void check(ByteMatrix a, ByteMatrix b) throws IllegalArgumentException { if (a == null) { throw new IllegalArgumentException("null mask"); } if (b == null) { throw new IllegalArgumentException("null mask"); } if (!a.sizeEquals(b)) { throw new IllegalArgumentException("unequal dimensions"); } } }