summaryrefslogtreecommitdiff
path: root/gsl-1.9/multifit/lmiterate.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsl-1.9/multifit/lmiterate.c')
-rw-r--r--gsl-1.9/multifit/lmiterate.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/gsl-1.9/multifit/lmiterate.c b/gsl-1.9/multifit/lmiterate.c
new file mode 100644
index 0000000..78d0ea6
--- /dev/null
+++ b/gsl-1.9/multifit/lmiterate.c
@@ -0,0 +1,222 @@
+static int
+iterate (void *vstate, gsl_multifit_function_fdf * fdf, gsl_vector * x, gsl_vector * f, gsl_matrix * J, gsl_vector * dx, int scale)
+{
+ lmder_state_t *state = (lmder_state_t *) vstate;
+
+ gsl_matrix *r = state->r;
+ gsl_vector *tau = state->tau;
+ gsl_vector *diag = state->diag;
+ gsl_vector *qtf = state->qtf;
+ gsl_vector *x_trial = state->x_trial;
+ gsl_vector *f_trial = state->f_trial;
+ gsl_vector *rptdx = state->rptdx;
+ gsl_vector *newton = state->newton;
+ gsl_vector *gradient = state->gradient;
+ gsl_vector *sdiag = state->sdiag;
+ gsl_vector *w = state->w;
+ gsl_vector *work1 = state->work1;
+ gsl_permutation *perm = state->perm;
+
+ double prered, actred;
+ double pnorm, fnorm1, fnorm1p, gnorm;
+ double ratio;
+ double dirder;
+
+ int iter = 0;
+
+ double p1 = 0.1, p25 = 0.25, p5 = 0.5, p75 = 0.75, p0001 = 0.0001;
+
+ if (state->fnorm == 0.0)
+ {
+ return GSL_SUCCESS;
+ }
+
+ /* Compute qtf = Q^T f */
+
+ gsl_vector_memcpy (qtf, f);
+ gsl_linalg_QR_QTvec (r, tau, qtf);
+
+ /* Compute norm of scaled gradient */
+
+ compute_gradient_direction (r, perm, qtf, diag, gradient);
+
+ {
+ size_t iamax = gsl_blas_idamax (gradient);
+
+ gnorm = fabs(gsl_vector_get (gradient, iamax) / state->fnorm);
+ }
+
+ /* Determine the Levenberg-Marquardt parameter */
+
+lm_iteration:
+
+ iter++ ;
+
+ {
+ int status = lmpar (r, perm, qtf, diag, state->delta, &(state->par), newton, gradient, sdiag, dx, w);
+ if (status)
+ return status;
+ }
+
+ /* Take a trial step */
+
+ gsl_vector_scale (dx, -1.0); /* reverse the step to go downhill */
+
+ compute_trial_step (x, dx, state->x_trial);
+
+ pnorm = scaled_enorm (diag, dx);
+
+ if (state->iter == 1)
+ {
+ if (pnorm < state->delta)
+ {
+#ifdef DEBUG
+ printf("set delta = pnorm = %g\n" , pnorm);
+#endif
+ state->delta = pnorm;
+ }
+ }
+
+ /* Evaluate function at x + p */
+ /* return immediately if evaluation raised error */
+ {
+ int status = GSL_MULTIFIT_FN_EVAL_F (fdf, x_trial, f_trial);
+ if (status)
+ return status;
+ }
+
+ fnorm1 = enorm (f_trial);
+
+ /* Compute the scaled actual reduction */
+
+ actred = compute_actual_reduction (state->fnorm, fnorm1);
+
+#ifdef DEBUG
+ printf("lmiterate: fnorm = %g fnorm1 = %g actred = %g\n", state->fnorm, fnorm1, actred);
+#endif
+
+ /* Compute rptdx = R P^T dx, noting that |J dx| = |R P^T dx| */
+
+ compute_rptdx (r, perm, dx, rptdx);
+
+ fnorm1p = enorm (rptdx);
+
+ /* Compute the scaled predicted reduction = |J dx|^2 + 2 par |D dx|^2 */
+
+ {
+ double t1 = fnorm1p / state->fnorm;
+ double t2 = (sqrt(state->par) * pnorm) / state->fnorm;
+
+ prered = t1 * t1 + t2 * t2 / p5;
+ dirder = -(t1 * t1 + t2 * t2);
+ }
+
+ /* compute the ratio of the actual to predicted reduction */
+
+ if (prered > 0)
+ {
+ ratio = actred / prered;
+ }
+ else
+ {
+ ratio = 0;
+ }
+
+#ifdef DEBUG
+ printf("lmiterate: prered = %g dirder = %g ratio = %g\n", prered, dirder,ratio);
+#endif
+
+
+ /* update the step bound */
+
+ if (ratio > p25)
+ {
+#ifdef DEBUG
+ printf("ratio > p25\n");
+#endif
+ if (state->par == 0 || ratio >= p75)
+ {
+ state->delta = pnorm / p5;
+ state->par *= p5;
+#ifdef DEBUG
+ printf("updated step bounds: delta = %g, par = %g\n", state->delta, state->par);
+#endif
+ }
+ }
+ else
+ {
+ double temp = (actred >= 0) ? p5 : p5*dirder / (dirder + p5 * actred);
+
+#ifdef DEBUG
+ printf("ratio < p25\n");
+#endif
+
+ if (p1 * fnorm1 >= state->fnorm || temp < p1 )
+ {
+ temp = p1;
+ }
+
+ state->delta = temp * GSL_MIN_DBL (state->delta, pnorm/p1);
+
+ state->par /= temp;
+#ifdef DEBUG
+ printf("updated step bounds: delta = %g, par = %g\n", state->delta, state->par);
+#endif
+ }
+
+
+ /* test for successful iteration, termination and stringent tolerances */
+
+ if (ratio >= p0001)
+ {
+ gsl_vector_memcpy (x, x_trial);
+ gsl_vector_memcpy (f, f_trial);
+
+ /* return immediately if evaluation raised error */
+ {
+ int status = GSL_MULTIFIT_FN_EVAL_DF (fdf, x_trial, J);
+ if (status)
+ return status;
+ }
+
+ /* wa2_j = diag_j * x_j */
+ state->xnorm = scaled_enorm(diag, x);
+ state->fnorm = fnorm1;
+ state->iter++;
+
+ /* Rescale if necessary */
+
+ if (scale)
+ {
+ update_diag (J, diag);
+ }
+
+ {
+ int signum;
+ gsl_matrix_memcpy (r, J);
+ gsl_linalg_QRPT_decomp (r, tau, perm, &signum, work1);
+ }
+
+ return GSL_SUCCESS;
+ }
+ else if (fabs(actred) <= GSL_DBL_EPSILON && prered <= GSL_DBL_EPSILON
+ && p5 * ratio <= 1.0)
+ {
+ return GSL_ETOLF ;
+ }
+ else if (state->delta <= GSL_DBL_EPSILON * state->xnorm)
+ {
+ return GSL_ETOLX;
+ }
+ else if (gnorm <= GSL_DBL_EPSILON)
+ {
+ return GSL_ETOLG;
+ }
+ else if (iter < 10)
+ {
+ /* Repeat inner loop if unsuccessful */
+ goto lm_iteration;
+ }
+
+ return GSL_CONTINUE;
+}