1 /* multifit/multilinear.c
3 * Copyright (C) 2000, 2007 Brian Gough
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include <gsl/gsl_errno.h>
22 #include <gsl/gsl_multifit.h>
23 #include <gsl/gsl_blas.h>
24 #include <gsl/gsl_linalg.h>
30 * where X is an M x N matrix of M observations for N variables.
35 gsl_multifit_linear (const gsl_matrix * X,
39 double *chisq, gsl_multifit_linear_workspace * work)
42 int status = gsl_multifit_linear_svd (X, y, GSL_DBL_EPSILON, &rank, c,
47 /* Handle the general case of the SVD with tolerance and rank */
50 gsl_multifit_linear_svd (const gsl_matrix * X,
56 double *chisq, gsl_multifit_linear_workspace * work)
58 if (X->size1 != y->size)
61 ("number of observations in y does not match rows of matrix X",
64 else if (X->size2 != c->size)
66 GSL_ERROR ("number of parameters c does not match columns of matrix X",
69 else if (cov->size1 != cov->size2)
71 GSL_ERROR ("covariance matrix is not square", GSL_ENOTSQR);
73 else if (c->size != cov->size1)
76 ("number of parameters does not match size of covariance matrix",
79 else if (X->size1 != work->n || X->size2 != work->p)
82 ("size of workspace does not match size of observation matrix",
87 GSL_ERROR ("tolerance must be positive", GSL_EINVAL);
91 const size_t n = X->size1;
92 const size_t p = X->size2;
96 gsl_matrix *A = work->A;
97 gsl_matrix *Q = work->Q;
98 gsl_matrix *QSI = work->QSI;
99 gsl_vector *S = work->S;
100 gsl_vector *xt = work->xt;
101 gsl_vector *D = work->D;
103 /* Copy X to workspace, A <= X */
105 gsl_matrix_memcpy (A, X);
107 /* Balance the columns of the matrix A */
109 gsl_linalg_balance_columns (A, D);
111 /* Decompose A into U S Q^T */
113 gsl_linalg_SV_decomp_mod (A, QSI, Q, S, xt);
115 /* Solve y = A c for c */
117 gsl_blas_dgemv (CblasTrans, 1.0, A, y, 0.0, xt);
119 /* Scale the matrix Q, Q' = Q S^-1 */
121 gsl_matrix_memcpy (QSI, Q);
124 double alpha0 = gsl_vector_get (S, 0);
127 for (j = 0; j < p; j++)
129 gsl_vector_view column = gsl_matrix_column (QSI, j);
130 double alpha = gsl_vector_get (S, j);
132 if (alpha <= tol * alpha0) {
139 gsl_vector_scale (&column.vector, alpha);
145 gsl_vector_set_zero (c);
147 gsl_blas_dgemv (CblasNoTrans, 1.0, QSI, xt, 0.0, c);
149 /* Unscale the balancing factors */
151 gsl_vector_div (c, D);
153 /* Compute chisq, from residual r = y - X c */
156 double s2 = 0, r2 = 0;
158 for (i = 0; i < n; i++)
160 double yi = gsl_vector_get (y, i);
161 gsl_vector_const_view row = gsl_matrix_const_row (X, i);
163 gsl_blas_ddot (&row.vector, c, &y_est);
168 s2 = r2 / (n - p_eff); /* p_eff == rank */
172 /* Form variance-covariance matrix cov = s2 * (Q S^-1) (Q S^-1)^T */
174 for (i = 0; i < p; i++)
176 gsl_vector_view row_i = gsl_matrix_row (QSI, i);
177 double d_i = gsl_vector_get (D, i);
179 for (j = i; j < p; j++)
181 gsl_vector_view row_j = gsl_matrix_row (QSI, j);
182 double d_j = gsl_vector_get (D, j);
185 gsl_blas_ddot (&row_i.vector, &row_j.vector, &s);
187 gsl_matrix_set (cov, i, j, s * s2 / (d_i * d_j));
188 gsl_matrix_set (cov, j, i, s * s2 / (d_i * d_j));
198 gsl_multifit_wlinear (const gsl_matrix * X,
199 const gsl_vector * w,
200 const gsl_vector * y,
203 double *chisq, gsl_multifit_linear_workspace * work)
206 int status = gsl_multifit_wlinear_svd (X, w, y, GSL_DBL_EPSILON, &rank, c,
213 gsl_multifit_wlinear_svd (const gsl_matrix * X,
214 const gsl_vector * w,
215 const gsl_vector * y,
220 double *chisq, gsl_multifit_linear_workspace * work)
222 if (X->size1 != y->size)
225 ("number of observations in y does not match rows of matrix X",
228 else if (X->size2 != c->size)
230 GSL_ERROR ("number of parameters c does not match columns of matrix X",
233 else if (w->size != y->size)
235 GSL_ERROR ("number of weights does not match number of observations",
238 else if (cov->size1 != cov->size2)
240 GSL_ERROR ("covariance matrix is not square", GSL_ENOTSQR);
242 else if (c->size != cov->size1)
245 ("number of parameters does not match size of covariance matrix",
248 else if (X->size1 != work->n || X->size2 != work->p)
251 ("size of workspace does not match size of observation matrix",
256 const size_t n = X->size1;
257 const size_t p = X->size2;
261 gsl_matrix *A = work->A;
262 gsl_matrix *Q = work->Q;
263 gsl_matrix *QSI = work->QSI;
264 gsl_vector *S = work->S;
265 gsl_vector *t = work->t;
266 gsl_vector *xt = work->xt;
267 gsl_vector *D = work->D;
269 /* Scale X, A = sqrt(w) X */
271 gsl_matrix_memcpy (A, X);
273 for (i = 0; i < n; i++)
275 double wi = gsl_vector_get (w, i);
281 gsl_vector_view row = gsl_matrix_row (A, i);
282 gsl_vector_scale (&row.vector, sqrt (wi));
286 /* Balance the columns of the matrix A */
288 gsl_linalg_balance_columns (A, D);
290 /* Decompose A into U S Q^T */
292 gsl_linalg_SV_decomp_mod (A, QSI, Q, S, xt);
294 /* Solve sqrt(w) y = A c for c, by first computing t = sqrt(w) y */
296 for (i = 0; i < n; i++)
298 double wi = gsl_vector_get (w, i);
299 double yi = gsl_vector_get (y, i);
302 gsl_vector_set (t, i, sqrt (wi) * yi);
305 gsl_blas_dgemv (CblasTrans, 1.0, A, t, 0.0, xt);
307 /* Scale the matrix Q, Q' = Q S^-1 */
309 gsl_matrix_memcpy (QSI, Q);
312 double alpha0 = gsl_vector_get (S, 0);
315 for (j = 0; j < p; j++)
317 gsl_vector_view column = gsl_matrix_column (QSI, j);
318 double alpha = gsl_vector_get (S, j);
320 if (alpha <= tol * alpha0) {
327 gsl_vector_scale (&column.vector, alpha);
333 gsl_vector_set_zero (c);
337 gsl_blas_dgemv (CblasNoTrans, 1.0, QSI, xt, 0.0, c);
339 /* Unscale the balancing factors */
341 gsl_vector_div (c, D);
343 /* Form covariance matrix cov = (Q S^-1) (Q S^-1)^T */
345 for (i = 0; i < p; i++)
347 gsl_vector_view row_i = gsl_matrix_row (QSI, i);
348 double d_i = gsl_vector_get (D, i);
350 for (j = i; j < p; j++)
352 gsl_vector_view row_j = gsl_matrix_row (QSI, j);
353 double d_j = gsl_vector_get (D, j);
356 gsl_blas_ddot (&row_i.vector, &row_j.vector, &s);
358 gsl_matrix_set (cov, i, j, s / (d_i * d_j));
359 gsl_matrix_set (cov, j, i, s / (d_i * d_j));
363 /* Compute chisq, from residual r = y - X c */
368 for (i = 0; i < n; i++)
370 double yi = gsl_vector_get (y, i);
371 double wi = gsl_vector_get (w, i);
372 gsl_vector_const_view row = gsl_matrix_const_row (X, i);
374 gsl_blas_ddot (&row.vector, c, &y_est);
388 gsl_multifit_linear_est (const gsl_vector * x,
389 const gsl_vector * c,
390 const gsl_matrix * cov, double *y, double *y_err)
393 if (x->size != c->size)
395 GSL_ERROR ("number of parameters c does not match number of observations x",
398 else if (cov->size1 != cov->size2)
400 GSL_ERROR ("covariance matrix is not square", GSL_ENOTSQR);
402 else if (c->size != cov->size1)
404 GSL_ERROR ("number of parameters c does not match size of covariance matrix cov",
412 gsl_blas_ddot(x, c, y); /* y = x.c */
416 for (i = 0; i < x->size; i++)
418 const double xi = gsl_vector_get (x, i);
419 var += xi * xi * gsl_matrix_get (cov, i, i);
421 for (j = 0; j < i; j++)
423 const double xj = gsl_vector_get (x, j);
424 var += 2 * xi * xj * gsl_matrix_get (cov, i, j);
435 gsl_multifit_linear_residuals()
436 Compute vector of residuals from fit
438 Inputs: X - design matrix
441 r - (output) where to store residuals
445 gsl_multifit_linear_residuals (const gsl_matrix *X, const gsl_vector *y,
446 const gsl_vector *c, gsl_vector *r)
448 if (X->size1 != y->size)
451 ("number of observations in y does not match rows of matrix X",
454 else if (X->size2 != c->size)
456 GSL_ERROR ("number of parameters c does not match columns of matrix X",
459 else if (y->size != r->size)
461 GSL_ERROR ("number of observations in y does not match number of residuals",
468 for (i = 0; i < y->size; ++i)
470 double yi = gsl_vector_get(y, i);
471 gsl_vector_const_view row = gsl_matrix_const_row(X, i);
474 gsl_blas_ddot(&row.vector, c, &y_est);
477 gsl_vector_set(r, i, ri);
482 } /* gsl_multifit_linear_residuals() */