-
Thomas Witkowski authoredThomas Witkowski authored
Cholesky.cc 3.37 KiB
#include "Cholesky.h"
bool Cholesky::factorization(Matrix<double> *A, Vector<double> *p)
{
FUNCNAME("Cholesky::factorization()");
int n = A->getNumRows();
// Checking memory for vector P of diagonal elements of factorization.
static Vector<double> *pT = NULL;
if (p)
{
if (p->getSize() != n)
p->resize(n);
}
else
{
if (pT)
{
if (pT->getSize() != n)
pT->resize(n);
}
else
pT = new Vector<double>(n);
p = pT;
}
// Constructs the Cholesky factorization A = L*L, with L lower triangular.
// Only the upper triangle need be given; it is not modified.
// The Cholesky factor L is stored in the lower triangle of A, except for
// its diagonal which is stored in P.
int i, j, k;
double sum;
for (i=0; i<n; i++)
{
for (j=i; j<n; j++)
{
for (sum=(*A)[i][j], k=i-1; k>=0; k--)
sum -= (*A)[i][k] * (*A)[j][k];
if (i==j)
{
if (sum<=0)
{
MSG("Matrix is (numerically) not positive definite!\n");
MSG("Cholesky decomposition does not work; choose another method for solving the system.\n");
return false;
}
(*p)[i] = sqrt(sum);
}
else
(*A)[j][i] = sum / (*p)[i];
}
}
return true;
}
bool Cholesky::solve(Matrix<double> *A, Vector<double> *b, Vector<double> *x,
Vector<double> *p)
{
FUNCNAME("Cholesky::solve");
bool success = true;
int n = b->getSize();
TEST_EXIT(n == A->getNumRows())
("Dimensions of matrix and vector do not match!\n");
// Checking memory for solution vector X.
if (x && (x->getSize() != n))
x->resize(n);
if (!x)
x = new Vector<double>(n);
// Checking vector P.
static Vector<double> *pT = NULL;
if (!p || (p->getSize() != n))
{
if (pT && pT->getSize() != n)
delete pT;
if (!pT)
pT = new Vector<double>(n);
p = pT;
success = factorization(A, p);
}
// Now solve the system by backsubstitution.
int i, k;
double sum;
for (i=0; i<n; i++) // Solve L*Y = B, storing Y in X.
{
for (sum=(*b)[i], k=i-1; k>=0; k--)
sum -= (*A)[i][k] * (*x)[k];
(*x)[i] = sum / (*p)[i];
}
for (i=n-1; i>=0; i--) // Solve L^T*X = Y.
{
for (sum=(*x)[i], k=i+1; k<n; k++)
sum -= (*A)[k][i] * (*x)[k];
(*x)[i] = sum / (*p)[i];
}
return success;
}
bool Cholesky::solve(Matrix<double> *A, Vector<WorldVector<double> > *b,
Vector<WorldVector<double> > *x, Vector<double> *p)
{
FUNCNAME("Cholesky::solve");
bool success = true;
int n = b->getSize();
TEST_EXIT(n == A->getNumRows())
("Dimensions of matrix and vector do not match!\n");
// Checking memory for solution vector X.
if (x && (x->getSize() != n))
x->resize(n);
if (!x)
x = new Vector<WorldVector<double> >(n);
// Checking vector P.
static Vector<double> *pT = NULL;
if (!p || (p->getSize() != n))
{
pT = new Vector<double>(n);
p = pT;
success = factorization(A, p);
}
// Now solve the system by backsubstitution.
int i, k;
WorldVector<double> vec_sum;
for (i=0; i<n; i++) // Solve L*Y = B, storing L in X.
{
for (vec_sum=(*b)[i], k=i-1; k>=0; k--)
vec_sum -= (*x)[k] * (*A)[i][k] ;
(*x)[i] = vec_sum * (1.0/(*p)[i]);
}
for (i=n-1; i>=0; i--) // Solve L^T*X = Y.
{
for (vec_sum=(*x)[i], k=i+1; k<n; k++)
vec_sum -= (*x)[k] * (*A)[k][i] ;
(*x)[i] = vec_sum * (1.0/(*p)[i]);
}
return success;
}