/************************************************************************** ** ** 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. */ /* solve.c 1.2 11/25/87 */ static char rcsid[] = "$Id: solve.c,v 1.3 1999/12/15 16:01:39 soliday Exp $"; #include #include #include "matrix2.h" /* Most matrix factorisation routines are in-situ unless otherwise specified */ /* Usolve -- back substitution with optional over-riding diagonal -- can be in-situ but doesn't need to be */ VEC *Usolve(matrix,b,out,diag) MAT *matrix; VEC *b, *out; double diag; { unsigned int dim /* , j */; int i, i_lim; Real **mat_ent, *mat_row, *b_ent, *out_ent, *out_col, sum, tiny; if ( matrix==(MAT *)NULL || b==(VEC *)NULL ) error(E_NULL,"Usolve"); dim = min(matrix->m,matrix->n); if ( b->dim < dim ) error(E_SIZES,"Usolve"); if ( out==(VEC *)NULL || out->dim < dim ) out = v_resize(out,matrix->n); mat_ent = matrix->me; b_ent = b->ve; out_ent = out->ve; tiny = 10.0/HUGE_VAL; for ( i=dim-1; i>=0; i-- ) if ( b_ent[i] != 0.0 ) break; else out_ent[i] = 0.0; i_lim = i; for ( ; i>=0; i-- ) { sum = b_ent[i]; mat_row = &(mat_ent[i][i+1]); out_col = &(out_ent[i+1]); sum -= __ip__(mat_row,out_col,i_lim-i); /****************************************************** for ( j=i+1; j<=i_lim; j++ ) sum -= mat_ent[i][j]*out_ent[j]; sum -= (*mat_row++)*(*out_col++); ******************************************************/ if ( diag==0.0 ) { if ( fabs(mat_ent[i][i]) <= tiny*fabs(sum) ) error(E_SING,"Usolve"); else out_ent[i] = sum/mat_ent[i][i]; } else out_ent[i] = sum/diag; } return (out); } /* Lsolve -- forward elimination with (optional) default diagonal value */ VEC *Lsolve(matrix,b,out,diag) MAT *matrix; VEC *b,*out; double diag; { unsigned int dim, i, i_lim /* , j */; Real **mat_ent, *mat_row, *b_ent, *out_ent, *out_col, sum, tiny; if ( matrix==(MAT *)NULL || b==(VEC *)NULL ) error(E_NULL,"Lsolve"); dim = min(matrix->m,matrix->n); if ( b->dim < dim ) error(E_SIZES,"Lsolve"); if ( out==(VEC *)NULL || out->dim < dim ) out = v_resize(out,matrix->n); mat_ent = matrix->me; b_ent = b->ve; out_ent = out->ve; for ( i=0; im,U->n); if ( b->dim < dim ) error(E_SIZES,"UTsolve"); out = v_resize(out,U->n); U_me = U->me; b_ve = b->ve; out_ve = out->ve; tiny = 10.0/HUGE_VAL; for ( i=0; idim); MEM_COPY(&(b_ve[i_lim]),&(out_ve[i_lim]),(dim-i_lim)*sizeof(Real)); } if ( diag == 0.0 ) { for ( ; im,A->n); if ( b->dim < dim ) error(E_SIZES,"Dsolve"); x = v_resize(x,A->n); tiny = 10.0/HUGE_VAL; dim = b->dim; for ( i=0; ime[i][i]) <= tiny*fabs(b->ve[i]) ) error(E_SING,"Dsolve"); else x->ve[i] = b->ve[i]/A->me[i][i]; return (x); } /* LTsolve -- back substitution with optional over-riding diagonal using the LOWER triangular part of matrix -- can be in-situ but doesn't need to be */ VEC *LTsolve(L,b,out,diag) MAT *L; VEC *b, *out; double diag; { unsigned int dim; int i, i_lim; Real **L_me, *b_ve, *out_ve, tmp, invdiag, tiny; if ( ! L || ! b ) error(E_NULL,"LTsolve"); dim = min(L->m,L->n); if ( b->dim < dim ) error(E_SIZES,"LTsolve"); out = v_resize(out,L->n); L_me = L->me; b_ve = b->ve; out_ve = out->ve; tiny = 10.0/HUGE_VAL; for ( i=dim-1; i>=0; i-- ) if ( b_ve[i] != 0.0 ) break; i_lim = i; if ( b != out ) { __zero__(out_ve,out->dim); MEM_COPY(b_ve,out_ve,(i_lim+1)*sizeof(Real)); } if ( diag == 0.0 ) { for ( ; i>=0; i-- ) { tmp = L_me[i][i]; if ( fabs(tmp) <= tiny*fabs(out_ve[i]) ) error(E_SING,"LTsolve"); out_ve[i] /= tmp; __mltadd__(out_ve,L_me[i],-out_ve[i],i); } } else { invdiag = 1.0/diag; for ( ; i>=0; i-- ) { out_ve[i] *= invdiag; __mltadd__(out_ve,L_me[i],-out_ve[i],i); } } return (out); }