    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.math3.stat.descriptive.moment;
    018
    019    import java.io.Serializable;
    020    import java.util.Arrays;
    021
    022    import org.apache.commons.math3.exception.DimensionMismatchException;
    023    import org.apache.commons.math3.linear.MatrixUtils;
    024    import org.apache.commons.math3.linear.RealMatrix;
    025
    026    /**
    027     * Returns the covariance matrix of the available vectors.
    028     * @since 1.2
    029     * @version $Id: VectorialCovariance.java 1416643 2012-12-03 19:37:14Z tn $
    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         * @throws 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            }
    139            if (!(obj instanceof VectorialCovariance)) {
    140                return false;
    141            }
    142            VectorialCovariance other = (VectorialCovariance) obj;
    143            if (isBiasCorrected != other.isBiasCorrected) {
    144                return false;
    145            }
    146            if (n != other.n) {
    147                return false;
    148            }
    149            if (!Arrays.equals(productsSums, other.productsSums)) {
    150                return false;
    151            }
    152            if (!Arrays.equals(sums, other.sums)) {
    153                return false;
    154            }
    155            return true;
    156        }
    157
    158    }