1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
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
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 }