1
2
3
4
5
6
7
8
9
10 package nl.tudelft.simulation.jstats.statistics;
11
12 import javax.swing.table.TableModel;
13
14 import nl.tudelft.simulation.event.EventInterface;
15 import nl.tudelft.simulation.event.EventListenerInterface;
16 import nl.tudelft.simulation.event.EventType;
17 import nl.tudelft.simulation.jstats.distributions.DistNormal;
18 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
19
20 /***
21 * The Tally class defines a statistics event tally.
22 * <p>
23 * (c) copyright 2003-2004 <a href="http://www.simulation.tudelft.nl">Delft
24 * University of Technology </a>, the Netherlands. <br>
25 * See for project information <a
26 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
27 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
28 * License (GPL) </a>, no warranty <br>
29 *
30 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">Peter
31 * Jacobs </a>
32 * @version 1.13, 2004-03-18
33 * @since 1.2
34 */
35 public class Tally extends StatisticsObject implements EventListenerInterface
36 {
37 /*** SAMPLE_MEAN_EVENT is fired whenever the sample mean is updated */
38 public static final EventType SAMPLE_MEAN_EVENT = new EventType(
39 "SAMPLE_MEAN_EVENT");
40
41 /***
42 * SAMPLE_VARIANCE_EVENT is fired whenever the sample variance is updated
43 */
44 public static final EventType SAMPLE_VARIANCE_EVENT = new EventType(
45 "SAMPLE_VARIANCE_EVENT");
46
47 /*** MIN_EVENT is fired whenever a new minimum value has reached */
48 public static final EventType MIN_EVENT = new EventType("MIN_EVENT");
49
50 /*** MAX_EVENT is fired whenever a new maximum value has reached */
51 public static final EventType MAX_EVENT = new EventType("MAX_EVENT");
52
53 /*** N_EVENT is fired whenever on a change in measurements */
54 public static final EventType N_EVENT = new EventType("N_EVENT");
55
56 /***
57 * STANDARD_DEVIATION_EVENT is fired whenever the standard deviation is
58 * updated
59 */
60 public static final EventType STANDARD_DEVIATION_EVENT = new EventType(
61 "STANDARD_DEVIATION_EVENT");
62
63 /*** SUM_EVENT is fired whenever the sum sis updated */
64 public static final EventType SUM_EVENT = new EventType("SUM_EVENT");
65
66 /*** LEFT_SIDE_CONFIDENCE refers to the left side confidence */
67 public static final short LEFT_SIDE_CONFIDENCE = -1;
68
69 /*** BOTH_SIDE_CONFIDENCE refers to both sides of the confidence */
70 public static final short BOTH_SIDE_CONFIDENCE = 0;
71
72 /*** RIGTH_SIDE_CONFIDENCE refers to the right side confidence */
73 public static final short RIGTH_SIDE_CONFIDENCE = 1;
74
75 /***
76 * sum refers to the sum of the tally
77 *
78 * @uml.property name="sum"
79 */
80 protected double sum = Double.NaN;
81
82 /***
83 * min refers to the min of the tally
84 *
85 * @uml.property name="min"
86 */
87 protected double min = Double.NaN;
88
89 /***
90 * maxrefers to the max of the tally
91 *
92 * @uml.property name="max"
93 */
94 protected double max = Double.NaN;
95
96 /***
97 * sampleMean refers to the mean of the tally
98 *
99 * @uml.property name="sampleMean"
100 */
101 protected double sampleMean = Double.NaN;
102
103
104 /*** varianceSum refers to the varianceSum of the tally */
105 protected double varianceSum = Double.NaN;
106
107 /***
108 * n refers to the number of measurements
109 *
110 * @uml.property name="n"
111 */
112 protected long n = Long.MIN_VALUE;
113
114 /***
115 * description refers to the description of this tally
116 *
117 * @uml.property name="description"
118 */
119 protected String description;
120
121
122 /*** the confidenceDistribution */
123 private DistNormal confidenceDistribution = new DistNormal(
124 new MersenneTwister());
125
126 /*** the semaphore */
127 protected Object semaphore = new Object();
128
129 /***
130 * Constructs a new Tally
131 *
132 * @param description the description of this tally
133 */
134 public Tally(final String description)
135 {
136 super();
137 this.description = description;
138 }
139
140 /***
141 * Returns the sampleMean of all oberservations since the initialization
142 *
143 * @return double the sampleMean
144 *
145 * @uml.property name="sampleMean"
146 */
147 public double getSampleMean()
148 {
149 return this.sampleMean;
150 }
151
152
153 /***
154 * returns the confidence interval on either side of the mean
155 *
156 * @param alpha Alpha is the significance level used to compute the
157 * confidence level. The confidence level equals 100*(1 - alpha)%, or
158 * in other words, an alpha of 0.05 indicates a 95 percent confidence
159 * level.
160 * @return double[] the confidence interval of this tally
161 */
162 public double[] getConfidenceInterval(final double alpha)
163 {
164 return this.getConfidenceInterval(alpha, Tally.BOTH_SIDE_CONFIDENCE);
165 }
166
167 /***
168 * returns the confidence interval based of the mean
169 *
170 * @param alpha Alpha is the significance level used to compute the
171 * confidence level. The confidence level equals 100*(1 - alpha)%, or
172 * in other words, an alpha of 0.05 indicates a 95 percent confidence
173 * level.
174 * @param side the side of the confidence interval with respect to the mean
175 * @return double[] the confidence interval of this tally
176 */
177 public double[] getConfidenceInterval(final double alpha, final short side)
178 {
179 if (!(side == LEFT_SIDE_CONFIDENCE || side == BOTH_SIDE_CONFIDENCE || side == RIGTH_SIDE_CONFIDENCE))
180 {
181 throw new IllegalArgumentException(
182 "side of confidence level is not defined");
183 }
184 if (alpha < 0 || alpha > 1)
185 {
186 throw new IllegalArgumentException("1 >= confidenceLevel >= 0");
187 }
188 synchronized (this.semaphore)
189 {
190 if (new Double(this.sampleMean).isNaN()
191 || new Double(this.getStdDev()).isNaN())
192 {
193 return null;
194 }
195 double level = 1 - alpha;
196 if (side == Tally.BOTH_SIDE_CONFIDENCE)
197 {
198 level = 1 - alpha / 2.0;
199 }
200 double z = this.confidenceDistribution
201 .getInverseCumulativeProbability(level);
202 double confidence = z
203 * Math.sqrt(this.getSampleVariance() / this.n);
204 double[] result = {this.sampleMean - confidence,
205 this.sampleMean + confidence};
206 if (side == Tally.LEFT_SIDE_CONFIDENCE)
207 {
208 result[1] = this.sampleMean;
209 }
210 if (side == Tally.RIGTH_SIDE_CONFIDENCE)
211 {
212 result[0] = this.sampleMean;
213 }
214 result[0] = Math.max(result[0], this.min);
215 result[1] = Math.min(result[1], this.max);
216 return result;
217 }
218 }
219
220 /***
221 * returns the description of this tally
222 *
223 * @return Sting description
224 *
225 * @uml.property name="description"
226 */
227 public String getDescription()
228 {
229 return this.description;
230 }
231
232 /***
233 * Returns the max.
234 *
235 * @return double
236 *
237 * @uml.property name="max"
238 */
239 public double getMax()
240 {
241 return this.max;
242 }
243
244 /***
245 * Returns the min.
246 *
247 * @return double
248 *
249 * @uml.property name="min"
250 */
251 public double getMin()
252 {
253 return this.min;
254 }
255
256 /***
257 * Returns the number of observations
258 *
259 * @return long n
260 *
261 * @uml.property name="n"
262 */
263 public long getN()
264 {
265 return this.n;
266 }
267
268
269 /***
270 * Returns the current tally standard deviation
271 *
272 * @return double the standard deviation
273 */
274 public double getStdDev()
275 {
276 synchronized (this.semaphore)
277 {
278 if (this.n > 1)
279 {
280 return Math.sqrt(this.varianceSum / (this.n - 1));
281 }
282 return Double.NaN;
283 }
284 }
285
286 /***
287 * returns the sum of the values of the observations
288 *
289 * @return double sum
290 *
291 * @uml.property name="sum"
292 */
293 public double getSum()
294 {
295 return this.sum;
296 }
297
298
299 /***
300 * Returns the current tally variance
301 *
302 * @return double samplevariance
303 */
304 public double getSampleVariance()
305 {
306 synchronized (this.semaphore)
307 {
308 if (this.n > 1)
309 {
310 return this.varianceSum / (this.n - 1);
311 }
312 return Double.NaN;
313 }
314 }
315
316 /***
317 * @see nl.tudelft.simulation.jstats.statistics.StatisticsObject #getTable()
318 */
319 public TableModel getTable()
320 {
321 String[] columnNames = {"field", "value"};
322 EventType[] eventTypes = {null, Tally.N_EVENT, Tally.MIN_EVENT,
323 Tally.MAX_EVENT, Tally.SAMPLE_MEAN_EVENT,
324 Tally.SAMPLE_VARIANCE_EVENT, Tally.STANDARD_DEVIATION_EVENT,
325 Tally.SUM_EVENT};
326 StatisticsTableModel result = new StatisticsTableModel(columnNames,
327 eventTypes, 8);
328 this.addListener(result, Tally.N_EVENT, false);
329 this.addListener(result, Tally.MAX_EVENT, false);
330 this.addListener(result, Tally.MIN_EVENT, false);
331 this.addListener(result, Tally.SAMPLE_MEAN_EVENT, false);
332 this.addListener(result, Tally.SAMPLE_VARIANCE_EVENT, false);
333 this.addListener(result, Tally.STANDARD_DEVIATION_EVENT, false);
334 this.addListener(result, Tally.SUM_EVENT, false);
335
336 result.setValueAt("name", 0, 0);
337 result.setValueAt("n", 1, 0);
338 result.setValueAt("min", 2, 0);
339 result.setValueAt("max", 3, 0);
340 result.setValueAt("sample-mean", 4, 0);
341 result.setValueAt("sample-variance", 5, 0);
342 result.setValueAt("st. dev.", 6, 0);
343 result.setValueAt("sum", 7, 0);
344
345
346
347 result.setValueAt(this.description, 0, 1);
348 result.setValueAt(new Long(this.n), 1, 1);
349 result.setValueAt(new Double(this.min), 2, 1);
350 result.setValueAt(new Double(this.max), 3, 1);
351 result.setValueAt(new Double(this.sampleMean), 4, 1);
352 result.setValueAt(new Double(this.getSampleVariance()), 5, 1);
353 result.setValueAt(new Double(this.getStdDev()), 6, 1);
354 result.setValueAt(new Double(this.getSum()), 7, 1);
355 return result;
356 }
357
358 /***
359 * initializes the Tally. This methods sets the max, min, n, sum and
360 * variance values to their initial values.
361 */
362 public void initialize()
363 {
364 synchronized (this.semaphore)
365 {
366 this.setMax(-Double.MAX_VALUE);
367 this.setMin(Double.MAX_VALUE);
368 this.setN(0);
369 this.setSum(0.0);
370 this.varianceSum = 0.0;
371 }
372 }
373
374 /***
375 * is this tally initialized?
376 *
377 * @return true whenever this.initialize is invoked.
378 */
379 public boolean isInitialized()
380 {
381 return !Double.isNaN(this.max);
382 }
383
384 /***
385 * @see nl.tudelft.simulation.event.EventListenerInterface
386 * #notify(nl.tudelft.simulation.event.EventInterface)
387 */
388 public void notify(final EventInterface event)
389 {
390 if (!(event.getContent() instanceof Number))
391 {
392 throw new IllegalArgumentException("Tally does not accept " + event);
393 }
394 double value = ((Number) event.getContent()).doubleValue();
395
396 synchronized (this.semaphore)
397 {
398 if (new Double(this.sampleMean).isNaN())
399 {
400 this.sampleMean = 0.0;
401 }
402
403
404 double newsampleMean = this.sampleMean + (value - this.sampleMean)
405 / (this.n + 1);
406 this.varianceSum += (value - this.sampleMean)
407 * (value - newsampleMean);
408 this.setSampleMean(newsampleMean);
409 this.setSum(this.sum + value);
410 this.setN(this.n + 1);
411 if (value < this.min)
412 {
413 this.setMin(value);
414 }
415 if (value > this.max)
416 {
417 this.setMax(value);
418 }
419 if (this.n > 1)
420 {
421 this.fireEvent(Tally.STANDARD_DEVIATION_EVENT, getStdDev());
422 this
423 .fireEvent(Tally.SAMPLE_VARIANCE_EVENT,
424 getSampleVariance());
425 }
426 }
427 }
428
429 /***
430 * @see java.lang.Object#toString()
431 */
432 public String toString()
433 {
434 return this.description;
435 }
436
437 //****************** PROTECTED METHODS **************/
438 /***
439 * sets sampleMean
440 *
441 * @param sampleMean the new mean
442 * @return double sampleMean
443 *
444 * @uml.property name="sampleMean"
445 */
446 protected double setSampleMean(final double sampleMean)
447 {
448 this.sampleMean = sampleMean;
449 this.fireEvent(Tally.SAMPLE_MEAN_EVENT, sampleMean);
450 return this.sampleMean;
451 }
452
453 /***
454 * sets min
455 *
456 * @param min the new minimum value
457 * @return double the input
458 *
459 * @uml.property name="min"
460 */
461 protected double setMin(final double min)
462 {
463 this.min = min;
464 this.fireEvent(Tally.MIN_EVENT, min);
465 return this.min;
466 }
467
468 /***
469 * sets max
470 *
471 * @param max the new maximum value
472 * @return double the input
473 *
474 * @uml.property name="max"
475 */
476 protected double setMax(final double max)
477 {
478 this.max = max;
479 this.fireEvent(Tally.MAX_EVENT, max);
480 return this.max;
481 }
482
483 /***
484 * sets n
485 *
486 * @param n the new n
487 * @return double the input
488 *
489 * @uml.property name="n"
490 */
491 protected long setN(final long n)
492 {
493 this.n = n;
494 this.fireEvent(Tally.N_EVENT, n);
495 return this.n;
496 }
497
498 /***
499 * sets the count
500 *
501 * @param sum the new sum
502 * @return double the input
503 *
504 * @uml.property name="sum"
505 */
506 protected double setSum(final double sum)
507 {
508 this.sum = sum;
509 this.fireEvent(Tally.SUM_EVENT, sum);
510 return this.sum;
511 }
512
513 }