View Javadoc
1   package org.djutils.stats.summarizers.event;
2   
3   import java.io.Serializable;
4   
5   import org.djutils.event.Event;
6   import org.djutils.event.EventInterface;
7   import org.djutils.event.EventListenerInterface;
8   import org.djutils.event.EventProducer;
9   import org.djutils.stats.ConfidenceInterval;
10  import org.djutils.stats.summarizers.Tally;
11  import org.djutils.stats.summarizers.TallyInterface;
12  import org.djutils.stats.summarizers.quantileaccumulator.NoStorageAccumulator;
13  import org.djutils.stats.summarizers.quantileaccumulator.QuantileAccumulator;
14  
15  /**
16   * The EventBasedTally class ingests a series of values and provides mean, standard deviation, etc. of the ingested values. It
17   * extends an EventProducer so it can keep listeners informed about new observations, and it listens to external events to be
18   * able to receive observations, in addition to the register(...) method.
19   * <p>
20   * Copyright (c) 2002-2022 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
21   * for project information <a href="https://simulation.tudelft.nl/" target="_blank"> https://simulation.tudelft.nl</a>. The DSOL
22   * project is distributed under a three-clause BSD-style license, which can be found at
23   * <a href="https://simulation.tudelft.nl/dsol/3.0/license.html" target="_blank">
24   * https://simulation.tudelft.nl/dsol/3.0/license.html</a>. <br>
25   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank"> Alexander Verbraeck</a>
26   * @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a>
27   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
28   */
29  public class EventBasedTally extends EventProducer implements EventListenerInterface, TallyInterface
30  {
31      /** */
32      private static final long serialVersionUID = 20200228L;
33  
34      /** the wrapped Tally. */
35      private final Tally wrappedTally;
36  
37      /**
38       * Constructs a new EventBasedTally.
39       * @param description String; the description of this tally
40       * @param quantileAccumulator QuantileAccumulator; the input series accumulator that can approximate or compute quantiles.
41       */
42      public EventBasedTally(final String description, final QuantileAccumulator quantileAccumulator)
43      {
44          this.wrappedTally = new Tally(description, quantileAccumulator);
45      }
46  
47      /**
48       * Convenience constructor that uses a NoStorageAccumulator to estimate quantiles.
49       * @param description String; the description of this tally
50       */
51      public EventBasedTally(final String description)
52      {
53          this(description, new NoStorageAccumulator());
54      }
55  
56      /** {@inheritDoc} */
57      @Override
58      public Serializable getSourceId()
59      {
60          return this;
61      }
62  
63      /** {@inheritDoc} */
64      @Override
65      public final double getSampleMean()
66      {
67          return this.wrappedTally.getSampleMean();
68      }
69  
70      /** {@inheritDoc} */
71      @Override
72      public final double getQuantile(final double probability)
73      {
74          return this.wrappedTally.getQuantile(probability);
75      }
76  
77      /** {@inheritDoc} */
78      @Override
79      public double getCumulativeProbability(final double quantile) throws IllegalArgumentException
80      {
81          return this.wrappedTally.getCumulativeProbability(quantile);
82      }
83  
84      /** {@inheritDoc} */
85      @Override
86      public final double[] getConfidenceInterval(final double alpha)
87      {
88          return this.wrappedTally.getConfidenceInterval(alpha);
89      }
90  
91      /** {@inheritDoc} */
92      @Override
93      public final double[] getConfidenceInterval(final double alpha, final ConfidenceInterval side)
94      {
95          return this.wrappedTally.getConfidenceInterval(alpha, side);
96      }
97  
98      /** {@inheritDoc} */
99      @Override
100     public final String getDescription()
101     {
102         return this.wrappedTally.getDescription();
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public final double getMax()
108     {
109         return this.wrappedTally.getMax();
110     }
111 
112     /** {@inheritDoc} */
113     @Override
114     public final double getMin()
115     {
116         return this.wrappedTally.getMin();
117     }
118 
119     /** {@inheritDoc} */
120     @Override
121     public final long getN()
122     {
123         return this.wrappedTally.getN();
124     }
125 
126     /** {@inheritDoc} */
127     @Override
128     public final double getSampleStDev()
129     {
130         return this.wrappedTally.getSampleStDev();
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public final double getPopulationStDev()
136     {
137         return this.wrappedTally.getPopulationStDev();
138     }
139 
140     /** {@inheritDoc} */
141     @Override
142     public final double getSum()
143     {
144         return this.wrappedTally.getSum();
145     }
146 
147     /** {@inheritDoc} */
148     @Override
149     public final double getSampleVariance()
150     {
151         return this.wrappedTally.getSampleVariance();
152     }
153 
154     /** {@inheritDoc} */
155     @Override
156     public final double getPopulationVariance()
157     {
158         return this.wrappedTally.getPopulationVariance();
159     }
160 
161     /** {@inheritDoc} */
162     @Override
163     public final double getSampleSkewness()
164     {
165         return this.wrappedTally.getSampleSkewness();
166     }
167 
168     /** {@inheritDoc} */
169     @Override
170     public final double getPopulationSkewness()
171     {
172         return this.wrappedTally.getPopulationSkewness();
173     }
174 
175     /** {@inheritDoc} */
176     @Override
177     public final double getSampleKurtosis()
178     {
179         return this.wrappedTally.getSampleKurtosis();
180     }
181 
182     /** {@inheritDoc} */
183     @Override
184     public final double getPopulationKurtosis()
185     {
186         return this.wrappedTally.getPopulationKurtosis();
187     }
188 
189     /** {@inheritDoc} */
190     @Override
191     public final double getSampleExcessKurtosis()
192     {
193         return this.wrappedTally.getSampleExcessKurtosis();
194     }
195 
196     /** {@inheritDoc} */
197     @Override
198     public final double getPopulationExcessKurtosis()
199     {
200         return this.wrappedTally.getPopulationExcessKurtosis();
201     }
202 
203     /** {@inheritDoc} */
204     @Override
205     public void initialize()
206     {
207         this.wrappedTally.initialize();
208         fireEvent(new Event(StatisticsEvents.INITIALIZED_EVENT, this, null));
209     }
210 
211     /** {@inheritDoc} */
212     @Override
213     @SuppressWarnings("checkstyle:designforextension")
214     public void notify(final EventInterface event)
215     {
216         if (!(event.getContent() instanceof Number))
217         {
218             throw new IllegalArgumentException("Tally does not accept " + event);
219         }
220         double value = ((Number) event.getContent()).doubleValue();
221         register(value);
222     }
223 
224     /** {@inheritDoc} */
225     @Override
226     public double register(final double value)
227     {
228         this.wrappedTally.register(value);
229         if (hasListeners())
230         {
231             fireEvent(new Event(StatisticsEvents.OBSERVATION_ADDED_EVENT, this, value));
232             fireEvents();
233         }
234         return value;
235     }
236 
237     /**
238      * Method that can be overridden to fire own events or additional events when ingesting an observation.
239      */
240     protected void fireEvents()
241     {
242         fireEvent(new Event(StatisticsEvents.N_EVENT, this, getN()));
243         fireEvent(new Event(StatisticsEvents.MIN_EVENT, this, getMin()));
244         fireEvent(new Event(StatisticsEvents.MAX_EVENT, this, getMax()));
245         fireEvent(new Event(StatisticsEvents.POPULATION_MEAN_EVENT, this, getPopulationMean()));
246         fireEvent(new Event(StatisticsEvents.POPULATION_VARIANCE_EVENT, this, getPopulationVariance()));
247         fireEvent(new Event(StatisticsEvents.POPULATION_SKEWNESS_EVENT, this, getPopulationSkewness()));
248         fireEvent(new Event(StatisticsEvents.POPULATION_KURTOSIS_EVENT, this, getPopulationKurtosis()));
249         fireEvent(new Event(StatisticsEvents.POPULATION_EXCESS_KURTOSIS_EVENT, this, getPopulationExcessKurtosis()));
250         fireEvent(new Event(StatisticsEvents.POPULATION_STDEV_EVENT, this, getPopulationStDev()));
251         fireEvent(new Event(StatisticsEvents.SUM_EVENT, this, getSum()));
252         fireEvent(new Event(StatisticsEvents.SAMPLE_MEAN_EVENT, this, getSampleMean()));
253         fireEvent(new Event(StatisticsEvents.SAMPLE_VARIANCE_EVENT, this, getSampleVariance()));
254         fireEvent(new Event(StatisticsEvents.SAMPLE_SKEWNESS_EVENT, this, getSampleSkewness()));
255         fireEvent(new Event(StatisticsEvents.SAMPLE_KURTOSIS_EVENT, this, getSampleKurtosis()));
256         fireEvent(new Event(StatisticsEvents.SAMPLE_EXCESS_KURTOSIS_EVENT, this, getSampleExcessKurtosis()));
257         fireEvent(new Event(StatisticsEvents.SAMPLE_STDEV_EVENT, this, getSampleStDev()));
258     }
259 
260     /** {@inheritDoc} */
261     @Override
262     @SuppressWarnings("checkstyle:designforextension")
263     public String toString()
264     {
265         return "EventBasedTally [wrappedTally=" + this.wrappedTally + "]";
266     }
267 
268 }