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