001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.math.stat.descriptive.moment;
018    
019    import java.io.Serializable;
020    import java.util.Arrays;
021    
022    import org.apache.commons.math.DimensionMismatchException;
023    import org.apache.commons.math.linear.MatrixUtils;
024    import org.apache.commons.math.linear.RealMatrix;
025    
026    /**
027     * Returns the covariance matrix of the available vectors.
028     * @since 1.2
029     * @version $Revision: 922714 $ $Date: 2010-03-14 02:35:14 +0100 (dim. 14 mars 2010) $
030     */
031    public class VectorialCovariance implements Serializable {
032    
033        /** Serializable version identifier */
034        private static final long serialVersionUID = 4118372414238930270L;
035    
036        /** Sums for each component. */
037        private final double[] sums;
038    
039        /** Sums of products for each component. */
040        private final double[] productsSums;
041    
042        /** Indicator for bias correction. */
043        private final boolean isBiasCorrected;
044    
045        /** Number of vectors in the sample. */
046        private long n;
047    
048        /** Constructs a VectorialCovariance.
049         * @param dimension vectors dimension
050         * @param isBiasCorrected if true, computed the unbiased sample covariance,
051         * otherwise computes the biased population covariance
052         */
053        public VectorialCovariance(int dimension, boolean isBiasCorrected) {
054            sums         = new double[dimension];
055            productsSums = new double[dimension * (dimension + 1) / 2];
056            n            = 0;
057            this.isBiasCorrected = isBiasCorrected;
058        }
059    
060        /**
061         * Add a new vector to the sample.
062         * @param v vector to add
063         * @exception DimensionMismatchException if the vector does not have the right dimension
064         */
065        public void increment(double[] v) throws DimensionMismatchException {
066            if (v.length != sums.length) {
067                throw new DimensionMismatchException(v.length, sums.length);
068            }
069            int k = 0;
070            for (int i = 0; i < v.length; ++i) {
071                sums[i] += v[i];
072                for (int j = 0; j <= i; ++j) {
073                    productsSums[k++] += v[i] * v[j];
074                }
075            }
076            n++;
077        }
078    
079        /**
080         * Get the covariance matrix.
081         * @return covariance matrix
082         */
083        public RealMatrix getResult() {
084    
085            int dimension = sums.length;
086            RealMatrix result = MatrixUtils.createRealMatrix(dimension, dimension);
087    
088            if (n > 1) {
089                double c = 1.0 / (n * (isBiasCorrected ? (n - 1) : n));
090                int k = 0;
091                for (int i = 0; i < dimension; ++i) {
092                    for (int j = 0; j <= i; ++j) {
093                        double e = c * (n * productsSums[k++] - sums[i] * sums[j]);
094                        result.setEntry(i, j, e);
095                        result.setEntry(j, i, e);
096                    }
097                }
098            }
099    
100            return result;
101    
102        }
103    
104        /**
105         * Get the number of vectors in the sample.
106         * @return number of vectors in the sample
107         */
108        public long getN() {
109            return n;
110        }
111    
112        /**
113         * Clears the internal state of the Statistic
114         */
115        public void clear() {
116            n = 0;
117            Arrays.fill(sums, 0.0);
118            Arrays.fill(productsSums, 0.0);
119        }
120    
121        /** {@inheritDoc} */
122        @Override
123        public int hashCode() {
124            final int prime = 31;
125            int result = 1;
126            result = prime * result + (isBiasCorrected ? 1231 : 1237);
127            result = prime * result + (int) (n ^ (n >>> 32));
128            result = prime * result + Arrays.hashCode(productsSums);
129            result = prime * result + Arrays.hashCode(sums);
130            return result;
131        }
132    
133        /** {@inheritDoc} */
134        @Override
135        public boolean equals(Object obj) {
136            if (this == obj)
137                return true;
138            if (!(obj instanceof VectorialCovariance))
139                return false;
140            VectorialCovariance other = (VectorialCovariance) obj;
141            if (isBiasCorrected != other.isBiasCorrected)
142                return false;
143            if (n != other.n)
144                return false;
145            if (!Arrays.equals(productsSums, other.productsSums))
146                return false;
147            if (!Arrays.equals(sums, other.sums))
148                return false;
149            return true;
150        }
151    
152    }