1 /***************************************************************************
5 ----------------------------------------------------------------------------
7 FUNCTION: general real matrix routines; includes
8 gaussj() for matrix inversion using
9 Gauss-Jordan method with full pivoting.
11 The routines in this module have come more or less from ref [1].
12 Note that, probably due to the heritage of ref [1] (which has a
13 FORTRAN version that was probably written first), the use of 1 as
14 the first element of an array (or vector) is used. This is accomplished
15 in memory by allocating, but not using, the 0 elements in each dimension.
16 While this wastes some memory, it allows the routines to be ported more
17 easily from FORTRAN (I suspect) as well as adhering to conventional
18 matrix notation. As a result, however, traditional ANSI C convention
19 (0-base indexing) is not followed; as the authors of ref [1] point out,
20 there is some question of the portability of the resulting routines
21 which sometimes access negative indexes. See ref [1] for more details.
23 ----------------------------------------------------------------------------
25 MODULE STATUS: developmental
27 ----------------------------------------------------------------------------
29 GENEALOGY: Created 950222 E. B. Jackson
31 ----------------------------------------------------------------------------
33 DESIGNED BY: from Numerical Recipes in C, by Press, et. al.
35 CODED BY: Bruce Jackson
39 ----------------------------------------------------------------------------
49 Revision 1.1 2002/09/10 01:14:02 curt
52 Revision 1.1.1.1 1999/06/17 18:07:34 curt
55 Revision 1.1.1.1 1999/04/05 21:32:45 curt
56 Start of 0.6.x branch.
58 Revision 1.1 1998/06/27 22:34:57 curt
61 * Revision 1.1 1995/02/27 19:55:44 bjax
65 ----------------------------------------------------------------------------
67 REFERENCES: [1] Press, William H., et. al, Numerical Recipes in
68 C, 2nd edition, Cambridge University Press, 1992
70 ----------------------------------------------------------------------------
74 ----------------------------------------------------------------------------
78 ----------------------------------------------------------------------------
82 ----------------------------------------------------------------------------
86 --------------------------------------------------------------------------*/
100 #include "ls_matrix.h"
103 #define SWAP(a,b) {temp=(a);(a)=(b);(b)=temp;}
105 static char rcsid[] = "$Id$";
108 int *nr_ivector(long nl, long nh)
112 v=(int *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(int)));
118 double **nr_matrix(long nrl, long nrh, long ncl, long nch)
119 /* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */
121 long i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
124 /* allocate pointers to rows */
125 m=(double **) malloc((size_t)((nrow+NR_END)*sizeof(double*)));
129 fprintf(stderr, "Memory failure in routine 'nr_matrix'.\n");
136 /* allocate rows and set pointers to them */
137 m[nrl] = (double *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(double)));
140 fprintf(stderr, "Memory failure in routine 'matrix'\n");
147 for (i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
149 /* return pointer to array of pointers to rows */
154 void nr_free_ivector(int *v, long nl /* , long nh */)
156 free( (char *) (v+nl-NR_END));
160 void nr_free_matrix(double **m, long nrl, long nrh, long ncl, long nch)
161 /* free a double matrix allocated by nr_matrix() */
163 free((char *) (m[nrl]+ncl-NR_END));
164 free((char *) (m+nrl-NR_END));
168 int nr_gaussj(double **a, int n, double **b, int m)
170 /* Linear equation solution by Gauss-Jordan elimination. a[1..n][1..n] is */
171 /* the input matrix. b[1..n][1..m] is input containing the m right-hand */
172 /* side vectors. On output, a is replaced by its matrix invers, and b is */
173 /* replaced by the corresponding set of solution vectors. */
175 /* Note: this routine modified by EBJ to make b optional, if m == 0 */
178 int *indxc, *indxr, *ipiv;
179 int i, icol, irow, j, k, l, ll;
180 double big, dum, pivinv, temp;
182 int bexists = ((m != 0) || (b == 0));
184 indxc = nr_ivector(1,n); /* The integer arrays ipiv, indxr, and */
185 indxr = nr_ivector(1,n); /* indxc are used for pivot bookkeeping */
186 ipiv = nr_ivector(1,n);
188 for (j=1;j<=n;j++) ipiv[j] = 0;
190 for (i=1;i<=n;i++) /* This is the main loop over columns */
193 for (j=1;j<=n;j++) /* This is outer loop of pivot search */
199 if (fabs(a[j][k]) >= big)
207 if (ipiv[k] > 1) return -1;
211 /* We now have the pivot element, so we interchange rows, if needed, */
212 /* to put the pivot element on the diagonal. The columns are not */
213 /* physically interchanged, only relabeled: indxc[i], the column of the */
214 /* ith pivot element, is the ith column that is reduced, while indxr[i] */
215 /* is the row in which that pivot element was orignally located. If */
216 /* indxr[i] != indxc[i] there is an implied column interchange. With */
217 /* this form of bookkeeping, the solution b's will end up in the correct */
218 /* order, and the inverse matrix will be scrambed by columns. */
222 /* for (l=1;1<=n;l++) SWAP(a[irow][l],a[icol][l]) */
226 a[irow][l]=a[icol][l];
229 if (bexists) for (l=1;l<=m;l++) SWAP(b[irow][l],b[icol][l])
231 indxr[i] = irow; /* We are now ready to divide the pivot row */
232 indxc[i] = icol; /* by the pivot element, a[irow][icol] */
233 if (a[icol][icol] == 0.0) return -1;
234 pivinv = 1.0/a[icol][icol];
236 for (l=1;l<=n;l++) a[icol][l] *= pivinv;
237 if (bexists) for (l=1;l<=m;l++) b[icol][l] *= pivinv;
238 for (ll=1;ll<=n;ll++) /* Next, we reduce the rows... */
239 if (ll != icol ) /* .. except for the pivot one */
243 for (l=1;l<=n;l++) a[ll][l] -= a[icol][l]*dum;
244 if (bexists) for (l=1;l<=m;l++) b[ll][i] -= b[icol][l]*dum;
248 /* This is the end of the mail loop over columns of the reduction. It
249 only remains to unscrambled the solution in view of the column
250 interchanges. We do this by interchanging pairs of columns in
251 the reverse order that the permutation was built up. */
255 if (indxr[l] != indxc[l])
257 SWAP(a[k][indxr[l]],a[k][indxc[l]])
260 /* and we are done */
262 nr_free_ivector(ipiv,1 /*,n*/ );
263 nr_free_ivector(indxr,1 /*,n*/ );
264 nr_free_ivector(indxc,1 /*,n*/ );
266 return 0; /* indicate success */
269 void nr_copymat(double **orig, int n, double **copy)
270 /* overwrites matrix 'copy' with copy of matrix 'orig' */
274 if ((orig==0)||(copy==0)||(n==0)) return;
278 copy[i][j] = orig[i][j];
281 void nr_multmat(double **m1, int n, double **m2, double **prod)
285 if ((m1==0)||(m2==0)||(prod==0)||(n==0)) return;
291 for(k=1;k<=n;k++) prod[i][j] += m1[i][k]*m2[k][j];
297 void nr_printmat(double **a, int n)
305 printf("% 9.4f ", a[i][j]);
313 void testmat( void ) /* main() for test purposes */
315 double **mat1, **mat2, **mat3;
317 int loop, i, j, n = 20;
318 long maxlong = RAND_MAX;
321 invmaxlong = 1.0/(double)maxlong;
322 mat1 = nr_matrix(1, n, 1, n );
323 mat2 = nr_matrix(1, n, 1, n );
324 mat3 = nr_matrix(1, n, 1, n );
326 /* for(i=1;i<=n;i++) mat1[i][i]= 5.0; */
328 for(loop=0;loop<maxloop;loop++)
333 mat1[i][j] = 2.0 - 4.0*invmaxlong*(double) rand();
335 printf("Original matrix:\n");
336 nr_printmat( mat1, n );
338 nr_copymat( mat1, n, mat2 );
340 i = nr_gaussj( mat2, n, 0, 0 );
342 if (i) printf("Singular matrix.\n");
344 printf("Inverted matrix:\n");
345 nr_printmat( mat2, n );
347 nr_multmat( mat1, n, mat2, mat3 );
349 printf("Original multiplied by inverse:\n");
350 nr_printmat( mat3, n );
352 if (loop < maxloop-1) /* sleep(1) */;
355 nr_free_matrix( mat1, 1, n, 1, n );
356 nr_free_matrix( mat2, 1, n, 1, n );
357 nr_free_matrix( mat3, 1, n, 1, n );