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