Skip to content
This repository

[lbfgsb] Adding a maximum iterations stopping condition #318

Closed
wants to merge 2 commits into from

2 participants

Gilles Rochefort Denis Laxalde
Gilles Rochefort

Here consider a new stopping condition for the l-bfgs-b based on maximum number of iterations (and not maximum number of function evaluations)

scipy/optimize/lbfgsb.py
... ... @@ -98,6 +98,11 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
98 98 `iprint` (i.e., `iprint` gets the value of `disp`).
99 99 maxfun : int
100 100 Maximum number of function evaluations.
  101 + maxiter : int
  102 + Maximum number of iterations.
1
Denis Laxalde Collaborator
dlax added a note

tab; please use whitespaces only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
scipy/optimize/lbfgsb.py
... ... @@ -168,13 +173,16 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
168 173 'ftol' : factr * np.finfo(float).eps,
169 174 'gtol' : pgtol,
170 175 'eps' : epsilon,
171   - 'maxiter': maxfun}
  176 + 'maxfun': maxfun,
  177 + 'maxiter': maxiter,
  178 + 'callback': callback }
1
Denis Laxalde Collaborator
dlax added a note

tab

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
scipy/optimize/lbfgsb.py
... ... @@ -183,8 +191,8 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
183 191
184 192 def _minimize_lbfgsb(fun, x0, args=(), jac=None, bounds=None,
185 193 disp=None, maxcor=10, ftol=2.2204460492503131e-09,
186   - gtol=1e-5, eps=1e-8, maxiter=15000, iprint=-1,
187   - **unknown_options):
  194 + gtol=1e-5, eps=1e-8, maxfun=15000, maxiter=15000, iprint=-1,
1
Denis Laxalde Collaborator
dlax added a note

line width must be below 80 characters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
scipy/optimize/lbfgsb.py
... ... @@ -281,6 +292,8 @@ def func_and_grad(x):
281 292 task[:] = 'START'
282 293
283 294 n_function_evals = 0
  295 + n_iterations = 0
  296 +
1
Denis Laxalde Collaborator
dlax added a note

trailing whitespaces, to be removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
scipy/optimize/lbfgsb.py
((10 lines not shown))
297 304 if n_function_evals > maxfun:
298 305 task[:] = 'STOP: TOTAL NO. of f AND g EVALUATIONS EXCEEDS LIMIT'
  306 + else:
  307 + # minimization routine wants f and g at the current x
  308 + n_function_evals += 1
  309 + # Overwrite f and g:
  310 + f, g = func_and_grad(x)
  311 + elif task_str.startswith(asbytes('NEW_X')):
  312 + # new iteration
  313 + if n_iterations > maxiter:
  314 + task[:] = 'STOP: TOTAL NO. of ITERATIONS EXCEEDS LIMIT'
  315 + else:
  316 + n_iterations += 1
  317 + if callback is not None:
  318 + callback(x)
1
Denis Laxalde Collaborator
dlax added a note

