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 */
017package org.apache.commons.math4.stat.descriptive.moment;
018
019import java.io.Serializable;
020import java.util.Arrays;
021
022import org.apache.commons.math4.exception.DimensionMismatchException;
023import org.apache.commons.math4.linear.MatrixUtils;
024import org.apache.commons.math4.linear.RealMatrix;
025
026/**
027 * Returns the covariance matrix of the available vectors.
028 * @since 1.2
029 */
030public class VectorialCovariance implements Serializable {
031
032    /** Serializable version identifier */
033    private static final long serialVersionUID = 4118372414238930270L;
034
035    /** Sums for each component. */
036    private final double[] sums;
037
038    /** Sums of products for each component. */
039    private final double[] productsSums;
040
041    /** Indicator for bias correction. */
042    private final boolean isBiasCorrected;
043
044    /** Number of vectors in the sample. */
045    private long n;
046
047    /** Constructs a VectorialCovariance.
048     * @param dimension vectors dimension
049     * @param isBiasCorrected if true, computed the unbiased sample covariance,
050     * otherwise computes the biased population covariance
051     */
052    public VectorialCovariance(int dimension, boolean isBiasCorrected) {
053        sums         = new double[dimension];
054        productsSums = new double[dimension * (dimension + 1) / 2];
055        n            = 0;
056        this.isBiasCorrected = isBiasCorrected;
057    }
058
059    /**
060     * Add a new vector to the sample.
061     * @param v vector to add
062     * @throws DimensionMismatchException if the vector does not have the right dimension
063     */
064    public void increment(double[] v) throws DimensionMismatchException {
065        if (v.length != sums.length) {
066            throw new DimensionMismatchException(v.length, sums.length);
067        }
068        int k = 0;
069        for (int i = 0; i < v.length; ++i) {
070            sums[i] += v[i];
071            for (int j = 0; j <= i; ++j) {
072                productsSums[k++] += v[i] * v[j];
073            }
074        }
075        n++;
076    }
077
078    /**
079     * Get the covariance matrix.
080     * @return covariance matrix
081     */
082    public RealMatrix getResult() {
083
084        int dimension = sums.length;
085        RealMatrix result = MatrixUtils.createRealMatrix(dimension, dimension);
086
087        if (n > 1) {
088            double c = 1.0 / (n * (isBiasCorrected ? (n - 1) : n));
089            int k = 0;
090            for (int i = 0; i < dimension; ++i) {
091                for (int j = 0; j <= i; ++j) {
092                    double e = c * (n * productsSums[k++] - sums[i] * sums[j]);
093                    result.setEntry(i, j, e);
094                    result.setEntry(j, i, e);
095                }
096            }
097        }
098
099        return result;
100
101    }
102
103    /**
104     * Get the number of vectors in the sample.
105     * @return number of vectors in the sample
106     */
107    public long getN() {
108        return n;
109    }
110
111    /**
112     * Clears the internal state of the Statistic
113     */
114    public void clear() {
115        n = 0;
116        Arrays.fill(sums, 0.0);
117        Arrays.fill(productsSums, 0.0);
118    }
119
120    /** {@inheritDoc} */
121    @Override
122    public int hashCode() {
123        final int prime = 31;
124        int result = 1;
125        result = prime * result + (isBiasCorrected ? 1231 : 1237);
126        result = prime * result + (int) (n ^ (n >>> 32));
127        result = prime * result + Arrays.hashCode(productsSums);
128        result = prime * result + Arrays.hashCode(sums);
129        return result;
130    }
131
132    /** {@inheritDoc} */
133    @Override
134    public boolean equals(Object obj) {
135        if (this == obj) {
136            return true;
137        }
138        if (!(obj instanceof VectorialCovariance)) {
139            return false;
140        }
141        VectorialCovariance other = (VectorialCovariance) obj;
142        if (isBiasCorrected != other.isBiasCorrected) {
143            return false;
144        }
145        if (n != other.n) {
146            return false;
147        }
148        if (!Arrays.equals(productsSums, other.productsSums)) {
149            return false;
150        }
151        if (!Arrays.equals(sums, other.sums)) {
152            return false;
153        }
154        return true;
155    }
156
157}