blob: 0e017dfe45076e8224141aeedaaffc3281bfc4d8 [file] [log] [blame]
// 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.spaceroots.mantissa.random;
import org.spaceroots.mantissa.linalg.SymetricalMatrix;
/** This class compute basic statistics on a scalar sample.
* @version $Id$
* @author L. Maisonobe
*/
public class VectorialSampleStatistics {
/** Dimension of the vectors to handle. */
private int dimension;
/** Number of sample points. */
private int n;
/** Indices of the minimal values occurrence in the sample. */
private int[] minIndices;
/** Minimal value in the sample. */
private double[] min;
/** Maximal value in the sample. */
private double[] max;
/** Indices of the maximal values occurrence in the sample. */
private int[] maxIndices;
/** Sum of the sample values. */
private double[] sum;
/** Sum of the squares of the sample values. */
private double[] sum2;
/** Simple constructor.
* Build a new empty instance
*/
public VectorialSampleStatistics() {
dimension = -1;
n = 0;
min = null;
minIndices = null;
max = null;
maxIndices = null;
sum = null;
sum2 = null;
}
/** Add one point to the instance.
* @param x value of the sample point
* @exception IllegalArgumentException if there is a dimension
* mismatch between this point and the ones already added (this
* cannot happen when the instance is empty)
*/
public void add(double[] x) {
if (n == 0) {
dimension = x.length;
minIndices = new int[dimension];
maxIndices = new int[dimension];
min = (double[]) x.clone();
max = (double[]) x.clone();
sum = (double[]) x.clone();
sum2 = new double[dimension * (dimension + 1) / 2];
int k = 0;
for (int i = 0; i < dimension; ++i) {
for (int j = 0; j <= i; ++j) {
sum2[k++] = x[i] * x[j];
}
}
} else {
int k = 0;
for (int i = 0; i < dimension; ++i) {
if (x[i] < min[i]) {
min[i] = x[i];
minIndices[i] = n;
} else if (x[i] > max[i]) {
max[i] = x[i];
maxIndices[i] = n;
}
sum[i] += x[i];
for (int j = 0; j <= i; ++j) {
sum2[k++] += x[i] * x[j];
}
}
}
++n;
}
/** Add all points of an array to the instance.
* @param points array of points
* @exception IllegalArgumentException if there is a dimension
* mismatch between these points and the ones already added (this
* cannot happen when the instance is empty)
*/
public void add(double[][] points) {
for (int i = 0; i < points.length; ++i) {
add(points[i]);
}
}
/** Add all the points of another sample to the instance.
* @param s samples to add
* @exception IllegalArgumentException if there is a dimension
* mismatch between this sample points and the ones already added
* (this cannot happen when the instance is empty)
*/
public void add(VectorialSampleStatistics s) {
if (s.n == 0) {
// nothing to add
return;
}
if (n == 0) {
dimension = s.dimension;
min = (double[]) s.min.clone();
minIndices = (int[]) s.minIndices.clone();
max = (double[]) s.max.clone();
maxIndices = (int[]) s.maxIndices.clone();
sum = (double[]) s.sum.clone();
sum2 = (double[]) s.sum2.clone();
} else {
int k = 0;
for (int i = 0; i < dimension; ++i) {
if (s.min[i] < min[i]) {
min[i] = s.min[i];
minIndices[i] = n;
} else if (s.max[i] > max[i]) {
max[i] = s.max[i];
maxIndices[i] = n;
}
sum[i] += s.sum[i];
for (int j = 0; j <= i; ++j) {
sum2[k] += s.sum2[k];
++k;
}
}
}
n += s.n;
}
/** Get the number of points in the sample.
* @return number of points in the sample
*/
public int size() {
return n;
}
/** Get the minimal value in the sample.
* <p>Since all components of the sample vector can reach their
* minimal value at different times, this vector should be
* considered as gathering all minimas of all components. The index
* of the sample at which the minimum was encountered can be
* retrieved with the {@link #getMinIndices getMinIndices}
* method.</p>
* @return minimal value in the sample (a new array is created
* at each call, the caller may do what it wants to with it)
* @see #getMinIndices
*/
public double[] getMin() {
return (double[]) min.clone();
}
/** Get the indices at which the minimal value occurred in the sample.
* @return a vector reporting at which occurrence each component of
* the sample reached its minimal value (a new array is created
* at each call, the caller may do what it wants to with it)
* @see #getMin
*/
public int[] getMinIndices() {
return (int[]) minIndices.clone();
}
/** Get the maximal value in the sample.
* <p>Since all components of the sample vector can reach their
* maximal value at different times, this vector should be
* considered as gathering all maximas of all components. The index
* of the sample at which the maximum was encountered can be
* retrieved with the {@link #getMaxIndices getMaxIndices}
* method.</p>
* @return maximal value in the sample (a new array is created
* at each call, the caller may do what it wants to with it)
* @see #getMaxIndices
*/
public double[] getMax() {
return (double[]) max.clone();
}
/** Get the indices at which the maximal value occurred in the sample.
* @return a vector reporting at which occurrence each component of
* the sample reached its maximal value (a new array is created
* at each call, the caller may do what it wants to with it)
* @see #getMax
*/
public int[] getMaxIndices() {
return (int[]) maxIndices.clone();
}
/** Get the mean value of the sample.
* @return mean value of the sample or an empty array
* if the sample is empty (a new array is created
* at each call, the caller may do what it wants to with it)
*/
public double[] getMean() {
if (n == 0) {
return new double[0];
}
double[] mean = new double[dimension];
for (int i = 0; i < dimension; ++i) {
mean[i] = sum[i] / n;
}
return mean;
}
/** Get the covariance matrix of the underlying law.
* This method estimate the covariance matrix considering that the
* data available are only a <em>sample</em> of all possible
* values. This value is the sample covariance matrix (as opposed
* to the population covariance matrix).
* @param covariance placeholder where to store the matrix, if null
* a new matrix will be allocated
* @return covariance matrix of the underlying or null if the
* sample has less than 2 points (reference to covariance if it was
* non-null, reference to a new matrix otherwise)
*/
public SymetricalMatrix getCovarianceMatrix(SymetricalMatrix covariance) {
if (n < 2) {
return null;
}
if (covariance == null) {
covariance = new SymetricalMatrix(dimension);
}
double c = 1.0 / (n * (n - 1));
int k = 0;
for (int i = 0; i < dimension; ++i) {
for (int j = 0; j <= i; ++j) {
double e = c * (n * sum2[k] - sum[i] * sum[j]);
covariance.setElementAndSymetricalElement(i, j, e);
++k;
}
}
return covariance;
}
}