/************************************************************************** ** ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved. ** ** Meschach Library ** ** This Meschach Library is provided "as is" without any express ** or implied warranty of any kind with respect to this software. ** In particular the authors shall not be liable for any direct, ** indirect, special, incidental or consequential damages arising ** in any way from use of the software. ** ** Everyone is granted permission to copy, modify and redistribute this ** Meschach Library, provided: ** 1. All copies contain this copyright notice. ** 2. All modified copies shall carry a notice stating who ** made the last modification and the date of such modification. ** 3. No charge is made for this software or works derived from it. ** This clause shall not be construed as constraining other software ** distributed on the same medium as this software, nor is a ** distribution fee considered a charge. ** ***************************************************************************/ /* Matrix factorisation routines to work with the other matrix files. Complex version */ static char rcsid[] = "$Id: zlufctr.c,v 1.3 1999/10/27 21:50:41 borland Exp $"; #include #include #include "zmatrix.h" #include "zmatrix2.h" #define is_zero(z) ((z).re == 0.0 && (z).im == 0.0) /* Most matrix factorisation routines are in-situ unless otherwise specified */ /* zLUfactor -- Gaussian elimination with scaled partial pivoting -- Note: returns LU matrix which is A */ ZMAT *zLUfactor(A,pivot) ZMAT *A; PERM *pivot; { unsigned int i, j, k, k_max, m, n; int i_max; Real dtemp, max1; complex **A_v, *A_piv, *A_row, temp; static VEC *scale = VNULL; if ( A==ZMNULL || pivot==PNULL ) error(E_NULL,"zLUfactor"); if ( pivot->size != A->m ) error(E_SIZES,"zLUfactor"); m = A->m; n = A->n; scale = v_resize(scale,A->m); MEM_STAT_REG(scale,TYPE_VEC); A_v = A->me; /* initialise pivot with identity permutation */ for ( i=0; ipe[i] = i; /* set scale parameters */ for ( i=0; ive[i] = max1; } /* main loop */ k_max = min(m,n)-1; for ( k=0; kve[i] > 0.0 ) { dtemp = zabs(A_v[i][k])/scale->ve[i]; if ( dtemp > max1 ) { max1 = dtemp; i_max = i; } } /* if no pivot then ignore column k... */ if ( i_max == -1 ) continue; /* do we pivot ? */ if ( i_max != k ) /* yes we do... */ { px_transp(pivot,i_max,k); for ( j=0; jm != A->n || A->n != b->dim ) error(E_SIZES,"zLUsolve"); x = px_zvec(pivot,b,x); /* x := P.b */ zLsolve(A,x,x,1.0); /* implicit diagonal = 1 */ zUsolve(A,x,x,0.0); /* explicit diagonal */ return (x); } /* zLUAsolve -- given an LU factorisation in A, solve A^*.x=b */ ZVEC *zLUAsolve(LU,pivot,b,x) ZMAT *LU; PERM *pivot; ZVEC *b,*x; { if ( ! LU || ! b || ! pivot ) error(E_NULL,"zLUAsolve"); if ( LU->m != LU->n || LU->n != b->dim ) error(E_SIZES,"zLUAsolve"); x = zv_copy(b,x); zUAsolve(LU,x,x,0.0); /* explicit diagonal */ zLAsolve(LU,x,x,1.0); /* implicit diagonal = 1 */ pxinv_zvec(pivot,x,x); /* x := P^*.x */ return (x); } /* zm_inverse -- returns inverse of A, provided A is not too rank deficient -- uses LU factorisation */ ZMAT *zm_inverse(A,out) ZMAT *A, *out; { int i; ZVEC *tmp, *tmp2; ZMAT *A_cp; PERM *pivot; if ( ! A ) error(E_NULL,"zm_inverse"); if ( A->m != A->n ) error(E_SQUARE,"zm_inverse"); if ( ! out || out->m < A->m || out->n < A->n ) out = zm_resize(out,A->m,A->n); A_cp = zm_copy(A,ZMNULL); tmp = zv_get(A->m); tmp2 = zv_get(A->m); pivot = px_get(A->m); tracecatch(zLUfactor(A_cp,pivot),"zm_inverse"); for ( i = 0; i < A->n; i++ ) { zv_zero(tmp); tmp->ve[i].re = 1.0; tmp->ve[i].im = 0.0; tracecatch(zLUsolve(A_cp,pivot,tmp,tmp2),"m_inverse"); zset_col(out,i,tmp2); } ZM_FREE(A_cp); ZV_FREE(tmp); ZV_FREE(tmp2); PX_FREE(pivot); return out; } /* zLUcondest -- returns an estimate of the condition number of LU given the LU factorisation in compact form */ double zLUcondest(LU,pivot) ZMAT *LU; PERM *pivot; { static ZVEC *y = ZVNULL, *z = ZVNULL; Real cond_est, L_norm, U_norm, norm, sn_inv; complex sum; int i, j, n; if ( ! LU || ! pivot ) error(E_NULL,"zLUcondest"); if ( LU->m != LU->n ) error(E_SQUARE,"zLUcondest"); if ( LU->n != pivot->size ) error(E_SIZES,"zLUcondest"); n = LU->n; y = zv_resize(y,n); z = zv_resize(z,n); MEM_STAT_REG(y,TYPE_ZVEC); MEM_STAT_REG(z,TYPE_ZVEC); cond_est = 0.0; /* should never be returned */ for ( i = 0; i < n; i++ ) { sum.re = 1.0; sum.im = 0.0; for ( j = 0; j < i; j++ ) /* sum -= LU->me[j][i]*y->ve[j]; */ sum = zsub(sum,zmlt(LU->me[j][i],y->ve[j])); /* sum -= (sum < 0.0) ? 1.0 : -1.0; */ sn_inv = 1.0 / zabs(sum); sum.re += sum.re * sn_inv; sum.im += sum.im * sn_inv; if ( is_zero(LU->me[i][i]) ) return HUGE; /* y->ve[i] = sum / LU->me[i][i]; */ y->ve[i] = zdiv(sum,LU->me[i][i]); } zLAsolve(LU,y,y,1.0); zLUsolve(LU,pivot,y,z); /* now estimate norm of A (even though it is not directly available) */ /* actually computes ||L||_inf.||U||_inf */ U_norm = 0.0; for ( i = 0; i < n; i++ ) { norm = 0.0; for ( j = i; j < n; j++ ) norm += zabs(LU->me[i][j]); if ( norm > U_norm ) U_norm = norm; } L_norm = 0.0; for ( i = 0; i < n; i++ ) { norm = 1.0; for ( j = 0; j < i; j++ ) norm += zabs(LU->me[i][j]); if ( norm > L_norm ) L_norm = norm; } tracecatch(cond_est = U_norm*L_norm*zv_norm_inf(z)/zv_norm_inf(y), "LUcondest"); return cond_est; }