|
Packit |
67cb25 |
/* multimin/directional_minimize.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 1996, 1997, 1998, 1999, 2000 Fabrice Rossi
|
|
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 |
static void
|
|
Packit |
67cb25 |
take_step (const gsl_vector * x, const gsl_vector * p,
|
|
Packit |
67cb25 |
double step, double lambda, gsl_vector * x1, gsl_vector * dx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_set_zero (dx);
|
|
Packit |
67cb25 |
gsl_blas_daxpy (-step * lambda, p, dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy (x1, x);
|
|
Packit |
67cb25 |
gsl_blas_daxpy (1.0, dx, x1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
intermediate_point (gsl_multimin_function_fdf * fdf,
|
|
Packit |
67cb25 |
const gsl_vector * x, const gsl_vector * p,
|
|
Packit |
67cb25 |
double lambda,
|
|
Packit |
67cb25 |
double pg,
|
|
Packit |
67cb25 |
double stepa, double stepc,
|
|
Packit |
67cb25 |
double fa, double fc,
|
|
Packit |
67cb25 |
gsl_vector * x1, gsl_vector * dx, gsl_vector * gradient,
|
|
Packit |
67cb25 |
double * step, double * f)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double stepb, fb;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
trial:
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double u = fabs (pg * lambda * stepc);
|
|
Packit |
67cb25 |
stepb = 0.5 * stepc * u / ((fc - fa) + u);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
take_step (x, p, stepb, lambda, x1, dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (gsl_vector_equal (x, x1))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Take fast exit if trial point does not move from initial point */
|
|
Packit |
67cb25 |
#ifdef DEBUG
|
|
Packit |
67cb25 |
printf ("fast exit x == x1 for stepb = %g\n", stepb);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
*step = 0;
|
|
Packit |
67cb25 |
*f = fa;
|
|
Packit |
67cb25 |
GSL_MULTIMIN_FN_EVAL_DF(fdf, x1, gradient);
|
|
Packit |
67cb25 |
return ;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
fb = GSL_MULTIMIN_FN_EVAL_F (fdf, x1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#ifdef DEBUG
|
|
Packit |
67cb25 |
printf ("trying stepb = %g fb = %.18e\n", stepb, fb);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fb >= fa && stepb > 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* downhill step failed, reduce step-size and try again */
|
|
Packit |
67cb25 |
fc = fb;
|
|
Packit |
67cb25 |
stepc = stepb;
|
|
Packit |
67cb25 |
goto trial;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#ifdef DEBUG
|
|
Packit |
67cb25 |
printf ("ok!\n");
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*step = stepb;
|
|
Packit |
67cb25 |
*f = fb;
|
|
Packit |
67cb25 |
GSL_MULTIMIN_FN_EVAL_DF(fdf, x1, gradient);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
minimize (gsl_multimin_function_fdf * fdf,
|
|
Packit |
67cb25 |
const gsl_vector * x, const gsl_vector * p,
|
|
Packit |
67cb25 |
double lambda,
|
|
Packit |
67cb25 |
double stepa, double stepb, double stepc,
|
|
Packit |
67cb25 |
double fa, double fb, double fc, double tol,
|
|
Packit |
67cb25 |
gsl_vector * x1, gsl_vector * dx1,
|
|
Packit |
67cb25 |
gsl_vector * x2, gsl_vector * dx2, gsl_vector * gradient,
|
|
Packit |
67cb25 |
double * step, double * f, double * gnorm)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Starting at (x0, f0) move along the direction p to find a minimum
|
|
Packit |
67cb25 |
f(x0 - lambda * p), returning the new point x1 = x0-lambda*p,
|
|
Packit |
67cb25 |
f1=f(x1) and g1 = grad(f) at x1. */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double u = stepb;
|
|
Packit |
67cb25 |
double v = stepa;
|
|
Packit |
67cb25 |
double w = stepc;
|
|
Packit |
67cb25 |
double fu = fb;
|
|
Packit |
67cb25 |
double fv = fa;
|
|
Packit |
67cb25 |
double fw = fc;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double old2 = fabs(w - v);
|
|
Packit |
67cb25 |
double old1 = fabs(v - u);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double stepm, fm, pg, gnorm1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int iter = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy (x2, x1);
|
|
Packit |
67cb25 |
gsl_vector_memcpy (dx2, dx1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*f = fb;
|
|
Packit |
67cb25 |
*step = stepb;
|
|
Packit |
67cb25 |
*gnorm = gsl_blas_dnrm2 (gradient);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
mid_trial:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
iter++;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (iter > 10)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return; /* MAX ITERATIONS */
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double dw = w - u;
|
|
Packit |
67cb25 |
double dv = v - u;
|
|
Packit |
67cb25 |
double du = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double e1 = ((fv - fu) * dw * dw + (fu - fw) * dv * dv);
|
|
Packit |
67cb25 |
double e2 = 2.0 * ((fv - fu) * dw + (fu - fw) * dv);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (e2 != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
du = e1 / e2;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (du > 0.0 && du < (stepc - stepb) && fabs(du) < 0.5 * old2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepm = u + du;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (du < 0.0 && du > (stepa - stepb) && fabs(du) < 0.5 * old2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepm = u + du;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if ((stepc - stepb) > (stepb - stepa))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepm = 0.38 * (stepc - stepb) + stepb;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepm = stepb - 0.38 * (stepb - stepa);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
take_step (x, p, stepm, lambda, x1, dx1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
fm = GSL_MULTIMIN_FN_EVAL_F (fdf, x1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#ifdef DEBUG
|
|
Packit |
67cb25 |
printf ("trying stepm = %g fm = %.18e\n", stepm, fm);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fm > fb)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (fm < fv)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
w = v;
|
|
Packit |
67cb25 |
v = stepm;
|
|
Packit |
67cb25 |
fw = fv;
|
|
Packit |
67cb25 |
fv = fm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (fm < fw)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
w = stepm;
|
|
Packit |
67cb25 |
fw = fm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (stepm < stepb)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepa = stepm;
|
|
Packit |
67cb25 |
fa = fm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepc = stepm;
|
|
Packit |
67cb25 |
fc = fm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
goto mid_trial;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (fm <= fb)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
old2 = old1;
|
|
Packit |
67cb25 |
old1 = fabs(u - stepm);
|
|
Packit |
67cb25 |
w = v;
|
|
Packit |
67cb25 |
v = u;
|
|
Packit |
67cb25 |
u = stepm;
|
|
Packit |
67cb25 |
fw = fv;
|
|
Packit |
67cb25 |
fv = fu;
|
|
Packit |
67cb25 |
fu = fm;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy (x2, x1);
|
|
Packit |
67cb25 |
gsl_vector_memcpy (dx2, dx1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
GSL_MULTIMIN_FN_EVAL_DF (fdf, x1, gradient);
|
|
Packit |
67cb25 |
gsl_blas_ddot (p, gradient, &pg;;
|
|
Packit |
67cb25 |
gnorm1 = gsl_blas_dnrm2 (gradient);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#ifdef DEBUG
|
|
Packit |
67cb25 |
printf ("p: "); gsl_vector_fprintf(stdout, p, "%g");
|
|
Packit |
67cb25 |
printf ("g: "); gsl_vector_fprintf(stdout, gradient, "%g");
|
|
Packit |
67cb25 |
printf ("gnorm: %.18e\n", gnorm1);
|
|
Packit |
67cb25 |
printf ("pg: %.18e\n", pg);
|
|
Packit |
67cb25 |
printf ("orth: %g\n", fabs (pg * lambda/ gnorm1));
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
*f = fm;
|
|
Packit |
67cb25 |
*step = stepm;
|
|
Packit |
67cb25 |
*gnorm = gnorm1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs (pg * lambda / gnorm1) < tol)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
#ifdef DEBUG
|
|
Packit |
67cb25 |
printf("ok!\n");
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
return; /* SUCCESS */
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (stepm < stepb)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepc = stepb;
|
|
Packit |
67cb25 |
fc = fb;
|
|
Packit |
67cb25 |
stepb = stepm;
|
|
Packit |
67cb25 |
fb = fm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
stepa = stepb;
|
|
Packit |
67cb25 |
fa = fb;
|
|
Packit |
67cb25 |
stepb = stepm;
|
|
Packit |
67cb25 |
fb = fm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
goto mid_trial;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|