View Javadoc
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   * <br>
22   * Copyright (c) 2011-2013 TU Delft, Faculty of TBM, Systems and Simulation <br>
23   * This software is licensed without restrictions to Nederlandse Organisatie voor Toegepast Natuurwetenschappelijk
24   * Onderzoek TNO (TNO), Erasmus University Rotterdam, Delft University of Technology, Panteia B.V., Stichting Projecten
25   * Binnenvaart, Ab Ovo Nederland B.V., Modality Software Solutions B.V., and Rijkswaterstaat - Dienst Water, Verkeer en
26   * Leefomgeving, including the right to sub-license sources and derived products to third parties. <br>
27   * 
28   * @version Mar 24, 2013 <br>
29   * @author <a href="http://tudelft.nl/averbraeck">Alexander Verbraeck </a>
30   */
31  @XStreamAlias("tally")
32  public class XTally implements Serializable
33  {
34      /** */
35      @XStreamOmitField
36      private static final long serialVersionUID = 1L;
37  
38      /** sum refers to the sum of the tally */
39      protected double sum = Double.NaN;
40  
41      /** min refers to the min of the tally */
42      protected double min = Double.NaN;
43  
44      /** maxrefers to the max of the tally */
45      protected double max = Double.NaN;
46  
47      /** varianceSum refers to the varianceSum of the tally */
48      protected double varianceSum = Double.NaN;
49  
50      /** n refers to the number of measurements */
51      protected long n = Long.MIN_VALUE;
52  
53      /** description refers to the description of this tally */
54      protected String description;
55  
56      /** the confidenceDistribution */
57      @XStreamOmitField
58      private DistNormal confidenceDistribution = new DistNormal(new MersenneTwister());
59  
60      /** the semaphore */
61      @XStreamOmitField
62      protected Object semaphore = new Object();
63  
64      /** LEFT_SIDE_CONFIDENCE refers to the left side confidence */
65      @XStreamOmitField
66      public static final short LEFT_SIDE_CONFIDENCE = -1;
67  
68      /** BOTH_SIDE_CONFIDENCE refers to both sides of the confidence */
69      @XStreamOmitField
70      public static final short BOTH_SIDE_CONFIDENCE = 0;
71  
72      /** RIGTH_SIDE_CONFIDENCE refers to the right side confidence */
73      @XStreamOmitField
74      public static final short RIGTH_SIDE_CONFIDENCE = 1;
75  
76      /**
77       * @param description description of the statistic
78       */
79      public XTally(String description)
80      {
81          super();
82          this.description = description;
83      }
84  
85      /**
86       * Returns the sampleMean of all oberservations since the initialization
87       * 
88       * @return double the sampleMean
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       * returns the confidence interval on either side of the mean
100      * 
101      * @param alpha Alpha is the significance level used to compute the confidence level. The confidence level equals
102      *            100*(1 - alpha)%, or in other words, an alpha of 0.05 indicates a 95 percent confidence level.
103      * @return double[] the confidence interval of this tally
104      */
105     public double[] getConfidenceInterval(final double alpha)
106     {
107         return this.getConfidenceInterval(alpha, Tally.BOTH_SIDE_CONFIDENCE);
108     }
109 
110     /**
111      * returns the confidence interval based of the mean
112      * 
113      * @param alpha Alpha is the significance level used to compute the confidence level. The confidence level equals
114      *            100*(1 - alpha)%, or in other words, an alpha of 0.05 indicates a 95 percent confidence level.
115      * @param side the side of the confidence interval with respect to the mean
116      * @return double[] the confidence interval of this tally
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      * returns the description of this tally
158      * 
159      * @return Sting description
160      */
161     public String getDescription()
162     {
163         return this.description;
164     }
165 
166     /**
167      * Returns the max.
168      * 
169      * @return double
170      */
171     public double getMax()
172     {
173         return this.max;
174     }
175 
176     /**
177      * Returns the min.
178      * 
179      * @return double
180      */
181     public double getMin()
182     {
183         return this.min;
184     }
185 
186     /**
187      * Returns the number of observations
188      * 
189      * @return long n
190      */
191     public long getN()
192     {
193         return this.n;
194     }
195 
196     /**
197      * Returns the current tally standard deviation
198      * 
199      * @return double the standard deviation
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      * returns the sum of the values of the observations
215      * 
216      * @return double sum
217      */
218     public double getSum()
219     {
220         return this.sum;
221     }
222 
223     /**
224      * Returns the current tally variance
225      * 
226      * @return double samplevariance
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      * initializes the Tally. This methods sets the max, min, n, sum and variance values to their initial values.
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      * is this tally initialized?
257      * 
258      * @return true whenever this.initialize is invoked.
259      */
260     public boolean isInitialized()
261     {
262         return !Double.isNaN(this.max);
263     }
264 
265     /**
266      * tally
267      * 
268      * @param value the value
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      * Write statistics to an excel spreadsheet, starting on row "startRow"
289      * 
290      * @param sheet the excel sheet to write to 
291      * @param startRow the first row of writing
292      * @return first free row after writing
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      * @see java.lang.Object#toString()
326      */
327     @Override
328     public String toString()
329     {
330         return this.description;
331     }
332 
333 }