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 Onderzoek TNO
24   * (TNO), Erasmus University Rotterdam, Delft University of Technology, Panteia B.V., Stichting Projecten Binnenvaart, Ab Ovo
25   * Nederland B.V., Modality Software Solutions B.V., and Rijkswaterstaat - Dienst Water, Verkeer en Leefomgeving, including the
26   * right to sub-license sources and derived products to third parties. <br>
27   * @version Mar 24, 2013 <br>
28   * @author <a href="http://tudelft.nl/averbraeck">Alexander Verbraeck </a>
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      /** 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 String; description of the statistic
78       */
79      public XTally(final String description)
80      {
81          super();
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, Tally.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 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      * returns the description of this tally.
155      * @return Sting description
156      */
157     public String getDescription()
158     {
159         return this.description;
160     }
161 
162     /**
163      * Returns the max.
164      * @return double
165      */
166     public double getMax()
167     {
168         return this.max;
169     }
170 
171     /**
172      * Returns the min.
173      * @return double
174      */
175     public double getMin()
176     {
177         return this.min;
178     }
179 
180     /**
181      * Returns the number of observations.
182      * @return long n
183      */
184     public long getN()
185     {
186         return this.n;
187     }
188 
189     /**
190      * Returns the current tally standard deviation.
191      * @return double the standard deviation
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      * returns the sum of the values of the observations.
207      * @return double sum
208      */
209     public double getSum()
210     {
211         return this.sum;
212     }
213 
214     /**
215      * Returns the current tally variance.
216      * @return double samplevariance
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      * initializes the Tally. This methods sets the max, min, n, sum and variance values to their initial values.
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      * is this tally initialized?
247      * @return true whenever this.initialize is invoked.
248      */
249     public boolean isInitialized()
250     {
251         return !Double.isNaN(this.max);
252     }
253 
254     /**
255      * tally.
256      * @param value double; the value
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      * Write statistics to an excel spreadsheet, starting on row "startRow".
277      * @param sheet Sheet; the excel sheet to write to
278      * @param startRow int; the first row of writing
279      * @return first free row after writing
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      * @see java.lang.Object#toString()
313      */
314     @Override
315     public String toString()
316     {
317         return this.description;
318     }
319 
320 }