You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2008/02/08 17:42:37 UTC

svn commit: r619934 - in /commons/proper/math/trunk/src: java/org/apache/commons/math/stat/descriptive/ site/xdoc/ test/org/apache/commons/math/stat/descriptive/

Author: luc
Date: Fri Feb  8 08:42:34 2008
New Revision: 619934

URL: http://svn.apache.org/viewvc?rev=619934&view=rev
Log:
added multivariate summary statistics

Added:
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java   (with props)
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummary.java   (with props)
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummaryValues.java   (with props)
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java   (with props)
    commons/proper/math/trunk/src/test/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatisticsTest.java   (with props)
Modified:
    commons/proper/math/trunk/src/site/xdoc/changes.xml

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java?rev=619934&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java Fri Feb  8 08:42:34 2008
@@ -0,0 +1,592 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.stat.descriptive;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.apache.commons.math.DimensionMismatchException;
+import org.apache.commons.math.linear.RealMatrix;
+import org.apache.commons.math.stat.descriptive.moment.GeometricMean;
+import org.apache.commons.math.stat.descriptive.moment.Mean;
+import org.apache.commons.math.stat.descriptive.moment.VectorialCovariance;
+import org.apache.commons.math.stat.descriptive.rank.Max;
+import org.apache.commons.math.stat.descriptive.rank.Min;
+import org.apache.commons.math.stat.descriptive.summary.Sum;
+import org.apache.commons.math.stat.descriptive.summary.SumOfLogs;
+import org.apache.commons.math.stat.descriptive.summary.SumOfSquares;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * <p>Computes summary statistics for a stream of data values added using the 
+ * {@link #addValue(double[]) addValue} method. The data values are not stored in
+ * memory, so this class can be used to compute statistics for very large
+ * data streams.</p>
+ * 
+ * <p>The {@link StorelessUnivariateStatistic} array instances used to maintain
+ * summary state and compute statistics are configurable via setters.
+ * For example, the default implementation for the mean can be overridden by
+ * calling {@link #setMeanImpl(StorelessUnivariateStatistic[])}. Actual
+ * parameters to these methods must implement the 
+ * {@link StorelessUnivariateStatistic} interface and configuration must be
+ * completed before <code>addValue</code> is called. No configuration is
+ * necessary to use the default, commons-math provided implementations.</p>
+ * 
+ * <p>Note: This class is not thread-safe. Use 
+ * {@link SynchronizedMultivariateSummaryStatistics} if concurrent access from multiple
+ * threads is required.</p>
+ *
+ * @since 1.2
+ * @version $Revision: 618097 $ $Date: 2008-02-03 22:39:08 +0100 (dim., 03 févr. 2008) $
+ */
+public class MultivariateSummaryStatistics
+  implements StatisticalMultivariateSummary, Serializable {
+
+    /** Serialization UID */
+    private static final long serialVersionUID = 2271900808994826718L;
+
+    /**
+     * Construct a MultivariateSummaryStatistics instance
+     * @param k dimension of the data
+     * @param isCovarianceBiasCorrected if true, the unbiased sample
+     * covariance is computed, otherwise the biased population covariance
+     * is computed
+     */
+    public MultivariateSummaryStatistics(int k, boolean isCovarianceBiasCorrected) {
+        this.k = k;
+
+        sumImpl     = new StorelessUnivariateStatistic[k];
+        sumSqImpl   = new StorelessUnivariateStatistic[k];
+        minImpl     = new StorelessUnivariateStatistic[k];
+        maxImpl     = new StorelessUnivariateStatistic[k];
+        sumLogImpl  = new StorelessUnivariateStatistic[k];
+        geoMeanImpl = new StorelessUnivariateStatistic[k];
+        meanImpl    = new StorelessUnivariateStatistic[k];
+
+        for (int i = 0; i < k; ++i) {
+            sumImpl[i]     = new Sum();
+            sumSqImpl[i]   = new SumOfSquares();
+            minImpl[i]     = new Min();
+            maxImpl[i]     = new Max();
+            sumLogImpl[i]  = new SumOfLogs();
+            geoMeanImpl[i] = new GeometricMean();
+            meanImpl[i]    = new Mean();
+        }
+
+        covarianceImpl =
+            new VectorialCovariance(k, isCovarianceBiasCorrected);
+
+    }
+
+    /** Dimension of the data. */
+    private int k;
+
+    /** Count of values that have been added */
+    private long n = 0;
+    
+    /** Sum statistic implementation - can be reset by setter. */
+    private StorelessUnivariateStatistic[] sumImpl;
+    
+    /** Sum of squares statistic implementation - can be reset by setter. */
+    private StorelessUnivariateStatistic[] sumSqImpl;
+    
+    /** Minimum statistic implementation - can be reset by setter. */
+    private StorelessUnivariateStatistic[] minImpl;
+    
+    /** Maximum statistic implementation - can be reset by setter. */
+    private StorelessUnivariateStatistic[] maxImpl;
+    
+    /** Sum of log statistic implementation - can be reset by setter. */
+    private StorelessUnivariateStatistic[] sumLogImpl;
+    
+    /** Geometric mean statistic implementation - can be reset by setter. */
+    private StorelessUnivariateStatistic[] geoMeanImpl;
+    
+    /** Mean statistic implementation - can be reset by setter. */
+    private StorelessUnivariateStatistic[] meanImpl;
+    
+    /** Covariance statistic implementation - cannot be reset. */
+    private VectorialCovariance covarianceImpl;
+
+    /**
+     * Return a {@link StatisticalMultivariateSummary} instance reporting current
+     * statistics.
+     * 
+     * @return Current values of statistics 
+     */
+    public StatisticalMultivariateSummary getSummary() {
+        return new StatisticalMultivariateSummaryValues(getDimension(), getMean(),
+                                                        getCovariance(), getStandardDeviation(),
+                                                        getN(), getMax(), getMin(),
+                                                        getSum(), getSumSq(), getSumLog());
+    }
+    
+    /**
+     * Add a value to the data
+     * 
+     * @param value  the value to add
+     * @throws DimensionMismatchException if the value dimension
+     * does not match the one used at construction
+     */
+    public void addValue(double[] value)
+      throws DimensionMismatchException {
+        if (value.length != k) {
+            throw new DimensionMismatchException(value.length, k);
+        }
+
+        for (int i = 0; i < k; ++i) {
+            double v = value[i];
+            sumImpl[i].increment(v);
+            sumSqImpl[i].increment(v);
+            minImpl[i].increment(v);
+            maxImpl[i].increment(v);
+            sumLogImpl[i].increment(v);
+            geoMeanImpl[i].increment(v);
+            meanImpl[i].increment(v);
+        }
+        covarianceImpl.increment(value);
+        n++;
+    }
+
+    /** 
+     * Returns the dimension of the data
+     * @return The dimension of the data
+     */
+    public int getDimension() {
+        return k;
+    }
+
+    /** 
+     * Returns the number of available values
+     * @return The number of available values
+     */
+    public long getN() {
+        return n;
+    }
+
+    /**
+     * Returns an array of the results of a statistic.
+     * @param stats univariate statistic array
+     * @return results array
+     */
+    private double[] getResults(StorelessUnivariateStatistic[] stats) {
+        double[] results = new double[stats.length];
+        for (int i = 0; i < results.length; ++i) {
+            results[i] = stats[i].getResult();
+        }
+        return results;
+    }
+
+    /**
+     * Returns the sum of the values that have been added
+     * @return The sum or <code>Double.NaN</code> if no values have been added
+     */
+    public double[] getSum() {
+        return getResults(sumImpl);
+    }
+
+    /**
+     * Returns the sum of the squares of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     * 
+     * @return The sum of squares
+     */
+    public double[] getSumSq() {
+        return getResults(sumSqImpl);
+    }
+
+    /**
+     * Returns the sum of the logarithms of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     * 
+     * @return The sum of logarithms
+     */
+    public double[] getSumLog() {
+        return getResults(sumLogImpl);
+    }
+
+    /**
+     * Returns the mean of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     * 
+     * @return the mean
+     */
+    public double[] getMean() {
+        return getResults(meanImpl);
+    }
+
+    /**
+     * Returns the standard deviation of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     * 
+     * @return the standard deviation
+     */
+    public double[] getStandardDeviation() {
+        double[] stdDev = new double[k];
+        if (getN() < 1) {
+            Arrays.fill(stdDev, Double.NaN);
+        } else if (getN() < 2) {
+            Arrays.fill(stdDev, 0.0);
+        } else {
+            RealMatrix matrix = covarianceImpl.getResult();
+            for (int i = 0; i < k; ++i) {
+                stdDev[i] = Math.sqrt(matrix.getEntry(i, i));
+            }
+        }
+        return stdDev;
+    }
+
+    /**
+     * Returns the covariance of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     *
+     * @return the variance 
+     */
+    public RealMatrix getCovariance() {
+        return covarianceImpl.getResult();
+    }
+
+    /**
+     * Returns the maximum of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     *
+     * @return the maximum  
+     */
+    public double[] getMax() {
+        return getResults(maxImpl);
+    }
+
+    /**
+     * Returns the minimum of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     *
+     * @return the minimum  
+     */
+    public double[] getMin() {
+        return getResults(minImpl);
+    }
+
+    /**
+     * Returns the geometric mean of the values that have been added.
+     * <p>
+     *  Double.NaN is returned if no values have been added.</p>
+     *
+     * @return the geometric mean  
+     */
+    public double[] getGeometricMean() {
+        return getResults(geoMeanImpl);
+    }
+    
+    /**
+     * Generates a text report displaying
+     * summary statistics from values that
+     * have been added.
+     * @return String with line feeds displaying statistics
+     */
+    public String toString() {
+        StringBuffer outBuffer = new StringBuffer();
+        outBuffer.append("MultivariateSummaryStatistics:\n");
+        outBuffer.append("n: " + getN() + "\n");
+        append(outBuffer, getMin(), "min: ", ", ", "\n");
+        append(outBuffer, getMax(), "max: ", ", ", "\n");
+        append(outBuffer, getMean(), "mean: ", ", ", "\n");
+        append(outBuffer, getGeometricMean(), "geometric mean: ", ", ", "\n");
+        append(outBuffer, getSumSq(), "sum of squares: ", ", ", "\n");
+        append(outBuffer, getSumLog(), "sum of logarithms: ", ", ", "\n");
+        append(outBuffer, getStandardDeviation(), "standard deviation: ", ", ", "\n");
+        outBuffer.append("covariance: " + getCovariance().toString() + "\n");
+        return outBuffer.toString();
+    }
+
+    /**
+     * Append a text representation of an array to a buffer.
+     * @param buffer buffer to fill
+     * @param data data array
+     * @param prefix text prefix
+     * @param separator elements separator
+     * @param suffix text suffix
+     */
+    private void append(StringBuffer buffer, double[] data,
+                        String prefix, String separator, String suffix) {
+        buffer.append(prefix);
+        for (int i = 0; i < data.length; ++i) {
+            if (i > 0) {
+                buffer.append(separator);
+            }
+            buffer.append(data[i]);
+        }
+        buffer.append(suffix);
+    }
+
+    /** 
+     * Resets all statistics and storage
+     */
+    public void clear() {
+        this.n = 0;
+        for (int i = 0; i < k; ++i) {
+            minImpl[i].clear();
+            maxImpl[i].clear();
+            sumImpl[i].clear();
+            sumLogImpl[i].clear();
+            sumSqImpl[i].clear();
+            geoMeanImpl[i].clear();
+            meanImpl[i].clear();
+        }
+        covarianceImpl.clear();
+    }
+    
+    /**
+     * Returns true iff <code>object</code> is a <code>SummaryStatistics</code>
+     * instance and all statistics have the same values as this.
+     * @param object the object to test equality against.
+     * @return true if object equals this
+     */
+    public boolean equals(Object object) {
+        if (object == this ) {
+            return true;
+        }
+        if (object instanceof MultivariateSummaryStatistics == false) {
+            return false;
+        }
+        MultivariateSummaryStatistics stat = (MultivariateSummaryStatistics) object;
+        return (MathUtils.equals(stat.getGeometricMean(), 
+                this.getGeometricMean()) &&
+                MathUtils.equals(stat.getMax(), this.getMax()) && 
+                MathUtils.equals(stat.getMean(),this.getMean()) &&
+                MathUtils.equals(stat.getMin(),this.getMin()) &&
+                MathUtils.equals(stat.getN(), this.getN()) &&
+                MathUtils.equals(stat.getSum(), this.getSum()) &&
+                MathUtils.equals(stat.getSumSq(),this.getSumSq()) &&
+                MathUtils.equals(stat.getSumLog(),this.getSumLog()) &&
+                stat.getCovariance().equals(this.getCovariance()));
+    }
+    
+    /**
+     * Returns hash code based on values of statistics
+     * 
+     * @return hash code
+     */
+    public int hashCode() {
+        int result = 31 + MathUtils.hash(getGeometricMean());
+        result = result * 31 + MathUtils.hash(getGeometricMean());
+        result = result * 31 + MathUtils.hash(getMax());
+        result = result * 31 + MathUtils.hash(getMean());
+        result = result * 31 + MathUtils.hash(getMin());
+        result = result * 31 + MathUtils.hash(getN());
+        result = result * 31 + MathUtils.hash(getSum());
+        result = result * 31 + MathUtils.hash(getSumSq());
+        result = result * 31 + MathUtils.hash(getSumLog());
+        result = result * 31 + getCovariance().hashCode();
+        return result;
+    }
+
+    // Getters and setters for statistics implementations
+    /**
+     * Returns the currently configured Sum implementation
+     * 
+     * @return the StorelessUnivariateStatistic implementing the sum
+     */
+    public StorelessUnivariateStatistic[] getSumImpl() {
+        return sumImpl;
+    }
+
+    /**
+     * <p>Sets the implementation for the Sum.</p>
+     * <p>This method must be activated before any data has been added - i.e.,
+     * before {@link #addValue(double[]) addValue} has been used to add data; 
+     * otherwise an IllegalStateException will be thrown.</p>
+     * 
+     * @param sumImpl the StorelessUnivariateStatistic instance to use
+     * for computing the Sum
+     * @throws IllegalArgumentException if the array dimension
+     * does not match the one used at construction
+     * @throws IllegalStateException if data has already been added
+     *  (i.e if n > 0)
+     */
+    public void setSumImpl(StorelessUnivariateStatistic[] sumImpl) {
+        checkEmpty();
+        this.sumImpl = sumImpl;
+    }
+
+    /**
+     * Returns the currently configured sum of squares implementation
+     * 
+     * @return the StorelessUnivariateStatistic implementing the sum of squares
+     */
+    public StorelessUnivariateStatistic[] getSumsqImpl() {
+        return sumSqImpl;
+    }
+
+    /**
+     * <p>Sets the implementation for the sum of squares.</p>
+     * <p>This method must be activated before any data has been added - i.e.,
+     * before {@link #addValue(double[]) addValue} has been used to add data; 
+     * otherwise an IllegalStateException will be thrown.</p>
+     * 
+     * @param sumsqImpl the StorelessUnivariateStatistic instance to use
+     * for computing the sum of squares
+     * @throws IllegalStateException if data has already been added
+     *  (i.e if n > 0)
+     */
+    public void setSumsqImpl(StorelessUnivariateStatistic[] sumsqImpl) {
+        checkEmpty();
+        this.sumSqImpl = sumsqImpl;
+    }
+
+    /**
+     * Returns the currently configured minimum implementation
+     * 
+     * @return the StorelessUnivariateStatistic implementing the minimum
+     */
+    public StorelessUnivariateStatistic[] getMinImpl() {
+        return minImpl;
+    }
+
+    /**
+     * <p>Sets the implementation for the minimum.</p>
+     * <p>This method must be activated before any data has been added - i.e.,
+     * before {@link #addValue(double[]) addValue} has been used to add data; 
+     * otherwise an IllegalStateException will be thrown.</p>
+     * 
+     * @param minImpl the StorelessUnivariateStatistic instance to use
+     * for computing the minimum
+     * @throws IllegalStateException if data has already been added
+     *  (i.e if n > 0)
+     */
+    public void setMinImpl(StorelessUnivariateStatistic[] minImpl) {
+        checkEmpty();
+        this.minImpl = minImpl;
+    }
+
+    /**
+     * Returns the currently configured maximum implementation
+     * 
+     * @return the StorelessUnivariateStatistic implementing the maximum
+     */
+    public StorelessUnivariateStatistic[] getMaxImpl() {
+        return maxImpl;
+    }
+
+    /**
+     * <p>Sets the implementation for the maximum.</p>
+     * <p>This method must be activated before any data has been added - i.e.,
+     * before {@link #addValue(double[]) addValue} has been used to add data; 
+     * otherwise an IllegalStateException will be thrown.</p>
+     * 
+     * @param maxImpl the StorelessUnivariateStatistic instance to use
+     * for computing the maximum
+     * @throws IllegalStateException if data has already been added
+     *  (i.e if n > 0)
+     */
+    public void setMaxImpl(StorelessUnivariateStatistic[] maxImpl) {
+        checkEmpty();
+        this.maxImpl = maxImpl;
+    }
+
+    /**
+     * Returns the currently configured sum of logs implementation
+     * 
+     * @return the StorelessUnivariateStatistic implementing the log sum
+     */
+    public StorelessUnivariateStatistic[] getSumLogImpl() {
+        return sumLogImpl;
+    }
+
+    /**
+     * <p>Sets the implementation for the sum of logs.</p>
+     * <p>This method must be activated before any data has been added - i.e.,
+     * before {@link #addValue(double[]) addValue} has been used to add data; 
+     * otherwise an IllegalStateException will be thrown.</p>
+     * 
+     * @param sumLogImpl the StorelessUnivariateStatistic instance to use
+     * for computing the log sum
+     * @throws IllegalStateException if data has already been added 
+     *  (i.e if n > 0)
+     */
+    public void setSumLogImpl(StorelessUnivariateStatistic[] sumLogImpl) {
+        checkEmpty();
+        this.sumLogImpl = sumLogImpl;
+    }
+
+    /**
+     * Returns the currently configured geometric mean implementation
+     * 
+     * @return the StorelessUnivariateStatistic implementing the geometric mean
+     */
+    public StorelessUnivariateStatistic[] getGeoMeanImpl() {
+        return geoMeanImpl;
+    }
+
+    /**
+     * <p>Sets the implementation for the geometric mean.</p>
+     * <p>This method must be activated before any data has been added - i.e.,
+     * before {@link #addValue(double[]) addValue} has been used to add data; 
+     * otherwise an IllegalStateException will be thrown.</p>
+     * 
+     * @param geoMeanImpl the StorelessUnivariateStatistic instance to use
+     * for computing the geometric mean
+     * @throws IllegalStateException if data has already been added
+     *  (i.e if n > 0)
+     */
+    public void setGeoMeanImpl(StorelessUnivariateStatistic[] geoMeanImpl) {
+        checkEmpty();
+        this.geoMeanImpl = geoMeanImpl;
+    }
+
+    /**
+     * Returns the currently configured mean implementation
+     * 
+     * @return the StorelessUnivariateStatistic implementing the mean
+     */
+    public StorelessUnivariateStatistic[] getMeanImpl() {
+        return meanImpl;
+    }
+
+    /**
+     * <p>Sets the implementation for the mean.</p>
+     * <p>This method must be activated before any data has been added - i.e.,
+     * before {@link #addValue(double[]) addValue} has been used to add data; 
+     * otherwise an IllegalStateException will be thrown.</p>
+     * 
+     * @param meanImpl the StorelessUnivariateStatistic instance to use
+     * for computing the mean
+     * @throws IllegalStateException if data has already been added
+     *  (i.e if n > 0)
+     */
+    public void setMeanImpl(StorelessUnivariateStatistic[] meanImpl) {
+        checkEmpty();
+        this.meanImpl = meanImpl;
+    }
+
+    /**
+     * Throws IllegalStateException if n > 0.
+     */
+    private void checkEmpty() {
+        if (n > 0) {
+            throw new IllegalStateException(
+                "Implementations must be configured before values are added.");
+        }
+    }
+
+}

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummary.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummary.java?rev=619934&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummary.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummary.java Fri Feb  8 08:42:34 2008
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.stat.descriptive;
+
+import org.apache.commons.math.linear.RealMatrix;
+
+/**
+ *  Reporting interface for basic multivariate statistics.
+ *
+ * @since 1.2
+ * @version $Revision: 480440 $ $Date: 2006-11-29 08:14:12 +0100 (mer., 29 nov. 2006) $
+ */
+public interface StatisticalMultivariateSummary {
+    /** 
+     * Returns the dimension of the data
+     * @return The dimension of the data
+     */
+    public int getDimension();
+    /** 
+     * Returns the <a href="http://www.xycoon.com/arithmetic_mean.htm">
+     * arithmetic mean </a> of the available values 
+     * @return The mean or null if no values have been added.
+     */
+    public abstract double[] getMean();
+    /** 
+     * Returns the covariance of the available values.
+     * @return The covariance, null if no values have been added 
+     * or a zeroed matrix for a single value set.  
+     */
+    public abstract RealMatrix getCovariance();
+    /** 
+     * Returns the standard deviation of the available values.
+     * @return The standard deviation, null if no values have been added 
+     * or a zeroed array for a single value set. 
+     */
+    public abstract double[] getStandardDeviation();
+    /** 
+     * Returns the maximum of the available values
+     * @return The max or null if no values have been added.
+     */
+    public abstract double[] getMax();
+    /** 
+    * Returns the minimum of the available values
+    * @return The min or null if no values have been added.
+    */
+    public abstract double[] getMin();
+    /** 
+     * Returns the number of available values
+     * @return The number of available values
+     */
+    public abstract long getN();
+    /**
+     * Returns the sum of the values that have been added.
+     * @return The sum or null if no values have been added
+     */
+    public abstract double[] getSum();
+    /**
+     * Returns the sum of the squares of the values that have been added.
+     * @return The sum or null if no values have been added
+     */
+    public abstract double[] getSumSq();
+    /**
+     * Returns the sum of the logarithms of the values that have been added.
+     * @return The sum or null if no values have been added
+     */
+    public abstract double[] getSumLog();
+}
\ No newline at end of file

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummary.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummaryValues.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummaryValues.java?rev=619934&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummaryValues.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummaryValues.java Fri Feb  8 08:42:34 2008
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.stat.descriptive;
+
+import java.io.Serializable;
+
+import org.apache.commons.math.linear.RealMatrix;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ *  Value object representing the results of a statistical multivariate summary.
+ *
+ * @since 1.2
+ * @version $Revision: 480440 $ $Date: 2006-11-29 08:14:12 +0100 (mer., 29 nov. 2006) $
+ */
+public class StatisticalMultivariateSummaryValues
+  implements Serializable, StatisticalMultivariateSummary {
+   
+    /** Serialization id */
+    private static final long serialVersionUID = 8152538650791979064L;
+
+    /** Dimension of the data. */
+    private final int k;
+
+    /** The sample mean */
+    private final double[] mean;
+    
+    /** The sample covariance */
+    private final RealMatrix covariance;
+
+    /** The sample standard deviation. */
+    private double[] stdev;
+    
+    /** The number of observations in the sample */
+    private final long n;
+    
+    /** The maximum value */
+    private final double[] max;
+    
+    /** The minimum value */
+    private final double[] min;
+    
+    /** The sum of the sample values */
+    private final double[] sum;
+    
+    /** The sum of the squares of the sample values */
+    private final double[] sumSq;
+    
+    /** The sum of the logarithms of the sample values */
+    private final double[] sumLog;
+    
+    /**
+      * Constructor
+      * 
+      * @param mean  the sample mean
+      * @param covariance  the sample covariance
+      * @param stdev  the sample standard deviation
+      * @param k dimension of the data
+      * @param n  the number of observations in the sample 
+      * @param max  the maximum value
+      * @param min  the minimum value
+      * @param sum  the sum of the values
+      * @param sumSq the sum of the squares of the values
+      * @param sumLog the sum of the logarithms of the values
+      */
+    public StatisticalMultivariateSummaryValues(int k, double[] mean,
+                                                RealMatrix covariance, double[] stdev,
+                                                long n, double[] max, double[] min,
+                                                double[] sum, double[] sumSq, double[] sumLog) {
+        super();
+        this.k = k;
+        this.mean = mean;
+        this.covariance = covariance;
+        this.stdev = stdev;
+        this.n = n;
+        this.max = max;
+        this.min = min;
+        this.sum = sum;
+        this.sumSq = sumSq;
+        this.sumLog = sumLog;
+    }
+
+    /** 
+     * Returns the dimension of the data
+     * @return The dimension of the data
+     */
+    public int getDimension() {
+        return k;
+    }
+
+    /**
+     * @return Returns the max.
+     */
+    public double[] getMax() {
+        return max;
+    }
+
+    /**
+     * @return Returns the mean.
+     */
+    public double[] getMean() {
+        return mean;
+    }
+
+    /**
+     * @return Returns the min.
+     */
+    public double[] getMin() {
+        return min;
+    }
+
+    /**
+     * @return Returns the number of values.
+     */
+    public long getN() {
+        return n;
+    }
+
+    /**
+     * @return Returns the sum.
+     */
+    public double[] getSum() {
+        return sum;
+    }
+    
+    /**
+     * @return Returns the sum of the squares.
+     */
+    public double[] getSumSq() {
+        return sumSq;
+    }
+    
+    /**
+     * @return Returns the sum of the logarithms.
+     */
+    public double[] getSumLog() {
+        return sumLog;
+    }
+    
+    /**
+     * @return Returns the standard deviation (roots of the diagonal elements)
+     */
+    public double[] getStandardDeviation() {
+        return stdev; 
+    }
+
+    /**
+     * @return Returns the covariance.
+     */
+    public RealMatrix getCovariance() {
+        return covariance;
+    }
+    
+    /**
+     * Returns true iff <code>object</code> is a 
+     * <code>StatisticalSummaryValues</code> instance and all statistics have
+     *  the same values as this.
+     * 
+     * @param object the object to test equality against.
+     * @return true if object equals this
+     */
+    public boolean equals(Object object) {
+        if (object == this ) {
+            return true;
+        }
+        if (object instanceof StatisticalMultivariateSummaryValues == false) {
+            return false;
+        }
+        StatisticalMultivariateSummaryValues stat = (StatisticalMultivariateSummaryValues) object;
+        return ((stat.getDimension() == this.getDimension()) &&
+                MathUtils.equals(stat.getMax(), this.getMax()) && 
+                MathUtils.equals(stat.getMean(),this.getMean()) &&
+                MathUtils.equals(stat.getMin(),this.getMin()) &&
+                MathUtils.equals(stat.getN(), this.getN()) &&
+                MathUtils.equals(stat.getSum(), this.getSum()) &&
+                MathUtils.equals(stat.getSumSq(), this.getSumSq()) &&
+                MathUtils.equals(stat.getSumLog(), this.getSumLog()) &&
+                MathUtils.equals(stat.getStandardDeviation(), this.getStandardDeviation()) &&
+                stat.getCovariance().equals(this.getCovariance()));
+    }
+    
+    /**
+     * Returns hash code based on values of statistics
+     * 
+     * @return hash code
+     */
+    public int hashCode() {
+        int result = getDimension();
+        result = result * 31 + MathUtils.hash(getMax());
+        result = result * 31 + MathUtils.hash(getMean());
+        result = result * 31 + MathUtils.hash(getMin());
+        result = result * 31 + MathUtils.hash(getN());
+        result = result * 31 + MathUtils.hash(getSum());
+        result = result * 31 + MathUtils.hash(getSumSq());
+        result = result * 31 + MathUtils.hash(getSumLog());
+        result = result * 31 + getCovariance().hashCode();
+        result = result * 31 + MathUtils.hash(getStandardDeviation());
+        return result;
+    }
+
+}

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/StatisticalMultivariateSummaryValues.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java?rev=619934&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java Fri Feb  8 08:42:34 2008
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.stat.descriptive;
+
+import org.apache.commons.math.DimensionMismatchException;
+import org.apache.commons.math.linear.RealMatrix;
+
+/**
+ * Implementation of
+ * {@link org.apache.commons.math.stat.descriptive.MultivariateSummaryStatistics} that
+ * is safe to use in a multithreaded environment.  Multiple threads can safely
+ * operate on a single instance without causing runtime exceptions due to race
+ * conditions.  In effect, this implementation makes modification and access
+ * methods atomic operations for a single instance.  That is to say, as one
+ * thread is computing a statistic from the instance, no other thread can modify
+ * the instance nor compute another statistic.
+ * @since 1.2
+ * @version $Revision: 618097 $ $Date: 2008-02-03 22:39:08 +0100 (dim., 03 févr. 2008) $
+ */
+public class SynchronizedMultivariateSummaryStatistics
+  extends MultivariateSummaryStatistics {
+
+    /** Serialization UID */
+    private static final long serialVersionUID = 7099834153347155363L;
+
+    /**
+     * Construct a SynchronizedMultivariateSummaryStatistics instance
+     * @param k dimension of the data
+     * @param isCovarianceBiasCorrected if true, the unbiased sample
+     * covariance is computed, otherwise the biased population covariance
+     * is computed
+     */
+    public SynchronizedMultivariateSummaryStatistics(int k, boolean isCovarianceBiasCorrected) {
+        super(k, isCovarianceBiasCorrected);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getSummary()
+     */
+    public synchronized StatisticalMultivariateSummary getSummary() {
+        return super.getSummary();
+    }
+    
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#addValue(double[])
+     */
+    public synchronized void addValue(double[] value)
+      throws DimensionMismatchException {
+      super.addValue(value);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getDimension()
+     */
+    public synchronized int getDimension() {
+        return super.getDimension();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getN()
+     */
+    public synchronized long getN() {
+        return super.getN();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getSum()
+     */
+    public synchronized double[] getSum() {
+        return super.getSum();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getSummSq()
+     */
+    public synchronized double[] getSumSq() {
+        return super.getSumSq();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getSumLog()
+     */
+    public synchronized double[] getSumLog() {
+        return super.getSumLog();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getMean()
+     */
+    public synchronized double[] getMean() {
+        return super.getMean();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getStandardDeviation()
+     */
+    public synchronized double[] getStandardDeviation() {
+        return super.getStandardDeviation();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getCovariance()
+     */
+    public synchronized RealMatrix getCovariance() {
+        return super.getCovariance();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getMax()
+     */
+    public synchronized double[] getMax() {
+        return super.getMax();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getMin()
+     */
+    public synchronized double[] getMin() {
+        return super.getMin();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getGeometricMean()
+     */
+    public synchronized double[] getGeometricMean() {
+        return super.getGeometricMean();
+    }
+    
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#toString()
+     */
+    public synchronized String toString() {
+        return super.toString();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#clear()
+     */
+    public synchronized void clear() {
+        super.clear();
+    }
+    
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#equals()
+     */
+    public synchronized boolean equals(Object object) {
+        return super.equals(object);
+    }
+    
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#hashCode()
+     */
+    public synchronized int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getSumImpl()
+     */
+    public synchronized StorelessUnivariateStatistic[] getSumImpl() {
+        return super.getSumImpl();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#setSumImpl(StorelessUnivariateStatistic[])
+     */
+    public synchronized void setSumImpl(StorelessUnivariateStatistic[] sumImpl) {
+        super.setSumImpl(sumImpl);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getSumsqImpl()
+     */
+    public synchronized StorelessUnivariateStatistic[] getSumsqImpl() {
+        return super.getSumsqImpl();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#setSumsqImpl(StorelessUnivariateStatistic[])
+     */
+    public synchronized void setSumsqImpl(StorelessUnivariateStatistic[] sumsqImpl) {
+        super.setSumsqImpl(sumsqImpl);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getMinImpl()
+     */
+    public synchronized StorelessUnivariateStatistic[] getMinImpl() {
+        return super.getMinImpl();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#setMinImpl(StorelessUnivariateStatistic[])
+     */
+    public synchronized void setMinImpl(StorelessUnivariateStatistic[] minImpl) {
+        super.setMinImpl(minImpl);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getMaxImpl()
+     */
+    public synchronized StorelessUnivariateStatistic[] getMaxImpl() {
+        return super.getMaxImpl();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#setMaxImpl(StorelessUnivariateStatistic[])
+     */
+    public synchronized void setMaxImpl(StorelessUnivariateStatistic[] maxImpl) {
+        super.setMaxImpl(maxImpl);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getSumLogImpl()
+     */
+    public synchronized StorelessUnivariateStatistic[] getSumLogImpl() {
+        return super.getSumLogImpl();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#setSumLogImpl(StorelessUnivariateStatistic[])
+     */
+    public synchronized void setSumLogImpl(StorelessUnivariateStatistic[] sumLogImpl) {
+        super.setSumLogImpl(sumLogImpl);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getGeoMeanImpl()
+     */
+    public synchronized StorelessUnivariateStatistic[] getGeoMeanImpl() {
+        return super.getGeoMeanImpl();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#setGeoMeanImpl(StorelessUnivariateStatistic[])
+     */
+    public synchronized void setGeoMeanImpl(StorelessUnivariateStatistic[] geoMeanImpl) {
+        super.setGeoMeanImpl(geoMeanImpl);
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#getMeanImpl()
+     */
+    public synchronized StorelessUnivariateStatistic[] getMeanImpl() {
+        return super.getMeanImpl();
+    }
+
+    /**
+     * @see org.apache.commons.math.stat.descriptive.MultivariateSummary#setMeanImpl(StorelessUnivariateStatistic[])
+     */
+    public synchronized void setMeanImpl(StorelessUnivariateStatistic[] meanImpl) {
+        super.setMeanImpl(meanImpl);
+    }
+
+}

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=619934&r1=619933&r2=619934&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Fri Feb  8 08:42:34 2008
@@ -154,6 +154,9 @@
         Added vectorial covariance computation (either sample or population
         covariance)
       </action>
+      <action dev="luc" type="update" >
+        Added multivariate summary statistics
+      </action>
     </release>
     <release version="1.1" date="2005-12-17"  
  description="This is a maintenance release containing bug fixes and enhancements.

Added: commons/proper/math/trunk/src/test/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatisticsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatisticsTest.java?rev=619934&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatisticsTest.java (added)
+++ commons/proper/math/trunk/src/test/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatisticsTest.java Fri Feb  8 08:42:34 2008
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.stat.descriptive;
+
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.commons.math.DimensionMismatchException;
+import org.apache.commons.math.TestUtils;
+import org.apache.commons.math.stat.descriptive.moment.Mean;
+
+/**
+ * Test cases for the {@link MultivariateSummaryStatistics} class.
+ *
+ * @version $Revision: 566833 $ $Date: 2007-08-16 13:36:33 -0700 (Thu, 16 Aug 2007) $
+ */
+
+public class MultivariateSummaryStatisticsTest extends TestCase {
+
+    public MultivariateSummaryStatisticsTest(String name) {
+        super(name);
+    }
+    
+    public static Test suite() {
+        TestSuite suite = new TestSuite(MultivariateSummaryStatisticsTest.class);
+        suite.setName("MultivariateSummaryStatistics tests");
+        return suite;
+    }
+
+    public void testSetterInjection() throws Exception {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(2, true);
+        u.setMeanImpl(new StorelessUnivariateStatistic[] {
+                        new sumMean(), new sumMean()
+                      });
+        u.addValue(new double[] { 1, 2 });
+        u.addValue(new double[] { 3, 4 });
+        assertEquals(4, u.getMean()[0], 1E-14);
+        assertEquals(6, u.getMean()[1], 1E-14);
+        u.clear();
+        u.addValue(new double[] { 1, 2 });
+        u.addValue(new double[] { 3, 4 });
+        assertEquals(4, u.getMean()[0], 1E-14);
+        assertEquals(6, u.getMean()[1], 1E-14);
+        u.clear();
+        u.setMeanImpl(new StorelessUnivariateStatistic[] {
+                        new Mean(), new Mean()
+                      }); // OK after clear
+        u.addValue(new double[] { 1, 2 });
+        u.addValue(new double[] { 3, 4 });
+        assertEquals(2, u.getMean()[0], 1E-14);
+        assertEquals(3, u.getMean()[1], 1E-14);
+    }
+    
+    public void testSetterIllegalState() throws Exception {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(2, true);
+        u.addValue(new double[] { 1, 2 });
+        u.addValue(new double[] { 3, 4 });
+        try {
+            u.setMeanImpl(new StorelessUnivariateStatistic[] {
+                            new sumMean(), new sumMean()
+                          });
+            fail("Expecting IllegalStateException");
+        } catch (IllegalStateException ex) {
+            // expected
+        }
+    }
+    
+    /**
+     * Bogus mean implementation to test setter injection.
+     * Returns the sum instead of the mean.
+     */
+    static class sumMean implements StorelessUnivariateStatistic {   
+        private static final long serialVersionUID = 6492471391340853423L;
+        private double sum = 0;
+        private long n = 0;
+        public double evaluate(double[] values, int begin, int length) {
+            return 0;
+        }
+        public double evaluate(double[] values) {
+            return 0;
+        }
+        public void clear() {
+          sum = 0; 
+          n = 0;
+        }
+        public long getN() {
+            return n;
+        }
+        public double getResult() {
+            return sum;
+        }
+        public void increment(double d) {
+            sum += d;
+            n++;
+        }
+        public void incrementAll(double[] values, int start, int length) {
+        }
+        public void incrementAll(double[] values) {
+        }   
+    }
+
+    public void testDimension() {
+        try {
+            new MultivariateSummaryStatistics(2, true).addValue(new double[3]);
+        } catch (DimensionMismatchException dme) {
+            // expected behavior
+        } catch (Exception e) {
+            fail("wrong exception caught");
+        }
+    }
+
+    /** test stats */
+    public void testStats() throws DimensionMismatchException {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(2, true);
+        assertEquals(0, u.getN());
+        u.addValue(new double[] { 1, 2 });
+        u.addValue(new double[] { 2, 3 });
+        u.addValue(new double[] { 2, 3 });
+        u.addValue(new double[] { 3, 4 });
+        assertEquals( 4, u.getN());
+        assertEquals( 8, u.getSum()[0], 1.0e-10);
+        assertEquals(12, u.getSum()[1], 1.0e-10);
+        assertEquals(18, u.getSumSq()[0], 1.0e-10);
+        assertEquals(38, u.getSumSq()[1], 1.0e-10);
+        assertEquals( 1, u.getMin()[0], 1.0e-10);
+        assertEquals( 2, u.getMin()[1], 1.0e-10);
+        assertEquals( 3, u.getMax()[0], 1.0e-10);
+        assertEquals( 4, u.getMax()[1], 1.0e-10);
+        assertEquals(2.4849066497880003102, u.getSumLog()[0], 1.0e-10);
+        assertEquals( 4.276666119016055311, u.getSumLog()[1], 1.0e-10);
+        assertEquals( 1.8612097182041991979, u.getGeometricMean()[0], 1.0e-10);
+        assertEquals( 2.9129506302439405217, u.getGeometricMean()[1], 1.0e-10);
+        assertEquals( 2, u.getMean()[0], 1.0e-10);
+        assertEquals( 3, u.getMean()[1], 1.0e-10);
+        assertEquals(Math.sqrt(2.0 / 3.0), u.getStandardDeviation()[0], 1.0e-10);
+        assertEquals(Math.sqrt(2.0 / 3.0), u.getStandardDeviation()[1], 1.0e-10);
+        assertEquals(2.0 / 3.0, u.getCovariance().getEntry(0, 0), 1.0e-10);
+        assertEquals(2.0 / 3.0, u.getCovariance().getEntry(0, 1), 1.0e-10);
+        assertEquals(2.0 / 3.0, u.getCovariance().getEntry(1, 0), 1.0e-10);
+        assertEquals(2.0 / 3.0, u.getCovariance().getEntry(1, 1), 1.0e-10);
+        u.clear();
+        assertEquals(0, u.getN());    
+    }     
+
+    public void testN0andN1Conditions() throws Exception {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(1, true);
+        assertTrue(Double.isNaN(u.getMean()[0]));
+        assertTrue(Double.isNaN(u.getStandardDeviation()[0]));
+
+        /* n=1 */
+        u.addValue(new double[] { 1 });
+        assertEquals(1.0, u.getMean()[0], 1.0e-10);
+        assertEquals(1.0, u.getGeometricMean()[0], 1.0e-10);
+        assertEquals(0.0, u.getStandardDeviation()[0], 1.0e-10);
+
+        /* n=2 */               
+        u.addValue(new double[] { 2 });
+        assertTrue(u.getStandardDeviation()[0] > 0);
+
+    }
+
+    public void testNaNContracts() throws DimensionMismatchException {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(1, true);
+        assertTrue(Double.isNaN(u.getMean()[0])); 
+        assertTrue(Double.isNaN(u.getMin()[0])); 
+        assertTrue(Double.isNaN(u.getStandardDeviation()[0])); 
+        assertTrue(Double.isNaN(u.getGeometricMean()[0]));
+
+        u.addValue(new double[] { 1.0 });
+        assertFalse(Double.isNaN(u.getMean()[0])); 
+        assertFalse(Double.isNaN(u.getMin()[0])); 
+        assertFalse(Double.isNaN(u.getStandardDeviation()[0])); 
+        assertFalse(Double.isNaN(u.getGeometricMean()[0]));
+
+    }
+
+    public void testGetSummary() throws DimensionMismatchException {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(2, true);
+        StatisticalMultivariateSummary summary = u.getSummary();
+        verifySummary(u, summary);
+        u.addValue(new double[] { 1, 2 });
+        summary = u.getSummary();
+        verifySummary(u, summary);
+        u.addValue(new double[] { 2, 5 });
+        summary = u.getSummary();
+        verifySummary(u, summary);
+        u.addValue(new double[] { 2, 2 });
+        summary = u.getSummary();
+        verifySummary(u, summary);     
+    }
+
+    public void testSerialization() throws DimensionMismatchException {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(2, true);
+        // Empty test
+        TestUtils.checkSerializedEquality(u);
+        MultivariateSummaryStatistics s = (MultivariateSummaryStatistics) TestUtils.serializeAndRecover(u);
+        StatisticalMultivariateSummary summary = s.getSummary();
+        verifySummary(u, summary);
+
+        // Add some data
+        u.addValue(new double[] { 2d, 1d });
+        u.addValue(new double[] { 1d, 1d });
+        u.addValue(new double[] { 3d, 1d });
+        u.addValue(new double[] { 4d, 1d });
+        u.addValue(new double[] { 5d, 1d });
+
+        // Test again
+        TestUtils.checkSerializedEquality(u);
+        s = (MultivariateSummaryStatistics) TestUtils.serializeAndRecover(u);
+        summary = s.getSummary();
+        verifySummary(u, summary);
+
+    }
+
+    public void testEqualsAndHashCode() throws DimensionMismatchException {
+        MultivariateSummaryStatistics u = new MultivariateSummaryStatistics(2, true);
+        MultivariateSummaryStatistics t = null;
+        int emptyHash = u.hashCode();
+        assertTrue(u.equals(u));
+        assertFalse(u.equals(t));
+        assertFalse(u.equals(new Double(0)));
+        t = new MultivariateSummaryStatistics(2, true);
+        assertTrue(t.equals(u));
+        assertTrue(u.equals(t));
+        assertEquals(emptyHash, t.hashCode());
+
+        // Add some data to u
+        u.addValue(new double[] { 2d, 1d });
+        u.addValue(new double[] { 1d, 1d });
+        u.addValue(new double[] { 3d, 1d });
+        u.addValue(new double[] { 4d, 1d });
+        u.addValue(new double[] { 5d, 1d });
+        assertFalse(t.equals(u));
+        assertFalse(u.equals(t));
+        assertTrue(u.hashCode() != t.hashCode());
+
+        //Add data in same order to t
+        t.addValue(new double[] { 2d, 1d });
+        t.addValue(new double[] { 1d, 1d });
+        t.addValue(new double[] { 3d, 1d });
+        t.addValue(new double[] { 4d, 1d });
+        t.addValue(new double[] { 5d, 1d });
+        assertTrue(t.equals(u));
+        assertTrue(u.equals(t));
+        assertEquals(u.hashCode(), t.hashCode());   
+
+        // Clear and make sure summaries are indistinguishable from empty summary
+        u.clear();
+        t.clear();
+        assertTrue(t.equals(u));
+        assertTrue(u.equals(t));
+        assertEquals(emptyHash, t.hashCode());
+        assertEquals(emptyHash, u.hashCode());
+    }
+
+    private void verifySummary(MultivariateSummaryStatistics u, StatisticalMultivariateSummary s) {
+        assertEquals(s.getN(), u.getN());
+        for (int i = 0; i < u.getDimension(); ++i) {
+            checkValue(s.getSum()[i], u.getSum()[i], 1.0e-10);
+            checkValue(s.getStandardDeviation()[i], u.getStandardDeviation()[i], 1.0e-10);
+            checkValue(s.getMean()[i], u.getMean()[i], 1.0e-10);
+            checkValue(s.getMin()[i], u.getMin()[i], 1.0e-10);
+            checkValue(s.getMax()[i], u.getMax()[i], 1.0e-10);
+            checkValue(s.getSumSq()[i], u.getSumSq()[i], 1.0e-10);
+            checkValue(s.getSumLog()[i], u.getSumLog()[i], 1.0e-10);
+            checkValue(s.getMax()[i], u.getMax()[i], 1.0e-10);
+        }
+    }
+
+    private void checkValue(double expected, double actual, double tolerance) {
+        if (Double.isNaN(expected)) {
+            assertTrue(Double.isNaN(actual));
+        } else {
+            assertEquals(expected, actual, tolerance);
+        }
+    }
+
+}

Propchange: commons/proper/math/trunk/src/test/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatisticsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native