Repository navigation
feat: add n_effective to DynestyDynamic; fix truncated runs under a finite iterations_per_full_update - #1665
Open
samlange04 wants to merge 4 commits into
Open
samlange04 wants to merge 4 commits into
samlange04 wants to merge 4 commits into
Conversation
…le size Expose dynesty's `n_effective` argument on `DynestyDynamic`. It is the minimum effective posterior sample size the dynamic sampler keeps adding batches until it reaches. When left as `None` (the default) the kwarg is not passed, so dynesty's own default (`max(10000, ndim**2)` in 2.x) applies and existing behaviour is unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ion budget Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s_per_full_update `run_search_internal` handed every `run_nested` chunk `maxcall=iterations_per_full_update`. That is right for the static sampler, whose call counter resets per call, but dynesty's dynamic sampler compares `maxcall` with its cumulative `self.ncall`. The second chunk's budget was therefore already spent, dynesty returned without sampling, the no-new-calls criterion fired and a baseline run cut short mid-way was returned as the converged result (ESS of 1 in the reproducer), with `n_effective` never reached. Hidden by the packaged default of 1e99, which gives a single chunk. A cumulative budget alone is not enough: dynesty cannot continue a baseline run that `maxcall` cut short (the next call `reset()`s it, and `resume=True` refuses after `RUN_DONE`). It can, however, add batches across `run_nested` calls. A chunked `DynestyDynamic` run now: - runs the whole baseline in the first chunk (`maxbatch=0`, `maxcall` only if set); - chunks the batch phase by cumulative budget `total_calls + iterations_per_full_update`; - counts calls with the sampler's own `ncall` (what dynesty compares against; `results.ncall` omits batch live-point initialisation and undercounts); - is finished only when a batch chunk stopped strictly inside its budget, or added no calls. These are three per-sampler hooks on `AbstractDynesty` (`maxcall_from`, `chunk_kwargs`, `chunk_is_finished`, plus `total_calls_from`) with the static behaviour as the default, so `DynestyStatic` is unchanged. The `run_search_internal` docstring, which stated the per-call reset for both samplers, is corrected. Verified with a 3-parameter Gaussian fit, `n_effective=3000`: 1e99 gives one chunk, ESS 3944; 1500 now gives baseline + 3 batch chunks + a no-op confirming chunk, ESS 3587, same logZ and parameters, where before it returned 232 samples with ESS 1. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The constructor-argument golden table (PyAutoLabs#1666) was frozen before this branch added n_effective to DynestyDynamic; register it so test_constructor_argument_set passes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
samlange04
force-pushed
the
feature/dynesty-dynamic-n-effective
branch
from
October 8, 2026 13:13
d6612c8 to
e6e7e5e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Discussion: https://github.com/orgs/PyAutoLabs/discussions/33
Two changes to
DynestyDynamic, both motivated by making a dynamic run cheaper while still writing output on the fly.n_effectiveargument. dynesty's dynamic sampler keeps adding batches until the estimated effective sample size reachesn_effective(dynesty 2.x defaultmax(10000, ndim ** 2)). PyAutoFit had no way to set it.DynestyDynamic.__init__now takesn_effective: Optional[int] = None, forwarded torun_nestedonly when notNone, so default behaviour is unchanged. Not an identifier field. No yaml default, following refactor: replace search YAML config with explicit Python defaults #1202.DynestyStaticis left alone because dynesty deprecatesn_effectiveon the staticrun_nested.Fix: a finite
iterations_per_full_updatetruncated a dynamic run.run_search_internalassumed dynesty's per-run call counter resets on everyrun_nestedcall. That is true for the static sampler but the dynamic sampler comparesmaxcallwith its cumulativeself.ncall, so the second chunk got a budget it had already spent, returned without sampling, and the "no new calls" criterion returned a cut-short baseline (ESS about 1, no batches). A baseline run cut bymaxcallalso cannot be continued (the next callreset()s it;resume=Truerefuses afterRUN_DONE), andresults.ncallundercounts the sampler's own counter (it omits batch live-point initialisation).The fix adds per-sampler hooks on
AbstractDynesty(total_calls_from,maxcall_from,chunk_kwargs,chunk_is_finished) whose defaults are the existing static behaviour.DynestyDynamicoverrides them: the first chunk of a chunked run completes the whole baseline (maxbatch=0, no budget), the batch phase is then chunked by cumulative budget, and a batch chunk is finished only if it stopped strictly inside it. Intermediate output for dynamic runs starts after the baseline. Therun_search_internaldocstring records the two samplers' counting conventions.API Changes
DynestyDynamic(n_effective=None): new optional keyword, defaultNone(dynesty's own default applies).AbstractDynesty:total_calls_from,maxcall_from,chunk_kwargs,chunk_is_finished. Defaults reproduce the previous static behaviour.DynestyDynamic.chunkedproperty.DynestyDynamicwith a finiteiterations_per_full_updatenow returns a complete run; its first on-the-fly update happens after the baseline rather than mid-baseline.Test Plan
test_dynesty.py:n_effectiveis passed torun_nestedonly when set; the dynamic hooks give the baseline chunk an unbounded budget andmaxbatch=0, cumulative budgets for batch chunks, and the strict-inside-budget finished criterion; the static defaults are unchanged.iterations_per_full_update=1500: before, ESS about 1 and no batches; after, baseline + 3 batch chunks + 1 no-op, ESS 3587 against 3944 for the same run in a single chunk, same logZ and parameters.n_effective=2000stops batching earlier with the ESS floored at what the baseline gives.DynestyStaticunaffected (4 chunks of about 1500 calls, same result).test_autofit/non_linear/search/nest/: 44 passed, 13 skipped on macOS / Python 3.13 / dynesty 2.1.5, on the branch rebased ontomainat 710f4b3.🤖 Generated with Claude Code