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 }