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); if (gsl_vector_equal (x, x1)) { /* Take fast exit if trial point does not move from initial point */ #ifdef DEBUG printf ("fast exit x == x1 for stepb = %g\n", stepb); #endif *step = 0; *f = fa; GSL_MULTIMIN_FN_EVAL_DF(fdf, x1, gradient); return ; } 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 double wrap_df(double alpha, void *params) { wrapper_t *w = (wrapper_t *) params; if (alpha == w->df_cache_key) { /* using previously cached df(alpha) */ return w->df_alpha; } moveto(alpha, w); if (alpha != w->g_cache_key) { GSL_MULTIMIN_FN_EVAL_DF(w->fdf, w->x_alpha, w->g_alpha); w->g_cache_key = alpha; } w->df_alpha = slope(w); w->df_cache_key = alpha; return w->df_alpha; }
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; } }
static int conjugate_fr_iterate (void *vstate, gsl_multimin_function_fdf * fdf, gsl_vector * x, double *f, gsl_vector * gradient, gsl_vector * dx) { conjugate_fr_state_t *state = (conjugate_fr_state_t *) vstate; gsl_vector *x1 = state->x1; gsl_vector *dx1 = state->dx1; gsl_vector *x2 = state->x2; gsl_vector *p = state->p; gsl_vector *g0 = state->g0; double pnorm = state->pnorm; double g0norm = state->g0norm; double fa = *f, fb, fc; double dir; double stepa = 0.0, stepb, stepc = state->step, tol = state->tol; double g1norm; double pg; if (pnorm == 0.0 || g0norm == 0.0) { gsl_vector_set_zero (dx); return GSL_ENOPROG; } /* Determine which direction is downhill, +p or -p */ gsl_blas_ddot (p, gradient, &pg); dir = (pg >= 0.0) ? +1.0 : -1.0; /* Compute new trial point at x_c= x - step * p, where p is the current direction */ take_step (x, p, stepc, dir / pnorm, x1, dx); /* Evaluate function and gradient at new point xc */ fc = GSL_MULTIMIN_FN_EVAL_F (fdf, x1); if (fc < fa) { /* Success, reduced the function value */ state->step = stepc * 2.0; *f = fc; gsl_vector_memcpy (x, x1); GSL_MULTIMIN_FN_EVAL_DF (fdf, x1, gradient); return GSL_SUCCESS; } #ifdef DEBUG printf ("got stepc = %g fc = %g\n", stepc, fc); #endif /* Do a line minimisation in the region (xa,fa) (xc,fc) to find an intermediate (xb,fb) satisifying fa > fb < fc. Choose an initial xb based on parabolic interpolation */ intermediate_point (fdf, x, p, dir / pnorm, pg, stepa, stepc, fa, fc, x1, dx1, gradient, &stepb, &fb); if (stepb == 0.0) { return GSL_ENOPROG; } minimize (fdf, x, p, dir / pnorm, stepa, stepb, stepc, fa, fb, fc, tol, x1, dx1, x2, dx, gradient, &(state->step), f, &g1norm); gsl_vector_memcpy (x, x2); /* Choose a new conjugate direction for the next step */ state->iter = (state->iter + 1) % x->size; if (state->iter == 0) { gsl_vector_memcpy (p, gradient); state->pnorm = g1norm; } else { /* p' = g1 - beta * p */ double beta = -pow (g1norm / g0norm, 2.0); gsl_blas_dscal (-beta, p); gsl_blas_daxpy (1.0, gradient, p); state->pnorm = gsl_blas_dnrm2 (p); } state->g0norm = g1norm; gsl_vector_memcpy (g0, gradient); #ifdef DEBUG printf ("updated conjugate directions\n"); printf ("p: "); gsl_vector_fprintf (stdout, p, "%g"); printf ("g: "); gsl_vector_fprintf (stdout, gradient, "%g"); #endif return GSL_SUCCESS; }
static int vector_bfgs_iterate (void *vstate, gsl_multimin_function_fdf * fdf, gsl_vector * x, double *f, gsl_vector * gradient, gsl_vector * dx) { vector_bfgs_state_t *state = (vector_bfgs_state_t *) vstate; gsl_vector *x1 = state->x1; gsl_vector *dx1 = state->dx1; gsl_vector *x2 = state->x2; gsl_vector *p = state->p; gsl_vector *g0 = state->g0; gsl_vector *x0 = state->x0; double pnorm = state->pnorm; double g0norm = state->g0norm; double fa = *f, fb, fc; double dir; double stepa = 0.0, stepb, stepc = state->step, tol = state->tol; double g1norm; double pg; if (pnorm == 0.0 || g0norm == 0.0) { gsl_vector_set_zero (dx); return GSL_ENOPROG; } /* Determine which direction is downhill, +p or -p */ gsl_blas_ddot (p, gradient, &pg); dir = (pg >= 0.0) ? +1.0 : -1.0; /* Compute new trial point at x_c= x - step * p, where p is the current direction */ take_step (x, p, stepc, dir / pnorm, x1, dx); /* Evaluate function and gradient at new point xc */ fc = GSL_MULTIMIN_FN_EVAL_F (fdf, x1); if (fc < fa) { /* Success, reduced the function value */ state->step = stepc * 2.0; *f = fc; gsl_vector_memcpy (x, x1); GSL_MULTIMIN_FN_EVAL_DF (fdf, x1, gradient); return GSL_SUCCESS; } #ifdef DEBUG printf ("got stepc = %g fc = %g\n", stepc, fc); #endif /* Do a line minimisation in the region (xa,fa) (xc,fc) to find an intermediate (xb,fb) satisifying fa > fb < fc. Choose an initial xb based on parabolic interpolation */ intermediate_point (fdf, x, p, dir / pnorm, pg, stepa, stepc, fa, fc, x1, dx1, gradient, &stepb, &fb); if (stepb == 0.0) { return GSL_ENOPROG; } minimize (fdf, x, p, dir / pnorm, stepa, stepb, stepc, fa, fb, fc, tol, x1, dx1, x2, dx, gradient, &(state->step), f, &g1norm); gsl_vector_memcpy (x, x2); /* Choose a new direction for the next step */ state->iter = (state->iter + 1) % x->size; if (state->iter == 0) { gsl_vector_memcpy (p, gradient); state->pnorm = g1norm; } else { /* This is the BFGS update: */ /* p' = g1 - A dx - B dg */ /* A = - (1+ dg.dg/dx.dg) B + dg.g/dx.dg */ /* B = dx.g/dx.dg */ gsl_vector *dx0 = state->dx0; gsl_vector *dg0 = state->dg0; double dxg, dgg, dxdg, dgnorm, A, B; /* dx0 = x - x0 */ gsl_vector_memcpy (dx0, x); gsl_blas_daxpy (-1.0, x0, dx0); /* dg0 = g - g0 */ gsl_vector_memcpy (dg0, gradient); gsl_blas_daxpy (-1.0, g0, dg0); gsl_blas_ddot (dx0, gradient, &dxg); gsl_blas_ddot (dg0, gradient, &dgg); gsl_blas_ddot (dx0, dg0, &dxdg); dgnorm = gsl_blas_dnrm2 (dg0); if (dxdg != 0) { B = dxg / dxdg; A = -(1.0 + dgnorm * dgnorm / dxdg) * B + dgg / dxdg; } else { B = 0; A = 0; } gsl_vector_memcpy (p, gradient); gsl_blas_daxpy (-A, dx0, p); gsl_blas_daxpy (-B, dg0, p); state->pnorm = gsl_blas_dnrm2 (p); } gsl_vector_memcpy (g0, gradient); gsl_vector_memcpy (x0, x); state->g0norm = gsl_blas_dnrm2 (g0); #ifdef DEBUG printf ("updated directions\n"); printf ("p: "); gsl_vector_fprintf (stdout, p, "%g"); printf ("g: "); gsl_vector_fprintf (stdout, gradient, "%g"); #endif return GSL_SUCCESS; }