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 import org.djutils.exceptions.Throw;
13 import org.djutils.stats.ConfidenceInterval;
14
15 import com.thoughtworks.xstream.annotations.XStreamAlias;
16 import com.thoughtworks.xstream.annotations.XStreamOmitField;
17
18 import nl.tudelft.simulation.jstats.distributions.DistNormal;
19 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
20
21
22
23
24
25
26
27
28
29
30
31 @XStreamAlias("tally")
32 @SuppressWarnings("checkstyle:visibilitymodifier")
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(final String description)
81 {
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, ConfidenceInterval.BOTH_SIDE_CONFIDENCE);
106 }
107
108
109
110
111
112
113
114
115 public double[] getConfidenceInterval(final double alpha, final ConfidenceInterval side)
116 {
117 Throw.whenNull(side, "type of confidence level cannot be null");
118 Throw.when(alpha < 0 || alpha > 1, IllegalArgumentException.class,
119 "confidenceLevel should be between 0 and 1 (inclusive)");
120 synchronized (this.semaphore)
121 {
122 if (Double.isNaN(this.getSampleMean()) || Double.isNaN(this.getStdDev()))
123 {
124 return null;
125 }
126 double level = 1 - alpha;
127 if (side.equals(ConfidenceInterval.BOTH_SIDE_CONFIDENCE))
128 {
129 level = 1 - alpha / 2.0;
130 }
131 double z = this.confidenceDistribution.getInverseCumulativeProbability(level);
132 double confidence = z * Math.sqrt(this.getSampleVariance() / this.n);
133 double[] result = {this.getSampleMean() - confidence, this.getSampleMean() + confidence};
134 if (side.equals(ConfidenceInterval.LEFT_SIDE_CONFIDENCE))
135 {
136 result[1] = this.getSampleMean();
137 }
138 if (side.equals(ConfidenceInterval.RIGHT_SIDE_CONFIDENCE))
139 {
140 result[0] = this.getSampleMean();
141 }
142 result[0] = Math.max(result[0], this.min);
143 result[1] = Math.min(result[1], this.max);
144 return result;
145 }
146 }
147
148
149
150
151
152 public String getDescription()
153 {
154 return this.description;
155 }
156
157
158
159
160
161 public double getMax()
162 {
163 return this.max;
164 }
165
166
167
168
169
170 public double getMin()
171 {
172 return this.min;
173 }
174
175
176
177
178
179 public long getN()
180 {
181 return this.n;
182 }
183
184
185
186
187
188 public double getStdDev()
189 {
190 synchronized (this.semaphore)
191 {
192 if (this.n > 1)
193 {
194 return Math.sqrt(this.varianceSum / (1.0 * this.n - 1.0));
195 }
196 return Double.NaN;
197 }
198 }
199
200
201
202
203
204 public double getSum()
205 {
206 return this.sum;
207 }
208
209
210
211
212
213 public double getSampleVariance()
214 {
215 synchronized (this.semaphore)
216 {
217 if (this.n > 1)
218 {
219 return this.varianceSum / (1.0 * this.n - 1.0);
220 }
221 return Double.NaN;
222 }
223 }
224
225
226
227
228 public void initialize()
229 {
230 synchronized (this.semaphore)
231 {
232 this.max = -Double.MAX_VALUE;
233 this.min = Double.MAX_VALUE;
234 this.n = 0;
235 this.sum = 0.0;
236 this.varianceSum = 0.0;
237 }
238 }
239
240
241
242
243
244 public boolean isInitialized()
245 {
246 return !Double.isNaN(this.max);
247 }
248
249
250
251
252
253 public void tally(final double value)
254 {
255 if (!Double.isNaN(value))
256 {
257 synchronized (this.semaphore)
258 {
259 this.varianceSum += value * value;
260 this.sum += value;
261 this.n += 1;
262 if (value < this.min)
263 this.min = value;
264 if (value > this.max)
265 this.max = value;
266 }
267 }
268 }
269
270
271
272
273
274
275
276 public int writeToExcel(final Sheet sheet, final int startRow)
277 {
278 DataFormat format = sheet.getWorkbook().createDataFormat();
279 CellStyle style = sheet.getWorkbook().createCellStyle();
280 style.setDataFormat(format.getFormat("0.00"));
281
282 int rownr = startRow;
283 Row row = sheet.createRow(rownr);
284
285 row.createCell(1).setCellValue(description);
286 row.createCell(2).setCellValue("tally [n, gem, stdev, min, max]");
287 row.createCell(3).setCellValue(getN());
288 if (getN() > 0)
289 {
290 row.createCell(4).setCellValue(getSampleMean());
291 row.getCell(4).setCellStyle(style);
292 if (getN() > 1 && !Double.isNaN(getStdDev()))
293 {
294 row.createCell(5).setCellValue(getStdDev());
295 row.getCell(5).setCellStyle(style);
296 }
297 row.createCell(6).setCellValue(getMin());
298 row.getCell(6).setCellStyle(style);
299 row.createCell(7).setCellValue(getMax());
300 row.getCell(7).setCellStyle(style);
301 }
302
303 return rownr + 1;
304 }
305
306
307
308
309 @Override
310 public String toString()
311 {
312 return this.description;
313 }
314
315 }