MultivariateSummaryStatistics.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.util.Arrays;

  19. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  20. import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
  21. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  22. import org.apache.commons.math4.legacy.linear.RealMatrix;
  23. import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean;
  24. import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean;
  25. import org.apache.commons.math4.legacy.stat.descriptive.moment.VectorialCovariance;
  26. import org.apache.commons.math4.legacy.stat.descriptive.rank.Max;
  27. import org.apache.commons.math4.legacy.stat.descriptive.rank.Min;
  28. import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum;
  29. import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs;
  30. import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares;
  31. import org.apache.commons.math4.core.jdkmath.JdkMath;
  32. import org.apache.commons.math4.legacy.core.MathArrays;
  33. import org.apache.commons.numbers.core.Precision;

  34. /**
  35.  * <p>Computes summary statistics for a stream of n-tuples added using the
  36.  * {@link #addValue(double[]) addValue} method. The data values are not stored
  37.  * in memory, so this class can be used to compute statistics for very large
  38.  * n-tuple streams.</p>
  39.  *
  40.  * <p>The {@link StorelessUnivariateStatistic} instances used to maintain
  41.  * summary state and compute statistics are configurable via setters.
  42.  * For example, the default implementation for the mean can be overridden by
  43.  * calling {@link #setMeanImpl(StorelessUnivariateStatistic[])}. Actual
  44.  * parameters to these methods must implement the
  45.  * {@link StorelessUnivariateStatistic} interface and configuration must be
  46.  * completed before <code>addValue</code> is called. No configuration is
  47.  * necessary to use the default, commons-math provided implementations.</p>
  48.  *
  49.  * <p>To compute statistics for a stream of n-tuples, construct a
  50.  * MultivariateStatistics instance with dimension n and then use
  51.  * {@link #addValue(double[])} to add n-tuples. The <code>getXxx</code>
  52.  * methods where Xxx is a statistic return an array of <code>double</code>
  53.  * values, where for <code>i = 0,...,n-1</code> the i<sup>th</sup> array element is the
  54.  * value of the given statistic for data range consisting of the i<sup>th</sup> element of
  55.  * each of the input n-tuples.  For example, if <code>addValue</code> is called
  56.  * with actual parameters {0, 1, 2}, then {3, 4, 5} and finally {6, 7, 8},
  57.  * <code>getSum</code> will return a three-element array with values
  58.  * {0+3+6, 1+4+7, 2+5+8}</p>
  59.  *
  60.  * <p>Note: This class is not thread-safe. Use
  61.  * {@link SynchronizedMultivariateSummaryStatistics} if concurrent access from multiple
  62.  * threads is required.</p>
  63.  *
  64.  * @since 1.2
  65.  */
  66. public class MultivariateSummaryStatistics
  67.     implements StatisticalMultivariateSummary {
  68.     /** Dimension of the data. */
  69.     private final int k;

  70.     /** Count of values that have been added. */
  71.     private long n;

  72.     /** Sum statistic implementation - can be reset by setter. */
  73.     private final StorelessUnivariateStatistic[] sumImpl;

  74.     /** Sum of squares statistic implementation - can be reset by setter. */
  75.     private final StorelessUnivariateStatistic[] sumSqImpl;

  76.     /** Minimum statistic implementation - can be reset by setter. */
  77.     private final StorelessUnivariateStatistic[] minImpl;

  78.     /** Maximum statistic implementation - can be reset by setter. */
  79.     private final StorelessUnivariateStatistic[] maxImpl;

  80.     /** Sum of log statistic implementation - can be reset by setter. */
  81.     private final StorelessUnivariateStatistic[] sumLogImpl;

  82.     /** Geometric mean statistic implementation - can be reset by setter. */
  83.     private final StorelessUnivariateStatistic[] geoMeanImpl;

  84.     /** Mean statistic implementation - can be reset by setter. */
  85.     private final StorelessUnivariateStatistic[] meanImpl;

  86.     /** Covariance statistic implementation - cannot be reset. */
  87.     private final VectorialCovariance covarianceImpl;

  88.     /**
  89.      * Construct a MultivariateSummaryStatistics instance.
  90.      * @param k dimension of the data
  91.      * @param isCovarianceBiasCorrected if true, the unbiased sample
  92.      * covariance is computed, otherwise the biased population covariance
  93.      * is computed
  94.      */
  95.     public MultivariateSummaryStatistics(int k, boolean isCovarianceBiasCorrected) {
  96.         this.k = k;

  97.         sumImpl     = new StorelessUnivariateStatistic[k];
  98.         sumSqImpl   = new StorelessUnivariateStatistic[k];
  99.         minImpl     = new StorelessUnivariateStatistic[k];
  100.         maxImpl     = new StorelessUnivariateStatistic[k];
  101.         sumLogImpl  = new StorelessUnivariateStatistic[k];
  102.         geoMeanImpl = new StorelessUnivariateStatistic[k];
  103.         meanImpl    = new StorelessUnivariateStatistic[k];

  104.         for (int i = 0; i < k; ++i) {
  105.             sumImpl[i]     = new Sum();
  106.             sumSqImpl[i]   = new SumOfSquares();
  107.             minImpl[i]     = new Min();
  108.             maxImpl[i]     = new Max();
  109.             sumLogImpl[i]  = new SumOfLogs();
  110.             geoMeanImpl[i] = new GeometricMean();
  111.             meanImpl[i]    = new Mean();
  112.         }

  113.         covarianceImpl =
  114.             new VectorialCovariance(k, isCovarianceBiasCorrected);
  115.     }

  116.     /**
  117.      * Add an n-tuple to the data.
  118.      *
  119.      * @param value  the n-tuple to add
  120.      * @throws DimensionMismatchException if the length of the array
  121.      * does not match the one used at construction
  122.      */
  123.     public void addValue(double[] value) throws DimensionMismatchException {
  124.         checkDimension(value.length);
  125.         for (int i = 0; i < k; ++i) {
  126.             double v = value[i];
  127.             sumImpl[i].increment(v);
  128.             sumSqImpl[i].increment(v);
  129.             minImpl[i].increment(v);
  130.             maxImpl[i].increment(v);
  131.             sumLogImpl[i].increment(v);
  132.             geoMeanImpl[i].increment(v);
  133.             meanImpl[i].increment(v);
  134.         }
  135.         covarianceImpl.increment(value);
  136.         n++;
  137.     }

  138.     /**
  139.      * Returns the dimension of the data.
  140.      * @return The dimension of the data
  141.      */
  142.     @Override
  143.     public int getDimension() {
  144.         return k;
  145.     }

  146.     /**
  147.      * Returns the number of available values.
  148.      * @return The number of available values
  149.      */
  150.     @Override
  151.     public long getN() {
  152.         return n;
  153.     }

  154.     /**
  155.      * Returns an array of the results of a statistic.
  156.      * @param stats univariate statistic array
  157.      * @return results array
  158.      */
  159.     private double[] getResults(StorelessUnivariateStatistic[] stats) {
  160.         double[] results = new double[stats.length];
  161.         for (int i = 0; i < results.length; ++i) {
  162.             results[i] = stats[i].getResult();
  163.         }
  164.         return results;
  165.     }

  166.     /**
  167.      * Returns an array whose i<sup>th</sup> entry is the sum of the.
  168.      * i<sup>th</sup> entries of the arrays that have been added using
  169.      * {@link #addValue(double[])}
  170.      *
  171.      * @return the array of component sums
  172.      */
  173.     @Override
  174.     public double[] getSum() {
  175.         return getResults(sumImpl);
  176.     }

  177.     /**
  178.      * Returns an array whose i<sup>th</sup> entry is the sum of squares of the.
  179.      * i<sup>th</sup> entries of the arrays that have been added using
  180.      * {@link #addValue(double[])}
  181.      *
  182.      * @return the array of component sums of squares
  183.      */
  184.     @Override
  185.     public double[] getSumSq() {
  186.         return getResults(sumSqImpl);
  187.     }

  188.     /**
  189.      * Returns an array whose i<sup>th</sup> entry is the sum of logs of the.
  190.      * i<sup>th</sup> entries of the arrays that have been added using
  191.      * {@link #addValue(double[])}
  192.      *
  193.      * @return the array of component log sums
  194.      */
  195.     @Override
  196.     public double[] getSumLog() {
  197.         return getResults(sumLogImpl);
  198.     }

  199.     /**
  200.      * Returns an array whose i<sup>th</sup> entry is the mean of the.
  201.      * i<sup>th</sup> entries of the arrays that have been added using
  202.      * {@link #addValue(double[])}
  203.      *
  204.      * @return the array of component means
  205.      */
  206.     @Override
  207.     public double[] getMean() {
  208.         return getResults(meanImpl);
  209.     }

  210.     /**
  211.      * Returns an array whose i<sup>th</sup> entry is the standard deviation of the.
  212.      * i<sup>th</sup> entries of the arrays that have been added using
  213.      * {@link #addValue(double[])}
  214.      *
  215.      * @return the array of component standard deviations
  216.      */
  217.     @Override
  218.     public double[] getStandardDeviation() {
  219.         double[] stdDev = new double[k];
  220.         if (getN() < 1) {
  221.             Arrays.fill(stdDev, Double.NaN);
  222.         } else if (getN() < 2) {
  223.             Arrays.fill(stdDev, 0.0);
  224.         } else {
  225.             RealMatrix matrix = covarianceImpl.getResult();
  226.             for (int i = 0; i < k; ++i) {
  227.                 stdDev[i] = JdkMath.sqrt(matrix.getEntry(i, i));
  228.             }
  229.         }
  230.         return stdDev;
  231.     }

  232.     /**
  233.      * Returns the covariance matrix of the values that have been added.
  234.      *
  235.      * @return the covariance matrix
  236.      */
  237.     @Override
  238.     public RealMatrix getCovariance() {
  239.         return covarianceImpl.getResult();
  240.     }

  241.     /**
  242.      * Returns an array whose i<sup>th</sup> entry is the maximum of the.
  243.      * i<sup>th</sup> entries of the arrays that have been added using
  244.      * {@link #addValue(double[])}
  245.      *
  246.      * @return the array of component maxima
  247.      */
  248.     @Override
  249.     public double[] getMax() {
  250.         return getResults(maxImpl);
  251.     }

  252.     /**
  253.      * Returns an array whose i<sup>th</sup> entry is the minimum of the.
  254.      * i<sup>th</sup> entries of the arrays that have been added using
  255.      * {@link #addValue(double[])}
  256.      *
  257.      * @return the array of component minima
  258.      */
  259.     @Override
  260.     public double[] getMin() {
  261.         return getResults(minImpl);
  262.     }

  263.     /**
  264.      * Returns an array whose i<sup>th</sup> entry is the geometric mean of the.
  265.      * i<sup>th</sup> entries of the arrays that have been added using
  266.      * {@link #addValue(double[])}
  267.      *
  268.      * @return the array of component geometric means
  269.      */
  270.     @Override
  271.     public double[] getGeometricMean() {
  272.         return getResults(geoMeanImpl);
  273.     }

  274.     /**
  275.      * Generates a text report displaying
  276.      * summary statistics from values that
  277.      * have been added.
  278.      * @return String with line feeds displaying statistics
  279.      */
  280.     @Override
  281.     public String toString() {
  282.         final String separator = ", ";
  283.         final String suffix = System.getProperty("line.separator");
  284.         StringBuilder outBuffer = new StringBuilder();
  285.         outBuffer.append("MultivariateSummaryStatistics:").append(suffix);
  286.         outBuffer.append("n: ").append(getN()).append(suffix);
  287.         append(outBuffer, getMin(), "min: ", separator, suffix);
  288.         append(outBuffer, getMax(), "max: ", separator, suffix);
  289.         append(outBuffer, getMean(), "mean: ", separator, suffix);
  290.         append(outBuffer, getGeometricMean(), "geometric mean: ", separator, suffix);
  291.         append(outBuffer, getSumSq(), "sum of squares: ", separator, suffix);
  292.         append(outBuffer, getSumLog(), "sum of logarithms: ", separator, suffix);
  293.         append(outBuffer, getStandardDeviation(), "standard deviation: ", separator, suffix);
  294.         outBuffer.append("covariance: ").append(getCovariance()).append(suffix);
  295.         return outBuffer.toString();
  296.     }

  297.     /**
  298.      * Append a text representation of an array to a buffer.
  299.      * @param buffer buffer to fill
  300.      * @param data data array
  301.      * @param prefix text prefix
  302.      * @param separator elements separator
  303.      * @param suffix text suffix
  304.      */
  305.     private void append(StringBuilder buffer, double[] data,
  306.                         String prefix, String separator, String suffix) {
  307.         buffer.append(prefix);
  308.         for (int i = 0; i < data.length; ++i) {
  309.             if (i > 0) {
  310.                 buffer.append(separator);
  311.             }
  312.             buffer.append(data[i]);
  313.         }
  314.         buffer.append(suffix);
  315.     }

  316.     /**
  317.      * Resets all statistics and storage.
  318.      */
  319.     public void clear() {
  320.         this.n = 0;
  321.         for (int i = 0; i < k; ++i) {
  322.             minImpl[i].clear();
  323.             maxImpl[i].clear();
  324.             sumImpl[i].clear();
  325.             sumLogImpl[i].clear();
  326.             sumSqImpl[i].clear();
  327.             geoMeanImpl[i].clear();
  328.             meanImpl[i].clear();
  329.         }
  330.         covarianceImpl.clear();
  331.     }

  332.     /**
  333.      * Returns true iff <code>object</code> is a <code>MultivariateSummaryStatistics</code>
  334.      * instance and all statistics have the same values as this.
  335.      * @param object the object to test equality against.
  336.      * @return true if object equals this
  337.      */
  338.     @Override
  339.     public boolean equals(Object object) {
  340.         if (object == this ) {
  341.             return true;
  342.         }
  343.         if (!(object instanceof MultivariateSummaryStatistics)) {
  344.             return false;
  345.         }
  346.         MultivariateSummaryStatistics stat = (MultivariateSummaryStatistics) object;
  347.         return MathArrays.equalsIncludingNaN(stat.getGeometricMean(), getGeometricMean()) &&
  348.                MathArrays.equalsIncludingNaN(stat.getMax(),           getMax())           &&
  349.                MathArrays.equalsIncludingNaN(stat.getMean(),          getMean())          &&
  350.                MathArrays.equalsIncludingNaN(stat.getMin(),           getMin())           &&
  351.                Precision.equalsIncludingNaN(stat.getN(),             getN())             &&
  352.                MathArrays.equalsIncludingNaN(stat.getSum(),           getSum())           &&
  353.                MathArrays.equalsIncludingNaN(stat.getSumSq(),         getSumSq())         &&
  354.                MathArrays.equalsIncludingNaN(stat.getSumLog(),        getSumLog())        &&
  355.                stat.getCovariance().equals( getCovariance());
  356.     }

  357.     /**
  358.      * Returns hash code based on values of statistics.
  359.      *
  360.      * @return hash code
  361.      */
  362.     @Override
  363.     public int hashCode() {
  364.         int result = 31 + Arrays.hashCode(getGeometricMean());
  365.         result = result * 31 + Arrays.hashCode(getGeometricMean());
  366.         result = result * 31 + Arrays.hashCode(getMax());
  367.         result = result * 31 + Arrays.hashCode(getMean());
  368.         result = result * 31 + Arrays.hashCode(getMin());
  369.         result = result * 31 + Double.hashCode(getN());
  370.         result = result * 31 + Arrays.hashCode(getSum());
  371.         result = result * 31 + Arrays.hashCode(getSumSq());
  372.         result = result * 31 + Arrays.hashCode(getSumLog());
  373.         result = result * 31 + getCovariance().hashCode();
  374.         return result;
  375.     }

  376.     // Getters and setters for statistics implementations
  377.     /**
  378.      * Sets statistics implementations.
  379.      * @param newImpl new implementations for statistics
  380.      * @param oldImpl old implementations for statistics
  381.      * @throws DimensionMismatchException if the array dimension
  382.      * does not match the one used at construction
  383.      * @throws MathIllegalStateException if data has already been added
  384.      * (i.e. if n > 0)
  385.      */
  386.     private void setImpl(StorelessUnivariateStatistic[] newImpl,
  387.                          StorelessUnivariateStatistic[] oldImpl) throws MathIllegalStateException,
  388.                          DimensionMismatchException {
  389.         checkEmpty();
  390.         checkDimension(newImpl.length);
  391.         System.arraycopy(newImpl, 0, oldImpl, 0, newImpl.length);
  392.     }

  393.     /**
  394.      * Returns the currently configured Sum implementation.
  395.      *
  396.      * @return the StorelessUnivariateStatistic implementing the sum
  397.      */
  398.     public StorelessUnivariateStatistic[] getSumImpl() {
  399.         return sumImpl.clone();
  400.     }

  401.     /**
  402.      * <p>Sets the implementation for the Sum.</p>
  403.      * <p>This method must be activated before any data has been added - i.e.,
  404.      * before {@link #addValue(double[]) addValue} has been used to add data;
  405.      * otherwise an IllegalStateException will be thrown.</p>
  406.      *
  407.      * @param sumImpl the StorelessUnivariateStatistic instance to use
  408.      * for computing the Sum
  409.      * @throws DimensionMismatchException if the array dimension
  410.      * does not match the one used at construction
  411.      * @throws MathIllegalStateException if data has already been added
  412.      *  (i.e if n &gt; 0)
  413.      */
  414.     public void setSumImpl(StorelessUnivariateStatistic[] sumImpl)
  415.     throws MathIllegalStateException, DimensionMismatchException {
  416.         setImpl(sumImpl, this.sumImpl);
  417.     }

  418.     /**
  419.      * Returns the currently configured sum of squares implementation.
  420.      *
  421.      * @return the StorelessUnivariateStatistic implementing the sum of squares
  422.      */
  423.     public StorelessUnivariateStatistic[] getSumsqImpl() {
  424.         return sumSqImpl.clone();
  425.     }

  426.     /**
  427.      * <p>Sets the implementation for the sum of squares.</p>
  428.      * <p>This method must be activated before any data has been added - i.e.,
  429.      * before {@link #addValue(double[]) addValue} has been used to add data;
  430.      * otherwise an IllegalStateException will be thrown.</p>
  431.      *
  432.      * @param sumsqImpl the StorelessUnivariateStatistic instance to use
  433.      * for computing the sum of squares
  434.      * @throws DimensionMismatchException if the array dimension
  435.      * does not match the one used at construction
  436.      * @throws MathIllegalStateException if data has already been added
  437.      *  (i.e if n &gt; 0)
  438.      */
  439.     public void setSumsqImpl(StorelessUnivariateStatistic[] sumsqImpl)
  440.     throws MathIllegalStateException, DimensionMismatchException {
  441.         setImpl(sumsqImpl, this.sumSqImpl);
  442.     }

  443.     /**
  444.      * Returns the currently configured minimum implementation.
  445.      *
  446.      * @return the StorelessUnivariateStatistic implementing the minimum
  447.      */
  448.     public StorelessUnivariateStatistic[] getMinImpl() {
  449.         return minImpl.clone();
  450.     }

  451.     /**
  452.      * <p>Sets the implementation for the minimum.</p>
  453.      * <p>This method must be activated before any data has been added - i.e.,
  454.      * before {@link #addValue(double[]) addValue} has been used to add data;
  455.      * otherwise an IllegalStateException will be thrown.</p>
  456.      *
  457.      * @param minImpl the StorelessUnivariateStatistic instance to use
  458.      * for computing the minimum
  459.      * @throws DimensionMismatchException if the array dimension
  460.      * does not match the one used at construction
  461.      * @throws MathIllegalStateException if data has already been added
  462.      *  (i.e if n &gt; 0)
  463.      */
  464.     public void setMinImpl(StorelessUnivariateStatistic[] minImpl)
  465.     throws MathIllegalStateException, DimensionMismatchException {
  466.         setImpl(minImpl, this.minImpl);
  467.     }

  468.     /**
  469.      * Returns the currently configured maximum implementation.
  470.      *
  471.      * @return the StorelessUnivariateStatistic implementing the maximum
  472.      */
  473.     public StorelessUnivariateStatistic[] getMaxImpl() {
  474.         return maxImpl.clone();
  475.     }

  476.     /**
  477.      * <p>Sets the implementation for the maximum.</p>
  478.      * <p>This method must be activated before any data has been added - i.e.,
  479.      * before {@link #addValue(double[]) addValue} has been used to add data;
  480.      * otherwise an IllegalStateException will be thrown.</p>
  481.      *
  482.      * @param maxImpl the StorelessUnivariateStatistic instance to use
  483.      * for computing the maximum
  484.      * @throws DimensionMismatchException if the array dimension
  485.      * does not match the one used at construction
  486.      * @throws MathIllegalStateException if data has already been added
  487.      *  (i.e if n &gt; 0)
  488.      */
  489.     public void setMaxImpl(StorelessUnivariateStatistic[] maxImpl)
  490.     throws MathIllegalStateException, DimensionMismatchException{
  491.         setImpl(maxImpl, this.maxImpl);
  492.     }

  493.     /**
  494.      * Returns the currently configured sum of logs implementation.
  495.      *
  496.      * @return the StorelessUnivariateStatistic implementing the log sum
  497.      */
  498.     public StorelessUnivariateStatistic[] getSumLogImpl() {
  499.         return sumLogImpl.clone();
  500.     }

  501.     /**
  502.      * <p>Sets the implementation for the sum of logs.</p>
  503.      * <p>This method must be activated before any data has been added - i.e.,
  504.      * before {@link #addValue(double[]) addValue} has been used to add data;
  505.      * otherwise an IllegalStateException will be thrown.</p>
  506.      *
  507.      * @param sumLogImpl the StorelessUnivariateStatistic instance to use
  508.      * for computing the log sum
  509.      * @throws DimensionMismatchException if the array dimension
  510.      * does not match the one used at construction
  511.      * @throws MathIllegalStateException if data has already been added
  512.      *  (i.e if n &gt; 0)
  513.      */
  514.     public void setSumLogImpl(StorelessUnivariateStatistic[] sumLogImpl)
  515.     throws MathIllegalStateException, DimensionMismatchException{
  516.         setImpl(sumLogImpl, this.sumLogImpl);
  517.     }

  518.     /**
  519.      * Returns the currently configured geometric mean implementation.
  520.      *
  521.      * @return the StorelessUnivariateStatistic implementing the geometric mean
  522.      */
  523.     public StorelessUnivariateStatistic[] getGeoMeanImpl() {
  524.         return geoMeanImpl.clone();
  525.     }

  526.     /**
  527.      * <p>Sets the implementation for the geometric mean.</p>
  528.      * <p>This method must be activated before any data has been added - i.e.,
  529.      * before {@link #addValue(double[]) addValue} has been used to add data;
  530.      * otherwise an IllegalStateException will be thrown.</p>
  531.      *
  532.      * @param geoMeanImpl the StorelessUnivariateStatistic instance to use
  533.      * for computing the geometric mean
  534.      * @throws DimensionMismatchException if the array dimension
  535.      * does not match the one used at construction
  536.      * @throws MathIllegalStateException if data has already been added
  537.      *  (i.e if n &gt; 0)
  538.      */
  539.     public void setGeoMeanImpl(StorelessUnivariateStatistic[] geoMeanImpl)
  540.     throws MathIllegalStateException, DimensionMismatchException {
  541.         setImpl(geoMeanImpl, this.geoMeanImpl);
  542.     }

  543.     /**
  544.      * Returns the currently configured mean implementation.
  545.      *
  546.      * @return the StorelessUnivariateStatistic implementing the mean
  547.      */
  548.     public StorelessUnivariateStatistic[] getMeanImpl() {
  549.         return meanImpl.clone();
  550.     }

  551.     /**
  552.      * <p>Sets the implementation for the mean.</p>
  553.      * <p>This method must be activated before any data has been added - i.e.,
  554.      * before {@link #addValue(double[]) addValue} has been used to add data;
  555.      * otherwise an IllegalStateException will be thrown.</p>
  556.      *
  557.      * @param meanImpl the StorelessUnivariateStatistic instance to use
  558.      * for computing the mean
  559.      * @throws DimensionMismatchException if the array dimension
  560.      * does not match the one used at construction
  561.      * @throws MathIllegalStateException if data has already been added
  562.      *  (i.e if n &gt; 0)
  563.      */
  564.     public void setMeanImpl(StorelessUnivariateStatistic[] meanImpl)
  565.     throws MathIllegalStateException, DimensionMismatchException{
  566.         setImpl(meanImpl, this.meanImpl);
  567.     }

  568.     /**
  569.      * Throws MathIllegalStateException if the statistic is not empty.
  570.      * @throws MathIllegalStateException if n > 0.
  571.      */
  572.     private void checkEmpty() throws MathIllegalStateException {
  573.         if (n > 0) {
  574.             throw new MathIllegalStateException(
  575.                     LocalizedFormats.VALUES_ADDED_BEFORE_CONFIGURING_STATISTIC, n);
  576.         }
  577.     }

  578.     /**
  579.      * Throws DimensionMismatchException if dimension != k.
  580.      * @param dimension dimension to check
  581.      * @throws DimensionMismatchException if dimension != k
  582.      */
  583.     private void checkDimension(int dimension) throws DimensionMismatchException {
  584.         if (dimension != k) {
  585.             throw new DimensionMismatchException(dimension, k);
  586.         }
  587.     }
  588. }