View Javadoc
1   /**
2    * 
3    */
4   package org.opentrafficsim.water.statistics;
5   
6   import java.io.Serializable;
7   import java.rmi.RemoteException;
8   
9   import org.apache.poi.ss.usermodel.CellStyle;
10  import org.apache.poi.ss.usermodel.DataFormat;
11  import org.apache.poi.ss.usermodel.Row;
12  import org.apache.poi.ss.usermodel.Sheet;
13  
14  import com.thoughtworks.xstream.annotations.XStreamAlias;
15  import com.thoughtworks.xstream.annotations.XStreamOmitField;
16  
17  import nl.tudelft.simulation.jstats.distributions.DistNormal;
18  import nl.tudelft.simulation.jstats.statistics.Tally;
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
25   * Onderzoek TNO (TNO), Erasmus University Rotterdam, Delft University of Technology, Panteia B.V., Stichting Projecten
26   * Binnenvaart, Ab Ovo Nederland B.V., Modality Software Solutions B.V., and Rijkswaterstaat - Dienst Water, Verkeer en
27   * Leefomgeving, including the right to sub-license sources and derived products to third parties. <br>
28   * 
29   * @version Mar 24, 2013 <br>
30   * @author <a href="http://tudelft.nl/averbraeck">Alexander Verbraeck </a>
31   */
32  @XStreamAlias("tally")
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 description of the statistic
79       */
80      public XTally(String description)
81      {
82          super();
83          this.description = description;
84      }
85  
86      /**
87       * Returns the sampleMean of all oberservations since the initialization
88       * 
89       * @return double the sampleMean
90       */
91      public double getSampleMean()
92      {
93          if (this.n > 0)
94              return this.sum / this.n;
95          else
96              return Double.NaN;
97      }
98  
99      /**
100      * returns the confidence interval on either side of the mean
101      * 
102      * @param alpha Alpha is the significance level used to compute the confidence level. The confidence level equals
103      *            100*(1 - alpha)%, or in other words, an alpha of 0.05 indicates a 95 percent confidence level.
104      * @return double[] the confidence interval of this tally
105      */
106     public double[] getConfidenceInterval(final double alpha)
107     {
108         return this.getConfidenceInterval(alpha, Tally.BOTH_SIDE_CONFIDENCE);
109     }
110 
111     /**
112      * returns the confidence interval based of the mean
113      * 
114      * @param alpha Alpha is the significance level used to compute the confidence level. The confidence level equals
115      *            100*(1 - alpha)%, or in other words, an alpha of 0.05 indicates a 95 percent confidence level.
116      * @param side the side of the confidence interval with respect to the mean
117      * @return double[] the confidence interval of this tally
118      */
119     public double[] getConfidenceInterval(final double alpha, final short side)
120     {
121         if (!(side == LEFT_SIDE_CONFIDENCE || side == BOTH_SIDE_CONFIDENCE || side == RIGTH_SIDE_CONFIDENCE))
122         {
123             throw new IllegalArgumentException("side of confidence level is not defined");
124         }
125         if (alpha < 0 || alpha > 1)
126         {
127             throw new IllegalArgumentException("1 >= confidenceLevel >= 0");
128         }
129         synchronized (this.semaphore)
130         {
131             if (Double.isNaN(this.getSampleMean()) || Double.isNaN(this.getStdDev()))
132             {
133                 return null;
134             }
135             double level = 1 - alpha;
136             if (side == Tally.BOTH_SIDE_CONFIDENCE)
137             {
138                 level = 1 - alpha / 2.0;
139             }
140             double z = this.confidenceDistribution.getInverseCumulativeProbability(level);
141             double confidence = z * Math.sqrt(this.getSampleVariance() / this.n);
142             double[] result = {this.getSampleMean() - confidence, this.getSampleMean() + confidence};
143             if (side == Tally.LEFT_SIDE_CONFIDENCE)
144             {
145                 result[1] = this.getSampleMean();
146             }
147             if (side == Tally.RIGTH_SIDE_CONFIDENCE)
148             {
149                 result[0] = this.getSampleMean();
150             }
151             result[0] = Math.max(result[0], this.min);
152             result[1] = Math.min(result[1], this.max);
153             return result;
154         }
155     }
156 
157     /**
158      * returns the description of this tally
159      * 
160      * @return Sting description
161      */
162     public String getDescription()
163     {
164         return this.description;
165     }
166 
167     /**
168      * Returns the max.
169      * 
170      * @return double
171      */
172     public double getMax()
173     {
174         return this.max;
175     }
176 
177     /**
178      * Returns the min.
179      * 
180      * @return double
181      */
182     public double getMin()
183     {
184         return this.min;
185     }
186 
187     /**
188      * Returns the number of observations
189      * 
190      * @return long n
191      */
192     public long getN()
193     {
194         return this.n;
195     }
196 
197     /**
198      * Returns the current tally standard deviation
199      * 
200      * @return double the standard deviation
201      */
202     public double getStdDev()
203     {
204         synchronized (this.semaphore)
205         {
206             if (this.n > 1)
207             {
208                 return Math.sqrt(this.varianceSum / (1.0 * this.n - 1.0));
209             }
210             return Double.NaN;
211         }
212     }
213 
214     /**
215      * returns the sum of the values of the observations
216      * 
217      * @return double sum
218      */
219     public double getSum()
220     {
221         return this.sum;
222     }
223 
224     /**
225      * Returns the current tally variance
226      * 
227      * @return double samplevariance
228      */
229     public double getSampleVariance()
230     {
231         synchronized (this.semaphore)
232         {
233             if (this.n > 1)
234             {
235                 return this.varianceSum / (1.0 * this.n - 1.0);
236             }
237             return Double.NaN;
238         }
239     }
240 
241     /**
242      * initializes the Tally. This methods sets the max, min, n, sum and variance values to their initial values.
243      */
244     public void initialize()
245     {
246         synchronized (this.semaphore)
247         {
248             this.max = -Double.MAX_VALUE;
249             this.min = Double.MAX_VALUE;
250             this.n = 0;
251             this.sum = 0.0;
252             this.varianceSum = 0.0;
253         }
254     }
255 
256     /**
257      * is this tally initialized?
258      * 
259      * @return true whenever this.initialize is invoked.
260      */
261     public boolean isInitialized()
262     {
263         return !Double.isNaN(this.max);
264     }
265 
266     /**
267      * tally
268      * 
269      * @param value the value
270      */
271     public void tally(final double value)
272     {
273         if (!Double.isNaN(value))
274         {
275             synchronized (this.semaphore)
276             {
277                 this.varianceSum += value * value;
278                 this.sum += value;
279                 this.n += 1;
280                 if (value < this.min)
281                     this.min = value;
282                 if (value > this.max)
283                     this.max = value;
284             }
285         }
286     }
287 
288     /**
289      * Write statistics to an excel spreadsheet, starting on row "startRow"
290      * 
291      * @param sheet the excel sheet to write to 
292      * @param startRow the first row of writing
293      * @return first free row after writing
294      */
295     public int writeToExcel(final Sheet sheet, final int startRow)
296     {
297         DataFormat format = sheet.getWorkbook().createDataFormat();
298         CellStyle style = sheet.getWorkbook().createCellStyle();
299         style.setDataFormat(format.getFormat("0.00"));
300 
301         int rownr = startRow;
302         Row row = sheet.createRow(rownr);
303 
304         row.createCell(1).setCellValue(description);
305         row.createCell(2).setCellValue("tally [n, gem, stdev, min, max]");
306         row.createCell(3).setCellValue(getN());
307         if (getN() > 0)
308         {
309             row.createCell(4).setCellValue(getSampleMean());
310             row.getCell(4).setCellStyle(style);
311             if (getN() > 1 && !Double.isNaN(getStdDev()))
312             {
313                 row.createCell(5).setCellValue(getStdDev());
314                 row.getCell(5).setCellStyle(style);
315             }
316             row.createCell(6).setCellValue(getMin());
317             row.getCell(6).setCellStyle(style);
318             row.createCell(7).setCellValue(getMax());
319             row.getCell(7).setCellStyle(style);
320         }
321 
322         return rownr + 1;
323     }
324 
325     /**
326      * @see java.lang.Object#toString()
327      */
328     @Override
329     public String toString()
330     {
331         return this.description;
332     }
333 
334 }