diff --git a/botorch/optim/utils/timeout.py b/botorch/optim/utils/timeout.py index f1e3460f76..e8b45d39e0 100644 --- a/botorch/optim/utils/timeout.py +++ b/botorch/optim/utils/timeout.py @@ -14,6 +14,7 @@ import numpy.typing as npt from botorch.exceptions.errors import OptimizationTimeoutError from scipy import optimize +from threadpoolctl import threadpool_limits def minimize_with_timeout( @@ -79,20 +80,23 @@ def wrapped_callback(xk: npt.NDArray) -> None: try: warnings.filterwarnings("error", message="Method .* cannot handle") - return optimize.minimize( - fun=fun, - x0=x0, - args=args, - method=method, - jac=jac, - hess=hess, - hessp=hessp, - bounds=bounds, - constraints=constraints, - tol=tol, - callback=wrapped_callback, - options=options, - ) + # To prevent slowdowns after scipy 1.15. + # See https://github.com/scipy/scipy/issues/22438. + with threadpool_limits(limits=1, user_api="blas"): + return optimize.minimize( + fun=fun, + x0=x0, + args=args, + method=method, + jac=jac, + hess=hess, + hessp=hessp, + bounds=bounds, + constraints=constraints, + tol=tol, + callback=wrapped_callback, + options=options, + ) except OptimizationTimeoutError as e: msg = f"Optimization timed out after {e.runtime} seconds." current_fun, *_ = fun(e.current_x, *args) diff --git a/requirements.txt b/requirements.txt index 2be9341c93..f2d5ed7dae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,6 @@ gpytorch==1.14 linear_operator==0.6 torch>=2.0.1 pyro-ppl>=1.8.4 -scipy<1.15 +scipy multipledispatch +threadpoolctl