Permalink
Browse files

BUG: make sure fmin_bfgs doesn't get stuck in infinite loop. Closes #…

  • Loading branch information...
1 parent bb4c46f commit a31acbf966f50665997d1fd1ced41d3a8b3e4187 @rgommers rgommers committed Aug 15, 2011
Showing with 24 additions and 5 deletions.
  1. +11 −5 scipy/optimize/optimize.py
  2. +13 −0 scipy/optimize/tests/test_optimize.py
View
@@ -559,6 +559,12 @@ def fmin_bfgs(f, x0, fprime=None, args=(), gtol=1e-5, norm=Inf,
if (gnorm <= gtol):
break
+ if not numpy.isfinite(old_fval):
+ # We correctly found +-Inf as optimal value, or something went
+ # wrong.
+ warnflag = 2
+ break
+
try: # this was handled in numeric, let it remaines for more safety
rhok = 1.0 / (numpy.dot(yk,sk))
except ZeroDivisionError:
@@ -1563,11 +1569,11 @@ def fmin_powell(func, x0, args=(), xtol=1e-4, ftol=1e-4, maxiter=None,
The technical conditions for replacing the direction of greatest
increase amount to checking that
- 1. No further gain can be made along the
- direction of greatest increase from that iteration
- 2.The direction of greatest increase accounted for a large sufficient
- fraction of the decrease in the function value from that
- iteration of the inner loop.
+ 1. No further gain can be made along the direction of greatest increase
+ from that iteration.
+ 2. The direction of greatest increase accounted for a large sufficient
+ fraction of the decrease in the function value from that iteration of
+ the inner loop.
References
@@ -105,6 +105,19 @@ def test_bfgs(self):
atol=1e-14, rtol=1e-7), self.trace[6:8])
+ def test_bfgs_infinite(self):
+ """Test corner case where -Inf is the minimum. See #1494."""
+ func = lambda x: -np.e**-x
+ fprime = lambda x: -func(x)
+ x0 = [0]
+ olderr = np.seterr(over='ignore')
+ try:
+ x = optimize.fmin_bfgs(func, x0, fprime, disp=False)
+ assert_(not np.isfinite(func(x)))
+ finally:
+ np.seterr(**olderr)
+
+
def test_powell(self):
""" Powell (direction set) optimization routine
"""

1 comment on commit a31acbf

Contributor

johannct commented on a31acbf Oct 24, 2011

this code seems to fix the occurrence of infinites. In the case of a nan returned value, the problem is different in the sense that the linesearch_wolfe1 internal loop within the "while 1" statement never exits. Looks like we need something like this patch :
diff --git a/scipy/optimize/linesearch.py b/scipy/optimize/linesearch.py
index 02e9375..f858744 100644
--- a/scipy/optimize/linesearch.py
+++ b/scipy/optimize/linesearch.py
@@ -145,7 +145,10 @@ def scalar_search_wolfe1(phi, derphi, phi0=None, old_phi0=None, derphi0=None,
stp, phi1, derphi1, task = minpack2.dcsrch(alpha1, phi1, derphi1,
c1, c2, xtol, task,
amin, amax, isave, dsave)

  •    if task[:2] == asbytes('FG'):
    
  •    if np.isnan(phi1):
    
  •        task[:5] == asbytes('ERROR')
    
  •        break
    
  •     if task[:2] == asbytes('FG'):
    
    alpha1 = stp
    phi1 = phi(stp)
    derphi1 = derphi(stp)
Please sign in to comment.