Blame multilarge_nlinear/dogleg.c

Packit 67cb25
/* multilarge_nlinear/dogleg.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_multilarge_nlinear.h>
Packit 67cb25
#include <gsl/gsl_errno.h>
Packit 67cb25
#include <gsl/gsl_blas.h>
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
 * This module contains an implementation of the Powell dogleg
Packit 67cb25
 * algorithm for nonlinear optimization problems. This implementation
Packit 67cb25
 * closely follows the following works:
Packit 67cb25
 *
Packit 67cb25
 * [1] H. B. Nielsen, K. Madsen, Introduction to Optimization and
Packit 67cb25
 *     Data Fitting, Informatics and Mathematical Modeling,
Packit 67cb25
 *     Technical University of Denmark (DTU), 2010.
Packit 67cb25
 *
Packit 67cb25
 * [2] J. E. Dennis and H. H. W. Mei, Two new unconstrained optimization
Packit 67cb25
 *     algorithms which use function and gradient values, J. Opt. Theory and
Packit 67cb25
 *     Appl., 28(4), 1979.
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
  gsl_vector *dx_gn;         /* Gauss-Newton step, size p */
Packit 67cb25
  gsl_vector *dx_sd;         /* steepest descent step, size p */
Packit 67cb25
  double norm_Dgn;           /* || D dx_gn || */
Packit 67cb25
  double norm_Dsd;           /* || D dx_sd || */
Packit 67cb25
  double norm_Dinvg;         /* || D^{-1} g || */
Packit 67cb25
  double norm_JDinv2g;       /* || J D^{-2} g || */
Packit 67cb25
  gsl_vector *workp1;        /* workspace, length p */
Packit 67cb25
  gsl_vector *workp2;        /* workspace, length p */
Packit 67cb25
  gsl_vector *workn;         /* workspace, length n */
Packit 67cb25
Packit 67cb25
  /* tunable parameters */
Packit 67cb25
  gsl_multilarge_nlinear_parameters params;
Packit 67cb25
} dogleg_state_t;
Packit 67cb25
Packit 67cb25
#include "common.c"
Packit 67cb25
Packit 67cb25
static void * dogleg_alloc (const void * params, const size_t n, const size_t p);
Packit 67cb25
static void dogleg_free(void *vstate);
Packit 67cb25
static int dogleg_init(const void *vtrust_state, void *vstate);
Packit 67cb25
static int dogleg_preloop(const void * vtrust_state, void * vstate);
Packit 67cb25
static int dogleg_step(const void * vtrust_state, const double delta,
Packit 67cb25
                       gsl_vector * dx, void * vstate);
Packit 67cb25
static int dogleg_double_step(const void * vtrust_state, const double delta,
Packit 67cb25
                              gsl_vector * dx, void * vstate);
Packit 67cb25
static int dogleg_preduction(const void * vtrust_state, const gsl_vector * dx,
Packit 67cb25
                             double * pred, void * vstate);
Packit 67cb25
static int dogleg_calc_gn(const gsl_multilarge_nlinear_trust_state * trust_state, gsl_vector * dx);
Packit 67cb25
static double dogleg_beta(const double t, const double delta,
Packit 67cb25
                          const gsl_vector * diag, dogleg_state_t * state);
Packit 67cb25
Packit 67cb25
static void *
Packit 67cb25
dogleg_alloc (const void * params, const size_t n, const size_t p)
Packit 67cb25
{
Packit 67cb25
  dogleg_state_t *state;
Packit 67cb25
  
Packit 67cb25
  state = calloc(1, sizeof(dogleg_state_t));
Packit 67cb25
  if (state == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate dogleg state", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->dx_gn = gsl_vector_alloc(p);
Packit 67cb25
  if (state->dx_gn == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for dx_gn", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->dx_sd = gsl_vector_alloc(p);
Packit 67cb25
  if (state->dx_sd == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for dx_sd", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->workp1 = gsl_vector_alloc(p);
Packit 67cb25
  if (state->workp1 == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for workp1", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->workp2 = gsl_vector_alloc(p);
Packit 67cb25
  if (state->workp2 == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for workp2", 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->n = n;
Packit 67cb25
  state->p = p;
Packit 67cb25
  state->params = *(const gsl_multilarge_nlinear_parameters *) params;
Packit 67cb25
Packit 67cb25
  return state;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
dogleg_free(void *vstate)
Packit 67cb25
{
Packit 67cb25
  dogleg_state_t *state = (dogleg_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  if (state->dx_gn)
Packit 67cb25
    gsl_vector_free(state->dx_gn);
Packit 67cb25
Packit 67cb25
  if (state->dx_sd)
Packit 67cb25
    gsl_vector_free(state->dx_sd);
Packit 67cb25
Packit 67cb25
  if (state->workp1)
Packit 67cb25
    gsl_vector_free(state->workp1);
Packit 67cb25
Packit 67cb25
  if (state->workp2)
Packit 67cb25
    gsl_vector_free(state->workp2);
Packit 67cb25
Packit 67cb25
  if (state->workn)
Packit 67cb25
    gsl_vector_free(state->workn);
Packit 67cb25
Packit 67cb25
  free(state);
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
dogleg_init()
Packit 67cb25
  Initialize dogleg solver
Packit 67cb25
Packit 67cb25
Inputs: vtrust_state - trust state
Packit 67cb25
        vstate       - workspace
Packit 67cb25
Packit 67cb25
Return: success/error
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dogleg_init(const void *vtrust_state, void *vstate)
Packit 67cb25
{
Packit 67cb25
  (void)vtrust_state;
Packit 67cb25
  (void)vstate;
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
dogleg_preloop()
Packit 67cb25
  Initialize dogleg method prior to iteration loop.
Packit 67cb25
This involves computing the steepest descent step. The
Packit 67cb25
Gauss-Newton step is computed later in the _step() functions
Packit 67cb25
if required.
Packit 67cb25
Packit 67cb25
Notes: on output,
Packit 67cb25
1) state->dx_sd contains steepest descent step
Packit 67cb25
2) state->norm_Dinvg contains || D^{-1} g ||
Packit 67cb25
3) state->norm_JDinv2g contains || J D^{-2} g ||
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dogleg_preloop(const void * vtrust_state, void * vstate)
Packit 67cb25
{
Packit 67cb25
  const gsl_multilarge_nlinear_trust_state *trust_state =
Packit 67cb25
    (const gsl_multilarge_nlinear_trust_state *) vtrust_state;
Packit 67cb25
  dogleg_state_t *state = (dogleg_state_t *) vstate;
Packit 67cb25
  double u;
Packit 67cb25
  double alpha; /* ||g||^2 / ||Jg||^2 */
Packit 67cb25
Packit 67cb25
  /* calculate the steepest descent step */
Packit 67cb25
Packit 67cb25
  /* compute workp1 = D^{-1} g and its norm */
Packit 67cb25
  gsl_vector_memcpy(state->workp1, trust_state->g);
Packit 67cb25
  gsl_vector_div(state->workp1, trust_state->diag);
Packit 67cb25
  state->norm_Dinvg = gsl_blas_dnrm2(state->workp1);
Packit 67cb25
Packit 67cb25
  /* compute workp1 = D^{-2} g */
Packit 67cb25
  gsl_vector_div(state->workp1, trust_state->diag);
Packit 67cb25
Packit 67cb25
  /* compute workp2 = J^T J D^{-2} g */
Packit 67cb25
  gsl_blas_dsymv(CblasLower, 1.0, trust_state->JTJ, state->workp1, 0.0, state->workp2);
Packit 67cb25
Packit 67cb25
  /* compute norm_JDinv2g = || J D^{-2} g || */
Packit 67cb25
  gsl_blas_ddot(state->workp1, state->workp2, &u);
Packit 67cb25
  state->norm_JDinv2g = sqrt(u);
Packit 67cb25
Packit 67cb25
  u = state->norm_Dinvg / state->norm_JDinv2g;
Packit 67cb25
  alpha = u * u;
Packit 67cb25
Packit 67cb25
  /* dx_sd = -alpha D^{-2} g */
Packit 67cb25
  gsl_vector_memcpy(state->dx_sd, state->workp1);
Packit 67cb25
  gsl_vector_scale(state->dx_sd, -alpha);
Packit 67cb25
Packit 67cb25
  state->norm_Dsd = scaled_enorm(trust_state->diag, state->dx_sd);
Packit 67cb25
  state->norm_Dgn = -1.0; /* computed later if needed */
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
dogleg_step()
Packit 67cb25
  Calculate a new step vector
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dogleg_step(const void * vtrust_state, const double delta,
Packit 67cb25
            gsl_vector * dx, void * vstate)
Packit 67cb25
{
Packit 67cb25
  const gsl_multilarge_nlinear_trust_state *trust_state =
Packit 67cb25
    (const gsl_multilarge_nlinear_trust_state *) vtrust_state;
Packit 67cb25
  dogleg_state_t *state = (dogleg_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  if (state->norm_Dsd >= delta)
Packit 67cb25
    {
Packit 67cb25
      /* steepest descent step is outside trust region;
Packit 67cb25
       * truncate steepest descent step to trust region boundary */
Packit 67cb25
      gsl_vector_memcpy(dx, state->dx_sd);
Packit 67cb25
      gsl_vector_scale(dx, delta / state->norm_Dsd);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      /* compute Gauss-Newton step if needed */
Packit 67cb25
      if (state->norm_Dgn < 0.0)
Packit 67cb25
        {
Packit 67cb25
          int status = dogleg_calc_gn(trust_state, state->dx_gn);
Packit 67cb25
Packit 67cb25
          if (status)
Packit 67cb25
            return status;
Packit 67cb25
Packit 67cb25
          /* compute || D dx_gn || */
Packit 67cb25
          state->norm_Dgn = scaled_enorm(trust_state->diag, state->dx_gn);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      if (state->norm_Dgn <= delta)
Packit 67cb25
        {
Packit 67cb25
          /* Gauss-Newton step is inside trust region, use it as final step
Packit 67cb25
           * since it is the global minimizer of the quadratic model function */
Packit 67cb25
          gsl_vector_memcpy(dx, state->dx_gn);
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          /* Gauss-Newton step is outside trust region, but steepest
Packit 67cb25
           * descent is inside; use dogleg step */
Packit 67cb25
Packit 67cb25
          double beta = dogleg_beta(1.0, delta, trust_state->diag, state);
Packit 67cb25
Packit 67cb25
          /* compute: workp1 = dx_gn - dx_sd */
Packit 67cb25
          scaled_addition(1.0, state->dx_gn, -1.0, state->dx_sd, state->workp1);
Packit 67cb25
Packit 67cb25
          /* dx = dx_sd + beta*(dx_gn - dx_sd) */
Packit 67cb25
          scaled_addition(beta, state->workp1, 1.0, state->dx_sd, dx);
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
dogleg_double_step()
Packit 67cb25
  Calculate a new step with double dogleg method. Based on
Packit 67cb25
section 3 of [2]
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dogleg_double_step(const void * vtrust_state, const double delta,
Packit 67cb25
                   gsl_vector * dx, void * vstate)
Packit 67cb25
{
Packit 67cb25
  const double alpha_fac = 0.8; /* recommended value from Dennis and Mei */
Packit 67cb25
  const gsl_multilarge_nlinear_trust_state *trust_state =
Packit 67cb25
    (const gsl_multilarge_nlinear_trust_state *) vtrust_state;
Packit 67cb25
  dogleg_state_t *state = (dogleg_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  if (state->norm_Dsd >= delta)
Packit 67cb25
    {
Packit 67cb25
      /* steepest descent step is outside trust region;
Packit 67cb25
       * truncate steepest descent step to trust region boundary */
Packit 67cb25
      gsl_vector_memcpy(dx, state->dx_sd);
Packit 67cb25
      gsl_vector_scale(dx, delta / state->norm_Dsd);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      /* compute Gauss-Newton step if needed */
Packit 67cb25
      if (state->norm_Dgn < 0.0)
Packit 67cb25
        {
Packit 67cb25
          int status = dogleg_calc_gn(trust_state, state->dx_gn);
Packit 67cb25
Packit 67cb25
          if (status)
Packit 67cb25
            return status;
Packit 67cb25
Packit 67cb25
          /* compute || D dx_gn || */
Packit 67cb25
          state->norm_Dgn = scaled_enorm(trust_state->diag, state->dx_gn);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      if (state->norm_Dgn <= delta)
Packit 67cb25
        {
Packit 67cb25
          /* Gauss-Newton step is inside trust region, use it as final step
Packit 67cb25
           * since it is the global minimizer of the quadratic model function */
Packit 67cb25
          gsl_vector_memcpy(dx, state->dx_gn);
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          double t, u, v, c;
Packit 67cb25
Packit 67cb25
          /* compute: u = ||D^{-1} g||^2 / ||J D^{-2} g||^2 */
Packit 67cb25
          v = state->norm_Dinvg / state->norm_JDinv2g;
Packit 67cb25
          u = v * v;
Packit 67cb25
Packit 67cb25
          /* compute: v = g^T dx_gn */
Packit 67cb25
          gsl_blas_ddot(trust_state->g, state->dx_gn, &v);
Packit 67cb25
Packit 67cb25
          /* compute: c = ||D^{-1} g||^4 / (||J D^{-2} g||^2 * |g^T dx_gn|) */
Packit 67cb25
          c = u * (state->norm_Dinvg / fabs(v)) * state->norm_Dinvg;
Packit 67cb25
Packit 67cb25
          /* compute: t = 1 - alpha_fac*(1-c) */
Packit 67cb25
          t = 1.0 - alpha_fac*(1.0 - c);
Packit 67cb25
Packit 67cb25
          if (t * state->norm_Dgn <= delta)
Packit 67cb25
            {
Packit 67cb25
              /* set dx = (delta / ||D dx_gn||) dx_gn */
Packit 67cb25
              gsl_vector_memcpy(dx, state->dx_gn);
Packit 67cb25
              gsl_vector_scale(dx, delta / state->norm_Dgn);
Packit 67cb25
            }
Packit 67cb25
          else
Packit 67cb25
            {
Packit 67cb25
              /* Cauchy point is inside, Gauss-Newton is outside trust region;
Packit 67cb25
               * use double dogleg step */
Packit 67cb25
Packit 67cb25
              double beta = dogleg_beta(t, delta, trust_state->diag, state);
Packit 67cb25
Packit 67cb25
              /* compute: workp1 = t*dx_gn - dx_sd */
Packit 67cb25
              scaled_addition(t, state->dx_gn, -1.0, state->dx_sd, state->workp1);
Packit 67cb25
Packit 67cb25
              /* dx = dx_sd + beta*(t*dx_gn - dx_sd) */
Packit 67cb25
              scaled_addition(beta, state->workp1, 1.0, state->dx_sd, dx);
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dogleg_preduction(const void * vtrust_state, const gsl_vector * dx,
Packit 67cb25
                  double * pred, void * vstate)
Packit 67cb25
{
Packit 67cb25
  const gsl_multilarge_nlinear_trust_state *trust_state =
Packit 67cb25
    (const gsl_multilarge_nlinear_trust_state *) vtrust_state;
Packit 67cb25
  dogleg_state_t *state = (dogleg_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  *pred = quadratic_preduction(trust_state, dx, state->workn);
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
dogleg_calc_gn()
Packit 67cb25
  Calculate Gauss-Newton step by solving
Packit 67cb25
Packit 67cb25
J^T J dx_gn = -J^T f
Packit 67cb25
Packit 67cb25
Inputs: trust_state - trust state variables
Packit 67cb25
        dx          - (output) Gauss-Newton step vector
Packit 67cb25
Packit 67cb25
Return: success/error
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dogleg_calc_gn(const gsl_multilarge_nlinear_trust_state * trust_state, gsl_vector * dx)
Packit 67cb25
{
Packit 67cb25
  int status;
Packit 67cb25
  const gsl_multilarge_nlinear_parameters *params = trust_state->params;
Packit 67cb25
Packit 67cb25
  /* initialize linear least squares solver */
Packit 67cb25
  status = (params->solver->init)(trust_state, trust_state->solver_state);
Packit 67cb25
  if (status)
Packit 67cb25
    return status;
Packit 67cb25
Packit 67cb25
  /* prepare the linear solver to compute Gauss-Newton step */
Packit 67cb25
  status = (params->solver->presolve)(0.0, trust_state, trust_state->solver_state);
Packit 67cb25
  if (status)
Packit 67cb25
    return status;
Packit 67cb25
Packit 67cb25
  /* solve: J dx_gn = -f for Gauss-Newton step */
Packit 67cb25
  status = (params->solver->solve)(trust_state->g,
Packit 67cb25
                                   dx,
Packit 67cb25
                                   trust_state,
Packit 67cb25
                                   trust_state->solver_state);
Packit 67cb25
  if (status)
Packit 67cb25
    return status;
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
dogleg_beta()
Packit 67cb25
  This function finds beta in [0,1] such that the step
Packit 67cb25
Packit 67cb25
dx = dx_sd + beta*(t*dx_gn - dx_sd)
Packit 67cb25
Packit 67cb25
has norm
Packit 67cb25
Packit 67cb25
||D dx|| = delta
Packit 67cb25
Packit 67cb25
beta is the positive root of the quadratic:
Packit 67cb25
Packit 67cb25
a beta^2 + b beta + c = 0
Packit 67cb25
Packit 67cb25
with
Packit 67cb25
Packit 67cb25
a = ||D(t*dx_gn - dx_sd)||^2
Packit 67cb25
b = 2 dx_sd^T D^T D (t*dx_gn - dx_sd)
Packit 67cb25
c = ||D dx_sd||^2 - delta^2 
Packit 67cb25
Packit 67cb25
Inputs: t     - amount of Gauss-Newton step to use for dogleg
Packit 67cb25
                (= 1 for classical dogleg, <= 1 for double dogleg)
Packit 67cb25
        delta - trust region radius
Packit 67cb25
        diag  - diag(D) scaling matrix
Packit 67cb25
        state - workspace
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static double
Packit 67cb25
dogleg_beta(const double t, const double delta,
Packit 67cb25
            const gsl_vector * diag, dogleg_state_t * state)
Packit 67cb25
{
Packit 67cb25
  double beta;
Packit 67cb25
  double a, b, c;
Packit 67cb25
Packit 67cb25
  /* compute: workp1 = t*dx_gn - dx_sd */
Packit 67cb25
  scaled_addition(t, state->dx_gn, -1.0, state->dx_sd, state->workp1);
Packit 67cb25
Packit 67cb25
  /* a = || D (t*dx_gn - dx_sd) ||^2 */
Packit 67cb25
  a = scaled_enorm(diag, state->workp1);
Packit 67cb25
  a *= a;
Packit 67cb25
Packit 67cb25
  /* workp1 = D^T D (t*dx_gn - dx_sd) */
Packit 67cb25
  gsl_vector_mul(state->workp1, diag);
Packit 67cb25
  gsl_vector_mul(state->workp1, diag);
Packit 67cb25
Packit 67cb25
  /* b = 2 dx_sd^T D^T D (t*dx_gn - dx-sd) */
Packit 67cb25
  gsl_blas_ddot(state->dx_sd, state->workp1, &b);
Packit 67cb25
  b *= 2.0;
Packit 67cb25
Packit 67cb25
  /* c = || D dx_sd ||^2 - delta^2 = (||D dx_sd|| + delta) (||D dx_sd|| - delta) */
Packit 67cb25
  c = (state->norm_Dsd + delta) * (state->norm_Dsd - delta);
Packit 67cb25
Packit 67cb25
  if (b > 0.0)
Packit 67cb25
    {
Packit 67cb25
      beta = (-2.0 * c) / (b + sqrt(b*b - 4.0*a*c));
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      beta = (-b + sqrt(b*b - 4.0*a*c)) / (2.0 * a);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return beta;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static const gsl_multilarge_nlinear_trs dogleg_type =
Packit 67cb25
{
Packit 67cb25
  "dogleg",
Packit 67cb25
  dogleg_alloc,
Packit 67cb25
  dogleg_init,
Packit 67cb25
  dogleg_preloop,
Packit 67cb25
  dogleg_step,
Packit 67cb25
  dogleg_preduction,
Packit 67cb25
  dogleg_free
Packit 67cb25
};
Packit 67cb25
Packit 67cb25
const gsl_multilarge_nlinear_trs *gsl_multilarge_nlinear_trs_dogleg = &dogleg_type;
Packit 67cb25
Packit 67cb25
static const gsl_multilarge_nlinear_trs ddogleg_type =
Packit 67cb25
{
Packit 67cb25
  "double-dogleg",
Packit 67cb25
  dogleg_alloc,
Packit 67cb25
  dogleg_init,
Packit 67cb25
  dogleg_preloop,
Packit 67cb25
  dogleg_double_step,
Packit 67cb25
  dogleg_preduction,
Packit 67cb25
  dogleg_free
Packit 67cb25
};
Packit 67cb25
Packit 67cb25
const gsl_multilarge_nlinear_trs *gsl_multilarge_nlinear_trs_ddogleg = &ddogleg_type;