Skip to content

Small-datasets cap: read SMALLSHP so capped datasets stop re-simulating, honour PYAUTO_DISABLE_JAX in the interferometer sparse operator, cap mesh shapes with the data - #529

Merged
Jammy2211 merged 1 commit into
mainfrom
claude/ci-test-timing-epic-ke2lul
Sep 6, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
claude/ci-test-timing-epic-ke2lul

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Closes #528. Phase 8c (library leg) of the ci-timing-fast-tests epic (PyAutoMind draft/feature/pyautoheart/ci_timing_fast_tests_epic.md): the three PyAutoArray findings of the phase-8 user-workspace smoke diagnosis (autolens_workspace#536). Merge after PyAutoNerves#160 (library-first): it reads the SMALLSHP card and the disable_jax() predicate that PR adds, both imported defensively so an older autonerves degrades to today's behaviour.

Summary

  • (a) Capped interferometer / multi_dataset datasets stop re-simulating on every run. dataset_util gains SMALLSHP readers, _capped_data_paths (resolving data.fits → {waveband}_data.fits → channel_*/data.fits by exact suffix — the file's own "Known gap"), and _is_capped_at_the_current_cap rewritten around them. One deliberate deviation from the issue's diff: the card records the writing process, not the array, so the diff as written would have kept a 180×180 image written in a capped shell (two existing tests caught it). The card is therefore read with the both-axes contradiction guard the full-resolution branch already applied (_shape_contradicts_the_cap), which still leaves interferometer (n_vis, 2) reachable. Path resolution is widened for the capped (delete → keep) branch only; the destructive branch is unchanged. One existing test that encoded the old always-regenerate contract is rewritten to pin the half that still stands (no card → still regenerates); nothing skipped or loosened.
  • (b) apply_sparse_operator honours PYAUTO_DISABLE_JAX=1 on the interferometer dataset via autonerves.test_mode.disable_jax(). Backed off on imaging with evidence: that method has no use_jax argument — it is the JAX implementation, its NumPy sibling apply_sparse_operator_cpu returns a different operator class and needs numba, and every measured JIT cost was interferometer. Documented in its docstring.
  • (c) Mesh shape= honours PYAUTO_SMALL_DATASETS like Grid2D.uniform / Mask2D.circular: cap_mesh_shape_for_small_datasets (per axis, min) in the rectangular mesh family's single self.shape assignment and image_mesh.Overlay, with the respect_small_datasets=True hatch threaded through the subclasses (not stored on the instance, so __eq__ / serialization are untouched). This subsumes the four script guards HowToLens#77 / HowToGalaxy#73 added (they now resolve to the same (16, 16) and can be reverted) and reaches ~28 further call sites.

Validation (this container, branches of the three libraries installed editable)

  • PyAutoArray suite: 1449 passed.
  • autolens_workspace_test gate 27/27, autogalaxy_workspace_test gate 39/39 (the _test JAX scripts run uncapped, so their pins did not move).
  • Re-simulation: should_simulate True → False on the second run of autolens_workspace interferometer/modeling.py (12.40 → 6.69 s warm), multi_dataset/modeling.py (10.48 → 6.32 s), autogalaxy_workspace interferometer/start_here.py (10.93 → 6.52 s). Estimated ~26 s per autolens_workspace CI run and ~28 s per autogalaxy_workspace run once the dataset cache carries a stamped set.
  • The four HowTo chapter-3 scripts unchanged in time (4.1–5.1 s), as expected.

Follow-ups (not here)

  • Bump the autonerves floor and delete the defensive try/except once the PyAutoNerves#160 release exists.
  • Revert the four HowTo script guards (now redundant) in a small workspace PR.

Test Plan

  • python3 -m pytest -q -n auto — 1449 passed
  • Both _test gates green with the branch installed
  • lib-tests.yml on the PR (both Python legs; the chain clones the same-named PyAutoNerves branch)

🤖 Generated with Claude Code

https://claude.ai/code/session_0151gQm9fk3XGLi5f18Urdba


Generated by Claude Code

…sh shapes

Three findings of the phase-8 diagnosis of the user-workspace smoke timings,
all of them the same shape: a harness-level fact the library did not act on.

1. Capped datasets whose shape cannot corroborate their stamp were deleted and
   re-simulated on every run. `_is_capped_at_the_current_cap` required
   `SMALLDAT = T` *and* a measured `data.fits` at exactly the cap, because
   `SMALLDAT` records "the env var was set at write time", not "capped at
   today's cap". Interferometer data is `(n_visibilities, 2)`, multi_dataset
   prefixes its FITS and datacubes nest theirs per channel, so none of them
   could ever corroborate: 5.2-6.5 s per script, ~26 s per autolens_workspace
   CI run and ~28 s per autogalaxy_workspace one, plus every local run.

   The `SMALLSHP` card (PyAutoNerves#159) states the proposition directly, so
   corroboration is no longer needed and those families are reachable. Two
   things keep the safety property intact. The card is read *with* the
   both-axes contradiction guard the full-resolution branch already applies --
   both cards record the writing *process*, so a 180x180 image written in a
   shell exporting `PYAUTO_SMALL_DATASETS=1` carries them while being full
   resolution, and reusing it in a capped run is the shape-mismatch class the
   capped branch exists to prevent. And an absent or malformed card falls back
   to the shape heuristic rather than being coerced, so every pre-card dataset
   behaves exactly as it did.

   The path resolution (`_capped_data_paths`) is widened for the capped branch
   only, by exact suffix at two known levels -- `data.fits`, then
   `{waveband}_data.fits`, then `channel_*/data.fits`, never a `*.fits` glob.
   The full-resolution branch still reads `data.fits` alone: widening the
   capped branch can only move a dataset from delete to keep, whereas widening
   the destructive one is its own change with its own review.

   `test__small_regime__interferometer_dataset__is_always_regenerated` asserted
   the conservative behaviour this issue exists to change, and is rewritten to
   pin the half that stands: without a cap card, that family still regenerates.

2. `apply_sparse_operator(use_jax=True)` ignored `PYAUTO_DISABLE_JAX=1`, so the
   smoke profile paid 2.3-3.2 s of JIT for a backend it had asked to disable.
   The interferometer method now lets the harness win over an explicit `True`,
   through `autonerves.test_mode.disable_jax()`.

   The imaging method is deliberately left alone, and says why in its docstring:
   it has no `use_jax` argument to override -- it *is* the JAX implementation,
   and its NumPy sibling `apply_sparse_operator_cpu` returns a different
   operator class and requires numba. Routing to that under an env var would
   change the returned type based on the environment, which is a larger and
   (on these measurements) unmotivated change.

3. Pixelization mesh `shape=` did not honour the cap the data does, so a capped
   run reconstructed 1600-2500 source pixels from ~80 image pixels. The
   rectangular meshes and `image_mesh.Overlay` now cap per axis under
   `PYAUTO_SMALL_DATASETS=1`, with the same `respect_small_datasets=True`
   escape hatch `Grid2D.uniform` carries. Measured on the four HowTo chapter-3
   scripts whose guards this subsumes: 43.6 s -> 17.3 s.

`disable_jax` is imported defensively: an autonerves too old to carry the
predicate is exactly the case the sibling literal in `dataset_util` exists for,
and a hard import would turn a safe degradation into an `ImportError` at module
load.

Refs #528

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0151gQm9fk3XGLi5f18Urdba
@Jammy2211
Jammy2211 merged commit bcd15cd into main Sep 6, 2026
3 checks passed
@Jammy2211
Jammy2211 deleted the claude/ci-test-timing-epic-ke2lul branch September 6, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants