|
Packit |
67cb25 |
/* multifit/lmniel.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2014 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_nlin.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_blas.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define SCALE 0
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This module contains an implementation of the Levenberg-Marquardt
|
|
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 |
|
|
Packit |
67cb25 |
typedef struct
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix *A; /* J^T J */
|
|
Packit |
67cb25 |
gsl_matrix *A_copy; /* copy of J^T J */
|
|
Packit |
67cb25 |
gsl_matrix *J; /* Jacobian J(x) */
|
|
Packit |
67cb25 |
gsl_vector *diag; /* D = diag(J^T J) */
|
|
Packit |
67cb25 |
gsl_vector *rhs; /* rhs vector = -g = -J^T f */
|
|
Packit |
67cb25 |
gsl_vector *x_trial; /* trial parameter vector */
|
|
Packit |
67cb25 |
gsl_vector *f_trial; /* trial function vector */
|
|
Packit |
67cb25 |
gsl_vector *work; /* workspace length p */
|
|
Packit |
67cb25 |
long nu; /* nu */
|
|
Packit |
67cb25 |
double mu; /* LM damping parameter mu */
|
|
Packit |
67cb25 |
double tau; /* initial scale factor for mu */
|
|
Packit |
67cb25 |
} lmniel_state_t;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "lmmisc.c"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define LM_ONE_THIRD (0.333333333333333)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int lmniel_alloc (void *vstate, const size_t n, const size_t p);
|
|
Packit |
67cb25 |
static void lmniel_free(void *vstate);
|
|
Packit |
67cb25 |
static int lmniel_set(void *vstate, const gsl_vector * swts,
|
|
Packit |
67cb25 |
gsl_multifit_function_fdf *fdf,
|
|
Packit |
67cb25 |
gsl_vector *x, gsl_vector *f, gsl_vector *dx);
|
|
Packit |
67cb25 |
static int lmniel_iterate(void *vstate, const gsl_vector *swts,
|
|
Packit |
67cb25 |
gsl_multifit_function_fdf *fdf,
|
|
Packit |
67cb25 |
gsl_vector *x, gsl_vector *f, gsl_vector *dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
lmniel_alloc (void *vstate, const size_t n, const size_t p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
lmniel_state_t *state = (lmniel_state_t *) vstate;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->A = gsl_matrix_alloc(p, p);
|
|
Packit |
67cb25 |
if (state->A == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("failed to allocate space for A", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->J = gsl_matrix_alloc(n, p);
|
|
Packit |
67cb25 |
if (state->J == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("failed to allocate space for J", 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 ("failed to allocate space for diag", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->rhs = gsl_vector_alloc(p);
|
|
Packit |
67cb25 |
if (state->rhs == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("failed to allocate space for rhs", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->work = gsl_vector_alloc(p);
|
|
Packit |
67cb25 |
if (state->work == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("failed to allocate space for work", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->A_copy = gsl_matrix_alloc(p, p);
|
|
Packit |
67cb25 |
if (state->A_copy == NULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("failed to allocate space for A_copy", 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 ("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 ("failed to allocate space for f_trial", GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->tau = 1.0e-3;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* lmniel_alloc() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
lmniel_free(void *vstate)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
lmniel_state_t *state = (lmniel_state_t *) vstate;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->A)
|
|
Packit |
67cb25 |
gsl_matrix_free(state->A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->J)
|
|
Packit |
67cb25 |
gsl_matrix_free(state->J);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->diag)
|
|
Packit |
67cb25 |
gsl_vector_free(state->diag);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->rhs)
|
|
Packit |
67cb25 |
gsl_vector_free(state->rhs);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->work)
|
|
Packit |
67cb25 |
gsl_vector_free(state->work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (state->A_copy)
|
|
Packit |
67cb25 |
gsl_matrix_free(state->A_copy);
|
|
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 |
} /* lmniel_free() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
lmniel_set(void *vstate, const gsl_vector *swts,
|
|
Packit |
67cb25 |
gsl_multifit_function_fdf *fdf, gsl_vector *x,
|
|
Packit |
67cb25 |
gsl_vector *f, gsl_vector *dx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
lmniel_state_t *state = (lmniel_state_t *) vstate;
|
|
Packit |
67cb25 |
const size_t p = x->size;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize counters for function and Jacobian evaluations */
|
|
Packit |
67cb25 |
fdf->nevalf = 0;
|
|
Packit |
67cb25 |
fdf->nevaldf = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* evaluate function and Jacobian at x and apply weight transform */
|
|
Packit |
67cb25 |
status = gsl_multifit_eval_wf(fdf, x, swts, f);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fdf->df)
|
|
Packit |
67cb25 |
status = gsl_multifit_eval_wdf(fdf, x, swts, state->J);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
status = gsl_multifit_fdfsolver_dif_df(x, swts, fdf, f, state->J);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute rhs = -J^T f */
|
|
Packit |
67cb25 |
gsl_blas_dgemv(CblasTrans, -1.0, state->J, f, 0.0, state->rhs);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if SCALE
|
|
Packit |
67cb25 |
gsl_vector_set_zero(state->diag);
|
|
Packit |
67cb25 |
#else
|
|
Packit |
67cb25 |
gsl_vector_set_all(state->diag, 1.0);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* set default parameters */
|
|
Packit |
67cb25 |
state->nu = 2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if SCALE
|
|
Packit |
67cb25 |
state->mu = state->tau;
|
|
Packit |
67cb25 |
#else
|
|
Packit |
67cb25 |
/* compute mu_0 = tau * max(diag(J^T J)) */
|
|
Packit |
67cb25 |
state->mu = -1.0;
|
|
Packit |
67cb25 |
for (i = 0; i < p; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view c = gsl_matrix_column(state->J, i);
|
|
Packit |
67cb25 |
double result; /* (J^T J)_{ii} */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_ddot(&c.vector, &c.vector, &result);
|
|
Packit |
67cb25 |
state->mu = GSL_MAX(state->mu, result);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
state->mu *= state->tau;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* lmniel_set() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
lmniel_iterate()
|
|
Packit |
67cb25 |
This function performs 1 iteration of the LM algorithm 6.18
|
|
Packit |
67cb25 |
from [1]. The algorithm is slightly modified to loop until we
|
|
Packit |
67cb25 |
find an acceptable step dx, in order to guarantee that each
|
|
Packit |
67cb25 |
function call contains a new input vector x.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Args: vstate - lm 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 |
dx - (output only) parameter step vector
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) On input, the following must be initialized in state:
|
|
Packit |
67cb25 |
nu, mu, rhs, J
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) On output, the following are updated with the current iterates:
|
|
Packit |
67cb25 |
nu, mu, rhs, J
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
rhs needs to be set on each output, so that lmniel_gradient supplies
|
|
Packit |
67cb25 |
the correct g = J^T f
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
lmniel_iterate(void *vstate, const gsl_vector *swts,
|
|
Packit |
67cb25 |
gsl_multifit_function_fdf *fdf, gsl_vector *x,
|
|
Packit |
67cb25 |
gsl_vector *f, gsl_vector *dx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status;
|
|
Packit |
67cb25 |
lmniel_state_t *state = (lmniel_state_t *) vstate;
|
|
Packit |
67cb25 |
gsl_matrix *J = state->J; /* Jacobian J(x) */
|
|
Packit |
67cb25 |
gsl_matrix *A = state->A; /* J^T J */
|
|
Packit |
67cb25 |
gsl_vector *rhs = state->rhs; /* -g = -J^T f */
|
|
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 dF; /* F(x) - F(x + dx) */
|
|
Packit |
67cb25 |
double dL; /* L(0) - L(dx) */
|
|
Packit |
67cb25 |
int foundstep = 0; /* found step dx */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute A = J^T J */
|
|
Packit |
67cb25 |
status = gsl_blas_dsyrk(CblasLower, CblasTrans, 1.0, J, 0.0, A);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* copy lower triangle to upper */
|
|
Packit |
67cb25 |
gsl_matrix_transpose_tricpy('L', 0, A, A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if SCALE
|
|
Packit |
67cb25 |
lmniel_update_diag(J, diag);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* loop until we find an acceptable step dx */
|
|
Packit |
67cb25 |
while (!foundstep)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* solve (A + mu*I) dx = g */
|
|
Packit |
67cb25 |
status = lmniel_calc_dx(state->mu, A, rhs, dx, state);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute x_trial = x + dx */
|
|
Packit |
67cb25 |
lmniel_trial_step(x, dx, x_trial);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute f(x + dx) */
|
|
Packit |
67cb25 |
status = gsl_multifit_eval_wf(fdf, x_trial, swts, f_trial);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute dF = F(x) - F(x + dx) */
|
|
Packit |
67cb25 |
dF = lmniel_calc_dF(f, f_trial);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute dL = L(0) - L(dx) = dx^T (mu*dx - g) */
|
|
Packit |
67cb25 |
dL = lmniel_calc_dL(state->mu, diag, dx, rhs);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* check that rho = dF/dL > 0 */
|
|
Packit |
67cb25 |
if ((dL > 0.0) && (dF >= 0.0))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* reduction in error, step acceptable */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double tmp;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* update LM parameter mu */
|
|
Packit |
67cb25 |
tmp = 2.0 * (dF / dL) - 1.0;
|
|
Packit |
67cb25 |
tmp = 1.0 - tmp*tmp*tmp;
|
|
Packit |
67cb25 |
state->mu *= GSL_MAX(LM_ONE_THIRD, tmp);
|
|
Packit |
67cb25 |
state->nu = 2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute J <- J(x + dx) */
|
|
Packit |
67cb25 |
if (fdf->df)
|
|
Packit |
67cb25 |
status = gsl_multifit_eval_wdf(fdf, x_trial, swts, J);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
status = gsl_multifit_fdfsolver_dif_df(x_trial, swts, fdf, f_trial, J);
|
|
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 rhs = -J^T f */
|
|
Packit |
67cb25 |
gsl_blas_dgemv(CblasTrans, -1.0, J, f, 0.0, rhs);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
foundstep = 1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
long nu2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* step did not reduce error, reject step */
|
|
Packit |
67cb25 |
state->mu *= (double) state->nu;
|
|
Packit |
67cb25 |
nu2 = state->nu << 1; /* 2*nu */
|
|
Packit |
67cb25 |
if (nu2 <= state->nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_view d = gsl_matrix_diagonal(A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* nu has wrapped around / overflown, reset mu and nu
|
|
Packit |
67cb25 |
* to original values and break to force another iteration
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
/*GSL_ERROR("nu parameter has overflown", GSL_EOVRFLW);*/
|
|
Packit |
67cb25 |
state->nu = 2;
|
|
Packit |
67cb25 |
state->mu = state->tau * gsl_vector_max(&d.vector);
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
state->nu = nu2;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* while (!foundstep) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* lmniel_iterate() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
lmniel_gradient(void *vstate, gsl_vector * g)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
lmniel_state_t *state = (lmniel_state_t *) vstate;
|
|
Packit |
67cb25 |
gsl_vector_memcpy(g, state->rhs);
|
|
Packit |
67cb25 |
gsl_vector_scale(g, -1.0);
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
lmniel_jac(void *vstate, gsl_matrix * J)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
lmniel_state_t *state = (lmniel_state_t *) vstate;
|
|
Packit |
67cb25 |
int s = gsl_matrix_memcpy(J, state->J);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static const gsl_multifit_fdfsolver_type lmniel_type =
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
"lmniel",
|
|
Packit |
67cb25 |
sizeof(lmniel_state_t),
|
|
Packit |
67cb25 |
&lmniel_alloc,
|
|
Packit |
67cb25 |
&lmniel_set,
|
|
Packit |
67cb25 |
&lmniel_iterate,
|
|
Packit |
67cb25 |
&lmniel_gradient,
|
|
Packit |
67cb25 |
&lmniel_jac,
|
|
Packit |
67cb25 |
&lmniel_free
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
const gsl_multifit_fdfsolver_type *gsl_multifit_fdfsolver_lmniel = &lmniel_type;
|