|
Packit |
67cb25 |
/* multifit/lmmisc.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2014 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 |
/* compute step dx by solving (J^T J + mu*I) dx = -J^T f */
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
lmniel_calc_dx(const double mu, const gsl_matrix *A, const gsl_vector *rhs,
|
|
Packit |
67cb25 |
gsl_vector *dx, lmniel_state_t *state)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
gsl_matrix *A_copy = state->A_copy;
|
|
Packit |
67cb25 |
gsl_vector_view diag = gsl_matrix_diagonal(A_copy);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* make a copy of J^T J matrix */
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(A_copy, A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* augment normal equations with LM parameter: A -> A + mu*I */
|
|
Packit |
67cb25 |
gsl_vector_add_constant(&diag.vector, mu);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_linalg_QR_decomp(A_copy, state->work);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_linalg_QR_solve(A_copy, state->work, rhs, dx);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* lmniel_calc_dx() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute x_trial = x + dx */
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
lmniel_trial_step(const gsl_vector * x, const gsl_vector * dx,
|
|
Packit |
67cb25 |
gsl_vector * x_trial)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i, N = x->size;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double dxi = gsl_vector_get (dx, i);
|
|
Packit |
67cb25 |
double xi = gsl_vector_get (x, i);
|
|
Packit |
67cb25 |
gsl_vector_set (x_trial, i, xi + dxi);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* lmniel_trial_step() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
lmniel_calc_dF()
|
|
Packit |
67cb25 |
Compute dF = F(x) - F(x + dx) = 1/2 (f - f_new)^T (f + f_new)
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
lmniel_calc_dF(const gsl_vector *f, const gsl_vector *f_new)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = f->size;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
double dF = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double fi = gsl_vector_get(f, i);
|
|
Packit |
67cb25 |
double fnewi = gsl_vector_get(f_new, i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dF += (fi - fnewi) * (fi + fnewi);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dF *= 0.5;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return dF;
|
|
Packit |
67cb25 |
} /* lmniel_calc_dF() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
lmniel_calc_dL()
|
|
Packit |
67cb25 |
Compute dL = L(0) - L(dx) = 1/2 dx^T (mu * D^T D dx - g)
|
|
Packit |
67cb25 |
Here, the mg input is -g
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
lmniel_calc_dL(const double mu, const gsl_vector *diag,
|
|
Packit |
67cb25 |
const gsl_vector *dx, const gsl_vector *mg)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t p = dx->size;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
double dL = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < p; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double dxi = gsl_vector_get(dx, i);
|
|
Packit |
67cb25 |
double di = gsl_vector_get(diag, i);
|
|
Packit |
67cb25 |
double mgi = gsl_vector_get(mg, i); /* -g_i */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dL += dxi * (mu * di * di * dxi + mgi);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dL *= 0.5;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return dL;
|
|
Packit |
67cb25 |
} /* lmniel_calc_dL() */
|