/* matinv.c

   written by Frederic Yves Bois
   28 August 1991
   
   Copyright (c) 1993.  Don Maszle, Frederic Bois.  All rights reserved.

   -- Revisions -----
     Logfile:  SCCS/s.matinv.c
    Revision:  1.1
        Date:  7/14/93
     Modtime:  19:14:44
      Author:  @a
   -- SCCS  ---------

   Invert a matrix.
*/

#ifdef __LOCAL_HDR__
#include "math.h"

#else
#include <math.h>
#endif

#include "global.h" 		/* must define dim1Max, max array length */

typedef long table1[dim1Max];


/*-------------------------------------------------------------------------*/
void matinv (double **mat, long dim, double *det)
{
/*---------------------------------------------------------------------------
This subroutine is based on the SSP subroutine of the same name. It is
designed to invert a general matrix.

       mat.............Input matrix, modified in the computation.
                       type matrixType11, square, is defined above
       dim.............The size of the square matrix mat
       det.............On output, the determinant of mat. A zero
                       determinant indicates a singular matrix

The Gauss Jordan technique with pivoting on the largest elements is used.
-----------------------------------------------------------------------------*/

  double tempo, pivot;
  table1 ipivot;   /* index line */
  table1 jpivot;   /* index column */
  long i, j, k;

  *det = 1.0;   /* initialization*/

  /* go along the diagonale : */
  for (k = 0; k < dim; k++) {
    pivot = mat[k][k];
    ipivot[k] = k + 1;
    jpivot[k] = k + 1;

    /* compare pivot to the elements of the minor : */
    for (i = k + 1; i <= dim; i++) {
      for (j = k + 1; j <= dim; j++) {
	if (fabs(mat[i - 1][j - 1]) > fabs(pivot)) {
	  pivot = mat[i - 1][j - 1];
	  ipivot[k] = i;
	  jpivot[k] = j;
	}
      }
    }

    /* interchange columns if pivot is not
       the diagonal elem. number k : */
    j = jpivot[k];
    if (j > k + 1) {
      for (i = 0; i < dim; i++) {
	tempo = -mat[i][k];
	mat[i][k] = mat[i][j - 1];
	mat[i][j - 1] = tempo;
      }
    }

    /* interchange lines if pivot is not
       the diagonal elem. number k : */
    i = ipivot[k];
    if (i > k + 1) {
      for (j = 0; j < dim; j++) {
	tempo = -mat[k][j];
	mat[k][j] = mat[i - 1][j];
	mat[i - 1][j] = tempo;
      }
    }

    /* divide line k by minus pivot, but the element number k : */

    if (pivot == 0.0) { /* singular matrix, det = 0, resume and quit */
      *det = 0.0;
      for (i = 0; i < dim; i++) {
	for (j = 0; j < dim; j++)
	  mat[i][j] = 0.0;
      }
      goto L666;
    }

    for (j = 0; j < dim; j++) {
      if (j + 1 != k + 1)
	mat[k][j] /= -pivot;
    }

    /* reduce matrix : */
    for (j = 0; j < dim; j++) {
      tempo = mat[k][j];
      for (i = 0; i < dim; i++) {
	if (i + 1 != k + 1 && j + 1 != k + 1)
	  mat[i][j] += tempo * mat[i][k];
      }
    }

    /* divide column number k by pivot, then product of pivots,
       then replace pivot by reciprocal : */
    for (i = 0; i < dim; i++) {
      if (i + 1 != k + 1)
	mat[i][k] /= pivot;
    }

    *det *= pivot;

    mat[k][k] = 1.0 / pivot;

  }  /* end of for k */

  /* final line and column interchange : */
  for (k = dim - 2; k >= 0; k--) {
    if (jpivot[k] > k + 1) {
      for (j = 0; j < dim; j++) {
	tempo = mat[k][j];
	mat[k][j] = -mat[jpivot[k] - 1][j];
	mat[jpivot[k] - 1][j] = tempo;
      }
    }

    if (ipivot[k] > k + 1) {
      for (i = 0; i < dim; i++) {
	tempo = mat[i][k];
	mat[i][k] = -mat[i][ipivot[k] - 1];
	mat[i][ipivot[k] - 1] = tempo;
      }

    }
  } /* end of for k */

L666: ; /* quick exit for singular matrix */

}  /* matinv */
