org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionLDL Maven / Gradle / Ivy
Show all versions of ejml Show documentation
/*
* Copyright (c) 2009-2012, Peter Abeles. All Rights Reserved.
*
* This file is part of Efficient Java Matrix Library (EJML).
*
* EJML is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* EJML is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EJML. If not, see .
*/
package org.ejml.alg.dense.decomposition.chol;
import org.ejml.data.DenseMatrix64F;
import org.ejml.factory.DecompositionInterface;
/**
*
* This variant on the Cholesky decomposition avoid the need to take the square root
* by performing the following decomposition:
*
* L*D*LT=A
*
* where L is a lower triangular matrix with zeros on the diagonal. D is a diagonal matrix.
* The diagonal elements of L are equal to one.
*
*
* Unfortunately the speed advantage of not computing the square root is washed out by the
* increased number of array accesses. There only appears to be a slight speed boost for
* very small matrices.
*
*
* @author Peter Abeles
*/
public class CholeskyDecompositionLDL
implements DecompositionInterface {
// it can decompose a matrix up to this width
private int maxWidth;
// width and height of the matrix
private int n;
// the decomposed matrix
private DenseMatrix64F L;
private double[] el;
// the D vector
private double[] d;
// tempoary variable used by various functions
double vv[];
public void setExpectedMaxSize( int numRows , int numCols ) {
if( numRows != numCols ) {
throw new IllegalArgumentException("Can only decompose square matrices");
}
this.maxWidth = numRows;
this.L = new DenseMatrix64F(maxWidth,maxWidth);
this.el = L.data;
this.vv = new double[maxWidth];
this.d = new double[maxWidth];
}
/**
*
* Performs Choleksy decomposition on the provided matrix.
*
*
*
* If the matrix is not positive definite then this function will return
* false since it can't complete its computations. Not all errors will be
* found.
*
* @param mat A symetric n by n positive definite matrix.
* @return True if it was able to finish the decomposition.
*/
public boolean decompose( DenseMatrix64F mat ) {
if( mat.numRows > maxWidth ) {
setExpectedMaxSize(mat.numRows,mat.numCols);
} else if( mat.numRows != mat.numCols ) {
throw new RuntimeException("Can only decompose square matrices");
}
n = mat.numRows;
L.setReshape(mat);
double d_inv=0;
for( int i = 0; i < n; i++ ) {
for( int j = i; j < n; j++ ) {
double sum = el[i*n+j];
for( int k = 0; k < i; k++ ) {
sum -= el[i*n+k]*el[j*n+k]*d[k];
}
if( i == j ) {
// is it positive-definate?
if( sum <= 0.0 )
return false;
d[i] = sum;
d_inv = 1.0/sum;
el[i*n+i] = 1;
} else {
el[j*n+i] = sum*d_inv;
}
}
}
// zero the top right corner.
for( int i = 0; i < n; i++ ) {
for( int j = i+1; j < n; j++ ) {
el[i*n+j] = 0.0;
}
}
return true;
}
@Override
public boolean inputModified() {
return false;
}
/**
* Diagonal elements of the diagonal D matrix.
*
* @return diagonal elements of D
*/
public double[] getD() {
return d;
}
/**
* Returns L matrix from the decomposition.
* L*D*LT=A
*
* @return A lower triangular matrix.
*/
public DenseMatrix64F getL() {
return L;
}
public double[] _getVV() {
return vv;
}
}