File Coverage

lib/PDL/MatrixOps/matrix.c
Criterion Covered Total %
statement 44 205 21.4
branch 22 118 18.6
condition n/a
subroutine n/a
pod n/a
total 66 323 20.4


line stmt bran cond sub pod time code
1             /*
2             * matrix.c - misc. routines for manipulating matrices and vectors.
3             *
4             * (C) Copyright 2001 by NetGroup A/S. All rights reserved.
5             *
6             * $Log$
7             * Revision 1.1 2006/06/20 15:57:22 djburke
8             * Hopefully a saner way to build Basic/MatrixOps
9             *
10             * Revision 1.1 2005/01/08 09:22:57 zowie
11             * Added non-symmetric matrices to eigens; updated version to 2.4.2cvs.
12             *
13             * Revision 1.1.1.1 2001/07/06 13:39:35 kneth
14             * Initial import of code.
15             *
16             *
17             *
18             * The matrices and vectors are indexed in C-style, i.e. from 0 to
19             * N-1. A matrix is assumed to be declared as double **, and it is
20             * allocated by MatrixAlloc.
21             *
22             *
23             * References:
24             * [1] Numerical Recipes in C, 2nd edition,
25             * W.H. Press, S.A. Teukolsky, W.T. Vitterling, and B.P. Flannery,
26             * Cambridge University Press, 1992.
27             * [2] Numerical Analysis,
28             * D. Kincaid and W. Cheney,
29             * Brooks/Cole Publishing Company, 1991.
30             * [3] The C Programming Language, 2nd edition,
31             * B.W. Kernighan and D.M. Ritchie,
32             * Prentice Hall, 1988.
33             * [4] Advanced Engineering Mathematics, 6th edition,
34             * E. Kreyszig,
35             * Wiley and Sons, 1988.
36             *
37             */
38              
39             #include
40             #include
41             #include
42              
43             #ifndef TINY
44             # define TINY 1.0e-18
45             #endif
46              
47             #include "sslib.h"
48             #include "matrix.h"
49              
50              
51             /*
52             * MatrixAlloc allocates storage for a square matrix with dimension
53             * n*n. An error message is printed, if it was impossible to allocate
54             * the neccesary space, [3].
55             *
56             */
57              
58 20           double **MatrixAlloc(const int n) {
59              
60             double **matrix;
61             int i;
62              
63 20           matrix=(double **)calloc(n, sizeof(double *));
64 20 50         if (matrix==NULL)
65 0           SSLerror("No memory available in routine MatrixAlloc");
66             else
67 74 100         for(i=0; i
68 54           matrix[i]=(double *)calloc(n, sizeof(double));
69 54 50         if (matrix[i]==NULL)
70 0           SSLerror("No memory available in routine MatrixAlloc");
71             } /* for i=1..n */
72 20           return matrix;
73             } /* MatrixAlloc */
74              
75              
76             /*
77             * VectorAlloc allocated space for an n-dimensional vector of the type
78             * double *, [3]. It can be freed by VectorFree.
79             *
80             */
81              
82 12           double *VectorAlloc(const int n) {
83              
84             double *temp;
85              
86 12           temp=(double *)calloc(n, sizeof(double));
87 12 50         if (temp==NULL)
88 0           SSLerror("No memory available in routine VectorAlloc");
89 12           return temp;
90             } /* VectorAlloc */
91              
92              
93             /*
94             * IntVectorAlloc is similar to VectorAlloc, except that the base type is
95             * integers (int) instead of reals (double), [3].
96             *
97             */
98              
99 7           int *IntVectorAlloc(const int n) {
100              
101             int *temp;
102              
103 7           temp=(int *)calloc(n, sizeof(int));
104 7 50         if (temp==NULL)
105 0           SSLerror("No memory available in routine IntVectorAlloc");
106 7           return temp;
107             } /* IntVectorAlloc */
108              
109              
110             /*
111             * SSL_ComplexMatrixAlloc allocates space for a nxn matrix with complex elements.
112             *
113             */
114              
115 0           complex double **SSL_ComplexMatrixAlloc(const int n) {
116              
117             int i;
118             complex double **temp;
119              
120 0           temp=(complex double **)calloc(n, sizeof(complex double *));
121 0 0         if (temp==NULL)
122 0           SSLerror("No memory available in routine SSL_ComplexMatrixAlloc");
123             else {
124 0 0         for(i=0; i
125 0           temp[i]=(complex double *)calloc(n, sizeof(complex double));
126 0 0         if (temp[i]==NULL)
127 0           SSLerror("No memory available in routine SSL_ComplexMatrixAlloc");
128             } /* for i=1..n */
129             } /* if else */
130 0           return temp;
131             } /* SSL_ComplexMatrixAlloc */
132              
133              
134             /*
135             * SSL_ComplexVectorAlloc allocates a vector of dimension n with complex
136             * elements.
137             *
138             */
139            
140 0           complex double *SSL_ComplexVectorAlloc(const int n) {
141              
142             complex double *temp;
143              
144 0           temp=(complex double *)calloc(n, sizeof(complex double));
145 0 0         if (temp==NULL)
146 0           SSLerror("No memory available in routine SSL_ComplexVectorAlloc");
147 0           return temp;
148             } /* SSL_ComplexVectorAlloc */
149              
150              
151             /*
152             * MatrixMul computes the product between two square matrices, [4, pp.
153             * 357-358]. Both matrices are assumed to have the dimension n*n. A and B are
154             * input, and res is the output, i.e. the routine computes res=A*B.
155             *
156             */
157              
158 9           void MatrixMul(const int n, double **res, double **A, double **B) {
159              
160             int i, j, k;
161             double x;
162              
163 33 100         for(i=0; i
164 96 100         for(j=0; j
165 72           x=0.0;
166 312 100         for(k=0; k
167 240           x+=A[i][k]*B[k][j];
168 72           res[i][j]=x;
169             } /* for j=1..n */
170 9           } /* MatrixMul */
171              
172              
173             /*
174             * Transpose is simply doing as the name says, i.e. transposing the
175             * matrix A, [4, pp. 368-370]. A is assumed to be a square matrix.
176             *
177             */
178              
179 3           void Transpose(const int n, double **res, double **A) {
180              
181             int i, j;
182              
183 11 100         for(i=0; i
184 32 100         for(j=0; j
185 24           res[j][i]=A[i][j];
186 3           } /* Transpose */
187              
188              
189             /*
190             * MatrixFree, VectorFree, IntVectorFree, SSL_ComplexMatrixFree, and
191             * SSL_ComplexVectorFree free the space used by the objects, [3].
192             *
193             */
194              
195 18           void MatrixFree(const int n, double **matrix) {
196              
197             int i;
198              
199 66 100         for(i=0; i
200 48           free((void *)matrix[i]);
201 18           free((void *)matrix);
202 18           } /* MatrixFree */
203              
204 0           void SSL_ComplexMatrixFree(const int n, complex double **matrix) {
205              
206             int i;
207              
208 0 0         for(i=0; i
209 0           free((void *)matrix[i]);
210 0           free((void *)matrix);
211 0           } /* SSL_ComplexMatrixFree */
212              
213 9           void VectorFree(const int n, double *vector) {
214              
215 9           free((void *)vector);
216 9           } /* VectorFree */
217              
218 6           void IntVectorFree(const int n, int *vector) {
219              
220 6           free((void *)vector);
221 6           } /* IntVectorFree */
222              
223 0           void SSL_ComplexVectorFree(const int n, complex double *vector) {
224              
225 0           free((void *)vector);
226 0           } /* SSL_ComplexVectorFree */
227              
228              
229             /*
230             * LUfact and LUsubst are plain LU decomposition and substitution routines,
231             * [1, pp. 43-50], [2, pp. 145-149]. The version here is Gaussian elimination
232             * with scaled row pivoting, and it is based on the algorithm given in [2].
233             *
234             * LUfact_fixed and LUsubst_fixed are specialised versions of LUfact and
235             * LUsubst. They are used in OEE solvers.
236             *
237             * The parameters are used:
238             * n the dimension of the matrix.
239             * a the matrix; it contains both L and U at termination.
240             * p permutation index.
241             * b the constant vector, and at termination it will contain
242             * the solution.
243             *
244             */
245              
246 0           void LUfact(const int n, double **a, int *p) {
247              
248             int i, j, k; /* counters */
249             double z; /* temporary real */
250             double *s; /* pivot elements */
251             int not_finished; /* loop control var. */
252             int i_swap; /* swap var. */
253             double temp; /* another temp. real */
254              
255 0           s=VectorAlloc(n);
256 0 0         for(i=0; i
257 0           p[i]=i;
258 0           s[i]=0.0;
259 0 0         for(j=0; j
260 0           z=fabs(a[i][j]);
261 0 0         if (s[i]
262 0           s[i]=z;
263             } /* for j */
264             } /* for i */
265              
266 0 0         for(k=0; k<(n-1); k++) {
267 0           j=k-1; /* select j>=k so ... */
268 0           not_finished=1;
269 0 0         while (not_finished) {
270 0           j++;
271 0           temp=fabs(a[p[j]][k]/s[p[j]]);
272 0 0         for(i=k; i
273 0 0         if (temp>=(fabs(a[p[i]][k])/s[p[i]]))
274 0           not_finished=0; /* end loop */
275             } /* while */
276 0           i_swap=p[k];
277 0           p[k]=p[j];
278 0           p[j]=i_swap;
279 0           temp=1.0/a[p[k]][k];
280 0 0         for(i=(k+1); i
281 0           z=a[p[i]][k]*temp;
282 0           a[p[i]][k]=z;
283 0 0         for(j=(k+1); j
284 0           a[p[i]][j]-=z*a[p[k]][j];
285             } /* for i */
286             } /* for k */
287              
288 0           VectorFree(n, s);
289 0           } /* LUfact */
290              
291 0           void LUsubst(const int n, double **a, int *p, double *b) {
292              
293             int i, j, k; /* counters */
294             double sum; /* temporary sum variable */
295             double *x; /* solution */
296            
297 0           x=VectorAlloc(n);
298              
299 0 0         for(k=0; k<(n-1); k++) /* forward subst */
300 0 0         for(i=(k+1); i
301 0           b[p[i]]-=a[p[i]][k]*b[p[k]];
302            
303 0 0         for(i=(n-1); i>=0; i--) { /* back subst */
304 0           sum=b[p[i]];
305 0 0         for(j=(i+1); j
306 0           sum-=a[p[i]][j]*x[j];
307 0           x[i]=sum/a[p[i]][i];
308             } /* for i */
309            
310 0 0         for(i=0; i
311 0           b[i]=x[i];
312              
313 0           VectorFree(n, x);
314 0           } /* LUsubst */
315              
316              
317             /*
318             * GaussSeidel is an implementation of the Gauss-Seidel method, which is an
319             * iterative method, [2, pp. 189-191]. The norm applied is the L1-norm.
320             *
321             * The parameters are:
322             * n the dimension.
323             * a the coefficient matrix.
324             * b the constant vector.
325             * x the initial guess, and at termination the solution.
326             * eps the precision.
327             * max_iter the maximal number of iterations allowed.
328             *
329             */
330              
331 0           void GaussSeidel(const int n, double **a, double *b, double *x, double eps,
332             int max_iter) {
333              
334             int iter, i, j; /* counter */
335             double sum; /* temporary real */
336             double *x_old; /* old solution */
337             double norm; /* L1-norm */
338              
339 0           x_old=VectorAlloc(n);
340              
341 0           iter=0;
342             do { /* repeat until safisfying sol. */
343 0           iter++;
344 0 0         for(i=0; i
345 0           x_old[i]=x[i];
346 0           norm=0.0; /* do an iteration */
347 0 0         for(i=0; i
348 0           sum=-a[i][i]*x[i]; /* don't include term i=j */
349 0 0         for(j=0; j
350 0           sum+=a[i][j]*x[j];
351 0           x[i]=(b[i]-sum)/a[i][i];
352 0           norm+=fabs(x_old[i]-x[i]);
353             } /* for i */
354 0 0         } while ((iter<=max_iter) && (norm>=eps));
    0          
355              
356 0           VectorFree(n, x_old);
357 0           } /* GaussSeidel */
358              
359              
360             /*
361             * Jacobi is an iterative equation solver, [2, pp. 185-189]. The algorithm
362             * can be optimised a bit, which is done in this implementation. The method
363             * is suitable for parallel computers.
364             *
365             * The arguments are the same as in GaussSeidel.
366             *
367             */
368              
369 0           void Jacobi(const int n, double **a, double *b, double *x, double eps,
370             int max_iter) {
371              
372             double d; /* temporary real */
373             int i, j, iter; /* counters */
374             double **a_new; /* a is altered */
375             double *b_new; /* b is altered */
376             double *u; /* new solution */
377             double norm; /* L1-norm */
378              
379 0           a_new=MatrixAlloc(3);
380 0           b_new=VectorAlloc(3);
381 0           u=VectorAlloc(3);
382              
383 0 0         for(i=0; i
384 0           d=1.0/a[i][i];
385 0           b_new[i]=d*b[i];
386 0 0         for(j=0; j
387 0           a_new[i][j]=d*a[i][j];
388             } /* for i */
389              
390 0           iter=0;
391             do {
392 0           iter++;
393 0           norm=0.0;
394 0 0         for(i=0; i
395 0           d=-a_new[i][i]*x[i]; /* don't include term i=j */
396 0 0         for(j=0; j
397 0           d+=a_new[i][j]*x[j];
398 0           u[i]=b_new[i]-d;
399 0           norm=fabs(u[i]-x[i]);
400             } /* for i */
401 0 0         for(i=0; i
402 0           x[i]=u[i];
403 0 0         } while ((iter<=max_iter) && (norm>=eps));
    0          
404            
405 0           MatrixFree(3, a_new);
406 0           VectorFree(3, b_new);
407 0           VectorFree(3, u);
408 0           } /* Jacobi */
409              
410              
411             /*
412             * DotProd computes the dot product between two vectors. They are assumed to
413             * be of the same dimension.
414             *
415             */
416              
417 0           double DotProd(const int n, double *u, double *v) {
418              
419             int i; /* counter */
420 0           double sum=0.0; /* temporary real */
421            
422 0 0         for(i=0; i
423 0           sum+=u[i]*v[i];
424 0           return sum;
425             } /* DotProd */
426              
427              
428             /*
429             * MatrixVecProd computes the matrix product between a matrix and a vector of
430             * the dimension n. The result is found in res.
431             *
432             */
433              
434 0           void MatrixVecProd(const int n, double **A, double *v, double *res) {
435              
436             int i, j; /* counters */
437              
438 0 0         for(i=0; i
439 0           res[i]=0.0;
440 0 0         for(j=0; j
441 0           res[i]+=A[i][j]*v[j];
442             } /* for i */
443 0           } /* MatrixVecProd */
444              
445              
446             /*
447             * MatrixCopy copies the elements of the matrix A to the B.
448             *
449             */
450              
451 12           void MatrixCopy(const int n, double **B, double **A) {
452              
453             int i, j;
454              
455 44 100         for(i=0; i
456 128 100         for(j=0; j
457 96           B[i][j]=A[i][j];
458 12           } /* MatrixCopy */
459              
460              
461             /*
462             * L2VectorNorm computes the L2 or Eucleadian norm of a vector.
463             *
464             */
465              
466 0           double L2VectorNorm(const int n, double *vec) {
467              
468             int i;
469 0           double norm=0.0;
470              
471 0 0         for(i=0; i
472 0           norm+=vec[i]*vec[i];
473 0           return sqrt(norm);
474             } /* L2VectorNorm */
475              
476             /*
477             * GSR is an implementation of the Gram-Schmidt Reorthonormalisation process,
478             * [2, pp. 246-250]. The n vectors are collected in a matrix, and the matrix is
479             * both input and output. The implementation is actually the modified algorithm
480             * as disucced in [2, p. 248]. Modified by the authors, so the vectors are
481             * normalised at the end.
482             *
483             */
484              
485 0           void GSR(const int n, double **A) {
486              
487             int i, j, k; /* counters */
488             double dot;
489              
490 0 0         for(k=0; k
491 0 0         for(j=(k+1); j
492 0           dot=0.0; /* dot product */
493 0 0         for(i=0; i
494 0           dot+=A[i][j]*A[i][k];
495 0 0         for(i=0; i
496 0           A[i][j]-=A[i][k]/dot;
497             } /* for j */
498             } /* for k */
499              
500 0 0         for(k=0; k
501 0           dot=0.0; /* Compute (L2 norm) */
502 0 0         for(i=0; i
503 0           dot+=A[i][k]*A[i][k];
504 0           dot=sqrt(dot);
505 0 0         if (dot==0.0)
506 0           SSLerror("Norm = 0 in routine GSR");
507 0 0         for(i=0; i
508 0           A[i][k]/=dot;
509             } /* for k */
510 0           } /* GSR */
511              
512              
513             /*
514             * InversMatrix calculates the inverse matrix. The method is the solution
515             * of n linear set of equations which are solved by a LU factorisation.
516             *
517             */
518              
519 0           void InversMatrix(const int n, double **b, double **ib) {
520              
521             double **a;
522             double *e;
523             int i,j;
524             int *p;
525              
526 0           a=MatrixAlloc(n);
527 0           e=VectorAlloc(n);
528 0           p=IntVectorAlloc(n);
529 0           MatrixCopy(n, a, b);
530 0           LUfact(n, a, p);
531 0 0         for(i=0; i
532 0 0         for(j=0; j
533 0           e[j]=0.0;
534 0           e[i]=1.0;
535 0           LUsubst(n, a, p, e);
536 0 0         for(j=0; j
537 0           ib[j][i]=e[j];
538             } /* for i=1..n */
539              
540 0           MatrixFree(n, a);
541 0           VectorFree(n, e);
542 0           IntVectorFree(n, p);
543 0           } /* InversMatrix */
544