DescriptiveStatistics.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.  *      http://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. package org.apache.commons.math4.legacy.stat.descriptive;

  18. import java.lang.reflect.InvocationTargetException;
  19. import java.util.Arrays;

  20. import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
  21. import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
  22. import org.apache.commons.math4.legacy.exception.NullArgumentException;
  23. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  24. import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean;
  25. import org.apache.commons.math4.legacy.stat.descriptive.moment.Kurtosis;
  26. import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean;
  27. import org.apache.commons.math4.legacy.stat.descriptive.moment.Skewness;
  28. import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance;
  29. import org.apache.commons.math4.legacy.stat.descriptive.rank.Max;
  30. import org.apache.commons.math4.legacy.stat.descriptive.rank.Min;
  31. import org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile;
  32. import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum;
  33. import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares;
  34. import org.apache.commons.math4.core.jdkmath.JdkMath;


  35. /**
  36.  * Maintains a dataset of values of a single variable and computes descriptive
  37.  * statistics based on stored data.
  38.  * <p>
  39.  * The {@link #getWindowSize() windowSize}
  40.  * property sets a limit on the number of values that can be stored in the
  41.  * dataset. The default value, INFINITE_WINDOW, puts no limit on the size of
  42.  * the dataset. This value should be used with caution, as the backing store
  43.  * will grow without bound in this case.  For very large datasets,
  44.  * {@link SummaryStatistics}, which does not store the dataset, should be used
  45.  * instead of this class. If <code>windowSize</code> is not INFINITE_WINDOW and
  46.  * more values are added than can be stored in the dataset, new values are
  47.  * added in a "rolling" manner, with new values replacing the "oldest" values
  48.  * in the dataset.
  49.  * <p>
  50.  * Note: this class is not threadsafe.  Use
  51.  * {@link SynchronizedDescriptiveStatistics} if concurrent access from multiple
  52.  * threads is required.
  53.  */
  54. public class DescriptiveStatistics implements StatisticalSummary {

  55.     /**
  56.      * Represents an infinite window size.  When the {@link #getWindowSize()}
  57.      * returns this value, there is no limit to the number of data values
  58.      * that can be stored in the dataset.
  59.      */
  60.     public static final int INFINITE_WINDOW = -1;

  61.     /** Name of the setQuantile method. */
  62.     private static final String SET_QUANTILE_METHOD_NAME = "setQuantile";

  63.     /** hold the window size. */
  64.     private int windowSize = INFINITE_WINDOW;

  65.     /** Stored data values. */
  66.     private ResizableDoubleArray eDA = new ResizableDoubleArray();

  67.     /** Mean statistic implementation - can be reset by setter. */
  68.     private UnivariateStatistic meanImpl = new Mean();

  69.     /** Geometric mean statistic implementation - can be reset by setter. */
  70.     private UnivariateStatistic geometricMeanImpl = new GeometricMean();

  71.     /** Kurtosis statistic implementation - can be reset by setter. */
  72.     private UnivariateStatistic kurtosisImpl = new Kurtosis();

  73.     /** Maximum statistic implementation - can be reset by setter. */
  74.     private UnivariateStatistic maxImpl = new Max();

  75.     /** Minimum statistic implementation - can be reset by setter. */
  76.     private UnivariateStatistic minImpl = new Min();

  77.     /** Percentile statistic implementation - can be reset by setter. */
  78.     private UnivariateStatistic percentileImpl = new Percentile();

  79.     /** Skewness statistic implementation - can be reset by setter. */
  80.     private UnivariateStatistic skewnessImpl = new Skewness();

  81.     /** Variance statistic implementation - can be reset by setter. */
  82.     private UnivariateStatistic varianceImpl = new Variance();

  83.     /** Sum of squares statistic implementation - can be reset by setter. */
  84.     private UnivariateStatistic sumsqImpl = new SumOfSquares();

  85.     /** Sum statistic implementation - can be reset by setter. */
  86.     private UnivariateStatistic sumImpl = new Sum();

  87.     /**
  88.      * Construct a {@code DescriptiveStatistics} instance with an infinite
  89.      * window.
  90.      */
  91.     public DescriptiveStatistics() {
  92.     }

  93.     /**
  94.      * Construct a {@code DescriptiveStatistics} instance with the specified
  95.      * window.
  96.      *
  97.      * @param window the window size.
  98.      * @throws MathIllegalArgumentException if window size is less than 1 but
  99.      * not equal to {@link #INFINITE_WINDOW}
  100.      */
  101.     public DescriptiveStatistics(int window) throws MathIllegalArgumentException {
  102.         setWindowSize(window);
  103.     }

  104.     /**
  105.      * Construct a {@code DescriptiveStatistics} instance with an infinite
  106.      * window and the initial data values in {@code initialDoubleArray}.
  107.      * If {@code initialDoubleArray} is {@code null}, then this constructor
  108.      * corresponds to the {@link #DescriptiveStatistics() default constructor}.
  109.      *
  110.      * @param initialDoubleArray the initial double[].
  111.      */
  112.     public DescriptiveStatistics(double[] initialDoubleArray) {
  113.         if (initialDoubleArray != null) {
  114.             eDA = new ResizableDoubleArray(initialDoubleArray);
  115.         }
  116.     }

  117.     /**
  118.      * Construct a DescriptiveStatistics instance with an infinite window
  119.      * and the initial data values in {@code initialDoubleArray}.
  120.      * If {@code initialDoubleArray} is {@code null}, then this constructor
  121.      * corresponds to {@link #DescriptiveStatistics() }.
  122.      *
  123.      * @param initialDoubleArray the initial Double[].
  124.      */
  125.     public DescriptiveStatistics(Double[] initialDoubleArray) {
  126.         if (initialDoubleArray != null) {
  127.             eDA = new ResizableDoubleArray(initialDoubleArray.length);
  128.             for(double initialValue : initialDoubleArray) {
  129.                 eDA.addElement(initialValue);
  130.             }
  131.         }
  132.     }

  133.     /**
  134.      * Copy constructor. Construct a new {@code DescriptiveStatistics} instance
  135.      * that is a copy of {@code original}.
  136.      *
  137.      * @param original DescriptiveStatistics instance to copy
  138.      * @throws NullArgumentException if original is null
  139.      */
  140.     public DescriptiveStatistics(DescriptiveStatistics original) throws NullArgumentException {
  141.         copy(original, this);
  142.     }

  143.     /**
  144.      * Adds the value to the dataset. If the dataset is at the maximum size
  145.      * (i.e., the number of stored elements equals the currently configured
  146.      * windowSize), the first (oldest) element in the dataset is discarded
  147.      * to make room for the new value.
  148.      *
  149.      * @param v the value to be added
  150.      */
  151.     public void addValue(double v) {
  152.         if (windowSize != INFINITE_WINDOW) {
  153.             if (getN() == windowSize) {
  154.                 eDA.addElementRolling(v);
  155.             } else if (getN() < windowSize) {
  156.                 eDA.addElement(v);
  157.             }
  158.         } else {
  159.             eDA.addElement(v);
  160.         }
  161.     }

  162.     /**
  163.      * Removes the most recent value from the dataset.
  164.      *
  165.      * @throws MathIllegalStateException if there are no elements stored
  166.      */
  167.     public void removeMostRecentValue() throws MathIllegalStateException {
  168.         try {
  169.             eDA.discardMostRecentElements(1);
  170.         } catch (MathIllegalArgumentException ex) {
  171.             throw new MathIllegalStateException(LocalizedFormats.NO_DATA);
  172.         }
  173.     }

  174.     /**
  175.      * Replaces the most recently stored value with the given value.
  176.      * There must be at least one element stored to call this method.
  177.      *
  178.      * @param v the value to replace the most recent stored value
  179.      * @return replaced value
  180.      * @throws MathIllegalStateException if there are no elements stored
  181.      */
  182.     public double replaceMostRecentValue(double v) throws MathIllegalStateException {
  183.         return eDA.substituteMostRecentElement(v);
  184.     }

  185.     /**
  186.      * Returns the <a href="http://www.xycoon.com/arithmetic_mean.htm">
  187.      * arithmetic mean </a> of the available values.
  188.      * @return The mean or Double.NaN if no values have been added.
  189.      */
  190.     @Override
  191.     public double getMean() {
  192.         return apply(meanImpl);
  193.     }

  194.     /**
  195.      * Returns the <a href="http://www.xycoon.com/geometric_mean.htm">
  196.      * geometric mean </a> of the available values.
  197.      * <p>
  198.      * See {@link GeometricMean} for details on the computing algorithm.</p>
  199.      *
  200.      * @return The geometricMean, Double.NaN if no values have been added,
  201.      * or if any negative values have been added.
  202.      */
  203.     public double getGeometricMean() {
  204.         return apply(geometricMeanImpl);
  205.     }

  206.     /**
  207.      * Returns the (sample) variance of the available values.
  208.      *
  209.      * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in
  210.      * the denominator).  Use {@link #getPopulationVariance()} for the non-bias-corrected
  211.      * population variance.</p>
  212.      *
  213.      * @return The variance, Double.NaN if no values have been added
  214.      * or 0.0 for a single value set.
  215.      */
  216.     @Override
  217.     public double getVariance() {
  218.         return apply(varianceImpl);
  219.     }

  220.     /**
  221.      * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
  222.      * population variance</a> of the available values.
  223.      *
  224.      * @return The population variance, Double.NaN if no values have been added,
  225.      * or 0.0 for a single value set.
  226.      */
  227.     public double getPopulationVariance() {
  228.         return apply(new Variance(false));
  229.     }

  230.     /**
  231.      * Returns the standard deviation of the available values.
  232.      * @return The standard deviation, Double.NaN if no values have been added
  233.      * or 0.0 for a single value set.
  234.      */
  235.     @Override
  236.     public double getStandardDeviation() {
  237.         double stdDev = Double.NaN;
  238.         if (getN() > 0) {
  239.             if (getN() > 1) {
  240.                 stdDev = JdkMath.sqrt(getVariance());
  241.             } else {
  242.                 stdDev = 0.0;
  243.             }
  244.         }
  245.         return stdDev;
  246.     }

  247.     /**
  248.      * Returns the quadratic mean, a.k.a.
  249.      * <a href="http://mathworld.wolfram.com/Root-Mean-Square.html">
  250.      * root-mean-square</a> of the available values
  251.      * @return The quadratic mean or {@code Double.NaN} if no values
  252.      * have been added.
  253.      */
  254.     public double getQuadraticMean() {
  255.         final long n = getN();
  256.         return n > 0 ? JdkMath.sqrt(getSumsq() / n) : Double.NaN;
  257.     }

  258.     /**
  259.      * Returns the skewness of the available values. Skewness is a
  260.      * measure of the asymmetry of a given distribution.
  261.      *
  262.      * @return The skewness, Double.NaN if less than 3 values have been added.
  263.      */
  264.     public double getSkewness() {
  265.         return apply(skewnessImpl);
  266.     }

  267.     /**
  268.      * Returns the Kurtosis of the available values. Kurtosis is a
  269.      * measure of the "peakedness" of a distribution.
  270.      *
  271.      * @return The kurtosis, Double.NaN if less than 4 values have been added.
  272.      */
  273.     public double getKurtosis() {
  274.         return apply(kurtosisImpl);
  275.     }

  276.     /**
  277.      * Returns the maximum of the available values.
  278.      * @return The max or Double.NaN if no values have been added.
  279.      */
  280.     @Override
  281.     public double getMax() {
  282.         return apply(maxImpl);
  283.     }

  284.     /**
  285.     * Returns the minimum of the available values.
  286.     * @return The min or Double.NaN if no values have been added.
  287.     */
  288.     @Override
  289.     public double getMin() {
  290.         return apply(minImpl);
  291.     }

  292.     /**
  293.      * Returns the number of available values.
  294.      * @return The number of available values
  295.      */
  296.     @Override
  297.     public long getN() {
  298.         return eDA.getNumElements();
  299.     }

  300.     /**
  301.      * Returns the sum of the values that have been added to Univariate.
  302.      * @return The sum or Double.NaN if no values have been added
  303.      */
  304.     @Override
  305.     public double getSum() {
  306.         return apply(sumImpl);
  307.     }

  308.     /**
  309.      * Returns the sum of the squares of the available values.
  310.      * @return The sum of the squares or Double.NaN if no
  311.      * values have been added.
  312.      */
  313.     public double getSumsq() {
  314.         return apply(sumsqImpl);
  315.     }

  316.     /**
  317.      * Resets all statistics and storage.
  318.      */
  319.     public void clear() {
  320.         eDA.clear();
  321.     }


  322.     /**
  323.      * Returns the maximum number of values that can be stored in the
  324.      * dataset, or INFINITE_WINDOW (-1) if there is no limit.
  325.      *
  326.      * @return The current window size or -1 if its Infinite.
  327.      */
  328.     public int getWindowSize() {
  329.         return windowSize;
  330.     }

  331.     /**
  332.      * WindowSize controls the number of values that contribute to the
  333.      * reported statistics.  For example, if windowSize is set to 3 and the
  334.      * values {1,2,3,4,5} have been added <strong> in that order</strong> then
  335.      * the <i>available values</i> are {3,4,5} and all reported statistics will
  336.      * be based on these values. If {@code windowSize} is decreased as a result
  337.      * of this call and there are more than the new value of elements in the
  338.      * current dataset, values from the front of the array are discarded to
  339.      * reduce the dataset to {@code windowSize} elements.
  340.      *
  341.      * @param windowSize sets the size of the window.
  342.      * @throws MathIllegalArgumentException if window size is less than 1 but
  343.      * not equal to {@link #INFINITE_WINDOW}
  344.      */
  345.     public void setWindowSize(int windowSize) throws MathIllegalArgumentException {
  346.         if (windowSize < 1 && windowSize != INFINITE_WINDOW) {
  347.             throw new MathIllegalArgumentException(
  348.                     LocalizedFormats.NOT_POSITIVE_WINDOW_SIZE, windowSize);
  349.         }

  350.         this.windowSize = windowSize;

  351.         // We need to check to see if we need to discard elements
  352.         // from the front of the array.  If the windowSize is less than
  353.         // the current number of elements.
  354.         if (windowSize != INFINITE_WINDOW && windowSize < eDA.getNumElements()) {
  355.             eDA.discardFrontElements(eDA.getNumElements() - windowSize);
  356.         }
  357.     }

  358.     /**
  359.      * Returns the current set of values in an array of double primitives.
  360.      * The order of addition is preserved.  The returned array is a fresh
  361.      * copy of the underlying data -- i.e., it is not a reference to the
  362.      * stored data.
  363.      *
  364.      * @return returns the current set of numbers in the order in which they
  365.      *         were added to this set
  366.      */
  367.     public double[] getValues() {
  368.         return eDA.getElements();
  369.     }

  370.     /**
  371.      * Returns the current set of values in an array of double primitives,
  372.      * sorted in ascending order.  The returned array is a fresh
  373.      * copy of the underlying data -- i.e., it is not a reference to the
  374.      * stored data.
  375.      * @return returns the current set of
  376.      * numbers sorted in ascending order
  377.      */
  378.     public double[] getSortedValues() {
  379.         double[] sort = getValues();
  380.         Arrays.sort(sort);
  381.         return sort;
  382.     }

  383.     /**
  384.      * Returns the element at the specified index.
  385.      * @param index The Index of the element
  386.      * @return return the element at the specified index
  387.      */
  388.     public double getElement(int index) {
  389.         return eDA.getElement(index);
  390.     }

  391.     /**
  392.      * Returns an estimate for the pth percentile of the stored values.
  393.      * <p>
  394.      * The implementation provided here follows the first estimation procedure presented
  395.      * <a href="http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm">here.</a>
  396.      * </p><p>
  397.      * <strong>Preconditions</strong>:<ul>
  398.      * <li><code>0 &lt; p &le; 100</code> (otherwise an
  399.      * <code>MathIllegalArgumentException</code> is thrown)</li>
  400.      * <li>at least one value must be stored (returns <code>Double.NaN
  401.      *     </code> otherwise)</li>
  402.      * </ul>
  403.      *
  404.      * @param p the requested percentile (scaled from 0 - 100)
  405.      * @return An estimate for the pth percentile of the stored data
  406.      * @throws MathIllegalStateException if percentile implementation has been
  407.      *  overridden and the supplied implementation does not support setQuantile
  408.      * @throws MathIllegalArgumentException if p is not a valid quantile
  409.      */
  410.     public double getPercentile(double p) throws MathIllegalStateException, MathIllegalArgumentException {
  411.         if (percentileImpl instanceof Percentile) {
  412.             ((Percentile) percentileImpl).setQuantile(p);
  413.         } else {
  414.             try {
  415.                 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME,
  416.                         new Class[] {Double.TYPE}).invoke(percentileImpl,
  417.                                 new Object[] {Double.valueOf(p)});
  418.             } catch (NoSuchMethodException e1) { // Setter guard should prevent
  419.                 throw new MathIllegalStateException(
  420.                       LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD,
  421.                       percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME);
  422.             } catch (IllegalAccessException e2) {
  423.                 throw new MathIllegalStateException(
  424.                       LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD,
  425.                       SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName());
  426.             } catch (InvocationTargetException e3) {
  427.                 throw new IllegalStateException(e3.getCause());
  428.             }
  429.         }
  430.         return apply(percentileImpl);
  431.     }

  432.     /**
  433.      * Generates a text report displaying univariate statistics from values
  434.      * that have been added.  Each statistic is displayed on a separate
  435.      * line.
  436.      *
  437.      * @return String with line feeds displaying statistics
  438.      */
  439.     @Override
  440.     public String toString() {
  441.         StringBuilder outBuffer = new StringBuilder();
  442.         String endl = "\n";
  443.         outBuffer.append("DescriptiveStatistics:").append(endl);
  444.         outBuffer.append("n: ").append(getN()).append(endl);
  445.         outBuffer.append("min: ").append(getMin()).append(endl);
  446.         outBuffer.append("max: ").append(getMax()).append(endl);
  447.         outBuffer.append("mean: ").append(getMean()).append(endl);
  448.         outBuffer.append("std dev: ").append(getStandardDeviation())
  449.             .append(endl);
  450.         try {
  451.             // No catch for MIAE because actual parameter is valid below
  452.             outBuffer.append("median: ").append(getPercentile(50)).append(endl);
  453.         } catch (MathIllegalStateException ex) {
  454.             outBuffer.append("median: unavailable").append(endl);
  455.         }
  456.         outBuffer.append("skewness: ").append(getSkewness()).append(endl);
  457.         outBuffer.append("kurtosis: ").append(getKurtosis()).append(endl);
  458.         return outBuffer.toString();
  459.     }

  460.     /**
  461.      * Apply the given statistic to the data associated with this set of statistics.
  462.      * @param stat the statistic to apply
  463.      * @return the computed value of the statistic.
  464.      */
  465.     public double apply(UnivariateStatistic stat) {
  466.         // No try-catch or advertised exception here because arguments are guaranteed valid
  467.         return eDA.compute(stat);
  468.     }

  469.     // Implementation getters and setter

  470.     /**
  471.      * Returns the currently configured mean implementation.
  472.      *
  473.      * @return the UnivariateStatistic implementing the mean
  474.      * @since 1.2
  475.      */
  476.     public synchronized UnivariateStatistic getMeanImpl() {
  477.         return meanImpl;
  478.     }

  479.     /**
  480.      * <p>Sets the implementation for the mean.</p>
  481.      *
  482.      * @param meanImpl the UnivariateStatistic instance to use
  483.      * for computing the mean
  484.      * @since 1.2
  485.      */
  486.     public synchronized void setMeanImpl(UnivariateStatistic meanImpl) {
  487.         this.meanImpl = meanImpl;
  488.     }

  489.     /**
  490.      * Returns the currently configured geometric mean implementation.
  491.      *
  492.      * @return the UnivariateStatistic implementing the geometric mean
  493.      * @since 1.2
  494.      */
  495.     public synchronized UnivariateStatistic getGeometricMeanImpl() {
  496.         return geometricMeanImpl;
  497.     }

  498.     /**
  499.      * Sets the implementation for the geometric mean.
  500.      *
  501.      * @param geometricMeanImpl the UnivariateStatistic instance to use
  502.      * for computing the geometric mean
  503.      * @since 1.2
  504.      */
  505.     public synchronized void setGeometricMeanImpl(
  506.             UnivariateStatistic geometricMeanImpl) {
  507.         this.geometricMeanImpl = geometricMeanImpl;
  508.     }

  509.     /**
  510.      * Returns the currently configured kurtosis implementation.
  511.      *
  512.      * @return the UnivariateStatistic implementing the kurtosis
  513.      * @since 1.2
  514.      */
  515.     public synchronized UnivariateStatistic getKurtosisImpl() {
  516.         return kurtosisImpl;
  517.     }

  518.     /**
  519.      * Sets the implementation for the kurtosis.
  520.      *
  521.      * @param kurtosisImpl the UnivariateStatistic instance to use
  522.      * for computing the kurtosis
  523.      * @since 1.2
  524.      */
  525.     public synchronized void setKurtosisImpl(UnivariateStatistic kurtosisImpl) {
  526.         this.kurtosisImpl = kurtosisImpl;
  527.     }

  528.     /**
  529.      * Returns the currently configured maximum implementation.
  530.      *
  531.      * @return the UnivariateStatistic implementing the maximum
  532.      * @since 1.2
  533.      */
  534.     public synchronized UnivariateStatistic getMaxImpl() {
  535.         return maxImpl;
  536.     }

  537.     /**
  538.      * Sets the implementation for the maximum.
  539.      *
  540.      * @param maxImpl the UnivariateStatistic instance to use
  541.      * for computing the maximum
  542.      * @since 1.2
  543.      */
  544.     public synchronized void setMaxImpl(UnivariateStatistic maxImpl) {
  545.         this.maxImpl = maxImpl;
  546.     }

  547.     /**
  548.      * Returns the currently configured minimum implementation.
  549.      *
  550.      * @return the UnivariateStatistic implementing the minimum
  551.      * @since 1.2
  552.      */
  553.     public synchronized UnivariateStatistic getMinImpl() {
  554.         return minImpl;
  555.     }

  556.     /**
  557.      * Sets the implementation for the minimum.
  558.      *
  559.      * @param minImpl the UnivariateStatistic instance to use
  560.      * for computing the minimum
  561.      * @since 1.2
  562.      */
  563.     public synchronized void setMinImpl(UnivariateStatistic minImpl) {
  564.         this.minImpl = minImpl;
  565.     }

  566.     /**
  567.      * Returns the currently configured percentile implementation.
  568.      *
  569.      * @return the UnivariateStatistic implementing the percentile
  570.      * @since 1.2
  571.      */
  572.     public synchronized UnivariateStatistic getPercentileImpl() {
  573.         return percentileImpl;
  574.     }

  575.     /**
  576.      * Sets the implementation to be used by {@link #getPercentile(double)}.
  577.      * The supplied <code>UnivariateStatistic</code> must provide a
  578.      * <code>setQuantile(double)</code> method; otherwise
  579.      * <code>IllegalArgumentException</code> is thrown.
  580.      *
  581.      * @param percentileImpl the percentileImpl to set
  582.      * @throws MathIllegalArgumentException if the supplied implementation does not
  583.      *  provide a <code>setQuantile</code> method
  584.      * @since 1.2
  585.      */
  586.     public synchronized void setPercentileImpl(UnivariateStatistic percentileImpl)
  587.     throws MathIllegalArgumentException {
  588.         try {
  589.             percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME,
  590.                     new Class[] {Double.TYPE}).invoke(percentileImpl,
  591.                             new Object[] {Double.valueOf(50.0d)});
  592.         } catch (NoSuchMethodException e1) {
  593.             throw new MathIllegalArgumentException(
  594.                   LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD,
  595.                   percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME);
  596.         } catch (IllegalAccessException e2) {
  597.             throw new MathIllegalArgumentException(
  598.                   LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD,
  599.                   SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName());
  600.         } catch (InvocationTargetException e3) {
  601.             throw new IllegalArgumentException(e3.getCause());
  602.         }
  603.         this.percentileImpl = percentileImpl;
  604.     }

  605.     /**
  606.      * Returns the currently configured skewness implementation.
  607.      *
  608.      * @return the UnivariateStatistic implementing the skewness
  609.      * @since 1.2
  610.      */
  611.     public synchronized UnivariateStatistic getSkewnessImpl() {
  612.         return skewnessImpl;
  613.     }

  614.     /**
  615.      * Sets the implementation for the skewness.
  616.      *
  617.      * @param skewnessImpl the UnivariateStatistic instance to use
  618.      * for computing the skewness
  619.      * @since 1.2
  620.      */
  621.     public synchronized void setSkewnessImpl(
  622.             UnivariateStatistic skewnessImpl) {
  623.         this.skewnessImpl = skewnessImpl;
  624.     }

  625.     /**
  626.      * Returns the currently configured variance implementation.
  627.      *
  628.      * @return the UnivariateStatistic implementing the variance
  629.      * @since 1.2
  630.      */
  631.     public synchronized UnivariateStatistic getVarianceImpl() {
  632.         return varianceImpl;
  633.     }

  634.     /**
  635.      * Sets the implementation for the variance.
  636.      *
  637.      * @param varianceImpl the UnivariateStatistic instance to use
  638.      * for computing the variance
  639.      * @since 1.2
  640.      */
  641.     public synchronized void setVarianceImpl(
  642.             UnivariateStatistic varianceImpl) {
  643.         this.varianceImpl = varianceImpl;
  644.     }

  645.     /**
  646.      * Returns the currently configured sum of squares implementation.
  647.      *
  648.      * @return the UnivariateStatistic implementing the sum of squares
  649.      * @since 1.2
  650.      */
  651.     public synchronized UnivariateStatistic getSumsqImpl() {
  652.         return sumsqImpl;
  653.     }

  654.     /**
  655.      * Sets the implementation for the sum of squares.
  656.      *
  657.      * @param sumsqImpl the UnivariateStatistic instance to use
  658.      * for computing the sum of squares
  659.      * @since 1.2
  660.      */
  661.     public synchronized void setSumsqImpl(UnivariateStatistic sumsqImpl) {
  662.         this.sumsqImpl = sumsqImpl;
  663.     }

  664.     /**
  665.      * Returns the currently configured sum implementation.
  666.      *
  667.      * @return the UnivariateStatistic implementing the sum
  668.      * @since 1.2
  669.      */
  670.     public synchronized UnivariateStatistic getSumImpl() {
  671.         return sumImpl;
  672.     }

  673.     /**
  674.      * Sets the implementation for the sum.
  675.      *
  676.      * @param sumImpl the UnivariateStatistic instance to use
  677.      * for computing the sum
  678.      * @since 1.2
  679.      */
  680.     public synchronized void setSumImpl(UnivariateStatistic sumImpl) {
  681.         this.sumImpl = sumImpl;
  682.     }

  683.     /**
  684.      * Returns a copy of this DescriptiveStatistics instance with the same internal state.
  685.      *
  686.      * @return a copy of this
  687.      */
  688.     public DescriptiveStatistics copy() {
  689.         DescriptiveStatistics result = new DescriptiveStatistics();
  690.         // No try-catch or advertised exception because parms are guaranteed valid
  691.         copy(this, result);
  692.         return result;
  693.     }

  694.     /**
  695.      * Copies source to dest.
  696.      * <p>Neither source nor dest can be null.</p>
  697.      *
  698.      * @param source DescriptiveStatistics to copy
  699.      * @param dest DescriptiveStatistics to copy to
  700.      * @throws NullArgumentException if either source or dest is null
  701.      */
  702.     public static void copy(DescriptiveStatistics source, DescriptiveStatistics dest)
  703.         throws NullArgumentException {
  704.         NullArgumentException.check(source);
  705.         NullArgumentException.check(dest);
  706.         // Copy data and window size
  707.         dest.eDA = source.eDA.copy();
  708.         dest.windowSize = source.windowSize;

  709.         // Copy implementations
  710.         dest.maxImpl = source.maxImpl.copy();
  711.         dest.meanImpl = source.meanImpl.copy();
  712.         dest.minImpl = source.minImpl.copy();
  713.         dest.sumImpl = source.sumImpl.copy();
  714.         dest.varianceImpl = source.varianceImpl.copy();
  715.         dest.sumsqImpl = source.sumsqImpl.copy();
  716.         dest.geometricMeanImpl = source.geometricMeanImpl.copy();
  717.         dest.kurtosisImpl = source.kurtosisImpl;
  718.         dest.skewnessImpl = source.skewnessImpl;
  719.         dest.percentileImpl = source.percentileImpl;
  720.     }
  721. }