diff --git a/autofit/non_linear/search/nest/dynesty/search/abstract.py b/autofit/non_linear/search/nest/dynesty/search/abstract.py index 8a3d99f7d..484316e79 100644 --- a/autofit/non_linear/search/nest/dynesty/search/abstract.py +++ b/autofit/non_linear/search/nest/dynesty/search/abstract.py @@ -2,6 +2,7 @@ import logging import os +import sys from abc import ABC from pathlib import Path from typing import Dict, Optional, Tuple, Union, TYPE_CHECKING @@ -397,7 +398,12 @@ def iterations_from( if isinstance(self.paths, NullPaths): if self.maxcall is not None: return self.maxcall, self.maxcall - return int(1e99), int(1e99) + # ``sys.maxsize`` rather than ``int(1e99)``: dynesty's dynamic sampler + # computes ``maxcall - ncall`` where ``ncall`` is a numpy int64, and a + # 99-digit Python int overflows that subtraction (OverflowError: + # Python int too large to convert to C long). ``sys.maxsize`` is the + # "unbounded" sentinel dynesty itself uses when ``maxcall=None``. + return sys.maxsize, sys.maxsize try: total_iterations = np.sum(search_internal.results.ncall) diff --git a/test_autofit/non_linear/search/nest/test_dynesty.py b/test_autofit/non_linear/search/nest/test_dynesty.py index 86f72372a..6eaaa2a8b 100644 --- a/test_autofit/non_linear/search/nest/test_dynesty.py +++ b/test_autofit/non_linear/search/nest/test_dynesty.py @@ -62,6 +62,29 @@ def test__explicit_params(): assert search.number_of_cores == 1 +@pytest.mark.parametrize("search_cls", [af.DynestyStatic, af.DynestyDynamic]) +def test__null_paths_iteration_budget_fits_c_long(search_cls): + """ + Without an output directory (NullPaths) the per-chunk budget is "unbounded". + It must be ``sys.maxsize``, not ``int(1e99)``: dynesty's dynamic sampler + subtracts a numpy int64 ``ncall`` from it, which raised + ``OverflowError: Python int too large to convert to C long``. + """ + import sys + from autofit.non_linear.paths.null import NullPaths + + search = search_cls() + assert isinstance(search.paths, NullPaths) + + iterations, total = search.iterations_from(MockDynestySampler(results=None)) + + assert iterations == total == sys.maxsize + assert iterations - np.int64(40) == sys.maxsize - 40 + + search = search_cls(maxcall=100) + assert search.iterations_from(MockDynestySampler(results=None)) == (100, 100) + + @pytest.mark.parametrize("search_cls", [af.DynestyStatic, af.DynestyDynamic]) def test__single_core_builds_no_pool(search_cls, monkeypatch): """