|
Packit |
67cb25 |
/* multifit_nlinear/trust.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2016 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 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_vector.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_matrix.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_linalg.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_multifit_nlinear.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_blas.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_permutation.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "common.c"
|
|
Packit |
67cb25 |
#include "nielsen.c"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This module contains a high level driver for a general trust
|
|
Packit |
67cb25 |
* region nonlinear least squares solver. This container handles
|
|
Packit |
67cb25 |
* the computation of all of the quantities relevant to all trust
|
|
Packit |
67cb25 |
* region methods, including:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* residual vector: f_k = f(x_k)
|
|
Packit |
67cb25 |
* Jacobian matrix: J_k = J(x_k)
|
|
Packit |
67cb25 |
* gradient vector: g_k = J_k^T f_k
|
|
Packit |
67cb25 |
* scaling matrix: D_k
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
typedef struct
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t n; /* number of observations */
|
|
Packit |
67cb25 |
size_t p; /* number of parameters */
|
|
Packit |
67cb25 |
double delta; /* trust region radius */
|
|
Packit |
67cb25 |
double mu; /* LM parameter */
|
|
Packit |
67cb25 |
long nu; /* for updating LM parameter */
|
|
Packit |
67cb25 |
gsl_vector *diag; /* D = diag(J^T J) */
|
|
Packit |
67cb25 |
gsl_vector *x_trial; /* trial parameter vector */
|
|
Packit |
67cb25 |
gsl_vector *f_trial; /* trial function vector */
|
|
Packit |
67cb25 |
gsl_vector *workp; /* workspace, length p */
|
|
Packit |
67cb25 |
gsl_vector *workn; /* workspace, length n */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void *trs_state; /* workspace for trust region subproblem */
|
|
Packit |
67cb25 |
void *solver_state; /* workspace for linear least squares solver */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double avratio; /* current |a| / |v| */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* tunable parameters */
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_parameters params;
|
|
Packit |
67cb25 |
} trust_state_t;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void * trust_alloc (const gsl_multifit_nlinear_parameters * params,
|
|
Packit |
67cb25 |
const size_t n, const size_t p);
|
|
Packit |
67cb25 |
static void trust_free(void *vstate);
|
|
Packit |
67cb25 |
static int trust_init(void *vstate, const gsl_vector * swts,
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_fdf *fdf, const gsl_vector *x,
|
|
Packit |
67cb25 |
gsl_vector *f, gsl_matrix *J, gsl_vector *g);
|
|
Packit |
67cb25 |
static int trust_iterate(void *vstate, const gsl_vector *swts,
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_fdf *fdf,
|
|
Packit |
67cb25 |
gsl_vector *x, gsl_vector *f, gsl_matrix *J,
|
|
Packit |
67cb25 |
gsl_vector *g, gsl_vector *dx);
|
|
Packit |
67cb25 |
static int trust_rcond(double *rcond, void *vstate);
|
|
Packit |
67cb25 |
static double trust_avratio(void *vstate);
|
|
Packit |
67cb25 |
static void trust_trial_step(const gsl_vector * x, const gsl_vector * dx,
|
|
Packit |
67cb25 |
gsl_vector * x_trial);
|
|
Packit |
67cb25 |
static double trust_calc_rho(const gsl_vector * f, const gsl_vector * f_trial,
|
|
Packit |
67cb25 |
const gsl_vector * g, const gsl_matrix * J,
|
|
Packit |
67cb25 |
const gsl_vector * dx, trust_state_t * state);
|
|
Packit |
67cb25 |
static int trust_eval_step(const gsl_vector * f, const gsl_vector * f_trial,
|
|
Packit |
67cb25 |
const gsl_vector * g, const gsl_matrix * J,
|
|
Packit |
67cb25 |
const gsl_vector * dx, double * rho, trust_state_t * state);
|
|
Packit |
67cb25 |
static double trust_scaled_norm(const gsl_vector *D, const gsl_vector *a);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void *
|
|
Packit |
67cb25 |
trust_alloc (const gsl_multifit_nlinear_parameters * params,
|
|
Packit |
67cb25 |
const size_t n, const size_t p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
trust_state_t *state;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state = calloc(1, sizeof(trust_state_t));
|
|
Packit |
67cb25 |
if (state == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate lm state", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->diag = gsl_vector_alloc(p);
|
|
Packit |
67cb25 |
if (state->diag == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for diag", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->workp = gsl_vector_alloc(p);
|
|
Packit |
67cb25 |
if (state->workp == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for workp", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->workn = gsl_vector_alloc(n);
|
|
Packit |
67cb25 |
if (state->workn == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for workn", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->x_trial = gsl_vector_alloc(p);
|
|
Packit |
67cb25 |
if (state->x_trial == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for x_trial", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->f_trial = gsl_vector_alloc(n);
|
|
Packit |
67cb25 |
if (state->f_trial == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for f_trial", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->trs_state = (params->trs->alloc)(params, n, p);
|
|
Packit |
67cb25 |
if (state->trs_state == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for trs state", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->solver_state = (params->solver->alloc)(n, p);
|
|
Packit |
67cb25 |
if (state->solver_state == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for solver state", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->n = n;
|
|
Packit |
67cb25 |
state->p = p;
|
|
Packit |
67cb25 |
state->delta = 0.0;
|
|
Packit |
67cb25 |
state->params = *params;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return state;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
trust_free(void *vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
trust_state_t *state = (trust_state_t *) vstate;
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_parameters *params = &(state->params);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->diag)
|
|
Packit |
67cb25 |
gsl_vector_free(state->diag);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->workp)
|
|
Packit |
67cb25 |
gsl_vector_free(state->workp);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->workn)
|
|
Packit |
67cb25 |
gsl_vector_free(state->workn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->x_trial)
|
|
Packit |
67cb25 |
gsl_vector_free(state->x_trial);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->f_trial)
|
|
Packit |
67cb25 |
gsl_vector_free(state->f_trial);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->trs_state)
|
|
Packit |
67cb25 |
(params->trs->free)(state->trs_state);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->solver_state)
|
|
Packit |
67cb25 |
(params->solver->free)(state->solver_state);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
free(state);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
trust_init()
|
|
Packit |
67cb25 |
Initialize trust region solver
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: vstate - workspace
|
|
Packit |
67cb25 |
swts - sqrt(W) vector
|
|
Packit |
67cb25 |
fdf - user callback functions
|
|
Packit |
67cb25 |
x - initial parameter values
|
|
Packit |
67cb25 |
f - (output) f(x) vector
|
|
Packit |
67cb25 |
J - (output) J(x) matrix
|
|
Packit |
67cb25 |
g - (output) J(x)' f(x) vector
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
trust_init(void *vstate, const gsl_vector *swts,
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_fdf *fdf, const gsl_vector *x,
|
|
Packit |
67cb25 |
gsl_vector *f, gsl_matrix *J, gsl_vector *g)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
trust_state_t *state = (trust_state_t *) vstate;
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_parameters *params = &(state->params);
|
|
Packit |
67cb25 |
double Dx;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* evaluate function and Jacobian at x and apply weight transform */
|
|
Packit |
67cb25 |
status = gsl_multifit_nlinear_eval_f(fdf, x, swts, f);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_multifit_nlinear_eval_df(x, f, swts, params->h_df,
|
|
Packit |
67cb25 |
params->fdtype, fdf, J, state->workn);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute g = J^T f */
|
|
Packit |
67cb25 |
gsl_blas_dgemv(CblasTrans, 1.0, J, f, 0.0, g);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize diagonal scaling matrix D */
|
|
Packit |
67cb25 |
(params->scale->init)(J, state->diag);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute initial trust region radius */
|
|
Packit |
67cb25 |
Dx = trust_scaled_norm(state->diag, x);
|
|
Packit |
67cb25 |
state->delta = 0.3 * GSL_MAX(1.0, Dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize LM parameter */
|
|
Packit |
67cb25 |
status = nielsen_init(J, state->diag, &(state->mu), &(state->nu));
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize trust region method solver */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_trust_state trust_state;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
trust_state.x = x;
|
|
Packit |
67cb25 |
trust_state.f = f;
|
|
Packit |
67cb25 |
trust_state.g = g;
|
|
Packit |
67cb25 |
trust_state.J = J;
|
|
Packit |
67cb25 |
trust_state.diag = state->diag;
|
|
Packit |
67cb25 |
trust_state.sqrt_wts = swts;
|
|
Packit |
67cb25 |
trust_state.mu = &(state->mu);
|
|
Packit |
67cb25 |
trust_state.params = params;
|
|
Packit |
67cb25 |
trust_state.solver_state = state->solver_state;
|
|
Packit |
67cb25 |
trust_state.fdf = fdf;
|
|
Packit |
67cb25 |
trust_state.avratio = &(state->avratio);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = (params->trs->init)(&trust_state, state->trs_state);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* set default parameters */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->avratio = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
trust_iterate()
|
|
Packit |
67cb25 |
This function performs 1 iteration of the trust region algorithm.
|
|
Packit |
67cb25 |
It calls a user-specified method for computing the next step
|
|
Packit |
67cb25 |
(LM or dogleg), then tests if the computed step is acceptable.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Args: vstate - trust workspace
|
|
Packit |
67cb25 |
swts - data weights (NULL if unweighted)
|
|
Packit |
67cb25 |
fdf - function and Jacobian pointers
|
|
Packit |
67cb25 |
x - on input, current parameter vector
|
|
Packit |
67cb25 |
on output, new parameter vector x + dx
|
|
Packit |
67cb25 |
f - on input, f(x)
|
|
Packit |
67cb25 |
on output, f(x + dx)
|
|
Packit |
67cb25 |
J - on input, J(x)
|
|
Packit |
67cb25 |
on output, J(x + dx)
|
|
Packit |
67cb25 |
g - on input, g(x) = J(x)' f(x)
|
|
Packit |
67cb25 |
on output, g(x + dx) = J(x + dx)' f(x + dx)
|
|
Packit |
67cb25 |
dx - (output only) parameter step vector
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return:
|
|
Packit |
67cb25 |
1) GSL_SUCCESS if we found a step which reduces the cost
|
|
Packit |
67cb25 |
function
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) GSL_ENOPROG if 15 successive attempts were to made to
|
|
Packit |
67cb25 |
find a good step without success
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
3) If a scaling matrix D is used, inputs and outputs are
|
|
Packit |
67cb25 |
set to the unscaled quantities (ie: J and g)
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
trust_iterate(void *vstate, const gsl_vector *swts,
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_fdf *fdf, gsl_vector *x,
|
|
Packit |
67cb25 |
gsl_vector *f, gsl_matrix *J, gsl_vector *g,
|
|
Packit |
67cb25 |
gsl_vector *dx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
trust_state_t *state = (trust_state_t *) vstate;
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_parameters *params = &(state->params);
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_trs *trs = params->trs;
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_trust_state trust_state;
|
|
Packit |
67cb25 |
gsl_vector *x_trial = state->x_trial; /* trial x + dx */
|
|
Packit |
67cb25 |
gsl_vector *f_trial = state->f_trial; /* trial f(x + dx) */
|
|
Packit |
67cb25 |
gsl_vector *diag = state->diag; /* diag(D) */
|
|
Packit |
67cb25 |
double rho; /* ratio actual_reduction/predicted_reduction */
|
|
Packit |
67cb25 |
int foundstep = 0; /* found step dx */
|
|
Packit |
67cb25 |
int bad_steps = 0; /* consecutive rejected steps */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* store all state parameters needed by low level methods */
|
|
Packit |
67cb25 |
trust_state.x = x;
|
|
Packit |
67cb25 |
trust_state.f = f;
|
|
Packit |
67cb25 |
trust_state.g = g;
|
|
Packit |
67cb25 |
trust_state.J = J;
|
|
Packit |
67cb25 |
trust_state.diag = state->diag;
|
|
Packit |
67cb25 |
trust_state.sqrt_wts = swts;
|
|
Packit |
67cb25 |
trust_state.mu = &(state->mu);
|
|
Packit |
67cb25 |
trust_state.params = params;
|
|
Packit |
67cb25 |
trust_state.solver_state = state->solver_state;
|
|
Packit |
67cb25 |
trust_state.fdf = fdf;
|
|
Packit |
67cb25 |
trust_state.avratio = &(state->avratio);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize trust region subproblem with this Jacobian */
|
|
Packit |
67cb25 |
status = (trs->preloop)(&trust_state, state->trs_state);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* loop until we find an acceptable step dx */
|
|
Packit |
67cb25 |
while (!foundstep)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* calculate new step */
|
|
Packit |
67cb25 |
status = (trs->step)(&trust_state, state->delta, dx, state->trs_state);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* occasionally the iterative methods (ie: CG Steihaug) can fail to find a step,
|
|
Packit |
67cb25 |
* so in this case skip rho calculation and count it as a rejected step */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (status == GSL_SUCCESS)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* compute x_trial = x + dx */
|
|
Packit |
67cb25 |
trust_trial_step(x, dx, x_trial);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute f_trial = f(x + dx) */
|
|
Packit |
67cb25 |
status = gsl_multifit_nlinear_eval_f(fdf, x_trial, swts, f_trial);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* check if step should be accepted or rejected */
|
|
Packit |
67cb25 |
status = trust_eval_step(f, f_trial, g, J, dx, &rho, state);
|
|
Packit |
67cb25 |
if (status == GSL_SUCCESS)
|
|
Packit |
67cb25 |
foundstep = 1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* an iterative TRS method failed to find a step vector */
|
|
Packit |
67cb25 |
rho = -1.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* update trust region radius: if rho is large,
|
|
Packit |
67cb25 |
* then the quadratic model is a good approximation
|
|
Packit |
67cb25 |
* to the objective function, enlarge trust region.
|
|
Packit |
67cb25 |
* If rho is small (or negative), the model function
|
|
Packit |
67cb25 |
* is a poor approximation so decrease trust region. This
|
|
Packit |
67cb25 |
* can happen even if the step is accepted.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
if (rho > 0.75)
|
|
Packit |
67cb25 |
state->delta *= params->factor_up;
|
|
Packit |
67cb25 |
else if (rho < 0.25)
|
|
Packit |
67cb25 |
state->delta /= params->factor_down;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (foundstep)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* step was accepted */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute J <- J(x + dx) */
|
|
Packit |
67cb25 |
status = gsl_multifit_nlinear_eval_df(x_trial, f_trial, swts,
|
|
Packit |
67cb25 |
params->h_df, params->fdtype,
|
|
Packit |
67cb25 |
fdf, J, state->workn);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* update x <- x + dx */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(x, x_trial);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* update f <- f(x + dx) */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(f, f_trial);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute new g = J^T f */
|
|
Packit |
67cb25 |
gsl_blas_dgemv(CblasTrans, 1.0, J, f, 0.0, g);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* update scaling matrix D */
|
|
Packit |
67cb25 |
(params->scale->update)(J, diag);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* step accepted, decrease LM parameter */
|
|
Packit |
67cb25 |
status = nielsen_accept(rho, &(state->mu), &(state->nu));
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
bad_steps = 0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* step rejected, increase LM parameter */
|
|
Packit |
67cb25 |
status = nielsen_reject(&(state->mu), &(state->nu));
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (++bad_steps > 15)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* if more than 15 consecutive rejected steps, report no progress */
|
|
Packit |
67cb25 |
return GSL_ENOPROG;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* trust_iterate() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
trust_rcond(double *rcond, void *vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
trust_state_t *state = (trust_state_t *) vstate;
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_parameters *params = &(state->params);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = (params->solver->rcond)(rcond, state->solver_state);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
trust_avratio(void *vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
trust_state_t *state = (trust_state_t *) vstate;
|
|
Packit |
67cb25 |
return state->avratio;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute x_trial = x + dx */
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
trust_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 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
trust_calc_rho()
|
|
Packit |
67cb25 |
Calculate ratio of actual reduction to predicted
|
|
Packit |
67cb25 |
reduction.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
rho = actual_reduction / predicted_reduction
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
actual_reduction = 1 - ( ||f+|| / ||f|| )^2
|
|
Packit |
67cb25 |
predicted_reduction = -2 g^T dx / ||f||^2 - ( ||J*dx|| / ||f|| )^2
|
|
Packit |
67cb25 |
= -2 fhat . beta - ||beta||^2
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
where: beta = J*dx / ||f||
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: f - f(x)
|
|
Packit |
67cb25 |
f_trial - f(x + dx)
|
|
Packit |
67cb25 |
g - gradient J^T f
|
|
Packit |
67cb25 |
J - Jacobian
|
|
Packit |
67cb25 |
dx - proposed step, size p
|
|
Packit |
67cb25 |
state - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: rho = actual_reduction / predicted_reduction
|
|
Packit |
67cb25 |
If actual_reduction is < 0, return rho = -1
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
trust_calc_rho(const gsl_vector * f, const gsl_vector * f_trial,
|
|
Packit |
67cb25 |
const gsl_vector * g, const gsl_matrix * J,
|
|
Packit |
67cb25 |
const gsl_vector * dx, trust_state_t * state)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_parameters *params = &(state->params);
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_trs *trs = params->trs;
|
|
Packit |
67cb25 |
const double normf = gsl_blas_dnrm2(f);
|
|
Packit |
67cb25 |
const double normf_trial = gsl_blas_dnrm2(f_trial);
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_trust_state trust_state;
|
|
Packit |
67cb25 |
double rho;
|
|
Packit |
67cb25 |
double actual_reduction;
|
|
Packit |
67cb25 |
double pred_reduction;
|
|
Packit |
67cb25 |
double u;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* if ||f(x+dx)|| > ||f(x)|| reject step immediately */
|
|
Packit |
67cb25 |
if (normf_trial >= normf)
|
|
Packit |
67cb25 |
return -1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
trust_state.x = NULL;
|
|
Packit |
67cb25 |
trust_state.f = f;
|
|
Packit |
67cb25 |
trust_state.g = g;
|
|
Packit |
67cb25 |
trust_state.J = J;
|
|
Packit |
67cb25 |
trust_state.diag = state->diag;
|
|
Packit |
67cb25 |
trust_state.sqrt_wts = NULL;
|
|
Packit |
67cb25 |
trust_state.mu = &(state->mu);
|
|
Packit |
67cb25 |
trust_state.params = params;
|
|
Packit |
67cb25 |
trust_state.solver_state = state->solver_state;
|
|
Packit |
67cb25 |
trust_state.fdf = NULL;
|
|
Packit |
67cb25 |
trust_state.avratio = &(state->avratio);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute numerator of rho (actual reduction) */
|
|
Packit |
67cb25 |
u = normf_trial / normf;
|
|
Packit |
67cb25 |
actual_reduction = 1.0 - u*u;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* compute denominator of rho (predicted reduction); this is calculated
|
|
Packit |
67cb25 |
* inside each trust region subproblem, since it depends on the local
|
|
Packit |
67cb25 |
* model used, which can vary according to each TRS
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
status = (trs->preduction)(&trust_state, dx, &pred_reduction, state->trs_state);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return -1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (pred_reduction > 0.0)
|
|
Packit |
67cb25 |
rho = actual_reduction / pred_reduction;
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
rho = -1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return rho;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
trust_eval_step()
|
|
Packit |
67cb25 |
Evaluate proposed step to determine if it should be
|
|
Packit |
67cb25 |
accepted or rejected
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
trust_eval_step(const gsl_vector * f, const gsl_vector * f_trial,
|
|
Packit |
67cb25 |
const gsl_vector * g, const gsl_matrix * J,
|
|
Packit |
67cb25 |
const gsl_vector * dx, double * rho, trust_state_t * state)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status = GSL_SUCCESS;
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_parameters *params = &(state->params);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (params->trs == gsl_multifit_nlinear_trs_lmaccel)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* reject step if acceleration is too large compared to velocity */
|
|
Packit |
67cb25 |
if (state->avratio > params->avmax)
|
|
Packit |
67cb25 |
status = GSL_FAILURE;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute rho */
|
|
Packit |
67cb25 |
*rho = trust_calc_rho(f, f_trial, g, J, dx, state);
|
|
Packit |
67cb25 |
if (*rho <= 0.0)
|
|
Packit |
67cb25 |
status = GSL_FAILURE;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute || diag(D) a || */
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
trust_scaled_norm(const gsl_vector *D, const gsl_vector *a)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t n = a->size;
|
|
Packit |
67cb25 |
double e2 = 0.0;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double Di = gsl_vector_get(D, i);
|
|
Packit |
67cb25 |
double ai = gsl_vector_get(a, i);
|
|
Packit |
67cb25 |
double u = Di * ai;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
e2 += u * u;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return sqrt (e2);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static const gsl_multifit_nlinear_type trust_type =
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
"trust-region",
|
|
Packit |
67cb25 |
trust_alloc,
|
|
Packit |
67cb25 |
trust_init,
|
|
Packit |
67cb25 |
trust_iterate,
|
|
Packit |
67cb25 |
trust_rcond,
|
|
Packit |
67cb25 |
trust_avratio,
|
|
Packit |
67cb25 |
trust_free
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_type *gsl_multifit_nlinear_trust = &trust_type;
|