#include #include #include "matinv.h" #define TINY 1.0e-20 /*....................................................................... * Use Gauss-Jordan elimination to invert a matrix. * * Input: * lhs double ** A SQUARE matrix organised as a C array of pointers * to vectors, and dimensioned as lhs[nu][nu]. * work1 int * Work array of length nu. * work2 int * Work array of length nu. * work3 int * Work array of length nu. * nu int The number of unknowns and thus the dimensions of * lhs and rhs above. * Output: * return int 0 - success, anything else means an error occurred. * -1 - singular matrix. */ int gj_invert(double **lhs, int *work1, int *work2, int *work3, int nu) { int *done=work1; /* Records which diagonals have been pivotted */ int *orig=work2; /* Records original row index of n'th pivot row */ int *dest=work3; /* Records destination row index of n'th pivot row */ int iter; /* Iteration counter. Every iteration reduces one row */ int maxcol=0; /* The diagonal element, lhs[diag][diag] being made 1 */ int maxrow=0; /* Row with new pivot in it, before row swap. */ int icol; /* Column number */ int irow; /* Row number */ double maxpiv=0.0; /* Maximum (absolute) usable pivot element in 'lhs'. */ double pivval=0.0; /* Signed value of maxpiv */ /* * No diagonals yet pivotted. */ for(irow=0; irow= 0.0 ? newval : -newval; if(absval > maxpiv) { pivval = newval; maxpiv = absval; maxrow = irow; maxcol = icol; }; }; }; }; }; /* * If no appropriate pivot was found, the matrix is singular * and so can't be solved. */ if(maxpiv==0.0) { fprintf(stderr, "gj_invert: Singular matrix.\n"); return -1; }; /* * Flag the diagonal that the newly found pivot will be used on, as done. */ done[maxcol] = 1; /* * Swap rows so that the new pivot will be on the associated diagonal. */ if(maxrow != maxcol) { double *row1 = lhs[maxrow]; double *row2 = lhs[maxcol]; for(icol=0; icol=0; iter--) { int acol = dest[iter]; int bcol = orig[iter]; for(irow=0; irow= 0.0 ? newval : -newval; if(absval > maxpiv) { pivval = newval; maxpiv = absval; maxrow = irow; maxcol = icol; }; }; }; }; }; /* * If no appropriate pivot was found, the matrix is singular * and so can't be solved. */ if(maxpiv==0.0) { fprintf(stderr, "gj_solve: Singular matrix.\n"); return -1; }; /* * Flag the diagonal that the newly found pivot will be used on, as done. */ done[maxcol] = 1; /* * Swap rows so that the new pivot will be on the associated diagonal. * Simply swap row pointers in the row[] copy of rhs[]. */ if(maxrow != maxcol) { { /* Swap lhs rows */ double *tmp = rows[maxrow]; rows[maxrow] = rows[maxcol]; rows[maxcol] = tmp; }; { /* Swap rhs rows */ double tmp = rhs[maxrow]; rhs[maxrow] = rhs[maxcol]; rhs[maxcol] = tmp; }; }; /* * Divide the pivot row by its pivot element. */ for(icol=0; icol maxval) maxval=absval; }; if(maxval == 0.0) { /* Check for singular matrix */ fprintf(stderr, "lu_decomp: Singular matrix.\n"); return -1; }; dwrk[row]=1.0/maxval; /* Store the normalisation factor */ }; /* * Loop over columns to implement Crout's method. */ for(col=0; col maxval) { maxval=absval; maxpiv=row; }; }; /* * Swap rows by swapping row pointers. */ ptmp=lhs[pivrow]; lhs[pivrow] = lhs[maxpiv]; lhs[maxpiv] = ptmp; /* * Swap the associated row normalization factors. */ dtmp=dwrk[pivrow]; dwrk[pivrow]=dwrk[maxpiv]; dwrk[maxpiv]=dtmp; /* * Record the row swap. */ indx[pivrow]=maxpiv; /* * Avoid singular matrix. */ if(lhs[col][col]==0.0) lhs[col][col] = TINY; /* * Divide the current column of the lower triangle by its pivot element. */ dtmp = 1.0/lhs[col][col]; for(j=col+1;j=0; row--) { sum=rhs[row]; for(col=row+1; col