/*
* Copyright (c) 2012-2015, Peter Abeles. All Rights Reserved.
*
* This file is part of DDogleg (http://ddogleg.org).
*
* Licensed 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.ddogleg.rand;
import org.ejml.alg.dense.mult.VectorVectorMult;
import org.ejml.data.DenseMatrix64F;
import org.ejml.factory.LinearSolverFactory;
import org.ejml.interfaces.decomposition.CholeskyDecomposition;
import org.ejml.interfaces.linsol.LinearSolver;
import org.ejml.ops.CommonOps;
import java.util.Random;
import static org.ejml.ops.CommonOps.multAdd;
/**
* Draw a number from a multivariate Gaussian distribution.
*/
public class MultivariateGaussianDraw {
private LinearSolver solver;
private DenseMatrix64F mean;
private DenseMatrix64F A;
private Random rand;
private DenseMatrix64F r;
private DenseMatrix64F Q_inv;
double likelihoodLeft;
/**
* Creates a random distribution with the specified mean and covariance. The references
* to the variables are not saved, their value are copied.
*
* @param rand Used to create the random numbers for the draw.
* @param mean If not null this will be the mean of the distribution, if null then nothing is assigned.
* this is useful if someone is being anal about performance and will soon call assignMean()
* @param cov The covariance of the distribution
*/
public MultivariateGaussianDraw( Random rand , DenseMatrix64F mean , DenseMatrix64F cov )
{
if( mean != null )
this.mean = new DenseMatrix64F(mean);
else
this.mean = new DenseMatrix64F(cov.numCols,1);
r = new DenseMatrix64F(cov.numRows,1);
Q_inv = new DenseMatrix64F(cov.numRows,cov.numCols);
solver = LinearSolverFactory.chol(cov.numRows);
// will invoke decompose in cholesky
solver.setA(cov);
CholeskyDecomposition chol = solver.getDecomposition();
A = chol.getT(null);
solver.invert(Q_inv);
likelihoodLeft = Math.pow(Math.PI*2,-this.mean.numRows/2.0)*Math.sqrt(CommonOps.det(cov));
this.rand = rand;
}
/**
* Uses the referenced variable as the internal mean. This does not perform a copy but
* actually points to the specified matrix as the mean.
*/
public void assignMean( DenseMatrix64F mean ) {
this.mean = mean;
}
/**
* Makes a draw on the distribution and stores the results in parameter 'x'
*/
public DenseMatrix64F next( DenseMatrix64F x )
{
for( int i = 0; i < r.numRows; i++ ) {
r.set(i,0,rand.nextGaussian());
}
x.set(mean);
multAdd(A,r,x);
return x;
}
public double computeLikelihoodP() {
double inner = VectorVectorMult.innerProdA(r,Q_inv,r);
return likelihoodLeft*Math.exp(-0.5*inner);
}
}
Ads help maintain this website.