Computes nth order polynomial least squares fit.
This function performs an nth order polynomial least squares fit to the provided data. It supports both weighted and unweighted fitting based on the standard deviations provided.
41 {
42 long i, j, nt, unweighted;
43 double xp, *x_i, x0;
44 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;
45 long status = 0;
46
47 nt = nf + 1;
48 if (nd < nt) {
49 printf("error: insufficient data for requested order of fit\n");
50 printf("(%ld data points, %ld terms in fit)\n", nd, nt);
51 exit(1);
52 }
53
54 unweighted = 1;
55 if (sy)
56 for (i = 1; i < nd; i++)
57 if (sy[i] != sy[0]) {
58 unweighted = 0;
59 break;
60 }
61
62
63 m_alloc(&X, nd, nt);
64 m_alloc(&Y, nd, 1);
65 m_alloc(&Yp, nd, 1);
66 m_alloc(&Xt, nt, nd);
67 if (!unweighted) {
68 m_alloc(&C, nd, nd);
69 m_alloc(&C_1, nd, nd);
70 m_zero(C);
71 m_zero(C_1);
72 }
73 m_alloc(&A, nt, 1);
74 m_alloc(&Ca, nt, nt);
75 m_alloc(&XtC, nt, nd);
76 m_alloc(&XtCX, nt, nt);
77 m_alloc(&T, nt, nd);
78 m_alloc(&Tt, nd, nt);
79 m_alloc(&TC, nt, nd);
80
81
82
83
84
85 for (i = 0; i < nd; i++) {
86 x_i = X->a[i];
87 x0 = xd[i];
88 xp = 1.0;
89 Y->a[i][0] = yd[i];
90 if (!unweighted) {
91 C->a[i][i] = sqr(sy[i]);
92 C_1->a[i][i] = 1 / C->a[i][i];
93 }
94 for (j = 0; j < nt; j++) {
95 x_i[j] = xp;
96 xp *= x0;
97 }
98 }
99
100
101
102
103
104 if (unweighted) {
105
106
107
108 if (!m_trans(Xt, X))
109 { status = p_merror("transposing X"); goto cleanup; }
110 if (!m_mult(XtCX, Xt, X))
111 { status = p_merror("multiplying Xt.X"); goto cleanup; }
112 if (!m_invert(XtCX, XtCX))
113 { status = p_merror("inverting XtCX"); goto cleanup; }
114 if (!m_mult(T, XtCX, Xt))
115 { status = p_merror("multiplying XtX.Xt"); goto cleanup; }
116 if (!m_mult(A, T, Y))
117 { status = p_merror("multiplying T.Y"); goto cleanup; }
118
119
120 if (!m_trans(Tt, T))
121 { status = p_merror("computing transpose of T"); goto cleanup; }
122 if (!m_mult(Ca, T, Tt))
123 { status = p_merror("multiplying T.Tt"); goto cleanup; }
124 if (!m_scmul(Ca, Ca, sy ? sqr(sy[0]) : 1))
125 { status = p_merror("multiplying T.Tt by scalar"); goto cleanup; }
126 } else {
127 if (!m_trans(Xt, X))
128 { status = p_merror("transposing X"); goto cleanup; }
129 if (!m_mult(XtC, Xt, C_1))
130 { status = p_merror("multiplying Xt.C_1"); goto cleanup; }
131 if (!m_mult(XtCX, XtC, X))
132 { status = p_merror("multiplying XtC.X"); goto cleanup; }
133 if (!m_invert(XtCX, XtCX))
134 { status = p_merror("inverting XtCX"); goto cleanup; }
135 if (!m_mult(T, XtCX, XtC))
136 { status = p_merror("multiplying XtCX.XtC"); goto cleanup; }
137 if (!m_mult(A, T, Y))
138 { status = p_merror("multiplying T.Y"); goto cleanup; }
139
140
141 if (!m_mult(TC, T, C))
142 { status = p_merror("multiplying T.C"); goto cleanup; }
143 if (!m_trans(Tt, T))
144 { status = p_merror("computing transpose of T"); goto cleanup; }
145 if (!m_mult(Ca, TC, Tt))
146 { status = p_merror("multiplying TC.Tt"); goto cleanup; }
147 }
148
149 for (i = 0; i < nt; i++) {
150 coef[i] = A->a[i][0];
151 if (s_coef)
152 s_coef[i] = sqrt(Ca->a[i][i]);
153 }
154
155
156 if (chi) {
157 if (!m_mult(Yp, X, A))
158 { status = p_merror("multiplying X.A"); goto cleanup; }
159 *chi = 0;
160 for (i = 0; i < nd; i++) {
161 xp = (Yp->a[i][0] - yd[i]);
162 if (diff != NULL)
163 diff[i] = xp;
164 xp /= sy ? sy[i] : 1;
165 *chi += xp * xp;
166 }
167 if (nd != nt)
168 *chi /= (nd - nt);
169 }
170
171 status = 1;
172
173cleanup:
174 m_free(&X);
175 m_free(&Y);
176 m_free(&Yp);
177 m_free(&Xt);
178 if (!unweighted) {
179 m_free(&C);
180 m_free(&C_1);
181 }
182 m_free(&A);
183 m_free(&Ca);
184 m_free(&XtC);
185 m_free(&XtCX);
186 m_free(&T);
187 m_free(&Tt);
188 m_free(&TC);
189 return (status);
190}