Annotation of OpenXM_contrib/gnuplot/matrix.c, Revision 1.1.1.3
1.1 maekawa 1: #ifndef lint
1.1.1.3 ! ohara 2: static char *RCSid = "$Id: matrix.c,v 1.12.2.1 2002/01/31 21:22:37 lhecking Exp $";
1.1 maekawa 3: #endif
4:
1.1.1.3 ! ohara 5: /* NOTICE: Change of Copyright Status
! 6: *
! 7: * The author of this module, Carsten Grammes, has expressed in
! 8: * personal email that he has no more interest in this code, and
! 9: * doesn't claim any copyright. He has agreed to put this module
! 10: * into the public domain.
! 11: *
! 12: * Lars Hecking 15-02-1999
! 13: */
! 14:
1.1 maekawa 15: /*
16: * Matrix algebra, part of
17: *
18: * Nonlinear least squares fit according to the
19: * Marquardt-Levenberg-algorithm
20: *
21: * added as Patch to Gnuplot (v3.2 and higher)
22: * by Carsten Grammes
23: * Experimental Physics, University of Saarbruecken, Germany
24: *
25: * Internet address: cagr@rz.uni-sb.de
26: *
27: * Copyright of this module: Carsten Grammes, 1993
28: *
29: * Permission to use, copy, and distribute this software and its
30: * documentation for any purpose with or without fee is hereby granted,
31: * provided that the above copyright notice appear in all copies and
32: * that both that copyright notice and this permission notice appear
33: * in supporting documentation.
34: *
35: * This software is provided "as is" without express or implied warranty.
36: */
37:
38:
39: #include "fit.h"
40: #include "matrix.h"
41: #include "stdfn.h"
42: #include "alloc.h"
43:
44: /*****************************************************************/
45:
46: #define Swap(a,b) {double temp = (a); (a) = (b); (b) = temp;}
47: #define WINZIG 1e-30
48:
49:
50: /*****************************************************************
51: internal prototypes
52: *****************************************************************/
53:
54: static GP_INLINE int fsign __PROTO((double x));
55:
56: /*****************************************************************
57: first straightforward vector and matrix allocation functions
58: *****************************************************************/
59: double *vec (n)
60: int n;
61: {
62: /* allocates a double vector with n elements */
63: double *dp;
64: if( n < 1 )
65: return (double *) NULL;
1.1.1.3 ! ohara 66: dp = (double *) gp_alloc (n * sizeof(double), "vec");
1.1 maekawa 67: return dp;
68: }
69:
70:
71: double **matr (rows, cols)
72: int rows;
73: int cols;
74: {
75: /* allocates a double matrix */
76:
77: register int i;
78: register double **m;
79:
80: if ( rows < 1 || cols < 1 )
81: return NULL;
1.1.1.3 ! ohara 82: m = (double **) gp_alloc (rows * sizeof(double *) , "matrix row pointers");
! 83: m[0] = (double *) gp_alloc (rows * cols * sizeof(double), "matrix elements");
1.1 maekawa 84: for ( i = 1; i<rows ; i++ )
85: m[i] = m[i-1] + cols;
86: return m;
87: }
88:
89:
90: void free_matr (m)
91: double **m;
92: {
93: free (m[0]);
94: free (m);
95: }
96:
97:
98: double *redim_vec (v, n)
99: double **v;
100: int n;
101: {
102: if ( n < 1 )
103: *v = NULL;
104: else
105: *v = (double *) gp_realloc (*v, n * sizeof(double), "vec");
106: return *v;
107: }
108:
109: void redim_ivec (v, n)
110: int **v;
111: int n;
112: {
113: if ( n < 1 ) {
114: *v = NULL;
115: return;
116: }
117: *v = (int *) gp_realloc (*v, n * sizeof(int), "ivec");
118: }
119:
120:
121: /* HBB: TODO: is there a better value for 'epsilon'? how to specify
122: * 'inline'? is 'fsign' really not available elsewhere? use
123: * row-oriented version (p. 309) instead?
124: */
125:
126: static GP_INLINE int fsign(x)
127: double x;
128: {
129: return( x>0 ? 1 : (x < 0) ? -1 : 0) ;
130: }
131:
132: /*****************************************************************
133:
134: Solve least squares Problem C*x+d = r, |r| = min!, by Given rotations
135: (QR-decomposition). Direct implementation of the algorithm
136: presented in H.R.Schwarz: Numerische Mathematik, 'equation'
137: number (7.33)
138:
139: If 'd == NULL', d is not accesed: the routine just computes the QR
140: decomposition of C and exits.
141:
142: If 'want_r == 0', r is not rotated back (\hat{r} is returned
143: instead).
144:
145: *****************************************************************/
146:
147: void Givens (C, d, x, r, N, n, want_r)
148: double **C;
149: double *d;
150: double *x;
151: double *r;
152: int N;
153: int n;
154: int want_r;
155: {
156: int i, j, k;
157: double w, gamma, sigma, rho, temp;
158: double epsilon = DBL_EPSILON; /* FIXME (?)*/
159:
160: /*
161: * First, construct QR decomposition of C, by 'rotating away'
162: * all elements of C below the diagonal. The rotations are
163: * stored in place as Givens coefficients rho.
164: * Vector d is also rotated in this same turn, if it exists
165: */
166: for (j = 0; j<n; j++)
167: for (i = j+1; i<N; i++)
168: if (C[i][j]) {
169: if (fabs(C[j][j])<epsilon*fabs(C[i][j])) { /* find the rotation parameters */
170: w = -C[i][j];
171: gamma = 0;
172: sigma = 1;
173: rho = 1;
174: } else {
175: w = fsign(C[j][j])*sqrt(C[j][j]*C[j][j] + C[i][j]*C[i][j]);
176: if (w == 0)
177: Eex3 ( "w = 0 in Givens(); Cjj = %g, Cij = %g", C[j][j], C[i][j]);
178: gamma = C[j][j]/w;
179: sigma = -C[i][j]/w;
180: rho = (fabs(sigma)<gamma) ? sigma : fsign(sigma)/gamma;
181: }
182: C[j][j] = w;
183: C[i][j] = rho; /* store rho in place, for later use */
184: for (k = j+1; k<n; k++) { /* rotation on index pair (i,j) */
185: temp = gamma*C[j][k] - sigma*C[i][k];
186: C[i][k] = sigma*C[j][k] + gamma*C[i][k];
187: C[j][k] = temp;
188:
189: }
190: if (d) { /* if no d vector given, don't use it */
191: temp = gamma*d[j] - sigma*d[i]; /* rotate d */
192: d[i] = sigma*d[j] + gamma*d[i];
193: d[j] = temp;
194: }
195: }
196: if (!d) /* stop here if no d was specified */
197: return;
198:
199: for (i = n-1; i >= 0; i--) { /* solve R*x+d = 0, by backsubstitution */
200: double s = d[i];
201: r[i] = 0; /* ... and also set r[i] = 0 for i<n */
202: for (k = i+1; k<n; k++)
203: s += C[i][k]*x[k];
204: if (C[i][i] == 0)
205: Eex ( "Singular matrix in Givens()");
206: x[i] = - s / C[i][i];
207: }
208: for (i = n; i < N; i++)
209: r[i] = d[i]; /* set the other r[i] to d[i] */
210:
211: if (!want_r) /* if r isn't needed, stop here */
212: return;
213:
214: /* rotate back the r vector */
215: for (j = n-1; j >= 0; j--)
216: for (i = N-1; i >= 0; i--) {
217: if ((rho = C[i][j]) == 1) { /* reconstruct gamma, sigma from stored rho */
218: gamma = 0;
219: sigma = 1;
220: } else if (fabs(rho)<1) {
221: sigma = rho;
222: gamma = sqrt(1-sigma*sigma);
223: } else {
224: gamma = 1/fabs(rho);
225: sigma = fsign(rho)*sqrt(1-gamma*gamma);
226: }
227: temp = gamma*r[j] + sigma*r[i]; /* rotate back indices (i,j) */
228: r[i] = -sigma*r[j] + gamma*r[i];
229: r[j] = temp;
230: }
231: }
232:
233:
234: /* Given a triangular Matrix R, compute (R^T * R)^(-1), by forward
235: * then back substitution
236: *
237: * R, I are n x n Matrices, I is for the result. Both must already be
238: * allocated.
239: *
240: * Will only calculate the lower triangle of I, as it is symmetric
241: */
242:
243: void Invert_RtR ( R, I, n)
244: double **R;
245: double **I;
246: int n;
247: {
248: int i, j, k;
249:
250: /* fill in the I matrix, and check R for regularity : */
251:
252: for (i = 0; i<n; i++) {
253: for (j = 0; j<i; j++) /* upper triangle isn't needed */
254: I[i][j] = 0;
255: I[i][i] = 1;
256: if (! R[i][i])
257: Eex ("Singular matrix in Invert_RtR")
258: }
259:
260: /* Forward substitution: Solve R^T * B = I, store B in place of I */
261:
262: for (k = 0; k<n; k++)
263: for (i = k; i<n; i++) { /* upper half needn't be computed */
264: double s = I[i][k];
265: for (j = k; j<i; j++) /* for j<k, I[j][k] always stays zero! */
266: s -= R[j][i] * I[j][k];
267: I[i][k] = s / R[i][i];
268: }
269:
270: /* Backward substitution: Solve R * A = B, store A in place of B */
271:
272: for (k = 0; k<n; k++)
273: for (i = n-1; i >= k; i--) { /* don't compute upper triangle of A */
274: double s = I[i][k];
275: for (j = i+1; j<n; j++)
276: s -= R[i][j] * I[j][k];
277: I[i][k] = s / R[i][i];
278: }
279: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>