|
Packit |
67cb25 |
/* L D L^T Decomposition
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2016 Patrick Alken
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This is free software; you can redistribute it and/or modify it
|
|
Packit |
67cb25 |
* under the terms of the GNU General Public License as published by the
|
|
Packit |
67cb25 |
* Free Software Foundation; either version 3, or (at your option) any
|
|
Packit |
67cb25 |
* later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This source is distributed in the hope that it will be useful, but WITHOUT
|
|
Packit |
67cb25 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit |
67cb25 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
Packit |
67cb25 |
* for more details.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* L D L^T decomposition of a symmetrix positive definite matrix.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This algorithm does:
|
|
Packit |
67cb25 |
* P A P' = L D L'
|
|
Packit |
67cb25 |
* with
|
|
Packit |
67cb25 |
* L := unit lower left triangle matrix
|
|
Packit |
67cb25 |
* D := diagonal matrix
|
|
Packit |
67cb25 |
* L' := the transposed form of L.
|
|
Packit |
67cb25 |
* P := permutation matrix
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <gsl/gsl_math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_vector.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_matrix.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_blas.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_linalg.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_permutation.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_permute_vector.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "cholesky_common.c"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double cholesky_LDLT_norm1(const gsl_matrix * LDLT, const gsl_permutation * p,
|
|
Packit |
67cb25 |
gsl_vector * work);
|
|
Packit |
67cb25 |
static int cholesky_LDLT_Ainv(CBLAS_TRANSPOSE_t TransA, gsl_vector * x, void * params);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
typedef struct
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const gsl_matrix * LDLT;
|
|
Packit |
67cb25 |
const gsl_permutation * perm;
|
|
Packit |
67cb25 |
} pcholesky_params;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
pcholesky_decomp()
|
|
Packit |
67cb25 |
Perform Pivoted Cholesky LDLT decomposition of a symmetric positive
|
|
Packit |
67cb25 |
semidefinite matrix
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: copy_uplo - copy lower triangle to upper to save original matrix
|
|
Packit |
67cb25 |
for rcond calculation later
|
|
Packit |
67cb25 |
A - (input) symmetric, positive semidefinite matrix,
|
|
Packit |
67cb25 |
stored in lower triangle
|
|
Packit |
67cb25 |
(output) lower triangle contains L; diagonal contains D
|
|
Packit |
67cb25 |
p - permutation vector
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) Based on algorithm 4.2.2 (Outer Product LDLT with Pivoting) of
|
|
Packit |
67cb25 |
Golub and Van Loan, Matrix Computations (4th ed).
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
pcholesky_decomp (const int copy_uplo, gsl_matrix * A, gsl_permutation * p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = A->size1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (N != A->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("LDLT decomposition requires square matrix", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (p->size != N)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("permutation length must match matrix size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view diag = gsl_matrix_diagonal(A);
|
|
Packit |
67cb25 |
size_t k;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (copy_uplo)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* save a copy of A in upper triangle (for later rcond calculation) */
|
|
Packit |
67cb25 |
gsl_matrix_transpose_tricpy('L', 0, A, A);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_permutation_init(p);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (k = 0; k < N; ++k)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view w;
|
|
Packit |
67cb25 |
size_t j;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute j = max_idx { A_kk, ..., A_nn } */
|
|
Packit |
67cb25 |
w = gsl_vector_subvector(&diag.vector, k, N - k);
|
|
Packit |
67cb25 |
j = gsl_vector_max_index(&w.vector) + k;
|
|
Packit |
67cb25 |
gsl_permutation_swap(p, k, j);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
cholesky_swap_rowcol(A, k, j);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (k < N - 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double alpha = gsl_matrix_get(A, k, k);
|
|
Packit |
67cb25 |
double alphainv = 1.0 / alpha;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* v = A(k+1:n, k) */
|
|
Packit |
67cb25 |
gsl_vector_view v = gsl_matrix_subcolumn(A, k, k + 1, N - k - 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* m = A(k+1:n, k+1:n) */
|
|
Packit |
67cb25 |
gsl_matrix_view m = gsl_matrix_submatrix(A, k + 1, k + 1, N - k - 1, N - k - 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* m = m - v v^T / alpha */
|
|
Packit |
67cb25 |
gsl_blas_dsyr(CblasLower, -alphainv, &v.vector, &m.matrix);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* v = v / alpha */
|
|
Packit |
67cb25 |
gsl_vector_scale(&v.vector, alphainv);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_decomp()
|
|
Packit |
67cb25 |
Perform Pivoted Cholesky LDLT decomposition of a symmetric positive
|
|
Packit |
67cb25 |
semidefinite matrix
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: A - (input) symmetric, positive semidefinite matrix,
|
|
Packit |
67cb25 |
stored in lower triangle
|
|
Packit |
67cb25 |
(output) lower triangle contains L; diagonal contains D
|
|
Packit |
67cb25 |
p - permutation vector
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) Based on algorithm 4.2.2 (Outer Product LDLT with Pivoting) of
|
|
Packit |
67cb25 |
Golub and Van Loan, Matrix Computations (4th ed).
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_decomp (gsl_matrix * A, gsl_permutation * p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status = pcholesky_decomp(1, A, p);
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_solve(const gsl_matrix * LDLT,
|
|
Packit |
67cb25 |
const gsl_permutation * p,
|
|
Packit |
67cb25 |
const gsl_vector * b,
|
|
Packit |
67cb25 |
gsl_vector * x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (LDLT->size1 != LDLT->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("LDLT matrix must be square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != p->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match permutation size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != b->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match b size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size2 != x->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy (x, b);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_linalg_pcholesky_svx (LDLT, p, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_svx(const gsl_matrix * LDLT,
|
|
Packit |
67cb25 |
const gsl_permutation * p,
|
|
Packit |
67cb25 |
gsl_vector * x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (LDLT->size1 != LDLT->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("LDLT matrix must be square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != p->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match permutation size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size2 != x->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_const_view D = gsl_matrix_const_diagonal(LDLT);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* x := P b */
|
|
Packit |
67cb25 |
gsl_permute_vector(p, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve: L w = P b */
|
|
Packit |
67cb25 |
gsl_blas_dtrsv(CblasLower, CblasNoTrans, CblasUnit, LDLT, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve: D y = w */
|
|
Packit |
67cb25 |
gsl_vector_div(x, &D.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve: L^T z = y */
|
|
Packit |
67cb25 |
gsl_blas_dtrsv(CblasLower, CblasTrans, CblasUnit, LDLT, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: x = P^T z */
|
|
Packit |
67cb25 |
gsl_permute_vector_inverse(p, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_decomp2(gsl_matrix * A, gsl_permutation * p,
|
|
Packit |
67cb25 |
gsl_vector * S)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t M = A->size1;
|
|
Packit |
67cb25 |
const size_t N = A->size2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (M != N)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("cholesky decomposition requires square matrix", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (N != p->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match permutation size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (N != S->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("S must have length N", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* save a copy of A in upper triangle (for later rcond calculation) */
|
|
Packit |
67cb25 |
gsl_matrix_transpose_tricpy('L', 0, A, A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute scaling factors to reduce cond(A) */
|
|
Packit |
67cb25 |
status = gsl_linalg_cholesky_scale(A, S);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* apply scaling factors */
|
|
Packit |
67cb25 |
status = gsl_linalg_cholesky_scale_apply(A, S);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute Cholesky decomposition of diag(S) A diag(S) */
|
|
Packit |
67cb25 |
status = pcholesky_decomp(0, A, p);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_solve2(const gsl_matrix * LDLT,
|
|
Packit |
67cb25 |
const gsl_permutation * p,
|
|
Packit |
67cb25 |
const gsl_vector * S,
|
|
Packit |
67cb25 |
const gsl_vector * b,
|
|
Packit |
67cb25 |
gsl_vector * x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (LDLT->size1 != LDLT->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("LDLT matrix must be square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != p->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match permutation size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != S->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match S", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != b->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match b size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size2 != x->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy (x, b);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_linalg_pcholesky_svx2 (LDLT, p, S, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_svx2(const gsl_matrix * LDLT,
|
|
Packit |
67cb25 |
const gsl_permutation * p,
|
|
Packit |
67cb25 |
const gsl_vector * S,
|
|
Packit |
67cb25 |
gsl_vector * x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (LDLT->size1 != LDLT->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("LDLT matrix must be square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != p->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match permutation size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != S->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match S", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size2 != x->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* x := S b */
|
|
Packit |
67cb25 |
gsl_vector_mul(x, S);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve: A~ x~ = b~, with A~ = S A S, b~ = S b */
|
|
Packit |
67cb25 |
status = gsl_linalg_pcholesky_svx(LDLT, p, x);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: x = S x~ */
|
|
Packit |
67cb25 |
gsl_vector_mul(x, S);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_invert()
|
|
Packit |
67cb25 |
Compute the inverse of a symmetric positive definite matrix in
|
|
Packit |
67cb25 |
Cholesky form.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: LDLT - matrix in cholesky form
|
|
Packit |
67cb25 |
p - permutation
|
|
Packit |
67cb25 |
Ainv - (output) A^{-1}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_invert(const gsl_matrix * LDLT, const gsl_permutation * p,
|
|
Packit |
67cb25 |
gsl_matrix * Ainv)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t M = LDLT->size1;
|
|
Packit |
67cb25 |
const size_t N = LDLT->size2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (M != N)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("LDLT matrix must be square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (LDLT->size1 != p->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("matrix size must match permutation size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (Ainv->size1 != Ainv->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("Ainv matrix must be square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (Ainv->size1 != M)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("Ainv matrix has wrong dimensions", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i, j;
|
|
Packit |
67cb25 |
gsl_vector_view v1, v2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* invert the lower triangle of LDLT */
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(Ainv, LDLT);
|
|
Packit |
67cb25 |
gsl_linalg_tri_lower_unit_invert(Ainv);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute sqrt(D^{-1}) L^{-1} in the lower triangle of Ainv */
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double di = gsl_matrix_get(LDLT, i, i);
|
|
Packit |
67cb25 |
double sqrt_di = sqrt(di);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < i; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double *Lij = gsl_matrix_ptr(Ainv, i, j);
|
|
Packit |
67cb25 |
*Lij /= sqrt_di;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_set(Ainv, i, i, 1.0 / sqrt_di);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* The lower triangle of Ainv now contains D^{-1/2} L^{-1}. Now compute
|
|
Packit |
67cb25 |
* A^{-1} = L^{-T} D^{-1} L^{-1}
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double aii = gsl_matrix_get(Ainv, i, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (i < N - 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double tmp;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
v1 = gsl_matrix_subcolumn(Ainv, i, i, N - i);
|
|
Packit |
67cb25 |
gsl_blas_ddot(&v1.vector, &v1.vector, &tmp);
|
|
Packit |
67cb25 |
gsl_matrix_set(Ainv, i, i, tmp);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (i > 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_view m = gsl_matrix_submatrix(Ainv, i + 1, 0, N - i - 1, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
v1 = gsl_matrix_subcolumn(Ainv, i, i + 1, N - i - 1);
|
|
Packit |
67cb25 |
v2 = gsl_matrix_subrow(Ainv, i, 0, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_dgemv(CblasTrans, 1.0, &m.matrix, &v1.vector, aii, &v2.vector);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
v1 = gsl_matrix_row(Ainv, N - 1);
|
|
Packit |
67cb25 |
gsl_blas_dscal(aii, &v1.vector);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* copy lower triangle to upper */
|
|
Packit |
67cb25 |
gsl_matrix_transpose_tricpy('L', 0, Ainv, Ainv);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* now apply permutation p to the matrix */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute L^{-T} D^{-1} L^{-1} P^T */
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
v1 = gsl_matrix_row(Ainv, i);
|
|
Packit |
67cb25 |
gsl_permute_vector_inverse(p, &v1.vector);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute P L^{-T} D^{-1} L^{-1} P^T */
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
v1 = gsl_matrix_column(Ainv, i);
|
|
Packit |
67cb25 |
gsl_permute_vector_inverse(p, &v1.vector);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_pcholesky_rcond (const gsl_matrix * LDLT, const gsl_permutation * p,
|
|
Packit |
67cb25 |
double * rcond, gsl_vector * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t M = LDLT->size1;
|
|
Packit |
67cb25 |
const size_t N = LDLT->size2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (M != N)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("cholesky matrix must be square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (work->size != 3 * N)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("work vector must have length 3*N", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
double Anorm = cholesky_LDLT_norm1(LDLT, p, work); /* ||A||_1 */
|
|
Packit |
67cb25 |
double Ainvnorm; /* ||A^{-1}||_1 */
|
|
Packit |
67cb25 |
pcholesky_params params;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*rcond = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* don't continue if matrix is singular */
|
|
Packit |
67cb25 |
if (Anorm == 0.0)
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
params.LDLT = LDLT;
|
|
Packit |
67cb25 |
params.perm = p;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* estimate ||A^{-1}||_1 */
|
|
Packit |
67cb25 |
status = gsl_linalg_invnorm1(N, cholesky_LDLT_Ainv, ¶ms, &Ainvnorm, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (Ainvnorm != 0.0)
|
|
Packit |
67cb25 |
*rcond = (1.0 / Anorm) / Ainvnorm;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
cholesky_LDLT_norm1
|
|
Packit |
67cb25 |
Compute 1-norm of original matrix A, stored in upper triangle of LDLT;
|
|
Packit |
67cb25 |
diagonal entries have to be reconstructed
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: LDLT - Cholesky L D L^T decomposition (lower triangle) with
|
|
Packit |
67cb25 |
original matrix in upper triangle
|
|
Packit |
67cb25 |
p - permutation vector
|
|
Packit |
67cb25 |
work - workspace, length 2*N
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
cholesky_LDLT_norm1(const gsl_matrix * LDLT, const gsl_permutation * p, gsl_vector * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = LDLT->size1;
|
|
Packit |
67cb25 |
gsl_vector_const_view D = gsl_matrix_const_diagonal(LDLT);
|
|
Packit |
67cb25 |
gsl_vector_view diagA = gsl_vector_subvector(work, N, N);
|
|
Packit |
67cb25 |
double max = 0.0;
|
|
Packit |
67cb25 |
size_t i, j;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* reconstruct diagonal entries of original matrix A */
|
|
Packit |
67cb25 |
for (j = 0; j < N; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double Ajj;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute diagonal (j,j) entry of A */
|
|
Packit |
67cb25 |
Ajj = gsl_vector_get(&D.vector, j);
|
|
Packit |
67cb25 |
for (i = 0; i < j; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double Di = gsl_vector_get(&D.vector, i);
|
|
Packit |
67cb25 |
double Lji = gsl_matrix_get(LDLT, j, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Ajj += Di * Lji * Lji;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(&diagA.vector, j, Ajj);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_permute_vector_inverse(p, &diagA.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < N; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double sum = 0.0;
|
|
Packit |
67cb25 |
double Ajj = gsl_vector_get(&diagA.vector, j);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < j; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double *wi = gsl_vector_ptr(work, i);
|
|
Packit |
67cb25 |
double Aij = gsl_matrix_get(LDLT, i, j);
|
|
Packit |
67cb25 |
double absAij = fabs(Aij);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
sum += absAij;
|
|
Packit |
67cb25 |
*wi += absAij;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(work, j, sum + fabs(Ajj));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double wi = gsl_vector_get(work, i);
|
|
Packit |
67cb25 |
max = GSL_MAX(max, wi);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return max;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* x := A^{-1} x = A^{-t} x, A = L D L^T */
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
cholesky_LDLT_Ainv(CBLAS_TRANSPOSE_t TransA, gsl_vector * x, void * params)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
pcholesky_params *par = (pcholesky_params *) params;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(void) TransA; /* unused parameter warning */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_linalg_pcholesky_svx(par->LDLT, par->perm, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|