tabs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
scipy/optimize/lbfgsb.py
((5 lines not shown))
314 337 'warnflag' : warnflag
315 338 }
316   -
317   - return Result(fun=f, jac=g, nfev=n_function_evals, status=warnflag,
  339 +
  340 + return Result(fun=f, jac=g, nfev=n_function_evals, nit=n_iterations, status=warnflag,
318 341 message=task_str, x=x, success=(warnflag==0))
1
Denis Laxalde Collaborator
dlax added a note

line too long and trailing whitespaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Denis Laxalde
Collaborator

This looks good. If you could correct style issues, change the commit messages to conform with SciPy's style (i.e. ENH: blah blah) and then rebase your branch, I'll merge it.

Thank you for your contribution.

scipy/optimize/lbfgsb.py
... ... @@ -221,7 +231,8 @@ def _minimize_lbfgsb(fun, x0, args=(), jac=None, bounds=None,
221 231 _check_unknown_options(unknown_options)
222 232 m = maxcor
223 233 epsilon = eps
224   - maxfun = maxiter
  234 + maxiter = maxiter
  235 + maxfun = maxfun
225 236 pgtol = gtol
1
Denis Laxalde Collaborator
dlax added a note

Also, these two lines are useless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Gilles Rochefort
Gilles Rochefort
Denis Laxalde dlax closed this
Denis Laxalde
Collaborator

Merged, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.

Showing 2 changed files with 39 additions and 18 deletions. Show diff stats Hide diff stats

  1. +1 1  scipy/optimize/_minimize.py
  2. +38 17 scipy/optimize/lbfgsb.py
2  scipy/optimize/_minimize.py
@@ -303,7 +303,7 @@ def minimize(fun, x0, args=(), method='BFGS', jac=None, hess=None,
303 303 warn('Method %s cannot handle bounds.' % method,
304 304 RuntimeWarning)
305 305 # - callback
306   - if (meth in ['anneal', 'l-bfgs-b', 'tnc', 'cobyla', 'slsqp'] and
  306 + if (meth in ['anneal', 'tnc', 'cobyla', 'slsqp'] and
307 307 callback is not None):
308 308 warn('Method %s does not support callback.' % method,
309 309 RuntimeWarning)
55 scipy/optimize/lbfgsb.py
@@ -46,7 +46,8 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
46 46 approx_grad=0,
47 47 bounds=None, m=10, factr=1e7, pgtol=1e-5,
48 48 epsilon=1e-8,
49   - iprint=-1, maxfun=15000, disp=None):
  49 + iprint=-1, maxfun=15000, maxiter=15000, disp=None,
  50 + callback=None):
50 51 """
51 52 Minimize a function func using the L-BFGS-B algorithm.
52 53
@@ -98,6 +99,11 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
98 99 `iprint` (i.e., `iprint` gets the value of `disp`).
99 100 maxfun : int
100 101 Maximum number of function evaluations.
  102 + maxiter : int
  103 + Maximum number of iterations.
  104 + callback : callable, optional
  105 + Called after each iteration, as ``callback(xk)``, where ``xk`` is the
  106 + current parameter vector.
101 107
102 108 Returns
103 109 -------
@@ -111,7 +117,7 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
111 117 * d['warnflag'] is
112 118
113 119 - 0 if converged,
114   - - 1 if too many function evaluations,
  120 + - 1 if too many function evaluations or too many iterations,
115 121 - 2 if stopped for another reason, given in d['task']
116 122
117 123 * d['grad'] is the gradient at the minimum (should be 0 ish)
@@ -168,13 +174,16 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
168 174 'ftol' : factr * np.finfo(float).eps,
169 175 'gtol' : pgtol,
170 176 'eps' : epsilon,
171   - 'maxiter': maxfun}
  177 + 'maxfun': maxfun,
  178 + 'maxiter': maxiter,
  179 + 'callback': callback }
172 180
173 181 res = _minimize_lbfgsb(fun, x0, args=args, jac=jac, bounds=bounds,
174 182 **opts)
175 183 d = {'grad': res['jac'],
176 184 'task': res['message'],
177 185 'funcalls': res['nfev'],
  186 + 'iter' : res['nit'],
178 187 'warnflag': res['status']}
179 188 f = res['fun']
180 189 x = res['x']
@@ -183,8 +192,8 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
183 192
184 193 def _minimize_lbfgsb(fun, x0, args=(), jac=None, bounds=None,
185 194 disp=None, maxcor=10, ftol=2.2204460492503131e-09,
186   - gtol=1e-5, eps=1e-8, maxiter=15000, iprint=-1,
187   - **unknown_options):
  195 + gtol=1e-5, eps=1e-8, maxfun=15000, maxiter=15000,
  196 + iprint=-1, callback=None, **unknown_options):
188 197 """
189 198 Minimize a scalar function of one or more variables using the L-BFGS-B
190 199 algorithm.
@@ -212,8 +221,10 @@ def _minimize_lbfgsb(fun, x0, args=(), jac=None, bounds=None,
212 221 Step size used for numerical approximation of the jacobian.
213 222 disp : int
214 223 Set to True to print convergence messages.
215   - maxiter : int
  224 + maxfun : int
216 225 Maximum number of function evaluations.
  226 + maxiter : int
  227 + Maximum number of iterations.
217 228
218 229 This function is called by the `minimize` function with
219 230 `method=L-BFGS-B`. It is not supposed to be called directly.
@@ -221,7 +232,6 @@ def _minimize_lbfgsb(fun, x0, args=(), jac=None, bounds=None,
221 232 _check_unknown_options(unknown_options)
222 233 m = maxcor
223 234 epsilon = eps
224   - maxfun = maxiter
225 235 pgtol = gtol
226 236 factr = ftol / np.finfo(float).eps
227 237
@@ -281,6 +291,8 @@ def func_and_grad(x):
281 291 task[:] = 'START'
282 292
283 293 n_function_evals = 0
  294 + n_iterations = 0
  295 +
284 296 while 1:
285 297 # x, f, g, wa, iwa, task, csave, lsave, isave, dsave = \
286 298 _lbfgsb.setulb(m, x, low_bnd, upper_bnd, nbd, f, g, factr,
@@ -288,14 +300,21 @@ def func_and_grad(x):
288 300 isave, dsave)
289 301 task_str = task.tostring()
290 302 if task_str.startswith(asbytes('FG')):
291   - # minimization routine wants f and g at the current x
292   - n_function_evals += 1
293   - # Overwrite f and g:
294   - f, g = func_and_grad(x)
295   - elif task_str.startswith(asbytes('NEW_X')):
296   - # new iteration
297 303 if n_function_evals > maxfun:
298 304 task[:] = 'STOP: TOTAL NO. of f AND g EVALUATIONS EXCEEDS LIMIT'
  305 + else:
  306 + # minimization routine wants f and g at the current x
  307 + n_function_evals += 1
  308 + # Overwrite f and g:
  309 + f, g = func_and_grad(x)
  310 + elif task_str.startswith(asbytes('NEW_X')):
  311 + # new iteration
  312 + if n_iterations > maxiter:
  313 + task[:] = 'STOP: TOTAL NO. of ITERATIONS EXCEEDS LIMIT'
  314 + else:
  315 + n_iterations += 1
  316 + if callback is not None:
  317 + callback(x)
299 318 else:
300 319 break
301 320
@@ -304,19 +323,21 @@ def func_and_grad(x):
304 323 warnflag = 0
305 324 elif n_function_evals > maxfun:
306 325 warnflag = 1
  326 + elif n_iterations > maxiter:
  327 + warnflag = 1
307 328 else:
308 329 warnflag = 2
309 330
310   -
311 331 d = {'grad' : g,
312 332 'task' : task_str,
313 333 'funcalls' : n_function_evals,
  334 + 'iter' : n_iterations,
314 335 'warnflag' : warnflag
315 336 }
316 337
317   - return Result(fun=f, jac=g, nfev=n_function_evals, status=warnflag,
318   - message=task_str, x=x, success=(warnflag==0))
319   -
  338 + return Result(fun=f, jac=g, nfev=n_function_evals, nit=n_iterations,
  339 + status=warnflag, message=task_str, x=x,
  340 + success=(warnflag==0))
320 341
321 342 if __name__ == '__main__':
322 343 def func(x):

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.