View Javadoc

1   /*
2    * Copyright (C) 2004-2006 Christian Siefkes <christian@siefkes.net>.
3    * Development of this software is supported by the German Research Society,
4    * Berlin-Brandenburg Graduate School in Distributed Information Systems
5    * (DFG grant no. GRK 316).
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, visit
19   * http://www.gnu.org/licenses/gpl.html or write to the Free Software
20   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21   */
22  package de.fu_berlin.ties.eval;
23  
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.commons.lang.StringUtils;
31  
32  /***
33   * Type-safe enumeration of possible evaluation states for predictions
34   * (unknown, correct, spurious etc.) and answer keys (missing etc.).
35   *
36   * @author Christian Siefkes
37   * @version $Revision: 1.9 $, $Date: 2006/10/21 16:04:11 $, $Author: siefkes $
38   */
39  public final class EvalStatus {
40  
41      /***
42       * A map of all instantiated instances of this class. The name of the
43       * instance is mapped to the instance itself. There is no need to
44       * synchronize this map as it is only modified during the static
45       * initialization of this class.
46       */
47      private static final Map<String, EvalStatus> ALL_INSTANCES =
48          new HashMap<String, EvalStatus>();
49  
50      /***
51       * Serialization key recommended for instances of this class.
52       */
53      public static final String KEY_EVAL_STATUS = "EvalStatus";
54  
55      /***
56       * Constant for predictions whose evaluation status is unknown (not
57       * yet evaluated).
58       */
59      public static final EvalStatus UNKNOWN =
60          new EvalStatus("unknown", true, false);
61  
62      /***
63       * Constant for items defined to be true (answer keys, "gold standard").
64       */
65      public static final EvalStatus TRUTH = new EvalStatus("truth", false, true);
66  
67      /***
68       * Constant for correct predictions (true positives) resp for answer
69       * keys matched by a prediction. This is the only instance that is suitable
70       * for both {@link #isAnswerState() answer keys} and
71       * {@link #isPredictionState() predictions}.
72       */
73      public static final EvalStatus CORRECT =
74          new EvalStatus("correct", true, true);
75  
76      /***
77       * Constant for missing answer keys (false negatives).
78       */
79      public static final EvalStatus MISSING =
80          new EvalStatus("missing", false, true);
81  
82      /***
83       * Constant for spurious predictions (false positives).
84       */
85      public static final EvalStatus SPURIOUS =
86          new EvalStatus("spurious", true, false);
87  
88      /***
89       * Constant for answer keys that could have been proposed as predictions but
90       * were not. When there is only a single instance of each type to predict
91       * ("best match" mode), one of the answer keys should be tagged as
92       * {@link #CORRECT} resp. {@link #MISSING}; the others should be tagged
93       * as {@link #ALTERNATIVE}s.
94       */
95      public static final EvalStatus ALTERNATIVE =
96          new EvalStatus("alternative", false, true);
97  
98      /***
99       * Constant for predictions that were ignored. When there is only a single
100      * instance of each type to predict ("best match" mode), the most probably
101      * prediction will be evaluated, while the others of the same type will be
102      * ignored.
103      */
104     public static final EvalStatus IGNORED =
105         new EvalStatus("ignored", true, false);
106 
107 
108     /***
109      * Returns all instances of this class, in random order.
110      * @return all instances of this class
111      */
112     public static Collection<EvalStatus> allInstances() {
113         return Collections.unmodifiableCollection(ALL_INSTANCES.values());
114     }
115 
116     /***
117      * Returns the string representations for all instances of this class,
118      * in random order.
119      *
120      * @return the string representations for all instances of this class
121      */
122     public static Set<String> allInstanceStrings() {
123         return Collections.unmodifiableSet(ALL_INSTANCES.keySet());
124     }
125 
126     /***
127      * Parses a textual representation into an eval status, without using a
128      * default object. This method can convert to results of {@link #getName()}
129      * and {@link #toString()} back into the corresponding instance.
130      *
131      * @param representation the textual representation to parse
132      * @return the eval status object corresponding to the given string
133      * @throws IllegalArgumentException if a given string does not represent a
134      * known evaluation status
135      */
136     public static EvalStatus parse(final String representation)
137             throws IllegalArgumentException {
138         return parse(representation, false);
139     }
140 
141     /***
142      * Parses a textual representation into an eval status. This method can
143      * convert to results of {@link #getName()} and {@link #toString()} back
144      * into the corresponding instance.
145      *
146      * @param representation the textual representation to parse
147      * @param useDefault if <code>true</code>, {@link #UNKNOWN} is returned if
148      * the representation is an unparsable (invalid) or <code>null</code>;
149      * otherwise an exception is thrown in this case
150      * @return the eval status object corresponding to the given string
151      * @throws IllegalArgumentException if a given string does not represent a
152      * known evaluation status and <code>useDefault</code> is <code>false</code>
153      */
154     public static EvalStatus parse(final String representation,
155             final boolean useDefault) throws IllegalArgumentException {
156         // using StringUtils so null is handled
157         final EvalStatus result =
158             ALL_INSTANCES.get(StringUtils.trim(representation));
159 
160         if (result != null) {
161             return result;
162         } else {
163             if (useDefault) {
164                 return EvalStatus.UNKNOWN;
165             }  else {
166                 throw new IllegalArgumentException(
167                         "Cannot parse to eval status: " + representation);
168             }
169         }
170     }
171 
172 
173     /***
174      * The name of this instance.
175      */
176     private final String name;
177 
178     /***
179      * Whether this state is suitable for an answer key.
180      */
181     private final boolean answerState;
182 
183     /***
184      * Whether this state is suitable for a prediction.
185      */
186     private final boolean predictionState;
187 
188     /***
189      * Private constructor to prevent creation of further instances.
190      * The static constants defined in this class are the only instantiations.
191      *
192      * @param newName the name of this instance
193      * @param predState whether this state is suitable for a prediction
194      * @param ansState whether this state is suitable for an answer key
195      * @throws IllegalArgumentException if the specified name is already used
196      * by another instance
197      */
198     private EvalStatus(final String newName, final boolean predState,
199             final boolean ansState) throws IllegalArgumentException {
200         super();
201         name = newName;
202         predictionState = predState;
203         answerState = ansState;
204 
205         // register myself
206         final EvalStatus previousValue = ALL_INSTANCES.put(newName, this);
207         if (previousValue != null) {
208             throw new IllegalArgumentException(
209                 "Name " + newName + " already in use!");
210         }
211     }
212 
213     /***
214      * Returns the name of this instance.
215      * @return the value of the attribute
216      */
217     public String getName() {
218         return name;
219     }
220 
221     /***
222      * Returns a string representation, printing the
223      * {@linkplain #getName() name} of this instance.
224      *
225      * @return a textual representation
226      */
227     public String toString() {
228         return name;
229     }
230 
231     /***
232      * Whether this state is suitable for an answer key.
233      * @return <code>true</code> iff this state is suitable for an answer key
234      */
235     public boolean isAnswerState() {
236         return answerState;
237     }
238 
239     /***
240      * Whether this state is suitable for a prediction.
241      * @return <code>true</code> iff this state is suitable for a prediction
242      */
243     public boolean isPredictionState() {
244         return predictionState;
245     }
246 
247 }