OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
svdfit.cpp
Go to the documentation of this file.
1 /* svdfit.C
2  SVD fitting routines
3 
4  NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5)
5 
6  Revision history
7  Date Description Programmer
8  ------------ -------------------------------------------- ------------
9  10/03/2006 Copied from "numerical recipies" Rene Bakker
10 
11  Last Revision:
12  $Id: svdfit.C 29 2007-04-14 17:03:18Z l_bakker $
13 */
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <math.h>
18 
21 
22 /* Internal functions
23  ========================================================================= */
24 
25 /* vector
26  allocate an array of doubles [0..n-1] and check memory */
27 static double *vector(int n) {
28  double *b;
29 
30  b = (double *) malloc(sizeof(double) * n);
31  if(!b) {
32  //writeBetError(errModeAll,errFatal,"Insufficient memory malloc %d bytes (svdfit.C)",sizeof(double)*n);
33  writeBetError("Insufficient memory in malloc svdfit.C");
34  }
35  return b;
36 } /* vector */
37 
38 static double **matrix(int n1, int n2)
39 /* allocate a double matrix with subscript range [0..n1-1][0..n2-1] */
40 {
41  int i;
42  double **m;
43 
44  /* allocate pointers to rows */
45  m = (double **) malloc(sizeof(double *) * (n1 + 1));
46  if(!m) {
47  //writeBetError(errModeAll,errFatal,"Allocation failure1 matrix(%d,%d) in svdfit.C\n",n1,n2);
48  writeBetError("allocation failure 1 in svdfit.C");
49  }
50 
51  for(i = 0; i < n1; i++) {
52  m[i] = (double *) malloc(sizeof(double) * n2);
53  if(!m[i]) {
54  //writeBetError(errModeAll,errFatal,"Allocation failure2 matrix(%d,%d) in svdfit.C at i=%d\n",n1,n2,i);
55  writeBetError("allocation failure 2 in svdfit.C");
56  }
57  }
58  m[n1] = NULL;
59  return m;
60 } /* matrix */
61 
62 static void free_matrix(double **m)
63 /* free a double matrix allocated by matrix() */
64 {
65  int i = 0;
66 
67  while(m[i] != NULL) {
68  free(m[i++]);
69  }
70  free(m);
71 } /* free_matrix */
72 
73 /* svdksb()
74  Solves A·X = B for a vector X, where A is specified by the arrays
75  u[1..m][1..n], w[1..n], v[1..n][1..n] as returned by svdcmp.
76  m and n are the dimensions of a, and will be equal for square matrices.
77  b[1..m] is the input right-hand side. x[1..n] is the output solution vector.
78  No input quantities are destroyed, so the routine may be called sequentially
79  with different b's.
80 */
81 static void svbksb
82 (
83  double **u, double w[], double **v, int m, int n, double b[], double x[]) {
84  int jj, j, i;
85  double s, *tmp;
86 
87  tmp = vector(n + 1);
88  for(j = 1; j <= n; j++) {
89  s = 0.0;
90  if(w[j]) {
91  for(i = 1; i <= m; i++) s += u[i][j] * b[i];
92  s /= w[j];
93  }
94  tmp[j] = s;
95  }
96  for(j = 1; j <= n; j++) {
97  s = 0.0;
98  for(jj = 1; jj <= n; jj++) s += v[j][jj] * tmp[jj];
99  x[j] = s;
100  }
101  free(tmp);
102 } /* svdksb() */
103 
104 
105 /* svdcmp
106  Given a matrix a[1..m][1..n], this routine computes its singular value
107  decomposition, A =U·W·V^T. The matrix U replaces a on output. The diagonal
108  matrix of singular values W is output as a vector w[1..n]. The matrix V
109  (not the transpose V^T ) is output as v[1..n][1..n].
110 */
111 
112 static double maxarg1, maxarg2;
113 #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\
114  (maxarg1) : (maxarg2))
115 
116 static int iminarg1, iminarg2;
117 #define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\
118  (iminarg1) : (iminarg2))
119 
120 #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
121 
122 static double sqrarg;
123 #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
124 
125 static double pythag(double a, double b) {
126  double absa, absb;
127  absa = fabs(a);
128  absb = fabs(b);
129  if(absa > absb) return absa * sqrt(1.0 + SQR(absb / absa));
130  else return (absb == 0.0 ? 0.0 : absb * sqrt(1.0 + SQR(absa / absb)));
131 }
132 
133 static void svdcmp(double **a, int m, int n, double w[], double **v) {
134  int flag, i, its, j, jj, k, l, nm = 0;
135  double anorm, c, f, g, h, s, scale, x, y, z, *rv1;
136 
137  rv1 = vector(n + 1);
138  g = scale = anorm = 0.0;
139  for(i = 1; i <= n; i++) {
140  l = i + 1;
141  rv1[i] = scale * g;
142  g = s = scale = 0.0;
143  if(i <= m) {
144  for(k = i; k <= m; k++) scale += fabs(a[k][i]);
145  if(scale) {
146  for(k = i; k <= m; k++) {
147  a[k][i] /= scale;
148  s += a[k][i] * a[k][i];
149  }
150  f = a[i][i];
151  g = -SIGN(sqrt(s), f);
152  h = f * g - s;
153  a[i][i] = f - g;
154  for(j = l; j <= n; j++) {
155  for(s = 0.0, k = i; k <= m; k++) s += a[k][i] * a[k][j];
156  f = s / h;
157  for(k = i; k <= m; k++) a[k][j] += f * a[k][i];
158  }
159  for(k = i; k <= m; k++) a[k][i] *= scale;
160  }
161  }
162  w[i] = scale * g;
163  g = s = scale = 0.0;
164  if(i <= m && i != n) {
165  for(k = l; k <= n; k++) scale += fabs(a[i][k]);
166  if(scale) {
167  for(k = l; k <= n; k++) {
168  a[i][k] /= scale;
169  s += a[i][k] * a[i][k];
170  }
171  f = a[i][l];
172  g = -SIGN(sqrt(s), f);
173  h = f * g - s;
174  a[i][l] = f - g;
175  for(k = l; k <= n; k++) rv1[k] = a[i][k] / h;
176  for(j = l; j <= m; j++) {
177  for(s = 0.0, k = l; k <= n; k++) s += a[j][k] * a[i][k];
178  for(k = l; k <= n; k++) a[j][k] += s * rv1[k];
179  }
180  for(k = l; k <= n; k++) a[i][k] *= scale;
181  }
182  }
183  anorm = FMAX(anorm, (fabs(w[i]) + fabs(rv1[i])));
184  }
185  for(i = n; i >= 1; i--) {
186  if(i < n) {
187  if(g) {
188  for(j = l; j <= n; j++)
189  v[j][i] = (a[i][j] / a[i][l]) / g;
190  for(j = l; j <= n; j++) {
191  for(s = 0.0, k = l; k <= n; k++) s += a[i][k] * v[k][j];
192  for(k = l; k <= n; k++) v[k][j] += s * v[k][i];
193  }
194  }
195  for(j = l; j <= n; j++) v[i][j] = v[j][i] = 0.0;
196  }
197  v[i][i] = 1.0;
198  g = rv1[i];
199  l = i;
200  }
201  for(i = IMIN(m, n); i >= 1; i--) {
202  l = i + 1;
203  g = w[i];
204  for(j = l; j <= n; j++) a[i][j] = 0.0;
205  if(g) {
206  g = 1.0 / g;
207  for(j = l; j <= n; j++) {
208  for(s = 0.0, k = l; k <= m; k++) s += a[k][i] * a[k][j];
209  f = (s / a[i][i]) * g;
210  for(k = i; k <= m; k++) a[k][j] += f * a[k][i];
211  }
212  for(j = i; j <= m; j++) a[j][i] *= g;
213  } else for(j = i; j <= m; j++) a[j][i] = 0.0;
214  ++a[i][i];
215  }
216  for(k = n; k >= 1; k--) {
217  for(its = 1; its <= 30; its++) {
218  flag = 1;
219  for(l = k; l >= 1; l--) {
220  nm = l - 1;
221  if((double)(fabs(rv1[l]) + anorm) == anorm) {
222  flag = 0;
223  break;
224  }
225  if((double)(fabs(w[nm]) + anorm) == anorm) break;
226  }
227  if(flag) {
228  c = 0.0;
229  s = 1.0;
230  for(i = l; i <= k; i++) {
231  f = s * rv1[i];
232  rv1[i] = c * rv1[i];
233  if((double)(fabs(f) + anorm) == anorm) break;
234  g = w[i];
235  h = pythag(f, g);
236  w[i] = h;
237  h = 1.0 / h;
238  c = g * h;
239  s = -f * h;
240  for(j = 1; j <= m; j++) {
241  y = a[j][nm];
242  z = a[j][i];
243  a[j][nm] = y * c + z * s;
244  a[j][i] = z * c - y * s;
245  }
246  }
247  }
248  z = w[k];
249  if(l == k) {
250  if(z < 0.0) {
251  w[k] = -z;
252  for(j = 1; j <= n; j++) v[j][k] = -v[j][k];
253  }
254  break;
255  }
256  if(its == 30) {
257  //writeBetError(errModeAll,errFatal,"svdfit(): no convergence in 30 svdcmp iterations");
258  writeBetError("svdfit() no convergence in 30 svdcmp iterations");
259  }
260  x = w[l];
261  nm = k - 1;
262  y = w[nm];
263  g = rv1[nm];
264  h = rv1[k];
265  f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
266  g = pythag(f, 1.0);
267  f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;
268  c = s = 1.0;
269  for(j = l; j <= nm; j++) {
270  i = j + 1;
271  g = rv1[i];
272  y = w[i];
273  h = s * g;
274  g = c * g;
275  z = pythag(f, h);
276  rv1[j] = z;
277  c = f / z;
278  s = h / z;
279  f = x * c + g * s;
280  g = g * c - x * s;
281  h = y * s;
282  y *= c;
283  for(jj = 1; jj <= n; jj++) {
284  x = v[jj][j];
285  z = v[jj][i];
286  v[jj][j] = x * c + z * s;
287  v[jj][i] = z * c - x * s;
288  }
289  z = pythag(f, h);
290  w[j] = z;
291  if(z) {
292  z = 1.0 / z;
293  c = f * z;
294  s = h * z;
295  }
296  f = c * g + s * y;
297  x = c * y - s * g;
298  for(jj = 1; jj <= m; jj++) {
299  y = a[jj][j];
300  z = a[jj][i];
301  a[jj][j] = y * c + z * s;
302  a[jj][i] = z * c - y * s;
303  }
304  }
305  rv1[l] = 0.0;
306  rv1[k] = f;
307  w[k] = x;
308  }
309  }
310  free(rv1);
311 }
312 
313 #undef FMAX
314 #undef IMIN
315 #undef SIGN
316 
317 /* svdfit
318  Given a set of data points x[1..ndata],y[1..ndata] with individual standard
319  deviations sig[1..ndata], use X^2 minimization to determine the coefficients
320  a[1..ma] of the fitting function y = Sum a[i]*afunci(x). Here we solve the
321  fitting equations using singular value decomposition of the ndata by ma matrix,
322  as in paragraph 2.6. Arrays u[1..ndata][1..ma], v[1..ma][1..ma], and w[1..ma]
323  provide workspace on input; on output they define the singular value decomposition,
324  and can be used to obtain the covariance matrix. The program returns values for the
325  ma fit parameters a, and X^2, chisq. The user supplies a routine funcs(x,afunc,ma)
326  that returns the ma basis functions evaluated at x = x in the array afunc[1..ma].
327 */
328 #define TOL 1.0e-12
329 
330 static void svdfit1
331 (
332  double x[], double y[], double sig[], int ndata, double a[], int ma,
333  double **u, double **v, double w[], double *chisq,
334  void (*funcs)(double, double [], int)) {
335  int j, i;
336  double wmax, tmp, thresh, sum, *b, *afunc;
337 
338  b = vector(ndata + 1);
339  afunc = vector(ma + 1);
340  for(i = 1; i <= ndata; i++) {
341  (*funcs)(x[i], afunc, ma);
342  tmp = 1.0 / sig[i];
343  for(j = 1; j <= ma; j++) u[i][j] = afunc[j] * tmp;
344  b[i] = y[i] * tmp;
345  }
346  svdcmp(u, ndata, ma, w, v);
347  wmax = 0.0;
348  for(j = 1; j <= ma; j++)
349  if(w[j] > wmax) wmax = w[j];
350  thresh = TOL * wmax;
351  for(j = 1; j <= ma; j++)
352  if(w[j] < thresh) w[j] = 0.0;
353  svbksb(u, w, v, ndata, ma, b, a);
354  *chisq = 0.0;
355  for(i = 1; i <= ndata; i++) {
356  (*funcs)(x[i], afunc, ma);
357  for(sum = 0.0, j = 1; j <= ma; j++) sum += a[j] * afunc[j];
358  *chisq += (tmp = (y[i] - sum) / sig[i], tmp * tmp);
359  }
360  free(afunc);
361  free(b);
362 }
363 
364 
365 /* svdvar()
366  To evaluate the covariance matrix cvm[1..ma][1..ma] of the fit for ma
367  parameters obtained by svdfit, call this routine with matrices
368  v[1..ma][1..ma], w[1..ma] as returned from svdfit.
369 */
370 void svdvar(double **v, int ma, double w[], double **cvm) {
371  int k, j, i;
372  double sum, *wti;
373 
374  wti = vector(ma + 1);
375  for(i = 1; i <= ma; i++) {
376  wti[i] = 0.0;
377  if(w[i]) wti[i] = 1.0 / (w[i] * w[i]);
378  }
379  for(i = 1; i <= ma; i++) {
380  for(j = 1; j <= i; j++) {
381  for(sum = 0.0, k = 1; k <= ma; k++) sum += v[i][k] * v[j][k] * wti[k];
382  cvm[j][i] = cvm[i][j] = sum;
383  }
384  }
385  free(wti);
386 }
387 
388 /* External functions
389  ========================================================================= */
390 
391 /* svdfit
392  Given a set of data points x[0..ndata-1],y[0..ndata-1], use X^2 minimization
393  to determine the coefficients a[0..ma-1] of the fitting function y = Sum a[i]*afunci(x).
394  Here we solve the fitting equations using singular value decomposition of the
395  ndata by ma matrix, as in paragraph 2.6.
396 
397  The program returns values for the ma fit parameters a, the estimated error,
398  and X^2, chisq. The user supplies a routine funcs(x,afunc,ma) that returns
399  the ma basis functions evaluated at x = x in the array afunc[0..ma-1].
400 */
401 
402 static void (*theFuncs)(double, double *, int);
403 
404 static void locFuncs(double x, double *p, int n) {
405  theFuncs(x, p + 1, n);
406 }
407 
408 void svdfit
409 (
410  double *x, double *y, double *sig, int ndata, double *a, int ma,
411  double *err, double *chisq,
412  void (*funcs)(double, double *, int)) {
413  int i;
414 
415  double
416  *w = vector(ndata + 1),
417  **u = matrix(ndata + 1, ma + 1),
418  **v = matrix(ndata + 1, ma + 1),
419  **cvm = matrix(ma + 1, ma + 1);
420 
421  /* Array coversion [0..n-1] to [1..n]
422  just lazy: instead of changing the routines above
423  I've just changed the array index on calling */
424 
425  theFuncs = funcs;
426  svdfit1(x - 1, y - 1, sig - 1, ndata, a - 1, ma, u, v, w, chisq, locFuncs);
427 
428  if(err) {
429  svdvar(v, ma, w, cvm);
430 
431  for(i = 0; i < ma; i++) {
432  err[i] = cvm[i+1][i+1];
433  }
434  }
435 
436  free_matrix(cvm);
437  free_matrix(u);
438  free_matrix(v);
439  free(w);
440 } /* svdfit */
441 
442 /* svdfit with sig[i] = 0.0, with i [0..ndata-1] */
443 void svdfit
444 (
445  double *x, double *y, int ndata, double *a, int ma,
446  double *err, double *chisq,
447  void (*funcs)(double, double *, int)) {
448  int i;
449  double
450  *sig = (double *) malloc(sizeof(double) * ndata);
451 
452  for(i = 0; i < ndata; i++) sig[i] = 1.0;
453 
454  svdfit(x, y, sig, ndata, a, ma, err, chisq, funcs);
455  free(sig);
456 } /* svdfit */
457 
458 
459 /* svdfit with sig[i] = 0.0 and i [0..ndata-1]
460  fit polynominal of order ma */
461 
462 static void fpoly(double x, double p[], int np) {
463  int j;
464 
465  p[0] = 1.0;
466  for(j = 1; j < np; j++) p[j] = p[j-1] * x;
467 }
468 
469 
470 void svdfitP
471 (
472  double *x, double *y, int ndata, double *a, int ma,
473  double *err, double *chisq) {
474  svdfit(x, y, ndata, a, ma, err, chisq, fpoly);
475 }
476 
477 #undef TOL
void svdvar(double **v, int ma, double w[], double **cvm)
Definition: svdfit.cpp:370
void svdfitP(double *x, double *y, int ndata, double *a, int ma, double *err, double *chisq)
Definition: svdfit.cpp:471
void writeBetError(std::string err)
Definition: BetError.cpp:36
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:815
void svdfit(double *x, double *y, double *sig, int ndata, double *a, int ma, double *err, double *chisq, void(*funcs)(double, double *, int))
Definition: svdfit.cpp:409
#define SQR(a)
Definition: svdfit.cpp:123
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1213
#define IMIN(a, b)
Definition: svdfit.cpp:117
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:52
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
#define TOL
Definition: svdfit.cpp:328
#define SIGN(a, b)
Definition: svdfit.cpp:120
#define FMAX(a, b)
Definition: svdfit.cpp:113