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 1998/06/27 22:34:57 curt
52 * Revision 1.1 1995/02/27 19:55:44 bjax
56 ----------------------------------------------------------------------------
58 REFERENCES: [1] Press, William H., et. al, Numerical Recipes in
59 C, 2nd edition, Cambridge University Press, 1992
61 ----------------------------------------------------------------------------
65 ----------------------------------------------------------------------------
69 ----------------------------------------------------------------------------
73 ----------------------------------------------------------------------------
77 --------------------------------------------------------------------------*/
91 #include "ls_matrix.h"
94 #define SWAP(a,b) {temp=(a);(a)=(b);(b)=temp;}
96 static char rcsid[] = "$Id$";
99 int *nr_ivector(long nl, long nh)
103 v=(int *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(int)));
109 double **nr_matrix(long nrl, long nrh, long ncl, long nch)
110 /* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */
112 long i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
115 /* allocate pointers to rows */
116 m=(double **) malloc((size_t)((nrow+NR_END)*sizeof(double*)));
120 fprintf(stderr, "Memory failure in routine 'nr_matrix'.\n");
127 /* allocate rows and set pointers to them */
128 m[nrl] = (double *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(double)));
131 fprintf(stderr, "Memory failure in routine 'matrix'\n");
138 for (i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
140 /* return pointer to array of pointers to rows */
145 void nr_free_ivector(int *v, long nl /* , long nh */)
147 free( (char *) (v+nl-NR_END));
151 void nr_free_matrix(double **m, long nrl, long nrh, long ncl, long nch)
152 /* free a double matrix allocated by nr_matrix() */
154 free((char *) (m[nrl]+ncl-NR_END));
155 free((char *) (m+nrl-NR_END));
159 int nr_gaussj(double **a, int n, double **b, int m)
161 /* Linear equation solution by Gauss-Jordan elimination. a[1..n][1..n] is */
162 /* the input matrix. b[1..n][1..m] is input containing the m right-hand */
163 /* side vectors. On output, a is replaced by its matrix invers, and b is */
164 /* replaced by the corresponding set of solution vectors. */
166 /* Note: this routine modified by EBJ to make b optional, if m == 0 */
169 int *indxc, *indxr, *ipiv;
170 int i, icol, irow, j, k, l, ll;
171 double big, dum, pivinv, temp;
173 int bexists = ((m != 0) || (b == 0));
175 indxc = nr_ivector(1,n); /* The integer arrays ipiv, indxr, and */
176 indxr = nr_ivector(1,n); /* indxc are used for pivot bookkeeping */
177 ipiv = nr_ivector(1,n);
179 for (j=1;j<=n;j++) ipiv[j] = 0;
181 for (i=1;i<=n;i++) /* This is the main loop over columns */
184 for (j=1;j<=n;j++) /* This is outer loop of pivot search */
190 if (fabs(a[j][k]) >= big)
198 if (ipiv[k] > 1) return -1;
202 /* We now have the pivot element, so we interchange rows, if needed, */
203 /* to put the pivot element on the diagonal. The columns are not */
204 /* physically interchanged, only relabeled: indxc[i], the column of the */
205 /* ith pivot element, is the ith column that is reduced, while indxr[i] */
206 /* is the row in which that pivot element was orignally located. If */
207 /* indxr[i] != indxc[i] there is an implied column interchange. With */
208 /* this form of bookkeeping, the solution b's will end up in the correct */
209 /* order, and the inverse matrix will be scrambed by columns. */
213 /* for (l=1;1<=n;l++) SWAP(a[irow][l],a[icol][l]) */
217 a[irow][l]=a[icol][l];
220 if (bexists) for (l=1;l<=m;l++) SWAP(b[irow][l],b[icol][l])
222 indxr[i] = irow; /* We are now ready to divide the pivot row */
223 indxc[i] = icol; /* by the pivot element, a[irow][icol] */
224 if (a[icol][icol] == 0.0) return -1;
225 pivinv = 1.0/a[icol][icol];
227 for (l=1;l<=n;l++) a[icol][l] *= pivinv;
228 if (bexists) for (l=1;l<=m;l++) b[icol][l] *= pivinv;
229 for (ll=1;ll<=n;ll++) /* Next, we reduce the rows... */
230 if (ll != icol ) /* .. except for the pivot one */
234 for (l=1;l<=n;l++) a[ll][l] -= a[icol][l]*dum;
235 if (bexists) for (l=1;l<=m;l++) b[ll][i] -= b[icol][l]*dum;
239 /* This is the end of the mail loop over columns of the reduction. It
240 only remains to unscrambled the solution in view of the column
241 interchanges. We do this by interchanging pairs of columns in
242 the reverse order that the permutation was built up. */
246 if (indxr[l] != indxc[l])
248 SWAP(a[k][indxr[l]],a[k][indxc[l]])
251 /* and we are done */
253 nr_free_ivector(ipiv,1 /*,n*/ );
254 nr_free_ivector(indxr,1 /*,n*/ );
255 nr_free_ivector(indxc,1 /*,n*/ );
257 return 0; /* indicate success */
260 void nr_copymat(double **orig, int n, double **copy)
261 /* overwrites matrix 'copy' with copy of matrix 'orig' */
265 if ((orig==0)||(copy==0)||(n==0)) return;
269 copy[i][j] = orig[i][j];
272 void nr_multmat(double **m1, int n, double **m2, double **prod)
276 if ((m1==0)||(m2==0)||(prod==0)||(n==0)) return;
282 for(k=1;k<=n;k++) prod[i][j] += m1[i][k]*m2[k][j];
288 void nr_printmat(double **a, int n)
296 printf("% 9.4f ", a[i][j]);
304 void testmat( void ) /* main() for test purposes */
306 double **mat1, **mat2, **mat3;
308 int loop, i, j, n = 20;
309 long maxlong = RAND_MAX;
312 invmaxlong = 1.0/(double)maxlong;
313 mat1 = nr_matrix(1, n, 1, n );
314 mat2 = nr_matrix(1, n, 1, n );
315 mat3 = nr_matrix(1, n, 1, n );
317 /* for(i=1;i<=n;i++) mat1[i][i]= 5.0; */
319 for(loop=0;loop<maxloop;loop++)
324 mat1[i][j] = 2.0 - 4.0*invmaxlong*(double) rand();
326 printf("Original matrix:\n");
327 nr_printmat( mat1, n );
329 nr_copymat( mat1, n, mat2 );
331 i = nr_gaussj( mat2, n, 0, 0 );
333 if (i) printf("Singular matrix.\n");
335 printf("Inverted matrix:\n");
336 nr_printmat( mat2, n );
338 nr_multmat( mat1, n, mat2, mat3 );
340 printf("Original multiplied by inverse:\n");
341 nr_printmat( mat3, n );
343 if (loop < maxloop-1) /* sleep(1) */;
346 nr_free_matrix( mat1, 1, n, 1, n );
347 nr_free_matrix( mat2, 1, n, 1, n );
348 nr_free_matrix( mat3, 1, n, 1, n );