SDDSlib
Loading...
Searching...
No Matches
lsfp.c
1
2/* routine: lsfp()
3 * purpose: compute nth order polynomial least squares, using only specified
4 * terms.
5 *
6 * Michael Borland, 1986.
7 */
8#include "matlib.h"
9#include "mdb.h"
10int p_merror(char *message);
11
12long lsfp(double *xd, double *yd, double *sy, /* data */
13 long n_pts, /* number of data points */
14 long n_terms, /* number of terms of the form An.x^n */
15 long *power, /* power for each term */
16 double *coef, /* place to put co-efficients */
17 double *s_coef, /* and their sigmas */
18 double *chi, /* place to put reduced chi-squared */
19 double *diff /* place to put difference table */
20) {
21 long i, j, unweighted;
22 double xp, *x_i, x0;
23 static MATRIX *X, *Y, *Yp, *C, *C_1, *Xt, *A, *Ca, *XtC, *XtCX, *T, *Tt, *TC;
24
25 if (n_pts < n_terms) {
26 printf("error: insufficient data for requested order of fit\n");
27 printf("(%ld data points, %ld terms in fit)\n", n_pts, n_terms);
28 exit(1);
29 }
30
31 unweighted = 1;
32 if (sy)
33 for (i = 1; i < n_pts; i++)
34 if (sy[i] != sy[0]) {
35 unweighted = 0;
36 break;
37 }
38
39 /* allocate matrices */
40 m_alloc(&X, n_pts, n_terms);
41 m_alloc(&Y, n_pts, 1);
42 m_alloc(&Yp, n_pts, 1);
43 m_alloc(&Xt, n_terms, n_pts);
44 if (!unweighted) {
45 m_alloc(&C, n_pts, n_pts);
46 m_alloc(&C_1, n_pts, n_pts);
47 m_zero(C);
48 m_zero(C_1);
49 }
50 m_alloc(&A, n_terms, 1);
51 m_alloc(&Ca, n_terms, n_terms);
52 m_alloc(&XtC, n_terms, n_pts);
53 m_alloc(&XtCX, n_terms, n_terms);
54 m_alloc(&T, n_terms, n_pts);
55 m_alloc(&Tt, n_pts, n_terms);
56 m_alloc(&TC, n_terms, n_pts);
57
58 /* Compute X, Y, C, C_1. X[i][j] = (xd[i])^power[j]. Y[i][0] = yd[i].
59 * C = delta(i,j)*sy[i]^2 (covariance matrix of yd)
60 * C_1 = INV(C)
61 */
62 for (i = 0; i < n_pts; i++) {
63 x_i = X->a[i];
64 Y->a[i][0] = yd[i];
65 if (!unweighted) {
66 C->a[i][i] = sqr(sy[i]);
67 C_1->a[i][i] = 1 / C->a[i][i];
68 }
69 x0 = xd[i];
70 for (j = 0; j < n_terms; j++)
71 x_i[j] = ipow(x0, power[j]);
72 }
73
74 /* Compute A, the matrix of coefficients.
75 * Weighted least-squares solution is A = INV(Xt.INV(C).X).Xt.INV(C).y
76 * Unweighted solution is A = INV(Xt.X).Xt.y
77 */
78 if (unweighted) {
79 /* eliminating 2 matrix operations makes this much faster than a weighted fit
80 * if there are many data points.
81 */
82 if (!m_trans(Xt, X))
83 return (p_merror("transposing X"));
84 if (!m_mult(XtCX, Xt, X))
85 return (p_merror("multiplying Xt.X"));
86 if (!m_invert(XtCX, XtCX))
87 return (p_merror("inverting XtCX"));
88 if (!m_mult(T, XtCX, Xt))
89 return (p_merror("multiplying XtX.Xt"));
90 if (!m_mult(A, T, Y))
91 return (p_merror("multiplying T.Y"));
92
93 /* Compute covariance matrix of A, Ca = (T.Tt)*C[0][0] */
94 if (!m_trans(Tt, T))
95 return (p_merror("computing transpose of T"));
96 if (!m_mult(Ca, T, Tt))
97 return (p_merror("multiplying T.Tt"));
98 if (!m_scmul(Ca, Ca, sy ? sqr(sy[0]) : 1))
99 return (p_merror("multiplying T.Tt by scalar"));
100 } else {
101 if (!m_trans(Xt, X))
102 return (p_merror("transposing X"));
103 if (!m_mult(XtC, Xt, C_1))
104 return (p_merror("multiplying Xt.C_1"));
105 if (!m_mult(XtCX, XtC, X))
106 return (p_merror("multiplying XtC.X"));
107 if (!m_invert(XtCX, XtCX))
108 return (p_merror("inverting XtCX"));
109 if (!m_mult(T, XtCX, XtC))
110 return (p_merror("multiplying XtCX.XtC"));
111 if (!m_mult(A, T, Y))
112 return (p_merror("multiplying T.Y"));
113
114 /* Compute covariance matrix of A, Ca = T.C.Tt */
115 if (!m_mult(TC, T, C))
116 return (p_merror("multiplying T.C"));
117 if (!m_trans(Tt, T))
118 return (p_merror("computing transpose of T"));
119 if (!m_mult(Ca, TC, Tt))
120 return (p_merror("multiplying TC.Tt"));
121 }
122
123 for (i = 0; i < n_terms; i++) {
124 coef[i] = A->a[i][0];
125 s_coef[i] = sqrt(Ca->a[i][i]);
126 }
127
128 /* Compute Yp = X.A, use to compute chi-squared */
129 if (!m_mult(Yp, X, A))
130 return (p_merror("multiplying X.A"));
131 *chi = 0;
132 for (i = 0; i < n_pts; i++) {
133 xp = (Yp->a[i][0] - yd[i]);
134 if (diff != NULL)
135 diff[i] = xp;
136 xp /= sy ? sy[i] : 1;
137 *chi += xp * xp;
138 }
139 if (n_terms != n_pts)
140 *chi /= (n_pts - n_terms);
141
142 m_free(&X);
143 m_free(&Y);
144 m_free(&Yp);
145 m_free(&Xt);
146 if (!unweighted) {
147 m_free(&C);
148 m_free(&C_1);
149 }
150 m_free(&A);
151 m_free(&Ca);
152 m_free(&XtC);
153 m_free(&XtCX);
154 m_free(&T);
155 m_free(&Tt);
156 m_free(&TC);
157 return (1);
158}
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
Definition ipow.c:33