From 7eb418b805e279bb3ee9c4f8e14a8be577ed3628 Mon Sep 17 00:00:00 2001 From: naoaki Date: Thu, 10 Jul 2008 13:06:47 +0000 Subject: [PATCH] Implemented a stopping criterion. git-svn-id: file:///home/svnrepos/software/liblbfgs/trunk@21 ecf4c44f-38d1-4fa4-9757-a0b4dd0349fc --- include/lbfgs.h | 11 ++++++++++ lib/lbfgs.c | 53 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/include/lbfgs.h b/include/lbfgs.h index 5223eef..808586e 100644 --- a/include/lbfgs.h +++ b/include/lbfgs.h @@ -74,6 +74,8 @@ typedef double lbfgsfloatval_t; enum { /** L-BFGS reaches convergence. */ LBFGS_SUCCESS = 0, + LBFGS_CONVERGENCE = 0, + LBFGS_STOP, /** The initial variables already minimize the objective function. */ LBFGS_ALREADY_MINIMIZED, @@ -91,6 +93,12 @@ enum { LBFGSERR_INVALID_N_SSE, /** The array x must be aligned to 16 (for SSE). */ LBFGSERR_INVALID_X_SSE, + /** Invalid parameter lbfgs_parameter_t::epsilon specified. */ + LBFGSERR_INVALID_EPSILON, + /** Invalid parameter lbfgs_parameter_t::past specified. */ + LBFGSERR_INVALID_TESTPERIOD, + /** Invalid parameter lbfgs_parameter_t::delta specified. */ + LBFGSERR_INVALID_DELTA, /** Invalid parameter lbfgs_parameter_t::linesearch specified. */ LBFGSERR_INVALID_LINESEARCH, /** Invalid parameter lbfgs_parameter_t::max_step specified. */ @@ -172,6 +180,9 @@ typedef struct { */ lbfgsfloatval_t epsilon; + int past; + lbfgsfloatval_t delta; + /** * The maximum number of iterations. * The lbfgs() function terminates an optimization process with diff --git a/lib/lbfgs.c b/lib/lbfgs.c index 76c202e..420e71a 100644 --- a/lib/lbfgs.c +++ b/lib/lbfgs.c @@ -111,7 +111,8 @@ struct tag_iteration_data { typedef struct tag_iteration_data iteration_data_t; static const lbfgs_parameter_t _defparam = { - 6, 1e-5, 0, LBFGS_LINESEARCH_DEFAULT, 20, + 6, 1e-5, 0, 1e-5, + 0, LBFGS_LINESEARCH_DEFAULT, 20, 1e-20, 1e20, 1e-4, 0.9, 1.0e-16, 0.0, 0, }; @@ -255,11 +256,12 @@ int lbfgs( const lbfgs_parameter_t* param = (_param != NULL) ? _param : &_defparam; const int m = param->m; - lbfgsfloatval_t *xp = NULL, *g = NULL, *gp = NULL, *d = NULL, *w = NULL; + lbfgsfloatval_t *xp = NULL, *g = NULL, *gp = NULL, *d = NULL, *w = NULL, *pf = NULL; iteration_data_t *lm = NULL, *it = NULL; lbfgsfloatval_t ys, yy; lbfgsfloatval_t xnorm, gnorm, beta; lbfgsfloatval_t fx = 0.; + lbfgsfloatval_t rate = 0.; line_search_proc linesearch = line_search_morethuente; /* Construct a callback data. */ @@ -286,6 +288,15 @@ int lbfgs( return LBFGSERR_INVALID_X_SSE; } #endif/*defined(USE_SSE)*/ + if (param->epsilon < 0.) { + return LBFGSERR_INVALID_EPSILON; + } + if (param->past < 0) { + return LBFGSERR_INVALID_TESTPERIOD; + } + if (param->delta < 0.) { + return LBFGSERR_INVALID_DELTA; + } if (param->min_step < 0.) { return LBFGSERR_INVALID_MINSTEP; } @@ -352,6 +363,11 @@ int lbfgs( } } + /* Allocate an array for storing previous values of the objective function. */ + if (0 < param->past) { + pf = (lbfgsfloatval_t*)vecalloc(param->past * sizeof(lbfgsfloatval_t)); + } + /* Evaluate the function value and its gradient. */ fx = cd.proc_evaluate(cd.instance, x, g, cd.n, 0); if (0. != param->orthantwise_c) { @@ -360,6 +376,11 @@ int lbfgs( fx += xnorm * param->orthantwise_c; } + /* Store the initial value of the objective function. */ + if (pf != NULL) { + pf[0] = fx; + } + /* Compute the direction; we assume the initial hessian matrix H_0 as the identity matrix. @@ -431,6 +452,28 @@ int lbfgs( break; } + /* + Test for stopping criterion. + The criterion is given by the following formula: + (f(past_x) - f(x)) / f(x) < \delta + */ + if (pf != NULL) { + /* We don't test the stopping criterion while k < past. */ + if (param->past <= k) { + /* Compute the relative improvement from the past. */ + rate = (pf[k % param->past] - fx) / fx; + + /* The stopping criterion. */ + if (rate < param->delta) { + ret = LBFGS_STOP; + break; + } + } + + /* Store the current value of the objective function. */ + pf[k % param->past] = fx; + } + if (param->max_iterations != 0 && param->max_iterations < k+1) { /* Maximum number of iterations. */ ret = LBFGSERR_MAXIMUMITERATION; @@ -524,6 +567,8 @@ lbfgs_exit: *ptr_fx = fx; } + vecfree(pf); + /* Free memory blocks used by this function. */ if (lm != NULL) { for (i = 0;i < m;++i) { @@ -555,7 +600,7 @@ static int line_search_backtracking( const lbfgs_parameter_t *param ) { - int i, ret = 0, count = 0; + int ret = 0, count = 0; lbfgsfloatval_t width = 0.5, norm = 0.; lbfgsfloatval_t finit, dginit = 0., dgtest; @@ -639,7 +684,7 @@ static int line_search_morethuente( const lbfgs_parameter_t *param ) { - int i, count = 0; + int count = 0; int brackt, stage1, uinfo = 0; lbfgsfloatval_t dg, norm; lbfgsfloatval_t stx, fx, dgx;