summaryrefslogtreecommitdiff
path: root/gsl-1.9/multiroots/hybrid.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsl-1.9/multiroots/hybrid.c')
-rw-r--r--gsl-1.9/multiroots/hybrid.c661
1 files changed, 661 insertions, 0 deletions
diff --git a/gsl-1.9/multiroots/hybrid.c b/gsl-1.9/multiroots/hybrid.c
new file mode 100644
index 0000000..ddb65e5
--- /dev/null
+++ b/gsl-1.9/multiroots/hybrid.c
@@ -0,0 +1,661 @@
+/* multiroots/hybrid.c
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000 Brian Gough
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_multiroots.h>
+#include <gsl/gsl_linalg.h>
+
+#include "dogleg.c"
+
+typedef struct
+{
+ size_t iter;
+ size_t ncfail;
+ size_t ncsuc;
+ size_t nslow1;
+ size_t nslow2;
+ double fnorm;
+ double delta;
+ gsl_matrix *J;
+ gsl_matrix *q;
+ gsl_matrix *r;
+ gsl_vector *tau;
+ gsl_vector *diag;
+ gsl_vector *qtf;
+ gsl_vector *newton;
+ gsl_vector *gradient;
+ gsl_vector *x_trial;
+ gsl_vector *f_trial;
+ gsl_vector *df;
+ gsl_vector *qtdf;
+ gsl_vector *rdx;
+ gsl_vector *w;
+ gsl_vector *v;
+}
+hybrid_state_t;
+
+static int hybrid_alloc (void *vstate, size_t n);
+static int hybrid_set (void *vstate, gsl_multiroot_function * func,
+ gsl_vector * x, gsl_vector * f, gsl_vector * dx);
+static int hybrids_set (void *vstate, gsl_multiroot_function * func,
+ gsl_vector * x, gsl_vector * f, gsl_vector * dx);
+static int set (void *vstate, gsl_multiroot_function * func, gsl_vector * x,
+ gsl_vector * f, gsl_vector * dx, int scale);
+static int hybrid_iterate (void *vstate, gsl_multiroot_function * func,
+ gsl_vector * x, gsl_vector * f, gsl_vector * dx);
+static void hybrid_free (void *vstate);
+static int iterate (void *vstate, gsl_multiroot_function * func,
+ gsl_vector * x, gsl_vector * f, gsl_vector * dx,
+ int scale);
+
+static int
+hybrid_alloc (void *vstate, size_t n)
+{
+ hybrid_state_t *state = (hybrid_state_t *) vstate;
+ gsl_matrix *J, *q, *r;
+ gsl_vector *tau, *diag, *qtf, *newton, *gradient, *x_trial, *f_trial,
+ *df, *qtdf, *rdx, *w, *v;
+
+ J = gsl_matrix_calloc (n, n);
+
+ if (J == 0)
+ {
+ GSL_ERROR ("failed to allocate space for J", GSL_ENOMEM);
+ }
+
+ state->J = J;
+
+ q = gsl_matrix_calloc (n, n);
+
+ if (q == 0)
+ {
+ gsl_matrix_free (J);
+
+ GSL_ERROR ("failed to allocate space for q", GSL_ENOMEM);
+ }
+
+ state->q = q;
+
+ r = gsl_matrix_calloc (n, n);
+
+ if (r == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+
+ GSL_ERROR ("failed to allocate space for r", GSL_ENOMEM);
+ }
+
+ state->r = r;
+
+ tau = gsl_vector_calloc (n);
+
+ if (tau == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+
+ GSL_ERROR ("failed to allocate space for tau", GSL_ENOMEM);
+ }
+
+ state->tau = tau;
+
+ diag = gsl_vector_calloc (n);
+
+ if (diag == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+
+ GSL_ERROR ("failed to allocate space for diag", GSL_ENOMEM);
+ }
+
+ state->diag = diag;
+
+ qtf = gsl_vector_calloc (n);
+
+ if (qtf == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+
+ GSL_ERROR ("failed to allocate space for qtf", GSL_ENOMEM);
+ }
+
+ state->qtf = qtf;
+
+ newton = gsl_vector_calloc (n);
+
+ if (newton == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+
+ GSL_ERROR ("failed to allocate space for newton", GSL_ENOMEM);
+ }
+
+ state->newton = newton;
+
+ gradient = gsl_vector_calloc (n);
+
+ if (gradient == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+
+ GSL_ERROR ("failed to allocate space for gradient", GSL_ENOMEM);
+ }
+
+ state->gradient = gradient;
+
+ x_trial = gsl_vector_calloc (n);
+
+ if (x_trial == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+ gsl_vector_free (gradient);
+
+ GSL_ERROR ("failed to allocate space for x_trial", GSL_ENOMEM);
+ }
+
+ state->x_trial = x_trial;
+
+ f_trial = gsl_vector_calloc (n);
+
+ if (f_trial == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+ gsl_vector_free (gradient);
+ gsl_vector_free (x_trial);
+
+ GSL_ERROR ("failed to allocate space for f_trial", GSL_ENOMEM);
+ }
+
+ state->f_trial = f_trial;
+
+ df = gsl_vector_calloc (n);
+
+ if (df == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+ gsl_vector_free (gradient);
+ gsl_vector_free (x_trial);
+ gsl_vector_free (f_trial);
+
+ GSL_ERROR ("failed to allocate space for df", GSL_ENOMEM);
+ }
+
+ state->df = df;
+
+ qtdf = gsl_vector_calloc (n);
+
+ if (qtdf == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+ gsl_vector_free (gradient);
+ gsl_vector_free (x_trial);
+ gsl_vector_free (f_trial);
+ gsl_vector_free (df);
+
+ GSL_ERROR ("failed to allocate space for qtdf", GSL_ENOMEM);
+ }
+
+ state->qtdf = qtdf;
+
+
+ rdx = gsl_vector_calloc (n);
+
+ if (rdx == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+ gsl_vector_free (gradient);
+ gsl_vector_free (x_trial);
+ gsl_vector_free (f_trial);
+ gsl_vector_free (df);
+ gsl_vector_free (qtdf);
+
+ GSL_ERROR ("failed to allocate space for rdx", GSL_ENOMEM);
+ }
+
+ state->rdx = rdx;
+
+ w = gsl_vector_calloc (n);
+
+ if (w == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+ gsl_vector_free (gradient);
+ gsl_vector_free (x_trial);
+ gsl_vector_free (f_trial);
+ gsl_vector_free (df);
+ gsl_vector_free (qtdf);
+ gsl_vector_free (rdx);
+
+ GSL_ERROR ("failed to allocate space for w", GSL_ENOMEM);
+ }
+
+ state->w = w;
+
+ v = gsl_vector_calloc (n);
+
+ if (v == 0)
+ {
+ gsl_matrix_free (J);
+ gsl_matrix_free (q);
+ gsl_matrix_free (r);
+ gsl_vector_free (tau);
+ gsl_vector_free (diag);
+ gsl_vector_free (qtf);
+ gsl_vector_free (newton);
+ gsl_vector_free (gradient);
+ gsl_vector_free (x_trial);
+ gsl_vector_free (f_trial);
+ gsl_vector_free (df);
+ gsl_vector_free (qtdf);
+ gsl_vector_free (rdx);
+ gsl_vector_free (w);
+
+ GSL_ERROR ("failed to allocate space for v", GSL_ENOMEM);
+ }
+
+ state->v = v;
+
+ return GSL_SUCCESS;
+}
+
+static int
+hybrid_set (void *vstate, gsl_multiroot_function * func, gsl_vector * x,
+ gsl_vector * f, gsl_vector * dx)
+{
+ int status = set (vstate, func, x, f, dx, 0);
+ return status;
+}
+
+static int
+hybrids_set (void *vstate, gsl_multiroot_function * func, gsl_vector * x,
+ gsl_vector * f, gsl_vector * dx)
+{
+ int status = set (vstate, func, x, f, dx, 1);
+ return status;
+}
+
+static int
+set (void *vstate, gsl_multiroot_function * func, gsl_vector * x,
+ gsl_vector * f, gsl_vector * dx, int scale)
+{
+ hybrid_state_t *state = (hybrid_state_t *) vstate;
+
+ gsl_matrix *J = state->J;
+ gsl_matrix *q = state->q;
+ gsl_matrix *r = state->r;
+ gsl_vector *tau = state->tau;
+ gsl_vector *diag = state->diag;
+
+ int status;
+
+ status = GSL_MULTIROOT_FN_EVAL (func, x, f);
+
+ if (status)
+ {
+ return status;
+ }
+
+ status = gsl_multiroot_fdjacobian (func, x, f, GSL_SQRT_DBL_EPSILON, J);
+
+ if (status)
+ {
+ return status;
+ }
+
+ state->iter = 1;
+ state->fnorm = enorm (f);
+ state->ncfail = 0;
+ state->ncsuc = 0;
+ state->nslow1 = 0;
+ state->nslow2 = 0;
+
+ gsl_vector_set_all (dx, 0.0);
+
+ /* Store column norms in diag */
+
+ if (scale)
+ compute_diag (J, diag);
+ else
+ gsl_vector_set_all (diag, 1.0);
+
+ /* Set delta to factor |D x| or to factor if |D x| is zero */
+
+ state->delta = compute_delta (diag, x);
+
+ /* Factorize J into QR decomposition */
+
+ status = gsl_linalg_QR_decomp (J, tau);
+
+ if (status)
+ {
+ return status;
+ }
+
+ status = gsl_linalg_QR_unpack (J, tau, q, r);
+
+ return status;
+}
+
+static int
+hybrid_iterate (void *vstate, gsl_multiroot_function * func, gsl_vector * x,
+ gsl_vector * f, gsl_vector * dx)
+{
+ int status = iterate (vstate, func, x, f, dx, 0);
+ return status;
+}
+
+static int
+hybrids_iterate (void *vstate, gsl_multiroot_function * func, gsl_vector * x,
+ gsl_vector * f, gsl_vector * dx)
+{
+ int status = iterate (vstate, func, x, f, dx, 1);
+ return status;
+}
+
+static int
+iterate (void *vstate, gsl_multiroot_function * func, gsl_vector * x,
+ gsl_vector * f, gsl_vector * dx, int scale)
+{
+ hybrid_state_t *state = (hybrid_state_t *) vstate;
+
+ const double fnorm = state->fnorm;
+
+ gsl_matrix *J = state->J;
+ gsl_matrix *q = state->q;
+ 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 *df = state->df;
+ gsl_vector *qtdf = state->qtdf;
+ gsl_vector *rdx = state->rdx;
+ gsl_vector *w = state->w;
+ gsl_vector *v = state->v;
+
+ double prered, actred;
+ double pnorm, fnorm1, fnorm1p;
+ double ratio;
+ double p1 = 0.1, p5 = 0.5, p001 = 0.001, p0001 = 0.0001;
+
+ /* Compute qtf = Q^T f */
+
+ compute_qtf (q, f, qtf);
+
+ /* Compute dogleg step */
+
+ dogleg (r, qtf, diag, state->delta, state->newton, state->gradient, dx);
+
+ /* Take a trial step */
+
+ compute_trial_step (x, dx, state->x_trial);
+
+ pnorm = scaled_enorm (diag, dx);
+
+ if (state->iter == 1)
+ {
+ if (pnorm < state->delta)
+ {
+ state->delta = pnorm;
+ }
+ }
+
+ /* Evaluate function at x + p */
+
+ {
+ int status = GSL_MULTIROOT_FN_EVAL (func, x_trial, f_trial);
+
+ if (status != GSL_SUCCESS)
+ {
+ return GSL_EBADFUNC;
+ }
+ }
+
+ /* Set df = f_trial - f */
+
+ compute_df (f_trial, f, df);
+
+ /* Compute the scaled actual reduction */
+
+ fnorm1 = enorm (f_trial);
+
+ actred = compute_actual_reduction (fnorm, fnorm1);
+
+ /* Compute rdx = R dx */
+
+ compute_rdx (r, dx, rdx);
+
+ /* Compute the scaled predicted reduction phi1p = |Q^T f + R dx| */
+
+ fnorm1p = enorm_sum (qtf, rdx);
+
+ prered = compute_predicted_reduction (fnorm, fnorm1p);
+
+ /* Compute the ratio of the actual to predicted reduction */
+
+ if (prered > 0)
+ {
+ ratio = actred / prered;
+ }
+ else
+ {
+ ratio = 0;
+ }
+
+ /* Update the step bound */
+
+ if (ratio < p1)
+ {
+ state->ncsuc = 0;
+ state->ncfail++;
+ state->delta *= p5;
+ }
+ else
+ {
+ state->ncfail = 0;
+ state->ncsuc++;
+
+ if (ratio >= p5 || state->ncsuc > 1)
+ state->delta = GSL_MAX (state->delta, pnorm / p5);
+ if (fabs (ratio - 1) <= p1)
+ state->delta = pnorm / p5;
+ }
+
+ /* Test for successful iteration */
+
+ if (ratio >= p0001)
+ {
+ gsl_vector_memcpy (x, x_trial);
+ gsl_vector_memcpy (f, f_trial);
+ state->fnorm = fnorm1;
+ state->iter++;
+ }
+
+ /* Determine the progress of the iteration */
+
+ state->nslow1++;
+ if (actred >= p001)
+ state->nslow1 = 0;
+
+ if (actred >= p1)
+ state->nslow2 = 0;
+
+ if (state->ncfail == 2)
+ {
+ gsl_multiroot_fdjacobian (func, x, f, GSL_SQRT_DBL_EPSILON, J);
+
+ state->nslow2++;
+
+ if (state->iter == 1)
+ {
+ if (scale)
+ compute_diag (J, diag);
+ state->delta = compute_delta (diag, x);
+ }
+ else
+ {
+ if (scale)
+ update_diag (J, diag);
+ }
+
+ /* Factorize J into QR decomposition */
+
+ gsl_linalg_QR_decomp (J, tau);
+ gsl_linalg_QR_unpack (J, tau, q, r);
+
+ return GSL_SUCCESS;
+ }
+
+ /* Compute qtdf = Q^T df, w = (Q^T df - R dx)/|dx|, v = D^2 dx/|dx| */
+
+ compute_qtf (q, df, qtdf);
+
+ compute_wv (qtdf, rdx, dx, diag, pnorm, w, v);
+
+ /* Rank-1 update of the jacobian Q'R' = Q(R + w v^T) */
+
+ gsl_linalg_QR_update (q, r, w, v);
+
+ /* No progress as measured by jacobian evaluations */
+
+ if (state->nslow2 == 5)
+ {
+ return GSL_ENOPROGJ;
+ }
+
+ /* No progress as measured by function evaluations */
+
+ if (state->nslow1 == 10)
+ {
+ return GSL_ENOPROG;
+ }
+
+ return GSL_SUCCESS;
+}
+
+
+static void
+hybrid_free (void *vstate)
+{
+ hybrid_state_t *state = (hybrid_state_t *) vstate;
+
+ gsl_vector_free (state->v);
+ gsl_vector_free (state->w);
+ gsl_vector_free (state->rdx);
+ gsl_vector_free (state->qtdf);
+ gsl_vector_free (state->df);
+ gsl_vector_free (state->f_trial);
+ gsl_vector_free (state->x_trial);
+ gsl_vector_free (state->gradient);
+ gsl_vector_free (state->newton);
+ gsl_vector_free (state->qtf);
+ gsl_vector_free (state->diag);
+ gsl_vector_free (state->tau);
+ gsl_matrix_free (state->r);
+ gsl_matrix_free (state->q);
+ gsl_matrix_free (state->J);
+}
+
+static const gsl_multiroot_fsolver_type hybrid_type = {
+ "hybrid", /* name */
+ sizeof (hybrid_state_t),
+ &hybrid_alloc,
+ &hybrid_set,
+ &hybrid_iterate,
+ &hybrid_free
+};
+
+static const gsl_multiroot_fsolver_type hybrids_type = {
+ "hybrids", /* name */
+ sizeof (hybrid_state_t),
+ &hybrid_alloc,
+ &hybrids_set,
+ &hybrids_iterate,
+ &hybrid_free
+};
+
+const gsl_multiroot_fsolver_type *gsl_multiroot_fsolver_hybrid = &hybrid_type;
+const gsl_multiroot_fsolver_type *gsl_multiroot_fsolver_hybrids =
+ &hybrids_type;