Repository: scipy/scipy

Issue:
b'STOP: TOTAL NO. of f AND g EVALUATIONS EXCEEDS LIMIT
### Describe your issue.

Hi guys

Or my understanding of the code is wrong or there is probably a bug here. I run an inversion test with `scipy.minimize(method = l_bfgs_b)` and it stops with the following message: `b'STOP: TOTAL NO. off AND g EVALUATIONS EXCEEDS LIMIT`. However, it does not correspond to the value of `maxfun=20`. Any idea what's going on here? Thanks!

### Reproducing Code Example

```python
# my code:
res_summary = optimize.minimize(
            fun, m_current,
            args=(m_t, model_current, sgs_obs),
            method='L-BFGS-B', jac=True, callback=fwi_callback, bounds=bounds,
            options={'ftol': 1e-6, 'gtol': 1e-20, 'maxfun': 20,
                     'maxiter': 30, 'disp': 99})

#my return:
###L_BFGS_B INVERSION INFORMATION###
Iteration: 1 | Evaluation: 3
Iteration: 2 | Evaluation: 6
Iteration: 3 | Evaluation: 9
Iteration: 4 | Evaluation: 9
```


### Error message

```shell
fun: 94149.87264966885
 hess_inv: <10201x10201 LbfgsInvHessProduct with dtype=float64>
      jac: array([ -37.70637123, -190.42026409, -277.88007295, ...,   -9.08818323,
         13.41612702,   43.94295883])
  message: b'STOP: TOTAL NO. of f AND g EVALUATIONS EXCEEDS LIMIT'
     nfev: 27
      nit: 4
     njev: 27
   status: 1
  success: False
        x: array([0.163554  , 0.16447512, 0.14660401, ..., 0.16269842, 0.16254759,
       0.16232158])
```


### SciPy/NumPy/Python version information

1.5.1 1.18.5 sys.version_info(major=3, minor=7, micro=6, releaselevel='final', serial=0)


Discussion:
Each time LBFGSB goes through the iteration loop it evaluates the user supplied function multiple times, especially if the gradient is estimated by numerical differentiation, which takes at least `N` function evaluations (`N+1` if `f0` has to be evaluated as well).
It's possible that maxfun is exceeded part way through the evaluation loop, during that numerical differentiation. If that's the case then that iteration will still complete, but not go around again. Thus, maxfun may be exceeded by a small amount, hence the error message.

- is there a reason why you set maxfun so low?
- how would you write the error message to improve it?
- how would you write the documentation to improve it?
Related discussion: https://github.com/scipy/scipy/pull/14805#issuecomment-937413098

Resolving patch:
diff --git a/scipy/optimize/_lbfgsb_py.py b/scipy/optimize/_lbfgsb_py.py
--- a/scipy/optimize/_lbfgsb_py.py
+++ b/scipy/optimize/_lbfgsb_py.py
@@ -105,7 +105,9 @@ def fmin_l_bfgs_b(func, x0, fprime=None, args=(),
         If zero, then no output. If a positive number, then this over-rides
         `iprint` (i.e., `iprint` gets the value of `disp`).
     maxfun : int, optional
-        Maximum number of function evaluations.
+        Maximum number of function evaluations. Note that this function
+        may violate the limit because of evaluating gradients by numerical
+        differentiation.
     maxiter : int, optional
         Maximum number of iterations.
     callback : callable, optional
diff --git a/scipy/optimize/_tnc.py b/scipy/optimize/_tnc.py
--- a/scipy/optimize/_tnc.py
+++ b/scipy/optimize/_tnc.py
@@ -147,7 +147,9 @@ def fmin_tnc(func, x0, fprime=None, args=(), approx_grad=0,
         max(1,min(50,n/2)). Defaults to -1.
     maxfun : int, optional
         Maximum number of function evaluation. If None, maxfun is
-        set to max(100, 10*len(x0)). Defaults to None.
+        set to max(100, 10*len(x0)). Defaults to None. Note that this function
+        may violate the limit because of evaluating gradients by numerical
+        differentiation.
     eta : float, optional
         Severity of the line search. If < 0 or > 1, set to 0.25.
         Defaults to -1.


Test patch:
diff --git a/scipy/optimize/tests/test_optimize.py b/scipy/optimize/tests/test_optimize.py
--- a/scipy/optimize/tests/test_optimize.py
+++ b/scipy/optimize/tests/test_optimize.py
@@ -534,7 +534,9 @@ def cost(x):
         return rng.random(1) * 1000  # never converged problem
 
     for imaxfev in [1, 10, 50]:
-        # TODO: extend to more methods
+        # "TNC" and "L-BFGS-B" also supports max function evaluation, but
+        # these may violate the limit because of evaluating gradients
+        # by numerical differentiation. See the discussion in PR #14805.
         for method in ['Powell', 'Nelder-Mead']:
             result = optimize.minimize(cost, rng.random(10),
                                        method=method,