StreamingStatistics.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.stat.descriptive;

  22. import java.io.Serializable;
  23. import java.util.function.DoubleConsumer;

  24. import org.hipparchus.exception.NullArgumentException;
  25. import org.hipparchus.random.RandomGenerator;
  26. import org.hipparchus.stat.descriptive.moment.GeometricMean;
  27. import org.hipparchus.stat.descriptive.moment.Mean;
  28. import org.hipparchus.stat.descriptive.moment.SecondMoment;
  29. import org.hipparchus.stat.descriptive.moment.Variance;
  30. import org.hipparchus.stat.descriptive.rank.Max;
  31. import org.hipparchus.stat.descriptive.rank.Min;
  32. import org.hipparchus.stat.descriptive.rank.RandomPercentile;
  33. import org.hipparchus.stat.descriptive.summary.Sum;
  34. import org.hipparchus.stat.descriptive.summary.SumOfLogs;
  35. import org.hipparchus.stat.descriptive.summary.SumOfSquares;
  36. import org.hipparchus.util.FastMath;
  37. import org.hipparchus.util.MathUtils;
  38. import org.hipparchus.util.Precision;

  39. /**
  40.  * Computes summary statistics for a stream of data values added using the
  41.  * {@link #addValue(double) addValue} method. The data values are not stored in
  42.  * memory, so this class can be used to compute statistics for very large data
  43.  * streams.
  44.  * <p>
  45.  * By default, all statistics other than percentiles are maintained.  Percentile
  46.  * calculations use an embedded {@link RandomPercentile} which carries more memory
  47.  * and compute overhead than the other statistics, so it is disabled by default.
  48.  * To enable percentiles, either pass {@code true} to the constructor or use a
  49.  * {@link StreamingStatisticsBuilder} to configure an instance with percentiles turned
  50.  * on. Other stats can also be selectively disabled using
  51.  * {@code StreamingStatisticsBulder}.
  52.  * <p>
  53.  * Note: This class is not thread-safe.
  54.  */
  55. public class StreamingStatistics
  56.     implements StatisticalSummary, AggregatableStatistic<StreamingStatistics>,
  57.                DoubleConsumer, Serializable {

  58.     /** Serialization UID */
  59.     private static final long serialVersionUID = 20160422L;

  60.     /** count of values that have been added */
  61.     private long n;

  62.     /** SecondMoment is used to compute the mean and variance */
  63.     private final SecondMoment secondMoment;
  64.     /** min of values that have been added */
  65.     private final Min minImpl;
  66.     /** max of values that have been added */
  67.     private final Max maxImpl;
  68.     /** sum of values that have been added */
  69.     private final Sum sumImpl;
  70.     /** sum of the square of each value that has been added */
  71.     private final SumOfSquares sumOfSquaresImpl;
  72.     /** sumLog of values that have been added */
  73.     private final SumOfLogs sumOfLogsImpl;
  74.     /** mean of values that have been added */
  75.     private final Mean meanImpl;
  76.     /** variance of values that have been added */
  77.     private final Variance varianceImpl;
  78.     /** geoMean of values that have been added */
  79.     private final GeometricMean geoMeanImpl;
  80.     /** population variance of values that have been added */
  81.     private final Variance populationVariance;
  82.     /** source of percentiles */
  83.     private final RandomPercentile randomPercentile;

  84.     /** whether or not moment stats (sum, mean, variance) are maintained */
  85.     private final boolean computeMoments;
  86.     /** whether or not sum of squares and quadratic mean are maintained */
  87.     private final boolean computeSumOfSquares;
  88.     /** whether or not sum of logs and geometric mean are maintained */
  89.     private final boolean computeSumOfLogs;
  90.     /** whether or not min and max are maintained */
  91.     private final boolean computeExtrema;

  92.     /**
  93.      * Construct a new StreamingStatistics instance, maintaining all statistics
  94.      * other than percentiles.
  95.      */
  96.     public StreamingStatistics() {
  97.        this(Double.NaN, null);
  98.     }

  99.     /**
  100.      * Construct a new StreamingStatistics instance, maintaining all statistics
  101.      * other than percentiles and with/without percentiles per the arguments.
  102.      *
  103.      * @param epsilon bound on quantile estimation error (see {@link RandomGenerator})
  104.      * @param randomGenerator PRNG used in sampling and merge operations (null if percentiles should not be computed)
  105.      * @since 2.3
  106.      */
  107.     public StreamingStatistics(final double epsilon, final RandomGenerator randomGenerator) {
  108.        this(true, true, true, true, epsilon, randomGenerator);
  109.     }

  110.     /**
  111.      * Private constructor used by {@link StreamingStatisticsBuilder}.
  112.      *
  113.      * @param computeMoments whether or not moment stats (mean, sum, variance) are maintained
  114.      * @param computeSumOfLogs whether or not sum of logs and geometric mean are maintained
  115.      * @param computeSumOfSquares whether or not sum of squares and quadratic mean are maintained
  116.      * @param computeExtrema whether or not min and max are maintained
  117.      * @param epsilon bound on quantile estimation error (see {@link RandomGenerator})
  118.      * @param randomGenerator PRNG used in sampling and merge operations (null if percentiles should not be computed)
  119.      * @since 2.3
  120.      */
  121.     private StreamingStatistics(final boolean computeMoments,
  122.                                 final boolean computeSumOfLogs, final boolean computeSumOfSquares,
  123.                                 final boolean computeExtrema,
  124.                                 final double epsilon, final RandomGenerator randomGenerator) {
  125.         this.computeMoments = computeMoments;
  126.         this.computeSumOfLogs = computeSumOfLogs;
  127.         this.computeSumOfSquares = computeSumOfSquares;
  128.         this.computeExtrema = computeExtrema;

  129.         this.secondMoment = computeMoments ? new SecondMoment() : null;
  130.         this.maxImpl = computeExtrema ? new Max() : null;
  131.         this.minImpl = computeExtrema ? new Min() : null;
  132.         this.sumImpl = computeMoments ? new Sum() : null;
  133.         this.sumOfSquaresImpl = computeSumOfSquares ? new SumOfSquares() : null;
  134.         this.sumOfLogsImpl = computeSumOfLogs ? new SumOfLogs() : null;
  135.         this.meanImpl = computeMoments ? new Mean(this.secondMoment) : null;
  136.         this.varianceImpl = computeMoments ?  new Variance(this.secondMoment) : null;
  137.         this.geoMeanImpl = computeSumOfLogs ? new GeometricMean(this.sumOfLogsImpl) : null;
  138.         this.populationVariance = computeMoments ? new Variance(false, this.secondMoment) : null;
  139.         this.randomPercentile = randomGenerator == null ? null : new RandomPercentile(epsilon, randomGenerator);
  140.     }

  141.     /**
  142.      * A copy constructor. Creates a deep-copy of the {@code original}.
  143.      *
  144.      * @param original the {@code StreamingStatistics} instance to copy
  145.      * @throws NullArgumentException if original is null
  146.      */
  147.     StreamingStatistics(StreamingStatistics original) throws NullArgumentException {
  148.         MathUtils.checkNotNull(original);

  149.         this.n                = original.n;
  150.         this.secondMoment     = original.computeMoments ? original.secondMoment.copy() : null;
  151.         this.maxImpl          = original.computeExtrema ? original.maxImpl.copy() : null;
  152.         this.minImpl          = original.computeExtrema ? original.minImpl.copy() : null;
  153.         this.sumImpl          = original.computeMoments ? original.sumImpl.copy() : null;
  154.         this.sumOfLogsImpl    = original.computeSumOfLogs ? original.sumOfLogsImpl.copy() : null;
  155.         this.sumOfSquaresImpl = original.computeSumOfSquares ? original.sumOfSquaresImpl.copy() : null;

  156.         // Keep statistics with embedded moments in synch
  157.         this.meanImpl     = original.computeMoments ? new Mean(this.secondMoment) : null;
  158.         this.varianceImpl = original.computeMoments ? new Variance(this.secondMoment) : null;
  159.         this.geoMeanImpl  = original.computeSumOfLogs ? new GeometricMean(this.sumOfLogsImpl) : null;
  160.         this.populationVariance = original.computeMoments ? new Variance(false, this.secondMoment) : null;
  161.         this.randomPercentile = original.randomPercentile != null ? original.randomPercentile.copy() : null;

  162.         this.computeMoments = original.computeMoments;
  163.         this.computeSumOfLogs = original.computeSumOfLogs;
  164.         this.computeSumOfSquares = original.computeSumOfSquares;
  165.         this.computeExtrema = original.computeExtrema;
  166.     }

  167.     /**
  168.      * Returns a copy of this StreamingStatistics instance with the same internal state.
  169.      *
  170.      * @return a copy of this
  171.      */
  172.     public StreamingStatistics copy() {
  173.         return new StreamingStatistics(this);
  174.     }

  175.     /**
  176.      * Return a {@link StatisticalSummaryValues} instance reporting current
  177.      * statistics.
  178.      * @return Current values of statistics
  179.      */
  180.     public StatisticalSummary getSummary() {
  181.         return new StatisticalSummaryValues(getMean(), getVariance(), getN(),
  182.                                             getMax(), getMin(), getSum());
  183.     }

  184.     /**
  185.      * Add a value to the data
  186.      * @param value the value to add
  187.      */
  188.     public void addValue(double value) {
  189.         if (computeMoments) {
  190.             secondMoment.increment(value);
  191.             sumImpl.increment(value);
  192.         }
  193.         if (computeExtrema) {
  194.             minImpl.increment(value);
  195.             maxImpl.increment(value);
  196.         }
  197.         if (computeSumOfSquares) {
  198.             sumOfSquaresImpl.increment(value);
  199.         }
  200.         if (computeSumOfLogs) {
  201.             sumOfLogsImpl.increment(value);
  202.         }
  203.         if (randomPercentile != null) {
  204.             randomPercentile.increment(value);
  205.         }
  206.         n++;
  207.     }

  208.     /** {@inheritDoc} */
  209.     @Override
  210.     public void accept(double value) {
  211.         addValue(value);
  212.     }

  213.     /**
  214.      * Resets all statistics and storage.
  215.      */
  216.     public void clear() {
  217.         this.n = 0;
  218.         if (computeExtrema) {
  219.             minImpl.clear();
  220.             maxImpl.clear();
  221.         }
  222.         if (computeMoments) {
  223.             sumImpl.clear();
  224.             secondMoment.clear();
  225.         }
  226.         if (computeSumOfLogs) {
  227.             sumOfLogsImpl.clear();
  228.         }
  229.         if (computeSumOfSquares) {
  230.             sumOfSquaresImpl.clear();
  231.         }
  232.         if (randomPercentile != null) {
  233.             randomPercentile.clear();
  234.         }
  235.     }

  236.     /** {@inheritDoc} */
  237.     @Override
  238.     public long getN() {
  239.         return n;
  240.     }

  241.     /** {@inheritDoc} */
  242.     @Override
  243.     public double getMax() {
  244.         return computeExtrema ? maxImpl.getResult() : Double.NaN;
  245.     }

  246.     /** {@inheritDoc} */
  247.     @Override
  248.     public double getMin() {
  249.         return computeExtrema ? minImpl.getResult() : Double.NaN;
  250.     }

  251.     /** {@inheritDoc} */
  252.     @Override
  253.     public double getSum() {
  254.         return computeMoments ? sumImpl.getResult() : Double.NaN;
  255.     }

  256.     /**
  257.      * Returns the sum of the squares of the values that have been added.
  258.      * <p>
  259.      * Double.NaN is returned if no values have been added.
  260.      *
  261.      * @return The sum of squares
  262.      */
  263.     public double getSumOfSquares() {
  264.         return computeSumOfSquares ? sumOfSquaresImpl.getResult() : Double.NaN;
  265.     }

  266.     /** {@inheritDoc} */
  267.     @Override
  268.     public double getMean() {
  269.         return computeMoments ? meanImpl.getResult() : Double.NaN;
  270.     }

  271.     /** {@inheritDoc} */
  272.     @Override
  273.     public double getVariance() {
  274.         return computeMoments ? varianceImpl.getResult() : Double.NaN;
  275.     }

  276.     /**
  277.      * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
  278.      * population variance</a> of the values that have been added.
  279.      * <p>
  280.      * Double.NaN is returned if no values have been added.
  281.      *
  282.      * @return the population variance
  283.      */
  284.     public double getPopulationVariance() {
  285.         return computeMoments ? populationVariance.getResult() : Double.NaN;
  286.     }

  287.     /**
  288.      * Returns the geometric mean of the values that have been added.
  289.      * <p>
  290.      * Double.NaN is returned if no values have been added.
  291.      *
  292.      * @return the geometric mean
  293.      */
  294.     public double getGeometricMean() {
  295.         return computeSumOfLogs ? geoMeanImpl.getResult() : Double.NaN;
  296.     }

  297.     /**
  298.      * Returns the sum of the logs of the values that have been added.
  299.      * <p>
  300.      * Double.NaN is returned if no values have been added.
  301.      *
  302.      * @return the sum of logs
  303.      */
  304.     public double getSumOfLogs() {
  305.         return computeSumOfLogs ? sumOfLogsImpl.getResult() : Double.NaN;
  306.     }

  307.     /**
  308.      * Returns a statistic related to the Second Central Moment. Specifically,
  309.      * what is returned is the sum of squared deviations from the sample mean
  310.      * among the values that have been added.
  311.      * <p>
  312.      * Returns <code>Double.NaN</code> if no data values have been added and
  313.      * returns <code>0</code> if there is just one value in the data set.
  314.      *
  315.      * @return second central moment statistic
  316.      */
  317.     public double getSecondMoment() {
  318.         return computeMoments ? secondMoment.getResult() : Double.NaN;
  319.     }

  320.     /**
  321.      * Returns the quadratic mean, a.k.a.
  322.      * <a href="http://mathworld.wolfram.com/Root-Mean-Square.html">
  323.      * root-mean-square</a> of the available values
  324.      *
  325.      * @return The quadratic mean or {@code Double.NaN} if no values
  326.      * have been added.
  327.      */
  328.     public double getQuadraticMean() {
  329.         if (computeSumOfSquares) {
  330.             long size = getN();
  331.             return size > 0 ? FastMath.sqrt(getSumOfSquares() / size) : Double.NaN;
  332.         } else {
  333.             return Double.NaN;
  334.         }
  335.     }

  336.     /**
  337.      * Returns the standard deviation of the values that have been added.
  338.      * <p>
  339.      * Double.NaN is returned if no values have been added.
  340.      *
  341.      * @return the standard deviation
  342.      */
  343.     @Override
  344.     public double getStandardDeviation() {
  345.         long size = getN();
  346.         if (computeMoments) {
  347.             if (size > 0) {
  348.                 return size > 1 ? FastMath.sqrt(getVariance()) : 0.0;
  349.             } else {
  350.                 return Double.NaN;
  351.             }
  352.         } else {
  353.             return Double.NaN;
  354.         }
  355.     }

  356.     /**
  357.      * Returns an estimate of the median of the values that have been entered.
  358.      * See {@link RandomPercentile} for a description of the algorithm used for large
  359.      * data streams.
  360.      *
  361.      * @return the median
  362.      */
  363.     public double getMedian() {
  364.         return randomPercentile != null ? randomPercentile.getResult(50d) : Double.NaN;
  365.     }

  366.     /**
  367.      * Returns an estimate of the given percentile of the values that have been entered.
  368.      * See {@link RandomPercentile} for a description of the algorithm used for large
  369.      * data streams.
  370.      *
  371.      * @param percentile the desired percentile (must be between 0 and 100)
  372.      * @return estimated percentile
  373.      */
  374.     public double getPercentile(double percentile) {
  375.         return randomPercentile == null ? Double.NaN : randomPercentile.getResult(percentile);
  376.     }

  377.     /**
  378.      * {@inheritDoc}
  379.      * Statistics are aggregated only when both this and other are maintaining them.  For example,
  380.      * if this.computeMoments is false, but other.computeMoments is true, the moment data in other
  381.      * will be lost.
  382.      */
  383.     @Override
  384.     public void aggregate(StreamingStatistics other) {
  385.         MathUtils.checkNotNull(other);

  386.         if (other.n > 0) {
  387.             this.n += other.n;
  388.             if (computeMoments && other.computeMoments) {
  389.                 this.secondMoment.aggregate(other.secondMoment);
  390.                 this.sumImpl.aggregate(other.sumImpl);
  391.             }
  392.             if (computeExtrema && other.computeExtrema) {
  393.                 this.minImpl.aggregate(other.minImpl);
  394.                 this.maxImpl.aggregate(other.maxImpl);
  395.             }
  396.             if (computeSumOfLogs && other.computeSumOfLogs) {
  397.                 this.sumOfLogsImpl.aggregate(other.sumOfLogsImpl);
  398.             }
  399.             if (computeSumOfSquares && other.computeSumOfSquares) {
  400.                 this.sumOfSquaresImpl.aggregate(other.sumOfSquaresImpl);
  401.             }
  402.             if (randomPercentile != null && other.randomPercentile != null) {
  403.                 this.randomPercentile.aggregate(other.randomPercentile);
  404.             }
  405.         }
  406.     }

  407.     /**
  408.      * Generates a text report displaying summary statistics from values that
  409.      * have been added.
  410.      *
  411.      * @return String with line feeds displaying statistics
  412.      */
  413.     @Override
  414.     public String toString() {
  415.         StringBuilder outBuffer = new StringBuilder(200); // the size is just a wild guess
  416.         String endl = "\n";
  417.         outBuffer.append("StreamingStatistics:").append(endl).
  418.                   append("n: ").append(getN()).append(endl).
  419.                   append("min: ").append(getMin()).append(endl).
  420.                   append("max: ").append(getMax()).append(endl).
  421.                   append("sum: ").append(getSum()).append(endl).
  422.                   append("mean: ").append(getMean()).append(endl).
  423.                   append("variance: ").append(getVariance()).append(endl).
  424.                   append("population variance: ").append(getPopulationVariance()).append(endl).
  425.                   append("standard deviation: ").append(getStandardDeviation()).append(endl).
  426.                   append("geometric mean: ").append(getGeometricMean()).append(endl).
  427.                   append("second moment: ").append(getSecondMoment()).append(endl).
  428.                   append("sum of squares: ").append(getSumOfSquares()).append(endl).
  429.                   append("sum of logs: ").append(getSumOfLogs()).append(endl);
  430.         return outBuffer.toString();
  431.     }

  432.     /**
  433.      * Returns true iff <code>object</code> is a <code>StreamingStatistics</code>
  434.      * instance and all statistics have the same values as this.
  435.      *
  436.      * @param object the object to test equality against.
  437.      * @return true if object equals this
  438.      */
  439.     @Override
  440.     public boolean equals(Object object) {
  441.         if (object == this) {
  442.             return true;
  443.         }
  444.         if (!(object instanceof StreamingStatistics)) {
  445.             return false;
  446.         }
  447.         StreamingStatistics other = (StreamingStatistics)object;
  448.         return other.getN() == getN()                                                     &&
  449.                Precision.equalsIncludingNaN(other.getMax(),           getMax())           &&
  450.                Precision.equalsIncludingNaN(other.getMin(),           getMin())           &&
  451.                Precision.equalsIncludingNaN(other.getSum(),           getSum())           &&
  452.                Precision.equalsIncludingNaN(other.getGeometricMean(), getGeometricMean()) &&
  453.                Precision.equalsIncludingNaN(other.getMean(),          getMean())          &&
  454.                Precision.equalsIncludingNaN(other.getSumOfSquares(),  getSumOfSquares())  &&
  455.                Precision.equalsIncludingNaN(other.getSumOfLogs(),     getSumOfLogs())     &&
  456.                Precision.equalsIncludingNaN(other.getVariance(),      getVariance())      &&
  457.                Precision.equalsIncludingNaN(other.getMedian(),        getMedian());
  458.     }

  459.     /**
  460.      * Returns hash code based on values of statistics.
  461.      * @return hash code
  462.      */
  463.     @Override
  464.     public int hashCode() {
  465.         int result = 31 + MathUtils.hash(getN());
  466.         result = result * 31 + MathUtils.hash(getMax());
  467.         result = result * 31 + MathUtils.hash(getMin());
  468.         result = result * 31 + MathUtils.hash(getSum());
  469.         result = result * 31 + MathUtils.hash(getGeometricMean());
  470.         result = result * 31 + MathUtils.hash(getMean());
  471.         result = result * 31 + MathUtils.hash(getSumOfSquares());
  472.         result = result * 31 + MathUtils.hash(getSumOfLogs());
  473.         result = result * 31 + MathUtils.hash(getVariance());
  474.         result = result * 31 + MathUtils.hash(getMedian());
  475.         return result;
  476.     }

  477.     /**
  478.      * Returns a {@link StreamingStatisticsBuilder} to source configured
  479.      * {@code StreamingStatistics} instances.
  480.      *
  481.      * @return a StreamingStatisticsBuilder instance
  482.      */
  483.     public static StreamingStatisticsBuilder builder() {
  484.         return new StreamingStatisticsBuilder();
  485.     }

  486.     /**
  487.      * Builder for StreamingStatistics instances.
  488.      */
  489.     public static class StreamingStatisticsBuilder {
  490.         /** whether or not moment statistics are maintained by instances created by this factory */
  491.         private boolean computeMoments;
  492.         /** whether or not sum of squares and quadratic mean are maintained by instances created by this factory */
  493.         private boolean computeSumOfSquares;
  494.         /** whether or not sum of logs and geometric mean are maintained by instances created by this factory */
  495.         private boolean computeSumOfLogs;
  496.         /** whether or not min and max are maintained by instances created by this factory */
  497.         private boolean computeExtrema;
  498.         /** bound on quantile estimation error for percentiles.
  499.          * @since 2.3
  500.          */
  501.         private double epsilon;
  502.         /** PRNG used in sampling and merge operations.
  503.          * @since 2.3
  504.          */
  505.         private RandomGenerator randomGenerator;

  506.         /** Simple constructor.
  507.          */
  508.         public StreamingStatisticsBuilder() {
  509.             computeMoments      = true;
  510.             computeSumOfSquares = true;
  511.             computeSumOfLogs    = true;
  512.             computeExtrema      = true;
  513.             percentiles(Double.NaN, null);
  514.         }

  515.         /**
  516.          * Sets the computeMoments setting of the factory
  517.          *
  518.          * @param arg whether or not instances created using {@link #build()} will
  519.          * maintain moment statistics
  520.          * @return a factory with the given computeMoments property set
  521.          */
  522.         public StreamingStatisticsBuilder moments(boolean arg) {
  523.             this.computeMoments = arg;
  524.             return this;
  525.         }

  526.         /**
  527.          * Sets the computeSumOfLogs setting of the factory
  528.          *
  529.          * @param arg whether or not instances created using {@link #build()} will
  530.          * maintain log sums
  531.          * @return a factory with the given computeSumOfLogs property set
  532.          */
  533.         public StreamingStatisticsBuilder sumOfLogs(boolean arg) {
  534.             this.computeSumOfLogs = arg;
  535.             return this;
  536.         }

  537.         /**
  538.          * Sets the computeSumOfSquares setting of the factory.
  539.          *
  540.          * @param arg whether or not instances created using {@link #build()} will
  541.          * maintain sums of squares
  542.          * @return a factory with the given computeSumOfSquares property set
  543.          */
  544.         public StreamingStatisticsBuilder sumOfSquares(boolean arg) {
  545.             this.computeSumOfSquares = arg;
  546.             return this;
  547.         }

  548.         /**
  549.          * Sets the computePercentiles setting of the factory.
  550.          * @param epsilonBound bound on quantile estimation error (see {@link RandomGenerator})
  551.          * @param generator PRNG used in sampling and merge operations
  552.          * @return a factory with the given computePercentiles property set
  553.          * @since 2.3
  554.          */
  555.         public StreamingStatisticsBuilder percentiles(final double epsilonBound, final RandomGenerator generator) {
  556.             this.epsilon         = epsilonBound;
  557.             this.randomGenerator = generator;
  558.             return this;
  559.         }

  560.         /**
  561.          * Sets the computeExtrema setting of the factory.
  562.          *
  563.          * @param arg whether or not instances created using {@link #build()} will
  564.          * compute min and max
  565.          * @return a factory with the given computeExtrema property set
  566.          */
  567.         public StreamingStatisticsBuilder extrema(boolean arg) {
  568.             this.computeExtrema = arg;
  569.             return this;
  570.         }

  571.         /**
  572.          * Builds a StreamingStatistics instance with currently defined properties.
  573.          *
  574.          * @return newly configured StreamingStatistics instance
  575.          */
  576.         public StreamingStatistics build() {
  577.             return new StreamingStatistics(computeMoments,
  578.                                            computeSumOfLogs, computeSumOfSquares,
  579.                                            computeExtrema,
  580.                                            epsilon, randomGenerator);
  581.         }
  582.     }
  583. }