|
Packit |
67cb25 |
/* multifit/multireg.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2015 Patrick Alken
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software
|
|
Packit |
67cb25 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* References:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [1] P. C. Hansen & D. P. O'Leary, "The use of the L-curve in
|
|
Packit |
67cb25 |
* the regularization of discrete ill-posed problems", SIAM J. Sci.
|
|
Packit |
67cb25 |
* Comput. 14 (1993), pp. 1487-1503.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [2] P. C. Hansen, "Discrete Inverse Problems: Insight and Algorithms,"
|
|
Packit |
67cb25 |
* SIAM Press, 2010.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_multifit.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_blas.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_vector.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_matrix.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_linalg.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "linear_common.c"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_solve (const double lambda,
|
|
Packit |
67cb25 |
const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
gsl_vector * c,
|
|
Packit |
67cb25 |
double *rnorm,
|
|
Packit |
67cb25 |
double *snorm,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t rank;
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = multifit_linear_solve(X, y, GSL_DBL_EPSILON, lambda, &rank, c,
|
|
Packit |
67cb25 |
rnorm, snorm, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
} /* gsl_multifit_linear_solve() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_applyW()
|
|
Packit |
67cb25 |
Apply weight matrix to (X,y) LS system
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: X - least squares matrix n-by-p
|
|
Packit |
67cb25 |
w - weight vector n-by-1 or NULL for W = I
|
|
Packit |
67cb25 |
y - right hand side n-by-1
|
|
Packit |
67cb25 |
WX - (output) sqrt(W) X, n-by-p
|
|
Packit |
67cb25 |
Wy - (output) sqrt(W) y, n-by-1
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) If w = NULL, on output WX = X and Wy = y
|
|
Packit |
67cb25 |
2) It is allowed for WX = X and Wy = y for in-place transform
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_applyW(const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * w,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
gsl_matrix * WX,
|
|
Packit |
67cb25 |
gsl_vector * Wy)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t n = X->size1;
|
|
Packit |
67cb25 |
const size_t p = X->size2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n != y->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("y vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (w != NULL && n != w->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("weight vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != WX->size1 || p != WX->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("WX matrix dimensions do not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != Wy->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("Wy vector must be length n", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* copy WX = X; Wy = y if distinct pointers */
|
|
Packit |
67cb25 |
if (WX != X)
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(WX, X);
|
|
Packit |
67cb25 |
if (Wy != y)
|
|
Packit |
67cb25 |
gsl_vector_memcpy(Wy, y);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w != NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* construct WX = sqrt(W) X and Wy = sqrt(W) y */
|
|
Packit |
67cb25 |
for (i = 0; i < n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double wi = gsl_vector_get(w, i);
|
|
Packit |
67cb25 |
double swi;
|
|
Packit |
67cb25 |
gsl_vector_view row = gsl_matrix_row(WX, i);
|
|
Packit |
67cb25 |
double *yi = gsl_vector_ptr(Wy, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (wi < 0.0)
|
|
Packit |
67cb25 |
wi = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
swi = sqrt(wi);
|
|
Packit |
67cb25 |
gsl_vector_scale(&row.vector, swi);
|
|
Packit |
67cb25 |
*yi *= swi;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_wstdform1()
|
|
Packit |
67cb25 |
Using regularization matrix
|
|
Packit |
67cb25 |
L = diag(l_1,l_2,...,l_p), transform to Tikhonov standard form:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
X~ = sqrt(W) X L^{-1}
|
|
Packit |
67cb25 |
y~ = sqrt(W) y
|
|
Packit |
67cb25 |
c~ = L c
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: L - Tikhonov matrix as a vector of diagonal elements p-by-1;
|
|
Packit |
67cb25 |
or NULL for L = I
|
|
Packit |
67cb25 |
X - least squares matrix n-by-p
|
|
Packit |
67cb25 |
y - right hand side vector n-by-1
|
|
Packit |
67cb25 |
w - weight vector n-by-1; or NULL for W = I
|
|
Packit |
67cb25 |
Xs - least squares matrix in standard form X~ n-by-p
|
|
Packit |
67cb25 |
ys - right hand side vector in standard form y~ n-by-1
|
|
Packit |
67cb25 |
work - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) It is allowed for X = Xs and y = ys
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_wstdform1 (const gsl_vector * L,
|
|
Packit |
67cb25 |
const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * w,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
gsl_matrix * Xs,
|
|
Packit |
67cb25 |
gsl_vector * ys,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t n = X->size1;
|
|
Packit |
67cb25 |
const size_t p = X->size2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n > work->nmax || p > work->pmax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("observation matrix larger than workspace", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (L != NULL && p != L->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("L vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != y->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("y vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (w != NULL && n != w->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("weight vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != Xs->size1 || p != Xs->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("Xs matrix dimensions do not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != ys->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("ys vector must be length n", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status = GSL_SUCCESS;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute Xs = sqrt(W) X and ys = sqrt(W) y */
|
|
Packit |
67cb25 |
status = gsl_multifit_linear_applyW(X, w, y, Xs, ys);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (L != NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t j;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* construct X~ = sqrt(W) X * L^{-1} matrix */
|
|
Packit |
67cb25 |
for (j = 0; j < p; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view Xj = gsl_matrix_column(Xs, j);
|
|
Packit |
67cb25 |
double lj = gsl_vector_get(L, j);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (lj == 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("L matrix is singular", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_scale(&Xj.vector, 1.0 / lj);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_stdform1()
|
|
Packit |
67cb25 |
Using regularization matrix L = diag(l_1,l_2,...,l_p),
|
|
Packit |
67cb25 |
and W = I, transform to Tikhonov standard form:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
X~ = X L^{-1}
|
|
Packit |
67cb25 |
y~ = y
|
|
Packit |
67cb25 |
c~ = L c
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: L - Tikhonov matrix as a vector of diagonal elements p-by-1
|
|
Packit |
67cb25 |
X - least squares matrix n-by-p
|
|
Packit |
67cb25 |
y - right hand side vector n-by-1
|
|
Packit |
67cb25 |
Xs - least squares matrix in standard form X~ n-by-p
|
|
Packit |
67cb25 |
ys - right hand side vector in standard form y~ n-by-1
|
|
Packit |
67cb25 |
work - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) It is allowed for X = Xs
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_stdform1 (const gsl_vector * L,
|
|
Packit |
67cb25 |
const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
gsl_matrix * Xs,
|
|
Packit |
67cb25 |
gsl_vector * ys,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_multifit_linear_wstdform1(L, X, NULL, y, Xs, ys, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_L_decomp (gsl_matrix * L, gsl_vector * tau)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t m = L->size1;
|
|
Packit |
67cb25 |
const size_t p = L->size2;
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (tau->size != GSL_MIN(m, p))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("tau vector must be min(m,p)", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (m >= p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* square or tall L matrix */
|
|
Packit |
67cb25 |
status = gsl_linalg_QR_decomp(L, tau);
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* more columns than rows, compute qr(L^T) */
|
|
Packit |
67cb25 |
gsl_matrix_view LTQR = gsl_matrix_view_array(L->data, p, m);
|
|
Packit |
67cb25 |
gsl_matrix *LT = gsl_matrix_alloc(p, m);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* XXX: use temporary storage due to difficulties in transforming
|
|
Packit |
67cb25 |
* a rectangular matrix in-place */
|
|
Packit |
67cb25 |
gsl_matrix_transpose_memcpy(LT, L);
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(<QR.matrix, LT);
|
|
Packit |
67cb25 |
gsl_matrix_free(LT);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_linalg_QR_decomp(<QR.matrix, tau);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_wstdform2()
|
|
Packit |
67cb25 |
Using regularization matrix L which is m-by-p, transform to Tikhonov
|
|
Packit |
67cb25 |
standard form. This routine is separated into two cases:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Case 1: m >= p, here we can use the QR decomposition of L = QR, and note
|
|
Packit |
67cb25 |
that ||L c|| = ||R c|| where R is p-by-p. Therefore,
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
X~ = X R^{-1} is n-by-p
|
|
Packit |
67cb25 |
y~ = y is n-by-1
|
|
Packit |
67cb25 |
c~ is p-by-1
|
|
Packit |
67cb25 |
M is not used
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Case 2: m < p
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
X~ is (n - p + m)-by-m
|
|
Packit |
67cb25 |
y~ is (n - p + m)-by-1
|
|
Packit |
67cb25 |
c~ is m-by-1
|
|
Packit |
67cb25 |
M is n-by-p (workspace)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: LQR - output from gsl_multifit_linear_L_decomp()
|
|
Packit |
67cb25 |
Ltau - output from gsl_multifit_linear_L_decomp()
|
|
Packit |
67cb25 |
X - least squares matrix n-by-p
|
|
Packit |
67cb25 |
w - weight vector n-by-1; or NULL for W = I
|
|
Packit |
67cb25 |
y - right hand side vector n-by-1
|
|
Packit |
67cb25 |
Xs - (output) least squares matrix in standard form
|
|
Packit |
67cb25 |
case 1: n-by-p
|
|
Packit |
67cb25 |
case 2: (n - p + m)-by-m
|
|
Packit |
67cb25 |
ys - (output) right hand side vector in standard form
|
|
Packit |
67cb25 |
case 1: n-by-1
|
|
Packit |
67cb25 |
case 2: (n - p + m)-by-1
|
|
Packit |
67cb25 |
M - (output) workspace matrix needed to reconstruct solution vector
|
|
Packit |
67cb25 |
case 1: not used
|
|
Packit |
67cb25 |
case 2: n-by-p
|
|
Packit |
67cb25 |
work - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) If m >= p, on output:
|
|
Packit |
67cb25 |
Xs = X R^{-1}
|
|
Packit |
67cb25 |
ys = y
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) If m < p, on output:
|
|
Packit |
67cb25 |
M(:,1:pm) contains QR decomposition of A * K_o, needed to reconstruct
|
|
Packit |
67cb25 |
solution vector, where pm = p - m; M(:,p) contains Householder scalars
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_wstdform2 (const gsl_matrix * LQR,
|
|
Packit |
67cb25 |
const gsl_vector * Ltau,
|
|
Packit |
67cb25 |
const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * w,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
gsl_matrix * Xs,
|
|
Packit |
67cb25 |
gsl_vector * ys,
|
|
Packit |
67cb25 |
gsl_matrix * M,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t m = LQR->size1;
|
|
Packit |
67cb25 |
const size_t n = X->size1;
|
|
Packit |
67cb25 |
const size_t p = X->size2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n > work->nmax || p > work->pmax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("observation matrix larger than workspace", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (p != LQR->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("LQR and X matrices have different numbers of columns", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != y->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("y vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (w != NULL && n != w->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("weights vector must be length n", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (m >= p) /* square or tall L matrix */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* the sizes of Xs and ys depend on whether m >= p or m < p */
|
|
Packit |
67cb25 |
if (n != Xs->size1 || p != Xs->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("Xs matrix must be n-by-p", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != ys->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("ys vector must have length n", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
gsl_matrix_const_view R = gsl_matrix_const_submatrix(LQR, 0, 0, p, p);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute Xs = sqrt(W) X and ys = sqrt(W) y */
|
|
Packit |
67cb25 |
status = gsl_multifit_linear_applyW(X, w, y, Xs, ys);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute X~ = X R^{-1} using QR decomposition of L */
|
|
Packit |
67cb25 |
for (i = 0; i < n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view v = gsl_matrix_row(Xs, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve: R^T y = X_i */
|
|
Packit |
67cb25 |
gsl_blas_dtrsv(CblasUpper, CblasTrans, CblasNonUnit, &R.matrix, &v.vector);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else /* L matrix with m < p */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t pm = p - m;
|
|
Packit |
67cb25 |
const size_t npm = n - pm;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This code closely follows section 2.6.1 of Hansen's
|
|
Packit |
67cb25 |
* "Regularization Tools" manual
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (npm != Xs->size1 || m != Xs->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("Xs matrix must be (n-p+m)-by-m", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (npm != ys->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("ys vector must be of length (n-p+m)", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != M->size1 || p != M->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("M matrix must be n-by-p", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
gsl_matrix_view A = gsl_matrix_submatrix(work->A, 0, 0, n, p);
|
|
Packit |
67cb25 |
gsl_vector_view b = gsl_vector_subvector(work->t, 0, n);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_view LTQR = gsl_matrix_view_array(LQR->data, p, m); /* qr(L^T) */
|
|
Packit |
67cb25 |
gsl_matrix_view Rp = gsl_matrix_view_array(LQR->data, m, m); /* R factor of L^T */
|
|
Packit |
67cb25 |
gsl_vector_const_view LTtau = gsl_vector_const_subvector(Ltau, 0, m);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* M(:,1:p-m) will hold QR decomposition of A K_o; M(:,p) will hold
|
|
Packit |
67cb25 |
* Householder scalars
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
gsl_matrix_view MQR = gsl_matrix_submatrix(M, 0, 0, n, pm);
|
|
Packit |
67cb25 |
gsl_vector_view Mtau = gsl_matrix_subcolumn(M, p - 1, 0, GSL_MIN(n, pm));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_view AKo, AKp, HqTAKp;
|
|
Packit |
67cb25 |
gsl_vector_view v;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute A = sqrt(W) X and b = sqrt(W) y */
|
|
Packit |
67cb25 |
status = gsl_multifit_linear_applyW(X, w, y, &A.matrix, &b.vector);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: A <- A K = [ A K_p ; A K_o ] */
|
|
Packit |
67cb25 |
gsl_linalg_QR_matQ(<QR.matrix, <tau.vector, &A.matrix);
|
|
Packit |
67cb25 |
AKp = gsl_matrix_submatrix(&A.matrix, 0, 0, n, m);
|
|
Packit |
67cb25 |
AKo = gsl_matrix_submatrix(&A.matrix, 0, m, n, pm);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute QR decomposition [H,T] = qr(A * K_o) and store in M */
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(&MQR.matrix, &AKo.matrix);
|
|
Packit |
67cb25 |
gsl_linalg_QR_decomp(&MQR.matrix, &Mtau.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* AKp currently contains A K_p; apply H^T from the left to get H^T A K_p */
|
|
Packit |
67cb25 |
gsl_linalg_QR_QTmat(&MQR.matrix, &Mtau.vector, &AKp.matrix);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* the last npm rows correspond to H_q^T A K_p */
|
|
Packit |
67cb25 |
HqTAKp = gsl_matrix_submatrix(&AKp.matrix, pm, 0, npm, m);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve: Xs R_p^T = H_q^T A K_p for Xs */
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(Xs, &HqTAKp.matrix);
|
|
Packit |
67cb25 |
for (i = 0; i < npm; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view x = gsl_matrix_row(Xs, i);
|
|
Packit |
67cb25 |
gsl_blas_dtrsv(CblasUpper, CblasNoTrans, CblasNonUnit, &Rp.matrix, &x.vector);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* compute: ys = H_q^T b; this is equivalent to computing
|
|
Packit |
67cb25 |
* the last q elements of H^T b (q = npm)
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
v = gsl_vector_subvector(&b.vector, pm, npm);
|
|
Packit |
67cb25 |
gsl_linalg_QR_QTvec(&MQR.matrix, &Mtau.vector, &b.vector);
|
|
Packit |
67cb25 |
gsl_vector_memcpy(ys, &v.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_stdform2 (const gsl_matrix * LQR,
|
|
Packit |
67cb25 |
const gsl_vector * Ltau,
|
|
Packit |
67cb25 |
const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
gsl_matrix * Xs,
|
|
Packit |
67cb25 |
gsl_vector * ys,
|
|
Packit |
67cb25 |
gsl_matrix * M,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_multifit_linear_wstdform2(LQR, Ltau, X, NULL, y, Xs, ys, M, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_genform1()
|
|
Packit |
67cb25 |
Backtransform regularized solution vector using matrix
|
|
Packit |
67cb25 |
L = diag(L)
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_genform1 (const gsl_vector * L,
|
|
Packit |
67cb25 |
const gsl_vector * cs,
|
|
Packit |
67cb25 |
gsl_vector * c,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (L->size > work->pmax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("L vector does not match workspace", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (L->size != cs->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("cs vector does not match L", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (L->size != c->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("c vector does not match L", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* compute true solution vector c = L^{-1} c~ */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(c, cs);
|
|
Packit |
67cb25 |
gsl_vector_div(c, L);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_wgenform2()
|
|
Packit |
67cb25 |
Backtransform regularized solution vector in standard form to recover
|
|
Packit |
67cb25 |
original vector
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: LQR - output from gsl_multifit_linear_L_decomp()
|
|
Packit |
67cb25 |
Ltau - output from gsl_multifit_linear_L_decomp()
|
|
Packit |
67cb25 |
X - original least squares matrix n-by-p
|
|
Packit |
67cb25 |
w - original weight vector n-by-1 or NULL for W = I
|
|
Packit |
67cb25 |
y - original rhs vector n-by-1
|
|
Packit |
67cb25 |
cs - standard form solution vector
|
|
Packit |
67cb25 |
c - (output) original solution vector p-by-1
|
|
Packit |
67cb25 |
M - matrix computed by gsl_multifit_linear_wstdform2()
|
|
Packit |
67cb25 |
work - workspace
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_wgenform2 (const gsl_matrix * LQR,
|
|
Packit |
67cb25 |
const gsl_vector * Ltau,
|
|
Packit |
67cb25 |
const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * w,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
const gsl_vector * cs,
|
|
Packit |
67cb25 |
const gsl_matrix * M,
|
|
Packit |
67cb25 |
gsl_vector * c,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t m = LQR->size1;
|
|
Packit |
67cb25 |
const size_t n = X->size1;
|
|
Packit |
67cb25 |
const size_t p = X->size2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n > work->nmax || p > work->pmax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("X matrix does not match workspace", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (p != LQR->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("LQR matrix does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (p != c->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("c vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (w != NULL && n != w->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("w vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != y->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("y vector does not match X", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (m >= p) /* square or tall L matrix */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (p != cs->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("cs vector must be length p", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int s;
|
|
Packit |
67cb25 |
gsl_matrix_const_view R = gsl_matrix_const_submatrix(LQR, 0, 0, p, p); /* R factor of L */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve R c = cs for true solution c, using QR decomposition of L */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(c, cs);
|
|
Packit |
67cb25 |
s = gsl_blas_dtrsv(CblasUpper, CblasNoTrans, CblasNonUnit, &R.matrix, c);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else /* rectangular L matrix with m < p */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (m != cs->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("cs vector must be length m", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != M->size1 || p != M->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("M matrix must be size n-by-p", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
const size_t pm = p - m;
|
|
Packit |
67cb25 |
gsl_matrix_view A = gsl_matrix_submatrix(work->A, 0, 0, n, p);
|
|
Packit |
67cb25 |
gsl_vector_view b = gsl_vector_subvector(work->t, 0, n);
|
|
Packit |
67cb25 |
gsl_matrix_view Rp = gsl_matrix_view_array(LQR->data, m, m); /* R_p */
|
|
Packit |
67cb25 |
gsl_matrix_view LTQR = gsl_matrix_view_array(LQR->data, p, m);
|
|
Packit |
67cb25 |
gsl_vector_const_view LTtau = gsl_vector_const_subvector(Ltau, 0, m);
|
|
Packit |
67cb25 |
gsl_matrix_const_view MQR = gsl_matrix_const_submatrix(M, 0, 0, n, pm);
|
|
Packit |
67cb25 |
gsl_vector_const_view Mtau = gsl_matrix_const_subcolumn(M, p - 1, 0, GSL_MIN(n, pm));
|
|
Packit |
67cb25 |
gsl_matrix_const_view To = gsl_matrix_const_submatrix(&MQR.matrix, 0, 0, pm, pm);
|
|
Packit |
67cb25 |
gsl_vector_view workp = gsl_vector_subvector(work->xt, 0, p);
|
|
Packit |
67cb25 |
gsl_vector_view v1, v2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute A = sqrt(W) X and b = sqrt(W) y */
|
|
Packit |
67cb25 |
status = gsl_multifit_linear_applyW(X, w, y, &A.matrix, &b.vector);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize c to zero */
|
|
Packit |
67cb25 |
gsl_vector_set_zero(c);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute c = L_inv cs = K_p R_p^{-T} cs */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* set c(1:m) = R_p^{-T} cs */
|
|
Packit |
67cb25 |
v1 = gsl_vector_subvector(c, 0, m);
|
|
Packit |
67cb25 |
gsl_vector_memcpy(&v1.vector, cs);
|
|
Packit |
67cb25 |
gsl_blas_dtrsv(CblasUpper, CblasTrans, CblasNonUnit, &Rp.matrix, &v1.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* c <- K R_p^{-T} cs = [ K_p R_p^{_T} cs ; 0 ] */
|
|
Packit |
67cb25 |
gsl_linalg_QR_Qvec(<QR.matrix, <tau.vector, c);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: b1 = b - A L_inv cs */
|
|
Packit |
67cb25 |
gsl_blas_dgemv(CblasNoTrans, -1.0, &A.matrix, c, 1.0, &b.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: b2 = H^T b1 */
|
|
Packit |
67cb25 |
gsl_linalg_QR_QTvec(&MQR.matrix, &Mtau.vector, &b.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: b3 = T_o^{-1} b2 */
|
|
Packit |
67cb25 |
v1 = gsl_vector_subvector(&b.vector, 0, pm);
|
|
Packit |
67cb25 |
gsl_blas_dtrsv(CblasUpper, CblasNoTrans, CblasNonUnit, &To.matrix, &v1.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: b4 = K_o b3 */
|
|
Packit |
67cb25 |
gsl_vector_set_zero(&workp.vector);
|
|
Packit |
67cb25 |
v2 = gsl_vector_subvector(&workp.vector, m, pm);
|
|
Packit |
67cb25 |
gsl_vector_memcpy(&v2.vector, &v1.vector);
|
|
Packit |
67cb25 |
gsl_linalg_QR_Qvec(<QR.matrix, <tau.vector, &workp.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* final solution vector */
|
|
Packit |
67cb25 |
gsl_vector_add(c, &workp.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_genform2 (const gsl_matrix * LQR,
|
|
Packit |
67cb25 |
const gsl_vector * Ltau,
|
|
Packit |
67cb25 |
const gsl_matrix * X,
|
|
Packit |
67cb25 |
const gsl_vector * y,
|
|
Packit |
67cb25 |
const gsl_vector * cs,
|
|
Packit |
67cb25 |
const gsl_matrix * M,
|
|
Packit |
67cb25 |
gsl_vector * c,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_multifit_linear_wgenform2(LQR, Ltau, X, NULL, y, cs, M, c, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_lreg()
|
|
Packit |
67cb25 |
Calculate regularization parameters to use in L-curve
|
|
Packit |
67cb25 |
analysis
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: smin - smallest singular value of LS system
|
|
Packit |
67cb25 |
smax - largest singular value of LS system > 0
|
|
Packit |
67cb25 |
reg_param - (output) vector of regularization parameters
|
|
Packit |
67cb25 |
derived from singular values
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_lreg (const double smin, const double smax,
|
|
Packit |
67cb25 |
gsl_vector * reg_param)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (smax <= 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("smax must be positive", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = reg_param->size;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* smallest regularization parameter */
|
|
Packit |
67cb25 |
const double smin_ratio = 16.0 * GSL_DBL_EPSILON;
|
|
Packit |
67cb25 |
const double new_smin = GSL_MAX(smin, smax*smin_ratio);
|
|
Packit |
67cb25 |
double ratio;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(reg_param, N - 1, new_smin);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* ratio so that reg_param(1) = s(1) */
|
|
Packit |
67cb25 |
ratio = pow(smax / new_smin, 1.0 / ((double)N - 1.0));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* calculate the regularization parameters */
|
|
Packit |
67cb25 |
for (i = N - 1; i > 0 && i--; )
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double rp1 = gsl_vector_get(reg_param, i + 1);
|
|
Packit |
67cb25 |
gsl_vector_set(reg_param, i, ratio * rp1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_lcurve()
|
|
Packit |
67cb25 |
Calculate L-curve using regularization parameters estimated
|
|
Packit |
67cb25 |
from singular values of least squares matrix
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: y - right hand side vector
|
|
Packit |
67cb25 |
reg_param - (output) vector of regularization parameters
|
|
Packit |
67cb25 |
derived from singular values
|
|
Packit |
67cb25 |
rho - (output) vector of residual norms ||y - X c||
|
|
Packit |
67cb25 |
eta - (output) vector of solution norms ||lambda c||
|
|
Packit |
67cb25 |
work - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) SVD of X must be computed first by calling multifit_linear_svd();
|
|
Packit |
67cb25 |
work->n and work->p are initialized by this function
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_lcurve (const gsl_vector * y,
|
|
Packit |
67cb25 |
gsl_vector * reg_param,
|
|
Packit |
67cb25 |
gsl_vector * rho, gsl_vector * eta,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t n = y->size;
|
|
Packit |
67cb25 |
const size_t N = rho->size; /* number of points on L-curve */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n != work->n)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("y vector does not match workspace", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (N < 3)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("at least 3 points are needed for L-curve analysis",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (N != eta->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("size of rho and eta vectors do not match",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (reg_param->size != eta->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("size of reg_param and eta vectors do not match",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status = GSL_SUCCESS;
|
|
Packit |
67cb25 |
const size_t p = work->p;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
size_t i, j;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_view A = gsl_matrix_submatrix(work->A, 0, 0, n, p);
|
|
Packit |
67cb25 |
gsl_vector_view S = gsl_vector_subvector(work->S, 0, p);
|
|
Packit |
67cb25 |
gsl_vector_view xt = gsl_vector_subvector(work->xt, 0, p);
|
|
Packit |
67cb25 |
gsl_vector_view workp = gsl_matrix_subcolumn(work->QSI, 0, 0, p);
|
|
Packit |
67cb25 |
gsl_vector_view workp2 = gsl_vector_subvector(work->D, 0, p); /* D isn't used for regularized problems */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
const double smax = gsl_vector_get(&S.vector, 0);
|
|
Packit |
67cb25 |
const double smin = gsl_vector_get(&S.vector, p - 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double dr; /* residual error from projection */
|
|
Packit |
67cb25 |
double normy = gsl_blas_dnrm2(y);
|
|
Packit |
67cb25 |
double normUTy;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute projection xt = U^T y */
|
|
Packit |
67cb25 |
gsl_blas_dgemv (CblasTrans, 1.0, &A.matrix, y, 0.0, &xt.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
normUTy = gsl_blas_dnrm2(&xt.vector);
|
|
Packit |
67cb25 |
dr = normy*normy - normUTy*normUTy;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* calculate regularization parameters */
|
|
Packit |
67cb25 |
gsl_multifit_linear_lreg(smin, smax, reg_param);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double lambda = gsl_vector_get(reg_param, i);
|
|
Packit |
67cb25 |
double lambda_sq = lambda * lambda;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < p; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double sj = gsl_vector_get(&S.vector, j);
|
|
Packit |
67cb25 |
double xtj = gsl_vector_get(&xt.vector, j);
|
|
Packit |
67cb25 |
double f = sj / (sj*sj + lambda_sq);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(&workp.vector, j, f * xtj);
|
|
Packit |
67cb25 |
gsl_vector_set(&workp2.vector, j, (1.0 - sj*f) * xtj);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(eta, i, gsl_blas_dnrm2(&workp.vector));
|
|
Packit |
67cb25 |
gsl_vector_set(rho, i, gsl_blas_dnrm2(&workp2.vector));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n > p && dr > 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* add correction to residual norm (see eqs 6-7 of [1]) */
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double rhoi = gsl_vector_get(rho, i);
|
|
Packit |
67cb25 |
double *ptr = gsl_vector_ptr(rho, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*ptr = sqrt(rhoi*rhoi + dr);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* restore D to identity matrix */
|
|
Packit |
67cb25 |
gsl_vector_set_all(work->D, 1.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_multifit_linear_lcurve() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_lcorner()
|
|
Packit |
67cb25 |
Determine point on L-curve of maximum curvature. For each
|
|
Packit |
67cb25 |
set of 3 points on the L-curve, the circle which passes through
|
|
Packit |
67cb25 |
the 3 points is computed. The radius of the circle is then used
|
|
Packit |
67cb25 |
as an estimate of the curvature at the middle point. The point
|
|
Packit |
67cb25 |
with maximum curvature is then selected.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: rho - vector of residual norms ||A x - b||
|
|
Packit |
67cb25 |
eta - vector of solution norms ||L x||
|
|
Packit |
67cb25 |
idx - (output) index i such that
|
|
Packit |
67cb25 |
(log(rho(i)),log(eta(i))) is the point of
|
|
Packit |
67cb25 |
maximum curvature
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_lcorner(const gsl_vector *rho,
|
|
Packit |
67cb25 |
const gsl_vector *eta,
|
|
Packit |
67cb25 |
size_t *idx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t n = rho->size;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n < 3)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("at least 3 points are needed for L-curve analysis",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != eta->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("size of rho and eta vectors do not match",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int s = GSL_SUCCESS;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
double x1, y1; /* first point of triangle on L-curve */
|
|
Packit |
67cb25 |
double x2, y2; /* second point of triangle on L-curve */
|
|
Packit |
67cb25 |
double rmin = -1.0; /* minimum radius of curvature */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initial values */
|
|
Packit |
67cb25 |
x1 = log(gsl_vector_get(rho, 0));
|
|
Packit |
67cb25 |
y1 = log(gsl_vector_get(eta, 0));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
x2 = log(gsl_vector_get(rho, 1));
|
|
Packit |
67cb25 |
y2 = log(gsl_vector_get(eta, 1));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 1; i < n - 1; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* The points (x1,y1), (x2,y2), (x3,y3) are the previous,
|
|
Packit |
67cb25 |
* current, and next point on the L-curve. We will find
|
|
Packit |
67cb25 |
* the circle which fits these 3 points and take its radius
|
|
Packit |
67cb25 |
* as an estimate of the curvature at this point.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
double x3 = log(gsl_vector_get(rho, i + 1));
|
|
Packit |
67cb25 |
double y3 = log(gsl_vector_get(eta, i + 1));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double x21 = x2 - x1;
|
|
Packit |
67cb25 |
double y21 = y2 - y1;
|
|
Packit |
67cb25 |
double x31 = x3 - x1;
|
|
Packit |
67cb25 |
double y31 = y3 - y1;
|
|
Packit |
67cb25 |
double h21 = x21*x21 + y21*y21;
|
|
Packit |
67cb25 |
double h31 = x31*x31 + y31*y31;
|
|
Packit |
67cb25 |
double d = fabs(2.0 * (x21*y31 - x31*y21));
|
|
Packit |
67cb25 |
double r = sqrt(h21*h31*((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2))) / d;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* if d =~ 0 then there are nearly colinear points */
|
|
Packit |
67cb25 |
if (gsl_finite(r))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* check for smallest radius of curvature */
|
|
Packit |
67cb25 |
if (r < rmin || rmin < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
rmin = r;
|
|
Packit |
67cb25 |
*idx = i;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* update previous/current L-curve values */
|
|
Packit |
67cb25 |
x1 = x2;
|
|
Packit |
67cb25 |
y1 = y2;
|
|
Packit |
67cb25 |
x2 = x3;
|
|
Packit |
67cb25 |
y2 = y3;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* check if a minimum radius was found */
|
|
Packit |
67cb25 |
if (rmin < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* possibly co-linear points */
|
|
Packit |
67cb25 |
GSL_ERROR("failed to find minimum radius", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_multifit_linear_lcorner() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_lcorner2()
|
|
Packit |
67cb25 |
Determine point on L-curve (lambda^2, ||c||^2) of maximum curvature.
|
|
Packit |
67cb25 |
For each set of 3 points on the L-curve, the circle which passes through
|
|
Packit |
67cb25 |
the 3 points is computed. The radius of the circle is then used
|
|
Packit |
67cb25 |
as an estimate of the curvature at the middle point. The point
|
|
Packit |
67cb25 |
with maximum curvature is then selected.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This routine is based on the paper
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
M. Rezghi and S. M. Hosseini, "A new variant of L-curve for Tikhonov
|
|
Packit |
67cb25 |
regularization", J. Comp. App. Math., 231 (2009).
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: reg_param - vector of regularization parameters
|
|
Packit |
67cb25 |
eta - vector of solution norms ||L x||
|
|
Packit |
67cb25 |
idx - (output) index i such that
|
|
Packit |
67cb25 |
(lambda(i)^2,eta(i)^2) is the point of
|
|
Packit |
67cb25 |
maximum curvature
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_lcorner2(const gsl_vector *reg_param,
|
|
Packit |
67cb25 |
const gsl_vector *eta,
|
|
Packit |
67cb25 |
size_t *idx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t n = reg_param->size;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (n < 3)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("at least 3 points are needed for L-curve analysis",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (n != eta->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("size of reg_param and eta vectors do not match",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int s = GSL_SUCCESS;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
double x1, y1; /* first point of triangle on L-curve */
|
|
Packit |
67cb25 |
double x2, y2; /* second point of triangle on L-curve */
|
|
Packit |
67cb25 |
double rmin = -1.0; /* minimum radius of curvature */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initial values */
|
|
Packit |
67cb25 |
x1 = gsl_vector_get(reg_param, 0);
|
|
Packit |
67cb25 |
x1 *= x1;
|
|
Packit |
67cb25 |
y1 = gsl_vector_get(eta, 0);
|
|
Packit |
67cb25 |
y1 *= y1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
x2 = gsl_vector_get(reg_param, 1);
|
|
Packit |
67cb25 |
x2 *= x2;
|
|
Packit |
67cb25 |
y2 = gsl_vector_get(eta, 1);
|
|
Packit |
67cb25 |
y2 *= y2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 1; i < n - 1; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* The points (x1,y1), (x2,y2), (x3,y3) are the previous,
|
|
Packit |
67cb25 |
* current, and next point on the L-curve. We will find
|
|
Packit |
67cb25 |
* the circle which fits these 3 points and take its radius
|
|
Packit |
67cb25 |
* as an estimate of the curvature at this point.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
double lamip1 = gsl_vector_get(reg_param, i + 1);
|
|
Packit |
67cb25 |
double etaip1 = gsl_vector_get(eta, i + 1);
|
|
Packit |
67cb25 |
double x3 = lamip1 * lamip1;
|
|
Packit |
67cb25 |
double y3 = etaip1 * etaip1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double x21 = x2 - x1;
|
|
Packit |
67cb25 |
double y21 = y2 - y1;
|
|
Packit |
67cb25 |
double x31 = x3 - x1;
|
|
Packit |
67cb25 |
double y31 = y3 - y1;
|
|
Packit |
67cb25 |
double h21 = x21*x21 + y21*y21;
|
|
Packit |
67cb25 |
double h31 = x31*x31 + y31*y31;
|
|
Packit |
67cb25 |
double d = fabs(2.0 * (x21*y31 - x31*y21));
|
|
Packit |
67cb25 |
double r = sqrt(h21*h31*((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2))) / d;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* if d =~ 0 then there are nearly colinear points */
|
|
Packit |
67cb25 |
if (gsl_finite(r))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* check for smallest radius of curvature */
|
|
Packit |
67cb25 |
if (r < rmin || rmin < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
rmin = r;
|
|
Packit |
67cb25 |
*idx = i;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* update previous/current L-curve values */
|
|
Packit |
67cb25 |
x1 = x2;
|
|
Packit |
67cb25 |
y1 = y2;
|
|
Packit |
67cb25 |
x2 = x3;
|
|
Packit |
67cb25 |
y2 = y3;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* check if a minimum radius was found */
|
|
Packit |
67cb25 |
if (rmin < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* possibly co-linear points */
|
|
Packit |
67cb25 |
GSL_ERROR("failed to find minimum radius", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_multifit_linear_lcorner2() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define GSL_MULTIFIT_MAXK 100
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_L()
|
|
Packit |
67cb25 |
Compute discrete approximation to derivative operator of order
|
|
Packit |
67cb25 |
k on a regular grid of p points, ie: L is (p-k)-by-p
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_Lk(const size_t p, const size_t k, gsl_matrix *L)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (p <= k)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("p must be larger than derivative order", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (k >= GSL_MULTIFIT_MAXK - 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("derivative order k too large", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (p - k != L->size1 || p != L->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("L matrix must be (p-k)-by-p", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double c_data[GSL_MULTIFIT_MAXK];
|
|
Packit |
67cb25 |
gsl_vector_view cv = gsl_vector_view_array(c_data, k + 1);
|
|
Packit |
67cb25 |
size_t i, j;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* zeroth derivative */
|
|
Packit |
67cb25 |
if (k == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set_identity(L);
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_set_zero(L);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set_zero(&cv.vector);
|
|
Packit |
67cb25 |
gsl_vector_set(&cv.vector, 0, -1.0);
|
|
Packit |
67cb25 |
gsl_vector_set(&cv.vector, 1, 1.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 1; i < k; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double cjm1 = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < k + 1; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double cj = gsl_vector_get(&cv.vector, j);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(&cv.vector, j, cjm1 - cj);
|
|
Packit |
67cb25 |
cjm1 = cj;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* build L, the c_i are the entries on the diagonals */
|
|
Packit |
67cb25 |
for (i = 0; i < k + 1; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view v = gsl_matrix_superdiagonal(L, i);
|
|
Packit |
67cb25 |
double ci = gsl_vector_get(&cv.vector, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set_all(&v.vector, ci);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_multifit_linear_Lk() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_multifit_linear_Lsobolev()
|
|
Packit |
67cb25 |
Construct Sobolev smoothing norm operator
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
L = [ a_0 I; a_1 L_1; a_2 L_2; ...; a_k L_k ]
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
by computing the Cholesky factor of L^T L
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: p - number of columns of L
|
|
Packit |
67cb25 |
kmax - maximum derivative order (< p)
|
|
Packit |
67cb25 |
alpha - vector of weights; alpha_k multiplies L_k, size kmax + 1
|
|
Packit |
67cb25 |
L - (output) upper triangular Sobolev matrix p-by-p,
|
|
Packit |
67cb25 |
stored in upper triangle
|
|
Packit |
67cb25 |
work - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) work->Q is used to store intermediate L_k matrices
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_multifit_linear_Lsobolev(const size_t p, const size_t kmax,
|
|
Packit |
67cb25 |
const gsl_vector *alpha, gsl_matrix *L,
|
|
Packit |
67cb25 |
gsl_multifit_linear_workspace *work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (p > work->pmax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("p is larger than workspace", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (p <= kmax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("p must be larger than derivative order", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (kmax + 1 != alpha->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("alpha must be size kmax + 1", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (p != L->size1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("L matrix is wrong size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (L->size1 != L->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("L matrix is not square", GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int s;
|
|
Packit |
67cb25 |
size_t j, k;
|
|
Packit |
67cb25 |
gsl_vector_view d = gsl_matrix_diagonal(L);
|
|
Packit |
67cb25 |
const double alpha0 = gsl_vector_get(alpha, 0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize L to alpha0^2 I */
|
|
Packit |
67cb25 |
gsl_matrix_set_zero(L);
|
|
Packit |
67cb25 |
gsl_vector_add_constant(&d.vector, alpha0 * alpha0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (k = 1; k <= kmax; ++k)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_view Lk = gsl_matrix_submatrix(work->Q, 0, 0, p - k, p);
|
|
Packit |
67cb25 |
double ak = gsl_vector_get(alpha, k);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute a_k L_k */
|
|
Packit |
67cb25 |
s = gsl_multifit_linear_Lk(p, k, &Lk.matrix);
|
|
Packit |
67cb25 |
if (s)
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_scale(&Lk.matrix, ak);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* LTL += L_k^T L_k */
|
|
Packit |
67cb25 |
gsl_blas_dsyrk(CblasLower, CblasTrans, 1.0, &Lk.matrix, 1.0, L);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
s = gsl_linalg_cholesky_decomp(L);
|
|
Packit |
67cb25 |
if (s)
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* copy Cholesky factor to upper triangle and zero out bottom */
|
|
Packit |
67cb25 |
gsl_matrix_transpose_tricpy('L', 1, L, L);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < p; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (k = 0; k < j; ++k)
|
|
Packit |
67cb25 |
gsl_matrix_set(L, j, k, 0.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|