Skip to content

fix: Nautilus/Dynesty test mode yields ESS=1, crashing corner_cornerpy #1541

Description

@Jammy2211

Overview

autofit_workspace/scripts/plot/nautilus_plotter.py fails under PyAutoHeart's release profile (PYAUTO_TEST_MODE=1) with corner's ValueError: ... 'range' is not valid or the sample is empty. Diagnosis: Nautilus.apply_test_mode sets n_like_max = 1, so the search stops after its initial 100-point batch with exactly one non-zero weight (ESS = 1). Since 8cdcff3a0 (forward weights= and caller kwargs to corner — correct), the script's range=0.999 becomes a weighted quantile over that single point and collapses to a sliver excluding every row. The data is fine (100 unique rows); the weights are degenerate. The corner guard counts rows, not effective samples, so it never fires. Dynesty.apply_test_mode (maxcall = 1) has the same defect but its plotter is in no_run.yaml.

Plan

  • Make TEST_MODE=1 for the nested samplers deliver what the release profile documents: a small but real posterior (Emcee parity — 20 walkers × 10 steps ≈ 200 evals).
  • Make corner_cornerpy's degeneracy skip use effective sample size, not row count, so a weight-degenerate sample takes the existing logged-skip path instead of crashing.
  • Leave the workspace script's range=0.999 alone — it is legitimate for a converged posterior.
  • Unit tests for both; verify nautilus_plotter.py and emcee_plotter.py pass under profile_release.yaml with a wiped output/test_mode.
Detailed implementation plan

Affected Repositories

  • PyAutoFit (primary)

Branch Survey

Repository Current Branch Dirty?
./PyAutoFit main clean

Suggested branch: feature/nautilus-test-mode-degenerate-corner

Implementation Steps

  1. autofit/non_linear/search/nest/nautilus/search.py apply_test_mode: replace n_like_max = 1 with a small real budget — reduce n_live (and n_eff if set) and set n_like_max to a few hundred, calibrated empirically so nautilus_plotter.py yields ESS ≥ ~20 in a few seconds. Update test_autofit/non_linear/search/nest/test_nautilus.py:65.
  2. autofit/non_linear/search/nest/dynesty/search/abstract.py apply_test_mode: same treatment for maxcall = 1 (small nlive, maxcall of a few hundred). Check test_autofit/interpolator/test_covariance.py which relies on maxcall=1 explicitly (it passes it directly, so unaffected — confirm).
  3. autofit/non_linear/plot/samples_plotters.py corner_cornerpy: compute ESS from samples.weight_list (sum(w)**2 / sum(w**2), or count of non-zero weights) and skip via the existing logger.info path when ESS <= n_params, alongside the row-count check. Do not add try/except around corner.corner.
  4. Tests in test_autofit/non_linear/plot/test_samples_plotters.py: weight-degenerate sample (many rows, one non-zero weight) with a caller range array → logged skip, no exception; healthy weights still plot.
  5. Verify: wipe autofit_workspace/output/test_mode, run nautilus_plotter.py and emcee_plotter.py with profile_release.yaml env from workspace CWD; also time one autolens_workspace Nautilus modeling script under TEST_MODE=1 before/after to confirm the release-wave runtime cost stays small.

Key Files

  • autofit/non_linear/search/nest/nautilus/search.pyapply_test_mode
  • autofit/non_linear/search/nest/dynesty/search/abstract.pyapply_test_mode
  • autofit/non_linear/plot/samples_plotters.pycorner_cornerpy guard

Original Prompt

Click to expand starting prompt

nautilus_plotter.py corner_cornerpy raises ValueError "range is not valid or the sample…

Type: bug
Target: PyAutoFit
Repos:

  • PyAutoFit
  • autofit_workspace
  • PyAutoHeart
    Difficulty: medium
    Autonomy: supervised
    Priority: normal
    Status: formalised

Found 2026-08-28 by PyAutoHeart's Release Integrate run
https://github.com/PyAutoLabs/PyAutoHeart/actions/runs/33177898708, job
integrate / run_scripts (3.12, autofit, plot), env profile
profile_release.yaml. Failed after 3.1s.

autofit_workspace/scripts/plot/nautilus_plotter.py fails; the sibling
emcee_plotter.py passed (8.3s) in the same job, and dynesty_plotter.py,
get_dist.py, zeus_plotter.py are skipped, so nautilus is the only live
failure in that directory.

Traceback tail

Preceded by three warnings that are themselves the tell — the sample handed to
corner is degenerate before corner ever rejects it:

scipy/stats/_kde.py:588: RuntimeWarning: Degrees of freedom <= 0 for slice
  self._data_covariance = atleast_2d(cov(self.dataset, rowvar=1,
numpy/lib/_function_base_impl.py:2901: RuntimeWarning: divide by zero encountered in divide
  c *= np.true_divide(1, fact)
corner/core.py:922: UserWarning: Attempting to set identical low and high ylims
  makes transformation singular; automatically expanding.

then:

Traceback (most recent call last):
  File ".../workspace/scripts/plot/nautilus_plotter.py", line 106, in <module>
    aplt.corner_cornerpy(
  File ".../autofit/non_linear/plot/plot_util.py", line 112, in wrapper
    return func(*args, **kwargs)
  File ".../autofit/non_linear/plot/samples_plotters.py", line 80, in corner_cornerpy
    corner.corner(data=data, **settings)
  File ".../corner/corner.py", line 248, in corner
    return corner_impl(
  File ".../corner/core.py", line 370, in corner_impl
    hist2d(
  File ".../corner/core.py", line 687, in hist2d
    raise ValueError(
ValueError: It looks like the provided 'range' is not valid or the sample is empty.

It did NOT fail under smoke

This did not reproduce in the same day's Workspace Smoke run
(https://github.com/PyAutoLabs/PyAutoHeart/actions/runs/33179766004). So it may
well be release-profile specific: the release profile runs the sampler for
real rather than in the truncated smoke configuration, so the Nautilus samples
object the plotter is handed differs between the two profiles. Establish which
profile produces which sample shape before assuming a plotting bug.

What to investigate

  • Reproduce under profile_release.yaml (not smoke) with the workspace CWD.
  • Determine what data actually is at samples_plotters.py:80 — empty,
    single-row, or zero-variance in one or more parameters. The Degrees of freedom <= 0 KDE warning points at a sample with <= 1 effective row for at
    least one slice.
  • Then decide the locus: is the Nautilus samples -> corner data conversion in
    PyAutoFit dropping or collapsing samples, or is the workspace script asking
    for a corner plot of a search result that legitimately has too few samples
    under this profile?

Out of scope

Do not fix this by try/excepting the plot call, by skipping the script, or by
adding a silent "if the sample is empty, return" guard. If the sample really is
degenerate, the fix is upstream of the plot.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions