|
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;
|