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