|
Packit |
67cb25 |
/* multifit_nlinear/subspace2D.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_poly.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This module implements a 2D subspace trust region subproblem method,
|
|
Packit |
67cb25 |
* as outlined in
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [1] G. A. Shultz, R. B. Schnabel, and R. H. Byrd
|
|
Packit |
67cb25 |
* A Family of Trust-Region-Based Algorithms for Unconstrained
|
|
Packit |
67cb25 |
* Minimization with Strong Global Convergence Properties,
|
|
Packit |
67cb25 |
* SIAM Journal on Numerical Analysis 1985 22:1, 47-67
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [2] R. H. Byrd, R. B. Schnabel, G. A. Shultz,
|
|
Packit |
67cb25 |
* Approximate solution of the trust region problem by
|
|
Packit |
67cb25 |
* minimization over two-dimensional subspaces,
|
|
Packit |
67cb25 |
* Mathematical Programming, January 1988, Volume 40,
|
|
Packit |
67cb25 |
* Issue 1, pp 247-263
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* The idea is to solve:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* min_{dx} g^T dx + 1/2 dx^T B dx
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* with constraints:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* ||D dx|| <= delta
|
|
Packit |
67cb25 |
* dx \in span{dx_sd, dx_gn}
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* where B is the Hessian matrix, B = J^T J
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* The steps are as follows:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* 1. preloop:
|
|
Packit |
67cb25 |
* a. Compute Gauss-Newton and steepest descent vectors,
|
|
Packit |
67cb25 |
* dx_gn, dx_sd
|
|
Packit |
67cb25 |
* b. Compute an orthonormal basis for span(D dx_sd, D dx_gn) by
|
|
Packit |
67cb25 |
* constructing W = [ D dx_sd, D dx_gn ] and performing a QR
|
|
Packit |
67cb25 |
* decomposition of W. The 2 columns of the Q matrix
|
|
Packit |
67cb25 |
* will then span the column space of W. W should have rank 2
|
|
Packit |
67cb25 |
* unless D*dx_sd and D*dx_gn are parallel, in which case it will
|
|
Packit |
67cb25 |
* have rank 1.
|
|
Packit |
67cb25 |
* c. Precompute various quantities needed for the step calculation
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* 2. step:
|
|
Packit |
67cb25 |
* a. If the Gauss-Newton step is inside the trust region, use it
|
|
Packit |
67cb25 |
* b. if W has rank 1, we cannot form a 2D subspace, so in this case
|
|
Packit |
67cb25 |
* follow the steepest descent direction to the trust region boundary
|
|
Packit |
67cb25 |
* and use that as the step.
|
|
Packit |
67cb25 |
* c. In the full rank 2 case, if the GN point is outside the trust region,
|
|
Packit |
67cb25 |
* then the minimizer of the objective function lies on the trust
|
|
Packit |
67cb25 |
* region boundary. Therefore the minimization problem becomes:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* min_{dx} g^T dx + 1/2 dx^T B dx, with ||dx|| = delta, dx = Q * x
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* where x is a 2-vector to be determined and the columns of Q are
|
|
Packit |
67cb25 |
* the orthonormal basis vectors of the subspace. Note the equality
|
|
Packit |
67cb25 |
* constraint now instead of <=. In terms of the new variable x,
|
|
Packit |
67cb25 |
* the minimization problem becomes:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* min_x subg^T x + 1/2 x^T subB x, with ||Q*x|| = ||x|| = delta
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* where:
|
|
Packit |
67cb25 |
* subg = Q^T g (2-by-1)
|
|
Packit |
67cb25 |
* subB = Q^T B Q (2-by-2)
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This equality constrained 2D minimization problem can be solved
|
|
Packit |
67cb25 |
* with a Lagrangian multiplier, which results in a 4th degree polynomial
|
|
Packit |
67cb25 |
* equation to be solved. The equation is:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* lambda^4 1
|
|
Packit |
67cb25 |
* + lambda^3 2 tr(B)
|
|
Packit |
67cb25 |
* + lambda^2 (tr(B)^2 + 2 det(B) - g^T g / delta^2)
|
|
Packit |
67cb25 |
* + lambda^1 (2 det(B) tr(B) - 2 g^T adj(B)^T g / delta^2)
|
|
Packit |
67cb25 |
* + lambda^0 (det(B)^2 - g^T adj(B)^T adj(B) g / delta^2)
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* where adj(B) is the adjugate matrix of B.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* We then check each of the 4 solutions for lambda to determine which
|
|
Packit |
67cb25 |
* lambda results in the smallest objective function value. This x
|
|
Packit |
67cb25 |
* is then used to construct the final step: dx = Q*x
|
|
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 |
gsl_vector *workp; /* workspace, length p */
|
|
Packit |
67cb25 |
gsl_vector *workn; /* workspace, length n */
|
|
Packit |
67cb25 |
gsl_matrix *W; /* orthonormal basis for 2D subspace, p-by-2 */
|
|
Packit |
67cb25 |
gsl_matrix *JQ; /* J * Q, n-by-p */
|
|
Packit |
67cb25 |
gsl_vector *tau; /* Householder scalars */
|
|
Packit |
67cb25 |
gsl_vector *subg; /* subspace gradient = W^T g, 2-by-1 */
|
|
Packit |
67cb25 |
gsl_matrix *subB; /* subspace Hessian = W^T B W, 2-by-2 */
|
|
Packit |
67cb25 |
gsl_permutation *perm; /* permutation matrix */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double trB; /* Tr(subB) */
|
|
Packit |
67cb25 |
double detB; /* det(subB) */
|
|
Packit |
67cb25 |
double normg; /* || subg || */
|
|
Packit |
67cb25 |
double term0; /* g^T adj(B)^T adj(B) g */
|
|
Packit |
67cb25 |
double term1; /* g^T adj(B)^T g */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
size_t rank; /* rank of [ dx_sd, dx_gn ] matrix */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_poly_complex_workspace *poly_p;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* tunable parameters */
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_parameters params;
|
|
Packit |
67cb25 |
} subspace2D_state_t;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "common.c"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void * subspace2D_alloc (const void * params, const size_t n, const size_t p);
|
|
Packit |
67cb25 |
static void subspace2D_free(void *vstate);
|
|
Packit |
67cb25 |
static int subspace2D_init(const void *vtrust_state, void *vstate);
|
|
Packit |
67cb25 |
static int subspace2D_preloop(const void * vtrust_state, void * vstate);
|
|
Packit |
67cb25 |
static int subspace2D_step(const void * vtrust_state, const double delta,
|
|
Packit |
67cb25 |
gsl_vector * dx, void * vstate);
|
|
Packit |
67cb25 |
static int subspace2D_preduction(const void * vtrust_state, const gsl_vector * dx,
|
|
Packit |
67cb25 |
double * pred, void * vstate);
|
|
Packit |
67cb25 |
static int subspace2D_solution(const double lambda, gsl_vector * x,
|
|
Packit |
67cb25 |
subspace2D_state_t * state);
|
|
Packit |
67cb25 |
static double subspace2D_objective(const gsl_vector * x, subspace2D_state_t * state);
|
|
Packit |
67cb25 |
static int subspace2D_calc_gn(const gsl_multifit_nlinear_trust_state * trust_state, gsl_vector * dx);
|
|
Packit |
67cb25 |
static int subspace2D_calc_sd(const gsl_multifit_nlinear_trust_state * trust_state, gsl_vector * dx,
|
|
Packit |
67cb25 |
subspace2D_state_t * state);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void *
|
|
Packit |
67cb25 |
subspace2D_alloc (const void * params, const size_t n, const size_t p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_parameters *par = (const gsl_multifit_nlinear_parameters *) params;
|
|
Packit |
67cb25 |
subspace2D_state_t *state;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state = calloc(1, sizeof(subspace2D_state_t));
|
|
Packit |
67cb25 |
if (state == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate subspace2D 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->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->W = gsl_matrix_alloc(p, 2);
|
|
Packit |
67cb25 |
if (state->W == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for W", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->JQ = gsl_matrix_alloc(n, p);
|
|
Packit |
67cb25 |
if (state->JQ == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for JQ", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->tau = gsl_vector_alloc(2);
|
|
Packit |
67cb25 |
if (state->tau == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for tau", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->subg = gsl_vector_alloc(2);
|
|
Packit |
67cb25 |
if (state->subg == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for subg", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->subB = gsl_matrix_alloc(2, 2);
|
|
Packit |
67cb25 |
if (state->subB == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for subB", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->perm = gsl_permutation_alloc(2);
|
|
Packit |
67cb25 |
if (state->perm == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for perm", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->poly_p = gsl_poly_complex_workspace_alloc(5);
|
|
Packit |
67cb25 |
if (state->poly_p == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for poly workspace", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->n = n;
|
|
Packit |
67cb25 |
state->p = p;
|
|
Packit |
67cb25 |
state->rank = 0;
|
|
Packit |
67cb25 |
state->params = *par;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return state;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
subspace2D_free(void *vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
subspace2D_state_t *state = (subspace2D_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->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->W)
|
|
Packit |
67cb25 |
gsl_matrix_free(state->W);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->JQ)
|
|
Packit |
67cb25 |
gsl_matrix_free(state->JQ);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->tau)
|
|
Packit |
67cb25 |
gsl_vector_free(state->tau);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->subg)
|
|
Packit |
67cb25 |
gsl_vector_free(state->subg);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->subB)
|
|
Packit |
67cb25 |
gsl_matrix_free(state->subB);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->perm)
|
|
Packit |
67cb25 |
gsl_permutation_free(state->perm);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->poly_p)
|
|
Packit |
67cb25 |
gsl_poly_complex_workspace_free(state->poly_p);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
free(state);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
subspace2D_init()
|
|
Packit |
67cb25 |
Initialize subspace2D 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 |
subspace2D_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 |
subspace2D_preloop()
|
|
Packit |
67cb25 |
Initialize subspace2D method prior to iteration loop.
|
|
Packit |
67cb25 |
This involves computing the Gauss-Newton step and
|
|
Packit |
67cb25 |
steepest descent step
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: on output,
|
|
Packit |
67cb25 |
1) state->dx_gn contains Gauss-Newton step
|
|
Packit |
67cb25 |
2) state->dx_sd contains steepest descent step
|
|
Packit |
67cb25 |
3) state->rank contains the rank([dx_sd, dx_gn])
|
|
Packit |
67cb25 |
4) if full rank subspace (rank = 2), then:
|
|
Packit |
67cb25 |
state->trB = Tr(subB)
|
|
Packit |
67cb25 |
state->detB = det(subB)
|
|
Packit |
67cb25 |
state->normg = || subg ||
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
subspace2D_preloop(const void * vtrust_state, void * vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_trust_state *trust_state =
|
|
Packit |
67cb25 |
(const gsl_multifit_nlinear_trust_state *) vtrust_state;
|
|
Packit |
67cb25 |
subspace2D_state_t *state = (subspace2D_state_t *) vstate;
|
|
Packit |
67cb25 |
gsl_vector_view v;
|
|
Packit |
67cb25 |
double work_data[2];
|
|
Packit |
67cb25 |
gsl_vector_view work = gsl_vector_view_array(work_data, 2);
|
|
Packit |
67cb25 |
int signum;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* calculate Gauss-Newton step */
|
|
Packit |
67cb25 |
status = subspace2D_calc_gn(trust_state, state->dx_gn);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* now calculate the steepest descent step */
|
|
Packit |
67cb25 |
status = subspace2D_calc_sd(trust_state, state->dx_sd, state);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* store norms */
|
|
Packit |
67cb25 |
state->norm_Dgn = scaled_enorm(trust_state->diag, state->dx_gn);
|
|
Packit |
67cb25 |
state->norm_Dsd = scaled_enorm(trust_state->diag, state->dx_sd);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* now compute orthonormal basis for span(D dx_sd, D dx_gn) using
|
|
Packit |
67cb25 |
* QR decomposition; set W = [ D dx_sd, D dx_gn ] and normalize each
|
|
Packit |
67cb25 |
* column to unit magnitude. Then the Q matrix will form a basis for Col(W)
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
v = gsl_matrix_column(state->W, 0);
|
|
Packit |
67cb25 |
gsl_vector_memcpy(&v.vector, state->dx_sd);
|
|
Packit |
67cb25 |
gsl_vector_mul(&v.vector, trust_state->diag);
|
|
Packit |
67cb25 |
if (state->norm_Dsd != 0)
|
|
Packit |
67cb25 |
gsl_vector_scale(&v.vector, 1.0 / state->norm_Dsd);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
v = gsl_matrix_column(state->W, 1);
|
|
Packit |
67cb25 |
gsl_vector_memcpy(&v.vector, state->dx_gn);
|
|
Packit |
67cb25 |
gsl_vector_mul(&v.vector, trust_state->diag);
|
|
Packit |
67cb25 |
if (state->norm_Dgn != 0)
|
|
Packit |
67cb25 |
gsl_vector_scale(&v.vector, 1.0 / state->norm_Dgn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* use a rank revealing QR decomposition in case dx_sd and dx_gn
|
|
Packit |
67cb25 |
* are parallel */
|
|
Packit |
67cb25 |
gsl_linalg_QRPT_decomp(state->W, state->tau, state->perm, &signum, &work.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* check for parallel dx_sd, dx_gn, in which case rank will be 1 */
|
|
Packit |
67cb25 |
state->rank = gsl_linalg_QRPT_rank(state->W, -1.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->rank == 2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* full rank subspace, compute:
|
|
Packit |
67cb25 |
* subg = Q^T D^{-1} g
|
|
Packit |
67cb25 |
* subB = Q^T D^{-1} B D^{-1} Q where B = J^T J
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
const size_t p = state->p;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
gsl_matrix_view JQ = gsl_matrix_submatrix(state->JQ, 0, 0, state->n, GSL_MIN(2, p));
|
|
Packit |
67cb25 |
double B00, B10, B11, g0, g1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute subg */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(state->workp, trust_state->g);
|
|
Packit |
67cb25 |
gsl_vector_div(state->workp, trust_state->diag);
|
|
Packit |
67cb25 |
gsl_linalg_QR_QTvec(state->W, state->tau, state->workp);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
g0 = gsl_vector_get(state->workp, 0);
|
|
Packit |
67cb25 |
g1 = gsl_vector_get(state->workp, 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(state->subg, 0, g0);
|
|
Packit |
67cb25 |
gsl_vector_set(state->subg, 1, g1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute subB */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute J D^{-1} */
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(state->JQ, trust_state->J);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < p; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view c = gsl_matrix_column(state->JQ, i);
|
|
Packit |
67cb25 |
double di = gsl_vector_get(trust_state->diag, i);
|
|
Packit |
67cb25 |
gsl_vector_scale(&c.vector, 1.0 / di);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute J D^{-1} Q */
|
|
Packit |
67cb25 |
gsl_linalg_QR_matQ(state->W, state->tau, state->JQ);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute subB = Q^T D^{-1} J^T J D^{-1} Q */
|
|
Packit |
67cb25 |
gsl_blas_dsyrk(CblasLower, CblasTrans, 1.0, &JQ.matrix, 0.0, state->subB);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
B00 = gsl_matrix_get(state->subB, 0, 0);
|
|
Packit |
67cb25 |
B10 = gsl_matrix_get(state->subB, 1, 0);
|
|
Packit |
67cb25 |
B11 = gsl_matrix_get(state->subB, 1, 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->trB = B00 + B11;
|
|
Packit |
67cb25 |
state->detB = B00*B11 - B10*B10;
|
|
Packit |
67cb25 |
state->normg = gsl_blas_dnrm2(state->subg);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* g^T adj(B)^T adj(B) g */
|
|
Packit |
67cb25 |
state->term0 = (B10*B10 + B11*B11)*g0*g0 -
|
|
Packit |
67cb25 |
2*B10*(B00 + B11)*g0*g1 +
|
|
Packit |
67cb25 |
(B00*B00 + B10*B10)*g1*g1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* g^T adj(B)^T g */
|
|
Packit |
67cb25 |
state->term1 = B11 * g0 * g0 + g1 * (B00*g1 - 2*B10*g0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
subspace2D_step()
|
|
Packit |
67cb25 |
Calculate a new step with 2D subspace method. Based on [1]. We
|
|
Packit |
67cb25 |
seek a vector dx in span{dx_gn, dx_sd} which minimizes the model
|
|
Packit |
67cb25 |
function subject to ||dx|| <= delta
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
subspace2D_step(const void * vtrust_state, const double delta,
|
|
Packit |
67cb25 |
gsl_vector * dx, void * vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_trust_state *trust_state =
|
|
Packit |
67cb25 |
(const gsl_multifit_nlinear_trust_state *) vtrust_state;
|
|
Packit |
67cb25 |
subspace2D_state_t *state = (subspace2D_state_t *) vstate;
|
|
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 if (state->rank < 2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* rank of [dx_sd, dx_gn] is 1, meaning dx_sd and dx_gn
|
|
Packit |
67cb25 |
* are parallel so we can't form a 2D subspace. Follow the steepest
|
|
Packit |
67cb25 |
* descent direction to the trust region boundary as our step */
|
|
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 |
int status;
|
|
Packit |
67cb25 |
const double delta_sq = delta * delta;
|
|
Packit |
67cb25 |
double u = state->normg / delta;
|
|
Packit |
67cb25 |
double a[5];
|
|
Packit |
67cb25 |
double z[8];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if 1
|
|
Packit |
67cb25 |
a[0] = state->detB * state->detB - state->term0 / delta_sq;
|
|
Packit |
67cb25 |
a[1] = 2 * state->detB * state->trB - 2 * state->term1 / delta_sq;
|
|
Packit |
67cb25 |
a[2] = state->trB * state->trB + 2 * state->detB - u * u;
|
|
Packit |
67cb25 |
a[3] = 2 * state->trB;
|
|
Packit |
67cb25 |
a[4] = 1.0;
|
|
Packit |
67cb25 |
#else
|
|
Packit |
67cb25 |
double TrB_D = state->trB * delta;
|
|
Packit |
67cb25 |
double detB_D = state->detB * delta;
|
|
Packit |
67cb25 |
double normg_sq = state->normg * state->normg;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
a[0] = detB_D * detB_D - state->term0;
|
|
Packit |
67cb25 |
a[1] = 2 * state->detB * state->trB * delta_sq - 2 * state->term1;
|
|
Packit |
67cb25 |
a[2] = TrB_D * TrB_D + 2 * state->detB * delta_sq - normg_sq;
|
|
Packit |
67cb25 |
a[3] = 2 * state->trB * delta_sq;
|
|
Packit |
67cb25 |
a[4] = delta_sq;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = gsl_poly_complex_solve(a, 5, state->poly_p, z);
|
|
Packit |
67cb25 |
if (status == GSL_SUCCESS)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
double min = 0.0;
|
|
Packit |
67cb25 |
int mini = -1;
|
|
Packit |
67cb25 |
double x_data[2];
|
|
Packit |
67cb25 |
gsl_vector_view x = gsl_vector_view_array(x_data, 2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* loop through all four values of the Lagrange multiplier
|
|
Packit |
67cb25 |
* lambda. For each lambda, evaluate the objective function
|
|
Packit |
67cb25 |
* with Re(lambda) to determine which lambda minimizes the
|
|
Packit |
67cb25 |
* function
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
for (i = 0; i < 4; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double cost, normx;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*fprintf(stderr, "root: %.12e + %.12e i\n",
|
|
Packit |
67cb25 |
z[2*i], z[2*i+1]);*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = subspace2D_solution(z[2*i], &x.vector, state);
|
|
Packit |
67cb25 |
if (status != GSL_SUCCESS)
|
|
Packit |
67cb25 |
continue; /* singular matrix system */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* ensure ||x|| = delta */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
normx = gsl_blas_dnrm2(&x.vector);
|
|
Packit |
67cb25 |
if (normx == 0.0)
|
|
Packit |
67cb25 |
continue;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_scale(&x.vector, delta / normx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* evaluate objective function to determine minimizer */
|
|
Packit |
67cb25 |
cost = subspace2D_objective(&x.vector, state);
|
|
Packit |
67cb25 |
if (mini < 0 || cost < min)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
mini = (int) i;
|
|
Packit |
67cb25 |
min = cost;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (mini < 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* did not find minimizer - should not get here */
|
|
Packit |
67cb25 |
return GSL_FAILURE;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* compute x which minimizes objective function */
|
|
Packit |
67cb25 |
subspace2D_solution(z[2*mini], &x.vector, state);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* dx = Q * x */
|
|
Packit |
67cb25 |
gsl_vector_set_zero(dx);
|
|
Packit |
67cb25 |
gsl_vector_set(dx, 0, gsl_vector_get(&x.vector, 0));
|
|
Packit |
67cb25 |
gsl_vector_set(dx, 1, gsl_vector_get(&x.vector, 1));
|
|
Packit |
67cb25 |
gsl_linalg_QR_Qvec(state->W, state->tau, dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute final dx by multiplying by D^{-1} */
|
|
Packit |
67cb25 |
gsl_vector_div(dx, trust_state->diag);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("gsl_poly_complex_solve failed", status);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
subspace2D_preduction(const void * vtrust_state, const gsl_vector * dx,
|
|
Packit |
67cb25 |
double * pred, void * vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_trust_state *trust_state =
|
|
Packit |
67cb25 |
(const gsl_multifit_nlinear_trust_state *) vtrust_state;
|
|
Packit |
67cb25 |
subspace2D_state_t *state = (subspace2D_state_t *) vstate;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*pred = quadratic_preduction(trust_state->f, trust_state->J, dx, state->workn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* solve 2D subspace problem: (B + lambda*I) x = -g */
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
subspace2D_solution(const double lambda, gsl_vector * x,
|
|
Packit |
67cb25 |
subspace2D_state_t * state)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status = GSL_SUCCESS;
|
|
Packit |
67cb25 |
double C_data[4];
|
|
Packit |
67cb25 |
gsl_matrix_view C = gsl_matrix_view_array(C_data, 2, 2);
|
|
Packit |
67cb25 |
double B00 = gsl_matrix_get(state->subB, 0, 0);
|
|
Packit |
67cb25 |
double B10 = gsl_matrix_get(state->subB, 1, 0);
|
|
Packit |
67cb25 |
double B11 = gsl_matrix_get(state->subB, 1, 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* construct C = B + lambda*I */
|
|
Packit |
67cb25 |
gsl_matrix_set(&C.matrix, 0, 0, B00 + lambda);
|
|
Packit |
67cb25 |
gsl_matrix_set(&C.matrix, 1, 0, B10);
|
|
Packit |
67cb25 |
gsl_matrix_set(&C.matrix, 0, 1, B10);
|
|
Packit |
67cb25 |
gsl_matrix_set(&C.matrix, 1, 1, B11 + lambda);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* use modified Cholesky in case C is not positive definite */
|
|
Packit |
67cb25 |
gsl_linalg_mcholesky_decomp(&C.matrix, state->perm, NULL);
|
|
Packit |
67cb25 |
gsl_linalg_mcholesky_solve(&C.matrix, state->perm, state->subg, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_scale(x, -1.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* evaluate 2D objective function: f(x) = g^T x + 1/2 x^T B x */
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
subspace2D_objective(const gsl_vector * x, subspace2D_state_t * state)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double f;
|
|
Packit |
67cb25 |
double y_data[2];
|
|
Packit |
67cb25 |
gsl_vector_view y = gsl_vector_view_array(y_data, 2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: y = g + 1/2 B x */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(&y.vector, state->subg);
|
|
Packit |
67cb25 |
gsl_blas_dsymv(CblasLower, 0.5, state->subB, x, 1.0, &y.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: f = x^T ( g + 1/2 B x ) */
|
|
Packit |
67cb25 |
gsl_blas_ddot(x, &y.vector, &f);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return f;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
subspace2D_calc_gn()
|
|
Packit |
67cb25 |
Calculate Gauss-Newton step which satisfies:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
J dx_gn = -f
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: trust_state - trust state variables
|
|
Packit |
67cb25 |
dx - (output) Gauss-Newton step
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
subspace2D_calc_gn(const gsl_multifit_nlinear_trust_state * trust_state, gsl_vector * dx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
const gsl_multifit_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->f,
|
|
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 |
subspace2D_calc_sd()
|
|
Packit |
67cb25 |
Calculate steepest descent step,
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dx_sd = - || D^{-1} g ||^2 / || J D^{-2} g ||^2 D^{-2} g
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: trust_state - trust state variables
|
|
Packit |
67cb25 |
dx - (output) steepest descent vector
|
|
Packit |
67cb25 |
state - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success/error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
subspace2D_calc_sd(const gsl_multifit_nlinear_trust_state * trust_state, gsl_vector * dx,
|
|
Packit |
67cb25 |
subspace2D_state_t * state)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double norm_Dinvg; /* || D^{-1} g || */
|
|
Packit |
67cb25 |
double norm_JDinv2g; /* || J D^{-2} g || */
|
|
Packit |
67cb25 |
double alpha; /* || D^{-1} g ||^2 / || J D^{-2} g ||^2 */
|
|
Packit |
67cb25 |
double u;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute workp = D^{-1} g and its norm */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(state->workp, trust_state->g);
|
|
Packit |
67cb25 |
gsl_vector_div(state->workp, trust_state->diag);
|
|
Packit |
67cb25 |
norm_Dinvg = gsl_blas_dnrm2(state->workp);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute workp = D^{-2} g */
|
|
Packit |
67cb25 |
gsl_vector_div(state->workp, trust_state->diag);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute: workn = J D^{-2} g */
|
|
Packit |
67cb25 |
gsl_blas_dgemv(CblasNoTrans, 1.0, trust_state->J, state->workp, 0.0, state->workn);
|
|
Packit |
67cb25 |
norm_JDinv2g = gsl_blas_dnrm2(state->workn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
u = norm_Dinvg / norm_JDinv2g;
|
|
Packit |
67cb25 |
alpha = u * u;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* dx_sd = -alpha D^{-2} g */
|
|
Packit |
67cb25 |
gsl_vector_memcpy(dx, state->workp);
|
|
Packit |
67cb25 |
gsl_vector_scale(dx, -alpha);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static const gsl_multifit_nlinear_trs subspace2D_type =
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
"2D-subspace",
|
|
Packit |
67cb25 |
subspace2D_alloc,
|
|
Packit |
67cb25 |
subspace2D_init,
|
|
Packit |
67cb25 |
subspace2D_preloop,
|
|
Packit |
67cb25 |
subspace2D_step,
|
|
Packit |
67cb25 |
subspace2D_preduction,
|
|
Packit |
67cb25 |
subspace2D_free
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_trs *gsl_multifit_nlinear_trs_subspace2D = &subspace2D_type;
|