/* * 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.random; import org.apache.commons.math.DimensionMismatchException; import org.apache.commons.math.linear.MatrixUtils; import org.apache.commons.math.linear.NotPositiveDefiniteMatrixException; import org.apache.commons.math.linear.RealMatrix; import org.apache.commons.math.util.FastMath; /** * A {@link RandomVectorGenerator} that generates vectors with with * correlated components. *
Random vectors with correlated components are built by combining * the uncorrelated components of another random vector in such a way that * the resulting correlations are the ones specified by a positive * definite covariance matrix.
*The main use for correlated random vector generation is for Monte-Carlo * simulation of physical problems with several variables, for example to * generate error vectors to be added to a nominal vector. A particularly * interesting case is when the generated vector should be drawn from a * Multivariate Normal Distribution. The approach using a Cholesky * decomposition is quite usual in this case. However, it can be extended * to other cases as long as the underlying random generator provides * {@link NormalizedRandomGenerator normalized values} like {@link * GaussianRandomGenerator} or {@link UniformRandomGenerator}.
*Sometimes, the covariance matrix for a given simulation is not
* strictly positive definite. This means that the correlations are
* not all independent from each other. In this case, however, the non
* strictly positive elements found during the Cholesky decomposition
* of the covariance matrix should not be negative either, they
* should be null. Another non-conventional extension handling this case
* is used here. Rather than computing C = UT.U
* where C
is the covariance matrix and U
* is an upper-triangular matrix, we compute C = B.BT
* where B
is a rectangular matrix having
* more rows than columns. The number of columns of B
is
* the rank of the covariance matrix, and it is the dimension of the
* uncorrelated random vector that is needed to compute the component
* of the correlated vector. This class handles this situation
* automatically.
Build a correlated random vector generator from its mean * vector and covariance matrix.
* @param mean expected mean values for all components * @param covariance covariance matrix * @param small diagonal elements threshold under which column are * considered to be dependent on previous ones and are discarded * @param generator underlying generator for uncorrelated normalized * components * @exception IllegalArgumentException if there is a dimension * mismatch between the mean vector and the covariance matrix * @exception NotPositiveDefiniteMatrixException if the * covariance matrix is not strictly positive definite * @exception DimensionMismatchException if the mean and covariance * arrays dimensions don't match */ public CorrelatedRandomVectorGenerator(double[] mean, RealMatrix covariance, double small, NormalizedRandomGenerator generator) throws NotPositiveDefiniteMatrixException, DimensionMismatchException { int order = covariance.getRowDimension(); if (mean.length != order) { throw new DimensionMismatchException(mean.length, order); } this.mean = mean.clone(); decompose(covariance, small); this.generator = generator; normalized = new double[rank]; } /** Simple constructor. *Build a null mean random correlated vector generator from its * covariance matrix.
* @param covariance covariance matrix * @param small diagonal elements threshold under which column are * considered to be dependent on previous ones and are discarded * @param generator underlying generator for uncorrelated normalized * components * @exception NotPositiveDefiniteMatrixException if the * covariance matrix is not strictly positive definite */ public CorrelatedRandomVectorGenerator(RealMatrix covariance, double small, NormalizedRandomGenerator generator) throws NotPositiveDefiniteMatrixException { int order = covariance.getRowDimension(); mean = new double[order]; for (int i = 0; i < order; ++i) { mean[i] = 0; } decompose(covariance, small); this.generator = generator; normalized = new double[rank]; } /** Get the underlying normalized components generator. * @return underlying uncorrelated components generator */ public NormalizedRandomGenerator getGenerator() { return generator; } /** Get the root of the covariance matrix. * The root is the rectangular matrixB
such that
* the covariance matrix is equal to B.BT
* @return root of the square matrix
* @see #getRank()
*/
public RealMatrix getRootMatrix() {
return root;
}
/** Get the rank of the covariance matrix.
* The rank is the number of independent rows in the covariance
* matrix, it is also the number of columns of the rectangular
* matrix of the decomposition.
* @return rank of the square matrix.
* @see #getRootMatrix()
*/
public int getRank() {
return rank;
}
/** Decompose the original square matrix.
* The decomposition is based on a Choleski decomposition * where additional transforms are performed: *