summaryrefslogtreecommitdiff
path: root/gsl-1.9/multimin/directional_minimize.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsl-1.9/multimin/directional_minimize.c')
-rw-r--r--gsl-1.9/multimin/directional_minimize.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/gsl-1.9/multimin/directional_minimize.c b/gsl-1.9/multimin/directional_minimize.c
new file mode 100644
index 0000000..8e1c366
--- /dev/null
+++ b/gsl-1.9/multimin/directional_minimize.c
@@ -0,0 +1,236 @@
+/* multimin/directional_minimize.c
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000 Fabrice Rossi
+ *
+ * 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.
+ */
+
+static void
+take_step (const gsl_vector * x, const gsl_vector * p,
+ double step, double lambda, gsl_vector * x1, gsl_vector * dx)
+{
+ gsl_vector_set_zero (dx);
+ gsl_blas_daxpy (-step * lambda, p, dx);
+
+ gsl_vector_memcpy (x1, x);
+ gsl_blas_daxpy (1.0, dx, x1);
+}
+
+static void
+intermediate_point (gsl_multimin_function_fdf * fdf,
+ const gsl_vector * x, const gsl_vector * p,
+ double lambda,
+ double pg,
+ double stepa, double stepc,
+ double fa, double fc,
+ gsl_vector * x1, gsl_vector * dx, gsl_vector * gradient,
+ double * step, double * f)
+{
+ double stepb, fb;
+
+trial:
+ {
+ double u = fabs (pg * lambda * stepc);
+ stepb = 0.5 * stepc * u / ((fc - fa) + u);
+ }
+
+ take_step (x, p, stepb, lambda, x1, dx);
+
+ fb = GSL_MULTIMIN_FN_EVAL_F (fdf, x1);
+
+#ifdef DEBUG
+ printf ("trying stepb = %g fb = %.18e\n", stepb, fb);
+#endif
+
+ if (fb >= fa && stepb > 0.0)
+ {
+ /* downhill step failed, reduce step-size and try again */
+ fc = fb;
+ stepc = stepb;
+ goto trial;
+ }
+#ifdef DEBUG
+ printf ("ok!\n");
+#endif
+
+ *step = stepb;
+ *f = fb;
+ GSL_MULTIMIN_FN_EVAL_DF(fdf, x1, gradient);
+}
+
+static void
+minimize (gsl_multimin_function_fdf * fdf,
+ const gsl_vector * x, const gsl_vector * p,
+ double lambda,
+ double stepa, double stepb, double stepc,
+ double fa, double fb, double fc, double tol,
+ gsl_vector * x1, gsl_vector * dx1,
+ gsl_vector * x2, gsl_vector * dx2, gsl_vector * gradient,
+ double * step, double * f, double * gnorm)
+{
+ /* Starting at (x0, f0) move along the direction p to find a minimum
+ f(x0 - lambda * p), returning the new point x1 = x0-lambda*p,
+ f1=f(x1) and g1 = grad(f) at x1. */
+
+ double u = stepb;
+ double v = stepa;
+ double w = stepc;
+ double fu = fb;
+ double fv = fa;
+ double fw = fc;
+
+ double old2 = fabs(w - v);
+ double old1 = fabs(v - u);
+
+ double stepm, fm, pg, gnorm1;
+
+ int iter = 0;
+
+ gsl_vector_memcpy (x2, x1);
+ gsl_vector_memcpy (dx2, dx1);
+
+ *f = fb;
+ *step = stepb;
+ *gnorm = gsl_blas_dnrm2 (gradient);
+
+mid_trial:
+
+ iter++;
+
+ if (iter > 10)
+ {
+ return; /* MAX ITERATIONS */
+ }
+
+ {
+ double dw = w - u;
+ double dv = v - u;
+ double du = 0.0;
+
+ double e1 = ((fv - fu) * dw * dw + (fu - fw) * dv * dv);
+ double e2 = 2.0 * ((fv - fu) * dw + (fu - fw) * dv);
+
+ if (e2 != 0.0)
+ {
+ du = e1 / e2;
+ }
+
+ if (du > 0.0 && du < (stepc - stepb) && fabs(du) < 0.5 * old2)
+ {
+ stepm = u + du;
+ }
+ else if (du < 0.0 && du > (stepa - stepb) && fabs(du) < 0.5 * old2)
+ {
+ stepm = u + du;
+ }
+ else if ((stepc - stepb) > (stepb - stepa))
+ {
+ stepm = 0.38 * (stepc - stepb) + stepb;
+ }
+ else
+ {
+ stepm = stepb - 0.38 * (stepb - stepa);
+ }
+ }
+
+ take_step (x, p, stepm, lambda, x1, dx1);
+
+ fm = GSL_MULTIMIN_FN_EVAL_F (fdf, x1);
+
+#ifdef DEBUG
+ printf ("trying stepm = %g fm = %.18e\n", stepm, fm);
+#endif
+
+ if (fm > fb)
+ {
+ if (fm < fv)
+ {
+ w = v;
+ v = stepm;
+ fw = fv;
+ fv = fm;
+ }
+ else if (fm < fw)
+ {
+ w = stepm;
+ fw = fm;
+ }
+
+ if (stepm < stepb)
+ {
+ stepa = stepm;
+ fa = fm;
+ }
+ else
+ {
+ stepc = stepm;
+ fc = fm;
+ }
+ goto mid_trial;
+ }
+ else if (fm <= fb)
+ {
+ old2 = old1;
+ old1 = fabs(u - stepm);
+ w = v;
+ v = u;
+ u = stepm;
+ fw = fv;
+ fv = fu;
+ fu = fm;
+
+ gsl_vector_memcpy (x2, x1);
+ gsl_vector_memcpy (dx2, dx1);
+
+ GSL_MULTIMIN_FN_EVAL_DF (fdf, x1, gradient);
+ gsl_blas_ddot (p, gradient, &pg);
+ gnorm1 = gsl_blas_dnrm2 (gradient);
+
+#ifdef DEBUG
+ printf ("p: "); gsl_vector_fprintf(stdout, p, "%g");
+ printf ("g: "); gsl_vector_fprintf(stdout, gradient, "%g");
+ printf ("gnorm: %.18e\n", gnorm1);
+ printf ("pg: %.18e\n", pg);
+ printf ("orth: %g\n", fabs (pg * lambda/ gnorm1));
+#endif
+ *f = fm;
+ *step = stepm;
+ *gnorm = gnorm1;
+
+ if (fabs (pg * lambda / gnorm1) < tol)
+ {
+#ifdef DEBUG
+ printf("ok!\n");
+#endif
+ return; /* SUCCESS */
+ }
+
+ if (stepm < stepb)
+ {
+ stepc = stepb;
+ fc = fb;
+ stepb = stepm;
+ fb = fm;
+ }
+ else
+ {
+ stepa = stepb;
+ fa = fb;
+ stepb = stepm;
+ fb = fm;
+ }
+ goto mid_trial;
+ }
+}