Blame multifit_nlinear/trust.c

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;