Blame multimin/directional_minimize.c

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
}