2 static char *RCSid() { return RCSid("$Id: matrix.c,v 1.10 2004/07/01 17:10:06 broeker Exp $"); }
5 /* NOTICE: Change of Copyright Status
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.
12 * Lars Hecking 15-02-1999
16 * Matrix algebra, part of
18 * Nonlinear least squares fit according to the
19 * Marquardt-Levenberg-algorithm
21 * added as Patch to Gnuplot (v3.2 and higher)
23 * Experimental Physics, University of Saarbruecken, Germany
25 * Previous copyright of this module: Carsten Grammes, 1993
35 /*****************************************************************/
37 #define Swap(a,b) {double temp = (a); (a) = (b); (b) = temp;}
38 /* HBB 20010424: unused: */
39 /* #define WINZIG 1e-30 */
42 /*****************************************************************
44 *****************************************************************/
46 static GP_INLINE int fsign __PROTO((double x));
48 /*****************************************************************
49 first straightforward vector and matrix allocation functions
50 *****************************************************************/
52 /* allocates a double vector with n elements */
60 dp = gp_alloc(n * sizeof(double), "vec");
65 /* allocates a double matrix */
67 matr(int rows, int cols)
72 if (rows < 1 || cols < 1)
74 m = gp_alloc(rows * sizeof(m[0]), "matrix row pointers");
75 m[0] = gp_alloc(rows * cols * sizeof(m[0][0]), "matrix elements");
76 for (i = 1; i < rows; i++)
77 m[i] = m[i - 1] + cols;
91 redim_vec(double **v, int n)
96 *v = gp_realloc(*v, n * sizeof((*v)[0]), "vec");
100 /* HBB: TODO: is there a better value for 'epsilon'? how to specify
101 * 'inline'? is 'fsign' really not available elsewhere? use
102 * row-oriented version (p. 309) instead?
108 return (x > 0 ? 1 : (x < 0) ? -1 : 0);
111 /*****************************************************************
113 Solve least squares Problem C*x+d = r, |r| = min!, by Given rotations
114 (QR-decomposition). Direct implementation of the algorithm
115 presented in H.R.Schwarz: Numerische Mathematik, 'equation'
118 If 'd == NULL', d is not accesed: the routine just computes the QR
119 decomposition of C and exits.
121 If 'want_r == 0', r is not rotated back (\hat{r} is returned
124 *****************************************************************/
137 double w, gamma, sigma, rho, temp;
138 double epsilon = DBL_EPSILON; /* FIXME (?) */
141 * First, construct QR decomposition of C, by 'rotating away'
142 * all elements of C below the diagonal. The rotations are
143 * stored in place as Givens coefficients rho.
144 * Vector d is also rotated in this same turn, if it exists
146 for (j = 0; j < n; j++) {
147 for (i = j + 1; i < N; i++) {
149 if (fabs(C[j][j]) < epsilon * fabs(C[i][j])) {
150 /* find the rotation parameters */
156 w = fsign(C[j][j]) * sqrt(C[j][j] * C[j][j] + C[i][j] * C[i][j]);
158 Eex3("w = 0 in Givens(); Cjj = %g, Cij = %g", C[j][j], C[i][j]);
160 sigma = -C[i][j] / w;
161 rho = (fabs(sigma) < gamma) ? sigma : fsign(sigma) / gamma;
164 C[i][j] = rho; /* store rho in place, for later use */
165 for (k = j + 1; k < n; k++) {
166 /* rotation on index pair (i,j) */
167 temp = gamma * C[j][k] - sigma * C[i][k];
168 C[i][k] = sigma * C[j][k] + gamma * C[i][k];
172 if (d) { /* if no d vector given, don't use it */
173 temp = gamma * d[j] - sigma * d[i]; /* rotate d */
174 d[i] = sigma * d[j] + gamma * d[i];
181 if (!d) /* stop here if no d was specified */
184 /* solve R*x+d = 0, by backsubstitution */
185 for (i = n - 1; i >= 0; i--) {
188 r[i] = 0; /* ... and also set r[i] = 0 for i<n */
189 for (k = i + 1; k < n; k++)
192 Eex("Singular matrix in Givens()");
196 for (i = n; i < N; i++)
197 r[i] = d[i]; /* set the other r[i] to d[i] */
199 if (!want_r) /* if r isn't needed, stop here */
202 /* rotate back the r vector */
203 for (j = n - 1; j >= 0; j--) {
204 for (i = N - 1; i >= 0; i--) {
205 if ((rho = C[i][j]) == 1) { /* reconstruct gamma, sigma from stored rho */
208 } else if (fabs(rho) < 1) {
210 gamma = sqrt(1 - sigma * sigma);
212 gamma = 1 / fabs(rho);
213 sigma = fsign(rho) * sqrt(1 - gamma * gamma);
215 temp = gamma * r[j] + sigma * r[i]; /* rotate back indices (i,j) */
216 r[i] = -sigma * r[j] + gamma * r[i];
223 /* Given a triangular Matrix R, compute (R^T * R)^(-1), by forward
224 * then back substitution
226 * R, I are n x n Matrices, I is for the result. Both must already be
229 * Will only calculate the lower triangle of I, as it is symmetric
233 Invert_RtR(double **R, double **I, int n)
237 /* fill in the I matrix, and check R for regularity : */
239 for (i = 0; i < n; i++) {
240 for (j = 0; j < i; j++) /* upper triangle isn't needed */
244 Eex("Singular matrix in Invert_RtR");
247 /* Forward substitution: Solve R^T * B = I, store B in place of I */
249 for (k = 0; k < n; k++) {
250 for (i = k; i < n; i++) { /* upper half needn't be computed */
252 for (j = k; j < i; j++) /* for j<k, I[j][k] always stays zero! */
253 s -= R[j][i] * I[j][k];
254 I[i][k] = s / R[i][i];
257 /* Backward substitution: Solve R * A = B, store A in place of B */
259 for (k = 0; k < n; k++) {
260 for (i = n - 1; i >= k; i--) { /* don't compute upper triangle of A */
262 for (j = i + 1; j < n; j++)
263 s -= R[i][j] * I[j][k];
264 I[i][k] = s / R[i][i];
269 /* HBB 20010424: Functions that used to be here in matrix.c, but were
270 * replaced by others and deleted, later. But the
271 * THIN_PLATE_SPLINES_GRID needed them, later, so they appeared in
272 * plot3d.c, where they don't belong --> moved them back here. */
275 lu_decomp(double **a, int n, int *indx, double *d)
277 int i, imax = -1, j, k; /* HBB: added initial value, to shut up gcc -Wall */
278 double large, dummy, temp, **ar, **lim, *limc, *ac, *dp, *vscal;
282 for (ar = a, lim = &(a[n]); ar < lim; ar++) {
284 for (ac = *ar, limc = &(ac[n]); ac < limc;)
285 if ((temp = fabs(*ac++)) > large)
288 int_error(NO_CARET, "Singular matrix in LU-DECOMP");
292 for (j = 0; j < n; j++, ar++) {
293 for (i = 0; i < j; i++) {
295 for (k = 0; k < i; k++)
296 *ac -= a[i][k] * a[k][j];
300 for (i = j; i < n; i++) {
302 for (k = 0; k < j; k++)
303 *ac -= a[i][k] * a[k][j];
304 if ((dummy = *dp++ * fabs(*ac)) >= large) {
312 for (k = 0; k < n; k++, ac++, dp++)
315 vscal[imax] = vscal[j];
318 if (*(dp = &(*ar)[j]) == 0)
322 dummy = 1 / (*ar)[j];
323 for (i = j + 1; i < n; i++)
331 lu_backsubst(double **a, int n, int *indx, double *b)
333 int i, memi = -1, ip, j;
335 double sum, *bp, *bip, **ar, *ac;
339 for (i = 0; i < n; i++, ar++) {
346 for (j = memi; j <= i - 1; j++)
347 sum -= *ac++ * *bp++;
353 for (i = n - 1; i >= 0; i--) {
357 for (j = i + 1; j < n; j++)
358 *bip -= *ac++ * *bp++;