/* routine: cm_invert() * purpose: invert a complex matrix * usage: cm_invert(A, B) ==> A=INV(B); A and B must point to matrix * structures of the same size. * Michael Borland, 1986 (after CITLIB routine MATINV), Louis Emery 1992. */ #include "complex.h" #include "cmatlib.h" #include "mdb.h" #define MAXIMUM_EXPONENT 126 int cm_invert(CMATRIX *A, CMATRIX *B) /* A=inv(B) */ { register long i, j, k, l, m, n; static long *ipivot=NULL, **index=NULL, *ind_l; static COMPLEX *pivot=NULL, piv, t; static double swap, *tmp, abs_amax; static long row, col, max_n=0; static double *ar_j, *ai_j, *ar_col, *ai_col, *ar_m, *ai_m; double mod_a_col_l; long exponent_mod_a_col_l; long exponent_t, exponent_piv; COMPLEX c; if (!A) bomb("NULL CMATRIX (A) passed to cm_invert", NULL); if (!B) bomb("NULL CMATRIX (B) passed to cm_invert", NULL); if (!A->ar || !A->ai) bomb("NULL CMATRIX data (A) in cm_invert", NULL); if (!B->ar || !B->ai) bomb("NULL CMATRIX data (A) in cm_invert", NULL); if ((n=A->n)!=A->m || A->m!=B->n || B->n!=B->m) { fprintf(stderr, "CMATRIX size mismatch (cm_invert)\n"); return(0); } if (max_nar[j]) || !(ai_j = A->ai[j])) { fprintf(stderr, "row %ld of CMATRIX A is NULL (cm_invert)", j); abort(); } if (ipivot[j]!=1) { for (k=0; k1) return(0); if (ipivot[k]!=1 && abs_amaxar[row]; A->ar[row] = A->ar[col]; A->ar[col] = tmp; tmp = A->ai[row]; A->ai[row] = A->ai[col]; A->ai[col] = tmp; } if (!index[i]) bomb("pivot index array has NULL element (cm_invert)", NULL); index[i][0] = row; index[i][1] = col; pivot[i] = cassign(A->ar[col][col],A->ai[col][col]); /* divide pivot row by pivot element */ A->ar[col][col] = 1.0; A->ai[col][col] = 0.0; ar_col = A->ar[col]; ai_col = A->ai[col]; piv = pivot[i]; frexp( cmod(piv), (int*) &exponent_piv ); /* frexp also return the unneeded mantissa */ for (l=0; l MAXIMUM_EXPONENT) { printf("error: floating overflow in cm_invert (pivot too small).\n"); return(0); } c=cdiv(cassign(ar_col[l],ai_col[l]),piv); ar_col[l]=c.r; ai_col[l]=c.i; } /* reduce non-pivot rows */ for (m=0; mar[m]; ai_m = A->ai[m]; t = cassign(ar_m[col],ai_m[col]); ar_m[col] = 0.; ai_m[col] = 0.; if (t.r!=0 || t.i!=0) frexp(cmod(t),(int*)&exponent_t); else exponent_t = 0; for (l=0; l 37) { */ if ((mod_a_col_l!=0?exponent_mod_a_col_l:0)+exponent_t > MAXIMUM_EXPONENT) { printf("error: floating-point overflow in cm_invert().\n"); return(0); } /* a_m[l] -= a_col[l]*t; */ c=csub(cassign(ar_m[l],ai_m[l]),cmul(cassign(ar_col[l],ai_col[l]),t)); ar_m[l]=c.r; ai_m[l]=c.i; } } } } /* interchange columns */ for (i=0; in) bomb("row out of range in column interchange (cm_invert)", NULL); if ((col = ind_l[1])<0 || col>n) bomb("column out of range in column interchange (cm_invert)", NULL); for (j=0; jar[j]; swap = ar_j[row]; ar_j[row] = ar_j[col]; ar_j[col] = swap; ai_j = A->ai[j]; swap = ai_j[row]; ai_j[row] = ai_j[col]; ai_j[col] = swap; } } return(1); }