|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* -- SuperLU routine (version 2.0) --
|
|
kusano |
7d535a |
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
|
kusano |
7d535a |
* and Lawrence Berkeley National Lab.
|
|
kusano |
7d535a |
* November 15, 1997
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
#include <math.h></math.h>
|
|
kusano |
7d535a |
#include "slu_cdefs.h"
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
int cgst01(int m, int n, SuperMatrix *A, SuperMatrix *L,
|
|
kusano |
7d535a |
SuperMatrix *U, int *perm_c, int *perm_r, float *resid)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
Purpose
|
|
kusano |
7d535a |
=======
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
CGST01 reconstructs a matrix A from its L*U factorization and
|
|
kusano |
7d535a |
computes the residual
|
|
kusano |
7d535a |
norm(L*U - A) / ( N * norm(A) * EPS ),
|
|
kusano |
7d535a |
where EPS is the machine epsilon.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
Arguments
|
|
kusano |
7d535a |
==========
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
M (input) INT
|
|
kusano |
7d535a |
The number of rows of the matrix A. M >= 0.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
N (input) INT
|
|
kusano |
7d535a |
The number of columns of the matrix A. N >= 0.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
A (input) SuperMatrix *, dimension (A->nrow, A->ncol)
|
|
kusano |
7d535a |
The original M x N matrix A.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
L (input) SuperMatrix *, dimension (L->nrow, L->ncol)
|
|
kusano |
7d535a |
The factor matrix L.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
U (input) SuperMatrix *, dimension (U->nrow, U->ncol)
|
|
kusano |
7d535a |
The factor matrix U.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
perm_c (input) INT array, dimension (N)
|
|
kusano |
7d535a |
The column permutation from CGSTRF.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
perm_r (input) INT array, dimension (M)
|
|
kusano |
7d535a |
The pivot indices from CGSTRF.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
RESID (output) FLOAT*
|
|
kusano |
7d535a |
norm(L*U - A) / ( N * norm(A) * EPS )
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
=====================================================================
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Local variables */
|
|
kusano |
7d535a |
complex zero = {0.0, 0.0};
|
|
kusano |
7d535a |
int i, j, k, arow, lptr,isub, urow, superno, fsupc, u_part;
|
|
kusano |
7d535a |
complex utemp, comp_temp;
|
|
kusano |
7d535a |
float anorm, tnorm, cnorm;
|
|
kusano |
7d535a |
float eps;
|
|
kusano |
7d535a |
complex *work;
|
|
kusano |
7d535a |
SCformat *Lstore;
|
|
kusano |
7d535a |
NCformat *Astore, *Ustore;
|
|
kusano |
7d535a |
complex *Aval, *Lval, *Uval;
|
|
kusano |
7d535a |
int *colbeg, *colend;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Function prototypes */
|
|
kusano |
7d535a |
extern float clangs(char *, SuperMatrix *);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Quick exit if M = 0 or N = 0. */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
if (m <= 0 || n <= 0) {
|
|
kusano |
7d535a |
*resid = 0.f;
|
|
kusano |
7d535a |
return 0;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
work = (complex *)complexCalloc(m);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
Astore = A->Store;
|
|
kusano |
7d535a |
Aval = Astore->nzval;
|
|
kusano |
7d535a |
Lstore = L->Store;
|
|
kusano |
7d535a |
Lval = Lstore->nzval;
|
|
kusano |
7d535a |
Ustore = U->Store;
|
|
kusano |
7d535a |
Uval = Ustore->nzval;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Determine EPS and the norm of A. */
|
|
kusano |
7d535a |
eps = slamch_("Epsilon");
|
|
kusano |
7d535a |
anorm = clangs("1", A);
|
|
kusano |
7d535a |
cnorm = 0.;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Compute the product L*U, one column at a time */
|
|
kusano |
7d535a |
for (k = 0; k < n; ++k) {
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* The U part outside the rectangular supernode */
|
|
kusano |
7d535a |
for (i = U_NZ_START(k); i < U_NZ_START(k+1); ++i) {
|
|
kusano |
7d535a |
urow = U_SUB(i);
|
|
kusano |
7d535a |
utemp = Uval[i];
|
|
kusano |
7d535a |
superno = Lstore->col_to_sup[urow];
|
|
kusano |
7d535a |
fsupc = L_FST_SUPC(superno);
|
|
kusano |
7d535a |
u_part = urow - fsupc + 1;
|
|
kusano |
7d535a |
lptr = L_SUB_START(fsupc) + u_part;
|
|
kusano |
7d535a |
work[L_SUB(lptr-1)].r -= utemp.r;
|
|
kusano |
7d535a |
work[L_SUB(lptr-1)].i -= utemp.i;
|
|
kusano |
7d535a |
for (j = L_NZ_START(urow) + u_part; j < L_NZ_START(urow+1); ++j) {
|
|
kusano |
7d535a |
isub = L_SUB(lptr);
|
|
kusano |
7d535a |
cc_mult(&comp_temp, &utemp, &Lval[j]);
|
|
kusano |
7d535a |
c_sub(&work[isub], &work[isub], &comp_temp);
|
|
kusano |
7d535a |
++lptr;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* The U part inside the rectangular supernode */
|
|
kusano |
7d535a |
superno = Lstore->col_to_sup[k];
|
|
kusano |
7d535a |
fsupc = L_FST_SUPC(superno);
|
|
kusano |
7d535a |
urow = L_NZ_START(k);
|
|
kusano |
7d535a |
for (i = fsupc; i <= k; ++i) {
|
|
kusano |
7d535a |
utemp = Lval[urow++];
|
|
kusano |
7d535a |
u_part = i - fsupc + 1;
|
|
kusano |
7d535a |
lptr = L_SUB_START(fsupc) + u_part;
|
|
kusano |
7d535a |
work[L_SUB(lptr-1)].r -= utemp.r;
|
|
kusano |
7d535a |
work[L_SUB(lptr-1)].i -= utemp.i;
|
|
kusano |
7d535a |
for (j = L_NZ_START(i)+u_part; j < L_NZ_START(i+1); ++j) {
|
|
kusano |
7d535a |
isub = L_SUB(lptr);
|
|
kusano |
7d535a |
cc_mult(&comp_temp, &utemp, &Lval[j]);
|
|
kusano |
7d535a |
c_sub(&work[isub], &work[isub], &comp_temp);
|
|
kusano |
7d535a |
++lptr;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Now compute A[k] - (L*U)[k] (Both matrices may be permuted.) */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
colbeg = intMalloc(n);
|
|
kusano |
7d535a |
colend = intMalloc(n);
|
|
kusano |
7d535a |
for (i = 0; i < n; i++) {
|
|
kusano |
7d535a |
colbeg[perm_c[i]] = Astore->colptr[i];
|
|
kusano |
7d535a |
colend[perm_c[i]] = Astore->colptr[i+1];
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
for (i = colbeg[k]; i < colend[k]; ++i) {
|
|
kusano |
7d535a |
arow = Astore->rowind[i];
|
|
kusano |
7d535a |
work[perm_r[arow]].r += Aval[i].r;
|
|
kusano |
7d535a |
work[perm_r[arow]].i += Aval[i].i;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Now compute the 1-norm of the column vector work */
|
|
kusano |
7d535a |
tnorm = 0.;
|
|
kusano |
7d535a |
for (i = 0; i < m; ++i) {
|
|
kusano |
7d535a |
tnorm += fabs(work[i].r) + fabs(work[i].i);
|
|
kusano |
7d535a |
work[i] = zero;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
cnorm = SUPERLU_MAX(tnorm, cnorm);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
*resid = cnorm;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
if (anorm <= 0.f) {
|
|
kusano |
7d535a |
if (*resid != 0.f) {
|
|
kusano |
7d535a |
*resid = 1.f / eps;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
} else {
|
|
kusano |
7d535a |
*resid = *resid / (float) n / anorm / eps;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
SUPERLU_FREE(work);
|
|
kusano |
7d535a |
SUPERLU_FREE(colbeg);
|
|
kusano |
7d535a |
SUPERLU_FREE(colend);
|
|
kusano |
7d535a |
return 0;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* End of CGST01 */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
} /* cgst01_ */
|
|
kusano |
7d535a |
|