View Javadoc
1   package org.djutils.stats.summarizers.quantileaccumulator;
2   
3   import org.djutils.exceptions.Throw;
4   import org.djutils.stats.summarizers.Tally;
5   
6   import com.tdunning.math.stats.TDigest;
7   
8   /**
9    * TDigestAccumulator.java. <br>
10   * <br>
11   * Copyright (c) 2020-2022 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
12   * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
13   * distributed under a three-clause BSD-style license, which can be found at
14   * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>. <br>
15   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
16   * @author <a href="https://www.tudelft.nl/pknoppers">Peter Knoppers</a>
17   */
18  public class TDigestAccumulator implements QuantileAccumulator
19  {
20      /** The TDigest that accumulates the ingested data into bins. */
21      private TDigest tDigest;
22  
23      /** The compression used to create the TDigest (required to re-initialize). */
24      private final int compression;
25  
26      /** The compression used by the parameter-less constructor. */
27      public static final int DEFAULT_COMPRESSION = 100;
28  
29      /**
30       * Construct a new TDigestAccumulator.
31       * @param compression int; the number of bins to compress the data into
32       */
33      public TDigestAccumulator(final int compression)
34      {
35          this.compression = compression;
36          initialize();
37      }
38  
39      /**
40       * Construct a new TDigestAccumulator with compression set to <code>DEFAULT_COMPRESSION</code>.
41       */
42      public TDigestAccumulator()
43      {
44          this(DEFAULT_COMPRESSION);
45      }
46  
47      /** {@inheritDoc} */
48      @Override
49      public double register(final double value)
50      {
51          Throw.when(Double.isNaN(value), IllegalArgumentException.class, "accumulator can not accumlate NaN value");
52          this.tDigest.add(value);
53          return value;
54      }
55  
56      /** {@inheritDoc} */
57      @Override
58      public double getQuantile(final Tally tally, final double probability)
59      {
60          Throw.whenNull(tally, "tally cannot be null");
61          Throw.when(probability < 0 || probability > 1, IllegalArgumentException.class,
62                  "probability should be between 0 and 1 (inclusive)");
63          return this.tDigest.quantile(probability);
64      }
65  
66      /** {@inheritDoc} */
67      @Override
68      public double getCumulativeProbability(final Tally tally, final double quantile)
69      {
70          return this.tDigest.cdf(quantile);
71      }
72  
73      /** {@inheritDoc} */
74      @Override
75      public void initialize()
76      {
77          this.tDigest = TDigest.createDigest(this.compression);
78      }
79  
80      /** {@inheritDoc} */
81      @Override
82      public final String toString()
83      {
84          return "TDigestAccumulator [tDigest=" + this.tDigest + ", compression=" + this.compression + "]";
85      }
86  
87  }