int gsl_multifit_wlinear (const gsl_matrix * X, const gsl_vector * w, const gsl_vector * y, gsl_vector * c, gsl_matrix * cov, double *chisq, gsl_multifit_linear_workspace * work) { int status; size_t rank = 0; double rnorm, snorm; gsl_vector_view b = gsl_vector_subvector(work->t, 0, y->size); /* compute A = sqrt(W) X, b = sqrt(W) y */ status = gsl_multifit_linear_applyW(X, w, y, work->A, &b.vector); if (status) return status; /* compute SVD of A */ status = gsl_multifit_linear_bsvd(work->A, work); if (status) return status; status = multifit_linear_solve(X, &b.vector, GSL_DBL_EPSILON, 0.0, &rank, c, &rnorm, &snorm, work); if (status) return status; *chisq = rnorm * rnorm; /* variance-covariance matrix cov = s2 * (Q S^-1) (Q S^-1)^T */ { const size_t p = X->size2; size_t i, j; gsl_matrix_view QSI = gsl_matrix_submatrix(work->QSI, 0, 0, p, p); gsl_vector_view D = gsl_vector_subvector(work->D, 0, p); for (i = 0; i < p; i++) { gsl_vector_view row_i = gsl_matrix_row (&QSI.matrix, i); double d_i = gsl_vector_get (&D.vector, i); for (j = i; j < p; j++) { gsl_vector_view row_j = gsl_matrix_row (&QSI.matrix, j); double d_j = gsl_vector_get (&D.vector, j); double s; gsl_blas_ddot (&row_i.vector, &row_j.vector, &s); gsl_matrix_set (cov, i, j, s / (d_i * d_j)); gsl_matrix_set (cov, j, i, s / (d_i * d_j)); } } } return GSL_SUCCESS; }
int gsl_multifit_linear_wgenform2 (const gsl_matrix * LQR, const gsl_vector * Ltau, const gsl_matrix * X, const gsl_vector * w, const gsl_vector * y, const gsl_vector * cs, const gsl_matrix * M, gsl_vector * c, gsl_multifit_linear_workspace * work) { const size_t m = LQR->size1; const size_t n = X->size1; const size_t p = X->size2; if (n > work->nmax || p > work->pmax) { GSL_ERROR("X matrix does not match workspace", GSL_EBADLEN); } else if (p != LQR->size2) { GSL_ERROR("LQR matrix does not match X", GSL_EBADLEN); } else if (p != c->size) { GSL_ERROR("c vector does not match X", GSL_EBADLEN); } else if (w != NULL && n != w->size) { GSL_ERROR("w vector does not match X", GSL_EBADLEN); } else if (n != y->size) { GSL_ERROR("y vector does not match X", GSL_EBADLEN); } else if (m >= p) /* square or tall L matrix */ { if (p != cs->size) { GSL_ERROR("cs vector must be length p", GSL_EBADLEN); } else { int s; gsl_matrix_const_view R = gsl_matrix_const_submatrix(LQR, 0, 0, p, p); /* R factor of L */ /* solve R c = cs for true solution c, using QR decomposition of L */ gsl_vector_memcpy(c, cs); s = gsl_blas_dtrsv(CblasUpper, CblasNoTrans, CblasNonUnit, &R.matrix, c); return s; } } else /* rectangular L matrix with m < p */ { if (m != cs->size) { GSL_ERROR("cs vector must be length m", GSL_EBADLEN); } else if (n != M->size1 || p != M->size2) { GSL_ERROR("M matrix must be size n-by-p", GSL_EBADLEN); } else { int status; const size_t pm = p - m; gsl_matrix_view A = gsl_matrix_submatrix(work->A, 0, 0, n, p); gsl_vector_view b = gsl_vector_subvector(work->t, 0, n); gsl_matrix_view Rp = gsl_matrix_view_array(LQR->data, m, m); /* R_p */ gsl_matrix_view LTQR = gsl_matrix_view_array(LQR->data, p, m); gsl_vector_const_view LTtau = gsl_vector_const_subvector(Ltau, 0, m); gsl_matrix_const_view MQR = gsl_matrix_const_submatrix(M, 0, 0, n, pm); gsl_vector_const_view Mtau = gsl_matrix_const_subcolumn(M, p - 1, 0, GSL_MIN(n, pm)); gsl_matrix_const_view To = gsl_matrix_const_submatrix(&MQR.matrix, 0, 0, pm, pm); gsl_vector_view workp = gsl_vector_subvector(work->xt, 0, p); gsl_vector_view v1, v2; /* compute A = sqrt(W) X and b = sqrt(W) y */ status = gsl_multifit_linear_applyW(X, w, y, &A.matrix, &b.vector); if (status) return status; /* initialize c to zero */ gsl_vector_set_zero(c); /* compute c = L_inv cs = K_p R_p^{-T} cs */ /* set c(1:m) = R_p^{-T} cs */ v1 = gsl_vector_subvector(c, 0, m); gsl_vector_memcpy(&v1.vector, cs); gsl_blas_dtrsv(CblasUpper, CblasTrans, CblasNonUnit, &Rp.matrix, &v1.vector); /* c <- K R_p^{-T} cs = [ K_p R_p^{_T} cs ; 0 ] */ gsl_linalg_QR_Qvec(<QR.matrix, <tau.vector, c); /* compute: b1 = b - A L_inv cs */ gsl_blas_dgemv(CblasNoTrans, -1.0, &A.matrix, c, 1.0, &b.vector); /* compute: b2 = H^T b1 */ gsl_linalg_QR_QTvec(&MQR.matrix, &Mtau.vector, &b.vector); /* compute: b3 = T_o^{-1} b2 */ v1 = gsl_vector_subvector(&b.vector, 0, pm); gsl_blas_dtrsv(CblasUpper, CblasNoTrans, CblasNonUnit, &To.matrix, &v1.vector); /* compute: b4 = K_o b3 */ gsl_vector_set_zero(&workp.vector); v2 = gsl_vector_subvector(&workp.vector, m, pm); gsl_vector_memcpy(&v2.vector, &v1.vector); gsl_linalg_QR_Qvec(<QR.matrix, <tau.vector, &workp.vector); /* final solution vector */ gsl_vector_add(c, &workp.vector); return GSL_SUCCESS; } } }
int gsl_multifit_linear_wstdform1 (const gsl_vector * L, const gsl_matrix * X, const gsl_vector * w, const gsl_vector * y, gsl_matrix * Xs, gsl_vector * ys, gsl_multifit_linear_workspace * work) { const size_t n = X->size1; const size_t p = X->size2; if (n > work->nmax || p > work->pmax) { GSL_ERROR("observation matrix larger than workspace", GSL_EBADLEN); } else if (L != NULL && p != L->size) { GSL_ERROR("L vector does not match X", GSL_EBADLEN); } else if (n != y->size) { GSL_ERROR("y vector does not match X", GSL_EBADLEN); } else if (w != NULL && n != w->size) { GSL_ERROR("weight vector does not match X", GSL_EBADLEN); } else if (n != Xs->size1 || p != Xs->size2) { GSL_ERROR("Xs matrix dimensions do not match X", GSL_EBADLEN); } else if (n != ys->size) { GSL_ERROR("ys vector must be length n", GSL_EBADLEN); } else { int status = GSL_SUCCESS; /* compute Xs = sqrt(W) X and ys = sqrt(W) y */ status = gsl_multifit_linear_applyW(X, w, y, Xs, ys); if (status) return status; if (L != NULL) { size_t j; /* construct X~ = sqrt(W) X * L^{-1} matrix */ for (j = 0; j < p; ++j) { gsl_vector_view Xj = gsl_matrix_column(Xs, j); double lj = gsl_vector_get(L, j); if (lj == 0.0) { GSL_ERROR("L matrix is singular", GSL_EDOM); } gsl_vector_scale(&Xj.vector, 1.0 / lj); } } return status; } }
int gsl_multifit_linear_wstdform2 (const gsl_matrix * LQR, const gsl_vector * Ltau, const gsl_matrix * X, const gsl_vector * w, const gsl_vector * y, gsl_matrix * Xs, gsl_vector * ys, gsl_matrix * M, gsl_multifit_linear_workspace * work) { const size_t m = LQR->size1; const size_t n = X->size1; const size_t p = X->size2; if (n > work->nmax || p > work->pmax) { GSL_ERROR("observation matrix larger than workspace", GSL_EBADLEN); } else if (p != LQR->size2) { GSL_ERROR("LQR and X matrices have different numbers of columns", GSL_EBADLEN); } else if (n != y->size) { GSL_ERROR("y vector does not match X", GSL_EBADLEN); } else if (w != NULL && n != w->size) { GSL_ERROR("weights vector must be length n", GSL_EBADLEN); } else if (m >= p) /* square or tall L matrix */ { /* the sizes of Xs and ys depend on whether m >= p or m < p */ if (n != Xs->size1 || p != Xs->size2) { GSL_ERROR("Xs matrix must be n-by-p", GSL_EBADLEN); } else if (n != ys->size) { GSL_ERROR("ys vector must have length n", GSL_EBADLEN); } else { int status; size_t i; gsl_matrix_const_view R = gsl_matrix_const_submatrix(LQR, 0, 0, p, p); /* compute Xs = sqrt(W) X and ys = sqrt(W) y */ status = gsl_multifit_linear_applyW(X, w, y, Xs, ys); if (status) return status; /* compute X~ = X R^{-1} using QR decomposition of L */ for (i = 0; i < n; ++i) { gsl_vector_view v = gsl_matrix_row(Xs, i); /* solve: R^T y = X_i */ gsl_blas_dtrsv(CblasUpper, CblasTrans, CblasNonUnit, &R.matrix, &v.vector); } return GSL_SUCCESS; } } else /* L matrix with m < p */ { const size_t pm = p - m; const size_t npm = n - pm; /* * This code closely follows section 2.6.1 of Hansen's * "Regularization Tools" manual */ if (npm != Xs->size1 || m != Xs->size2) { GSL_ERROR("Xs matrix must be (n-p+m)-by-m", GSL_EBADLEN); } else if (npm != ys->size) { GSL_ERROR("ys vector must be of length (n-p+m)", GSL_EBADLEN); } else if (n != M->size1 || p != M->size2) { GSL_ERROR("M matrix must be n-by-p", GSL_EBADLEN); } else { int status; gsl_matrix_view A = gsl_matrix_submatrix(work->A, 0, 0, n, p); gsl_vector_view b = gsl_vector_subvector(work->t, 0, n); gsl_matrix_view LTQR = gsl_matrix_view_array(LQR->data, p, m); /* qr(L^T) */ gsl_matrix_view Rp = gsl_matrix_view_array(LQR->data, m, m); /* R factor of L^T */ gsl_vector_const_view LTtau = gsl_vector_const_subvector(Ltau, 0, m); /* * M(:,1:p-m) will hold QR decomposition of A K_o; M(:,p) will hold * Householder scalars */ gsl_matrix_view MQR = gsl_matrix_submatrix(M, 0, 0, n, pm); gsl_vector_view Mtau = gsl_matrix_subcolumn(M, p - 1, 0, GSL_MIN(n, pm)); gsl_matrix_view AKo, AKp, HqTAKp; gsl_vector_view v; size_t i; /* compute A = sqrt(W) X and b = sqrt(W) y */ status = gsl_multifit_linear_applyW(X, w, y, &A.matrix, &b.vector); if (status) return status; /* compute: A <- A K = [ A K_p ; A K_o ] */ gsl_linalg_QR_matQ(<QR.matrix, <tau.vector, &A.matrix); AKp = gsl_matrix_submatrix(&A.matrix, 0, 0, n, m); AKo = gsl_matrix_submatrix(&A.matrix, 0, m, n, pm); /* compute QR decomposition [H,T] = qr(A * K_o) and store in M */ gsl_matrix_memcpy(&MQR.matrix, &AKo.matrix); gsl_linalg_QR_decomp(&MQR.matrix, &Mtau.vector); /* AKp currently contains A K_p; apply H^T from the left to get H^T A K_p */ gsl_linalg_QR_QTmat(&MQR.matrix, &Mtau.vector, &AKp.matrix); /* the last npm rows correspond to H_q^T A K_p */ HqTAKp = gsl_matrix_submatrix(&AKp.matrix, pm, 0, npm, m); /* solve: Xs R_p^T = H_q^T A K_p for Xs */ gsl_matrix_memcpy(Xs, &HqTAKp.matrix); for (i = 0; i < npm; ++i) { gsl_vector_view x = gsl_matrix_row(Xs, i); gsl_blas_dtrsv(CblasUpper, CblasNoTrans, CblasNonUnit, &Rp.matrix, &x.vector); } /* * compute: ys = H_q^T b; this is equivalent to computing * the last q elements of H^T b (q = npm) */ v = gsl_vector_subvector(&b.vector, pm, npm); gsl_linalg_QR_QTvec(&MQR.matrix, &Mtau.vector, &b.vector); gsl_vector_memcpy(ys, &v.vector); return GSL_SUCCESS; } } }
static int secs2d_fit(void * vstate) { secs2d_state_t *state = (secs2d_state_t *) vstate; const size_t npts = 200; /* Note: to get a reasonable current map, use tol = 3e-1 */ const double tol = 1.0e-2; gsl_vector *reg_param = gsl_vector_alloc(npts); gsl_vector *rho = gsl_vector_alloc(npts); gsl_vector *eta = gsl_vector_alloc(npts); gsl_vector *G = gsl_vector_alloc(npts); gsl_matrix_view A = gsl_matrix_submatrix(state->X, 0, 0, state->n, state->p); gsl_vector_view b = gsl_vector_subvector(state->rhs, 0, state->n); gsl_vector_view wts = gsl_vector_subvector(state->wts, 0, state->n); double lambda_gcv, lambda_l, G_gcv; double rnorm, snorm; size_t i; const char *lambda_file = "lambda.dat"; FILE *fp = fopen(lambda_file, "w"); double s0; /* largest singular value */ if (state->n < state->p) return -1; fprintf(stderr, "\n"); fprintf(stderr, "\t n = %zu\n", state->n); fprintf(stderr, "\t p = %zu\n", state->p); #if 1 /* TSVD */ { double chisq; size_t rank; gsl_multifit_wlinear_tsvd(&A.matrix, &wts.vector, &b.vector, tol, state->c, state->cov, &chisq, &rank, state->multifit_p); rnorm = sqrt(chisq); snorm = gsl_blas_dnrm2(state->c); fprintf(stderr, "secs2d_fit: rank = %zu/%zu\n", rank, state->p); } #else /* Tikhonov / L-curve */ /* convert to standard form */ gsl_multifit_linear_applyW(&A.matrix, &wts.vector, &b.vector, &A.matrix, &b.vector); fprintf(stderr, "\t computing SVD..."); /* compute SVD of A */ gsl_multifit_linear_svd(&A.matrix, state->multifit_p); s0 = gsl_vector_get(state->multifit_p->S, 0); fprintf(stderr, "done\n"); /* compute GCV curve */ gsl_multifit_linear_gcv(&b.vector, reg_param, G, &lambda_gcv, &G_gcv, state->multifit_p); /* compute L-curve */ gsl_multifit_linear_lcurve(&b.vector, reg_param, rho, eta, state->multifit_p); fprintf(stderr, "\t secs2d_fit: writing %s...", lambda_file); for (i = 0; i < npts; ++i) { fprintf(fp, "%e %e %e %e\n", gsl_vector_get(reg_param, i), gsl_vector_get(rho, i), gsl_vector_get(eta, i), gsl_vector_get(G, i)); } fprintf(stderr, "done\n"); gsl_multifit_linear_lcorner(rho, eta, &i); lambda_l = gsl_vector_get(reg_param, i); /* lower bound on lambda */ lambda_l = GSL_MAX(lambda_l, tol * s0); /* solve regularized system with lambda_l */ gsl_multifit_linear_solve(lambda_l, &A.matrix, &b.vector, state->c, &rnorm, &snorm, state->multifit_p); fprintf(stderr, "\t s0 = %.12e\n", s0); fprintf(stderr, "\t lambda_l = %.12e\n", lambda_l); fprintf(stderr, "\t lambda_gcv = %.12e\n", lambda_gcv); fprintf(stderr, "\t rnorm = %.12e\n", rnorm); fprintf(stderr, "\t snorm = %.12e\n", snorm); fprintf(stderr, "\t cond(X) = %.12e\n", 1.0 / gsl_multifit_linear_rcond(state->multifit_p)); #endif gsl_vector_free(reg_param); gsl_vector_free(rho); gsl_vector_free(eta); gsl_vector_free(G); fclose(fp); return 0; }