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  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   * <br>
23   * Copyright (c) 2011-2013 TU Delft, Faculty of TBM, Systems and Simulation <br>
24   * This software is licensed without restrictions to Nederlandse Organisatie voor Toegepast Natuurwetenschappelijk Onderzoek TNO
25   * (TNO), Erasmus University Rotterdam, Delft University of Technology, Panteia B.V., Stichting Projecten Binnenvaart, Ab Ovo
26   * Nederland B.V., Modality Software Solutions B.V., and Rijkswaterstaat - Dienst Water, Verkeer en Leefomgeving, including the
27   * right to sub-license sources and derived products to third parties. <br>
28   * @version Mar 24, 2013 <br>
29   * @author <a href="http://tudelft.nl/averbraeck">Alexander Verbraeck </a>
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      /** sum refers to the sum of the tally. */
40      protected double sum = Double.NaN;
41  
42      /** min refers to the min of the tally. */
43      protected double min = Double.NaN;
44  
45      /** maxrefers to the max of the tally. */
46      protected double max = Double.NaN;
47  
48      /** varianceSum refers to the varianceSum of the tally. */
49      protected double varianceSum = Double.NaN;
50  
51      /** n refers to the number of measurements. */
52      protected long n = Long.MIN_VALUE;
53  
54      /** description refers to the description of this tally. */
55      protected String description;
56  
57      /** the confidenceDistribution. */
58      @XStreamOmitField
59      private DistNormal confidenceDistribution = new DistNormal(new MersenneTwister());
60  
61      /** the semaphore. */
62      @XStreamOmitField
63      protected Object semaphore = new Object();
64  
65      /** LEFT_SIDE_CONFIDENCE refers to the left side confidence. */
66      @XStreamOmitField
67      public static final short LEFT_SIDE_CONFIDENCE = -1;
68  
69      /** BOTH_SIDE_CONFIDENCE refers to both sides of the confidence. */
70      @XStreamOmitField
71      public static final short BOTH_SIDE_CONFIDENCE = 0;
72  
73      /** RIGTH_SIDE_CONFIDENCE refers to the right side confidence. */
74      @XStreamOmitField
75      public static final short RIGTH_SIDE_CONFIDENCE = 1;
76  
77      /**
78       * @param description String; description of the statistic
79       */
80      public XTally(final String description)
81      {
82          this.description = description;
83      }
84  
85      /**
86       * Returns the sampleMean of all oberservations since the initialization.
87       * @return double the sampleMean
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       * returns the confidence interval on either side of the mean.
99       * @param alpha double; Alpha is the significance level used to compute the confidence level. The confidence level equals
100      *            100*(1 - alpha)%, or in other words, an alpha of 0.05 indicates a 95 percent confidence level.
101      * @return double[] the confidence interval of this tally
102      */
103     public double[] getConfidenceInterval(final double alpha)
104     {
105         return this.getConfidenceInterval(alpha, ConfidenceInterval.BOTH_SIDE_CONFIDENCE);
106     }
107 
108     /**
109      * returns the confidence interval based of the mean.
110      * @param alpha double; Alpha is the significance level used to compute the confidence level. The confidence level equals
111      *            100*(1 - alpha)%, or in other words, an alpha of 0.05 indicates a 95 percent confidence level.
112      * @param side short; the side of the confidence interval with respect to the mean
113      * @return double[] the confidence interval of this tally
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      * returns the description of this tally.
150      * @return Sting description
151      */
152     public String getDescription()
153     {
154         return this.description;
155     }
156 
157     /**
158      * Returns the max.
159      * @return double
160      */
161     public double getMax()
162     {
163         return this.max;
164     }
165 
166     /**
167      * Returns the min.
168      * @return double
169      */
170     public double getMin()
171     {
172         return this.min;
173     }
174 
175     /**
176      * Returns the number of observations.
177      * @return long n
178      */
179     public long getN()
180     {
181         return this.n;
182     }
183 
184     /**
185      * Returns the current tally standard deviation.
186      * @return double the standard deviation
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      * returns the sum of the values of the observations.
202      * @return double sum
203      */
204     public double getSum()
205     {
206         return this.sum;
207     }
208 
209     /**
210      * Returns the current tally variance.
211      * @return double samplevariance
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      * initializes the Tally. This methods sets the max, min, n, sum and variance values to their initial values.
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      * is this tally initialized?
242      * @return true whenever this.initialize is invoked.
243      */
244     public boolean isInitialized()
245     {
246         return !Double.isNaN(this.max);
247     }
248 
249     /**
250      * tally.
251      * @param value double; the value
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      * Write statistics to an excel spreadsheet, starting on row "startRow".
272      * @param sheet Sheet; the excel sheet to write to
273      * @param startRow int; the first row of writing
274      * @return first free row after writing
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      * @see java.lang.Object#toString()
308      */
309     @Override
310     public String toString()
311     {
312         return this.description;
313     }
314 
315 }