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 @XStreamAlias("tally")
31 @SuppressWarnings("checkstyle:visibilitymodifier")
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(final String description)
80 {
81 super();
82 this.description = description;
83 }
84
85
86
87
88
89 public double getSampleMean()
90 {
91 if (this.n > 0)
92 return this.sum / this.n;
93 else
94 return Double.NaN;
95 }
96
97
98
99
100
101
102
103 public double[] getConfidenceInterval(final double alpha)
104 {
105 return this.getConfidenceInterval(alpha, Tally.BOTH_SIDE_CONFIDENCE);
106 }
107
108
109
110
111
112
113
114
115 public double[] getConfidenceInterval(final double alpha, final short side)
116 {
117 if (!(side == LEFT_SIDE_CONFIDENCE || side == BOTH_SIDE_CONFIDENCE || side == RIGTH_SIDE_CONFIDENCE))
118 {
119 throw new IllegalArgumentException("side of confidence level is not defined");
120 }
121 if (alpha < 0 || alpha > 1)
122 {
123 throw new IllegalArgumentException("1 >= confidenceLevel >= 0");
124 }
125 synchronized (this.semaphore)
126 {
127 if (Double.isNaN(this.getSampleMean()) || Double.isNaN(this.getStdDev()))
128 {
129 return null;
130 }
131 double level = 1 - alpha;
132 if (side == Tally.BOTH_SIDE_CONFIDENCE)
133 {
134 level = 1 - alpha / 2.0;
135 }
136 double z = this.confidenceDistribution.getInverseCumulativeProbability(level);
137 double confidence = z * Math.sqrt(this.getSampleVariance() / this.n);
138 double[] result = { this.getSampleMean() - confidence, this.getSampleMean() + confidence };
139 if (side == Tally.LEFT_SIDE_CONFIDENCE)
140 {
141 result[1] = this.getSampleMean();
142 }
143 if (side == Tally.RIGTH_SIDE_CONFIDENCE)
144 {
145 result[0] = this.getSampleMean();
146 }
147 result[0] = Math.max(result[0], this.min);
148 result[1] = Math.min(result[1], this.max);
149 return result;
150 }
151 }
152
153
154
155
156
157 public String getDescription()
158 {
159 return this.description;
160 }
161
162
163
164
165
166 public double getMax()
167 {
168 return this.max;
169 }
170
171
172
173
174
175 public double getMin()
176 {
177 return this.min;
178 }
179
180
181
182
183
184 public long getN()
185 {
186 return this.n;
187 }
188
189
190
191
192
193 public double getStdDev()
194 {
195 synchronized (this.semaphore)
196 {
197 if (this.n > 1)
198 {
199 return Math.sqrt(this.varianceSum / (1.0 * this.n - 1.0));
200 }
201 return Double.NaN;
202 }
203 }
204
205
206
207
208
209 public double getSum()
210 {
211 return this.sum;
212 }
213
214
215
216
217
218 public double getSampleVariance()
219 {
220 synchronized (this.semaphore)
221 {
222 if (this.n > 1)
223 {
224 return this.varianceSum / (1.0 * this.n - 1.0);
225 }
226 return Double.NaN;
227 }
228 }
229
230
231
232
233 public void initialize()
234 {
235 synchronized (this.semaphore)
236 {
237 this.max = -Double.MAX_VALUE;
238 this.min = Double.MAX_VALUE;
239 this.n = 0;
240 this.sum = 0.0;
241 this.varianceSum = 0.0;
242 }
243 }
244
245
246
247
248
249 public boolean isInitialized()
250 {
251 return !Double.isNaN(this.max);
252 }
253
254
255
256
257
258 public void tally(final double value)
259 {
260 if (!Double.isNaN(value))
261 {
262 synchronized (this.semaphore)
263 {
264 this.varianceSum += value * value;
265 this.sum += value;
266 this.n += 1;
267 if (value < this.min)
268 this.min = value;
269 if (value > this.max)
270 this.max = value;
271 }
272 }
273 }
274
275
276
277
278
279
280
281 public int writeToExcel(final Sheet sheet, final int startRow)
282 {
283 DataFormat format = sheet.getWorkbook().createDataFormat();
284 CellStyle style = sheet.getWorkbook().createCellStyle();
285 style.setDataFormat(format.getFormat("0.00"));
286
287 int rownr = startRow;
288 Row row = sheet.createRow(rownr);
289
290 row.createCell(1).setCellValue(description);
291 row.createCell(2).setCellValue("tally [n, gem, stdev, min, max]");
292 row.createCell(3).setCellValue(getN());
293 if (getN() > 0)
294 {
295 row.createCell(4).setCellValue(getSampleMean());
296 row.getCell(4).setCellStyle(style);
297 if (getN() > 1 && !Double.isNaN(getStdDev()))
298 {
299 row.createCell(5).setCellValue(getStdDev());
300 row.getCell(5).setCellStyle(style);
301 }
302 row.createCell(6).setCellValue(getMin());
303 row.getCell(6).setCellStyle(style);
304 row.createCell(7).setCellValue(getMax());
305 row.getCell(7).setCellStyle(style);
306 }
307
308 return rownr + 1;
309 }
310
311
312
313
314 @Override
315 public String toString()
316 {
317 return this.description;
318 }
319
320 }