1
2
3
4 package org.opentrafficsim.water.statistics;
5
6 import java.io.Serializable;
7
8 import org.apache.poi.ss.usermodel.CellStyle;
9 import org.apache.poi.ss.usermodel.DataFormat;
10 import org.apache.poi.ss.usermodel.Row;
11 import org.apache.poi.ss.usermodel.Sheet;
12
13 import com.thoughtworks.xstream.annotations.XStreamAlias;
14 import com.thoughtworks.xstream.annotations.XStreamOmitField;
15
16 import nl.tudelft.simulation.jstats.distributions.DistNormal;
17 import nl.tudelft.simulation.jstats.statistics.Tally;
18 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
19
20
21
22
23
24
25
26
27
28
29
30
31 @XStreamAlias("tally")
32 public class XTally implements Serializable
33 {
34
35 @XStreamOmitField
36 private static final long serialVersionUID = 1L;
37
38
39 protected double sum = Double.NaN;
40
41
42 protected double min = Double.NaN;
43
44
45 protected double max = Double.NaN;
46
47
48 protected double varianceSum = Double.NaN;
49
50
51 protected long n = Long.MIN_VALUE;
52
53
54 protected String description;
55
56
57 @XStreamOmitField
58 private DistNormal confidenceDistribution = new DistNormal(new MersenneTwister());
59
60
61 @XStreamOmitField
62 protected Object semaphore = new Object();
63
64
65 @XStreamOmitField
66 public static final short LEFT_SIDE_CONFIDENCE = -1;
67
68
69 @XStreamOmitField
70 public static final short BOTH_SIDE_CONFIDENCE = 0;
71
72
73 @XStreamOmitField
74 public static final short RIGTH_SIDE_CONFIDENCE = 1;
75
76
77
78
79 public XTally(String description)
80 {
81 super();
82 this.description = description;
83 }
84
85
86
87
88
89
90 public double getSampleMean()
91 {
92 if (this.n > 0)
93 return this.sum / this.n;
94 else
95 return Double.NaN;
96 }
97
98
99
100
101
102
103
104
105 public double[] getConfidenceInterval(final double alpha)
106 {
107 return this.getConfidenceInterval(alpha, Tally.BOTH_SIDE_CONFIDENCE);
108 }
109
110
111
112
113
114
115
116
117
118 public double[] getConfidenceInterval(final double alpha, final short side)
119 {
120 if (!(side == LEFT_SIDE_CONFIDENCE || side == BOTH_SIDE_CONFIDENCE || side == RIGTH_SIDE_CONFIDENCE))
121 {
122 throw new IllegalArgumentException("side of confidence level is not defined");
123 }
124 if (alpha < 0 || alpha > 1)
125 {
126 throw new IllegalArgumentException("1 >= confidenceLevel >= 0");
127 }
128 synchronized (this.semaphore)
129 {
130 if (Double.isNaN(this.getSampleMean()) || Double.isNaN(this.getStdDev()))
131 {
132 return null;
133 }
134 double level = 1 - alpha;
135 if (side == Tally.BOTH_SIDE_CONFIDENCE)
136 {
137 level = 1 - alpha / 2.0;
138 }
139 double z = this.confidenceDistribution.getInverseCumulativeProbability(level);
140 double confidence = z * Math.sqrt(this.getSampleVariance() / this.n);
141 double[] result = {this.getSampleMean() - confidence, this.getSampleMean() + confidence};
142 if (side == Tally.LEFT_SIDE_CONFIDENCE)
143 {
144 result[1] = this.getSampleMean();
145 }
146 if (side == Tally.RIGTH_SIDE_CONFIDENCE)
147 {
148 result[0] = this.getSampleMean();
149 }
150 result[0] = Math.max(result[0], this.min);
151 result[1] = Math.min(result[1], this.max);
152 return result;
153 }
154 }
155
156
157
158
159
160
161 public String getDescription()
162 {
163 return this.description;
164 }
165
166
167
168
169
170
171 public double getMax()
172 {
173 return this.max;
174 }
175
176
177
178
179
180
181 public double getMin()
182 {
183 return this.min;
184 }
185
186
187
188
189
190
191 public long getN()
192 {
193 return this.n;
194 }
195
196
197
198
199
200
201 public double getStdDev()
202 {
203 synchronized (this.semaphore)
204 {
205 if (this.n > 1)
206 {
207 return Math.sqrt(this.varianceSum / (1.0 * this.n - 1.0));
208 }
209 return Double.NaN;
210 }
211 }
212
213
214
215
216
217
218 public double getSum()
219 {
220 return this.sum;
221 }
222
223
224
225
226
227
228 public double getSampleVariance()
229 {
230 synchronized (this.semaphore)
231 {
232 if (this.n > 1)
233 {
234 return this.varianceSum / (1.0 * this.n - 1.0);
235 }
236 return Double.NaN;
237 }
238 }
239
240
241
242
243 public void initialize()
244 {
245 synchronized (this.semaphore)
246 {
247 this.max = -Double.MAX_VALUE;
248 this.min = Double.MAX_VALUE;
249 this.n = 0;
250 this.sum = 0.0;
251 this.varianceSum = 0.0;
252 }
253 }
254
255
256
257
258
259
260 public boolean isInitialized()
261 {
262 return !Double.isNaN(this.max);
263 }
264
265
266
267
268
269
270 public void tally(final double value)
271 {
272 if (!Double.isNaN(value))
273 {
274 synchronized (this.semaphore)
275 {
276 this.varianceSum += value * value;
277 this.sum += value;
278 this.n += 1;
279 if (value < this.min)
280 this.min = value;
281 if (value > this.max)
282 this.max = value;
283 }
284 }
285 }
286
287
288
289
290
291
292
293
294 public int writeToExcel(final Sheet sheet, final int startRow)
295 {
296 DataFormat format = sheet.getWorkbook().createDataFormat();
297 CellStyle style = sheet.getWorkbook().createCellStyle();
298 style.setDataFormat(format.getFormat("0.00"));
299
300 int rownr = startRow;
301 Row row = sheet.createRow(rownr);
302
303 row.createCell(1).setCellValue(description);
304 row.createCell(2).setCellValue("tally [n, gem, stdev, min, max]");
305 row.createCell(3).setCellValue(getN());
306 if (getN() > 0)
307 {
308 row.createCell(4).setCellValue(getSampleMean());
309 row.getCell(4).setCellStyle(style);
310 if (getN() > 1 && !Double.isNaN(getStdDev()))
311 {
312 row.createCell(5).setCellValue(getStdDev());
313 row.getCell(5).setCellStyle(style);
314 }
315 row.createCell(6).setCellValue(getMin());
316 row.getCell(6).setCellStyle(style);
317 row.createCell(7).setCellValue(getMax());
318 row.getCell(7).setCellStyle(style);
319 }
320
321 return rownr + 1;
322 }
323
324
325
326
327 @Override
328 public String toString()
329 {
330 return this.description;
331 }
332
333 }