Skip to content

perf: symmetric row-restricted direct_conv curvature kernel - #636

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/direct-conv-symmetric
Oct 17, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/direct-conv-symmetric

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

With serial numba, the interferometer curvature matrix F = Aᵀ W̃ A can now be built by a new symmetric, row-restricted kernel, curvature_direct_conv_symmetric.

  • Ranking. Source columns are ranked by their top extent row (ymin, stable sort, empty columns last).
  • Row restriction. Each column convolves only the extent rows that later-ranked columns span, and only each row's mask x-range.
  • Gather and mirror. A branch-free ranked-CSC sweep gathers the ranked upper triangle, then a mirror pass fills the rest.
  • Exactness. Every computed entry is bit-identical to curvature_direct_conv.

Routing.

  • The kernel runs when its geometry work fraction f is at or below interferometer_direct_conv_symmetric_max_work_fraction. The packaged default is 0.7.
  • Mapping operators with non-finite weights fall back to the full kernel, so NaN evidence propagates as before.
  • The parallel path is unchanged.
  • The route cost model multiplies t_dc by min(1, κf) with κ = 1.32, so the factory routes on the kernel that will actually run. real_space_mask_from passes the mask, and only on NumPy.

Human decision (2026-10-16, on #635): rank by ascending ymin (not centroid) and raise the default gate from 0.5 to 0.7. The model says the kernel wins while κf < 1 (f < 0.76). Real Aris Delaunay columns are tall because of multiple imaging: the median span is 90 of 341 rows, against 15 on the synthetic geometry. That puts f at about 0.50–0.51, which the old 0.5 gate excluded.

Campaign: PyAutoLabs/PyAutoPulse#62 (task interferometer_large_mask_aris, lever L2).

Closes #635

API Changes

These are additive. The default behaviour changes only in speed: serial numba interferometer inversions with f ≤ 0.7 use the new kernel, with F identical to round-off.

  • New Settings(interferometer_direct_conv_symmetric_max_work_fraction=...) and the general.yaml key of the same name (default 0.7; 0 disables; null means the default).
  • New numba util functions and constants: curvature_direct_conv_symmetric, symmetric_restriction_inputs_from, symmetric_work_fraction_from, SYMMETRIC_KERNEL_KEYS, DIRECT_CONV_SYMMETRIC_WORK_FACTOR.
  • curvature_route_seconds_from gains an optional work_fraction argument.

See full details below.

Witness (RAL, euclid-ral-compute-1, ral partition, --exclusive, 1 thread, load ≤ 1.0 during timing)

Software: PyAutoArray e59d5fa9 plus this diff (v3 patch), PyAutoNerves 7f3055b, PyAutoFit 9b394e73, PyAutoGalaxy 9f9ac947, PyAutoLens 4723668a; numba 0.65.1, numpy 2.2.6. Compile time is excluded: each figure is the minimum of two repeats with a warm numba cache.

Real Aris SPT2319-55 data (5,516,930 visibilities, 512×512 mask, extent 341², regular overlay Delaunay mesh, ConstantSplit). Jobs 412490, 412491 (FFT arm), 412492 and 412493 (control).

vertices f (ymin) full direct_conv symmetric speed-up κf model FFT route log L / FoM full vs symmetric
1,459 0.511 22.43 s 15.08 s 1.49× 1.48× 15.32 s bit-identical
2,577 0.504 22.83 s 14.95 s 1.53× 1.50× not run rel 3e-16 / 5e-16
5,746 0.495 24.22 s 15.35 s 1.58× 1.53× not run rel 2e-12 / 2e-10 (see below)
  • Gate (≥ 1.3× on the curvature step on real data, matching log L): passed.
  • 5,746 vertices. The log det moves by 0.0071 nats (rel 8e-8). This is round-off amplified by cond(F+H) = 7.2e13:
    • Both F matrices agree to 4.4e-16 relative.
    • The full kernel's own F, factorised from its lower triangle versus its upper triangle, already differs by 0.0077 nats in the log det (control job 412493).
  • At 1,459 vertices the gain over the previous default route is about 1.02×. The old default sent this cell to FFT (15.32 s on this node), so most of the 1.49× there is against the full kernel. Two things follow:
    • The cost model still chooses direct_conv (correct, but marginally).
    • On RAL, FFT/full direct_conv is 0.68, against 0.89 predicted from laptop calibration. Refitting the FFT constant belongs to the next phase (FFT size levers) and is not part of this PR.
  • At 2,577 and 5,746 vertices, direct_conv was already the route, so the speed-up applies in full.

Synthetic Aris-512 geometry (341² extent, 91,361 px, 3-NN, nnz 274,083), ymin order, job 412490:

S f full symmetric speed-up κf model A-A / C-C spread
1,428 0.414 22.08 s 12.08 s 1.83× 1.83× 1.008 / 1.007
2,540 0.408 22.53 s 12.11 s 1.86× 1.86× 1.001 / 1.002
5,712 0.403 23.94 s 12.59 s 1.90× 1.88× 1.001 / 1.004

The ranked triangle is bit-identical in all three, and the full-matrix max relative difference is ≤ 1.3e-15, which equals the full kernel's own asymmetry.

Heart

pyauto-heart readiness --json (canonical, 2026-10-17T11:48:54Z): STALE, score 85. red_reasons: []. The stale reason is "release validation incomplete: no rehearsal for current source". STALE passes for development shipping, so no RED override was needed.

Test Plan

  • PyAutoArray full suite: 2086 passed, 4 xfailed. The new test_curvature_direct_conv_symmetric.py has 21 tests.
  • PyAutoGalaxy 1357 passed; PyAutoLens 832 passed, 1 xfailed (against this branch).
  • RAL real-data and synthetic witnesses (tables above).
  • Independent review of v2: CLEAN (600-trial adversarial fuzz). v3 changes only the ordering, the default and the docstrings.
  • Workspace smoke (pyauto-heart smoke, local library roots): 165/165 passed across autofit, autogalaxy, autolens, autolens_test, euclid and howtolens. The autocti and autocti_test environments failed to build before execution because GSL headers are missing on the laptop; that is unrelated to this change, which does not touch CTI.
  • CI green
Full API Changes (for automation & release notes)

Added

  • Settings(interferometer_direct_conv_symmetric_max_work_fraction: Optional[float] = None) and the property of the same name. Default 0.7 from general.yaml inversion.interferometer_direct_conv_symmetric_max_work_fraction; 0 always uses the full kernel; negative raises ValueError.
  • inversion_interferometer_numba_util.curvature_direct_conv_symmetric(..., order, rank, ylo_suffix, xlo_row, xhi_row): the serial symmetric kernel.
  • inversion_interferometer_numba_util.symmetric_restriction_inputs_from(iy, ix, cscptr, csc_row, ny, nx, pix_pixels): ordering, row restriction, x-ranges and work_fraction.
  • inversion_interferometer_numba_util.symmetric_work_fraction_from(...): f from the mapper triplets, used by the router.
  • SYMMETRIC_KERNEL_KEYS and DIRECT_CONV_SYMMETRIC_WORK_FACTOR = 1.32.
  • InversionInterferometerSparseNumba.symmetric_restriction_inputs and .use_symmetric_kernel.
  • interferometer.abstract.real_space_mask_from(dataset).

Changed

  • curvature_route_seconds_from(source_pixels, nnz, extent_shape, work_fraction=None): t_dc is scaled by min(1, κ·work_fraction) when the argument is given.

Migration

Generated by the PyAutoLabs agent workflow.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QBeyBLN7ntDChx9v1fmt6M

Serial numba interferometer curvature F = A^T W~ A now has a symmetric,
row-restricted kernel, curvature_direct_conv_symmetric. Source columns are
ranked by their top extent row (ymin, stable, empty columns last); each column
convolves only the extent rows later-ranked columns span, clipped to each row's
mask x-range, gathers the ranked upper triangle with a branch-free ranked-CSC
sweep, then mirrors. Computed entries are bit-identical to curvature_direct_conv.

The kernel runs when numba is serial and its geometry work fraction f is at or
below Settings.interferometer_direct_conv_symmetric_max_work_fraction (packaged
0.7; 0 disables; null means the default). Non-finite mapping weights fall back
to the full kernel. The route cost model scales t_dc by min(1, 1.32 f), so the
factory routes on the cheaper kernel (real_space_mask_from passes the mask).

RAL witness (euclid-ral-compute-1, ral partition, exclusive, 1 thread):
synthetic Aris-512 geometry 1.83/1.86/1.90x at S 1,428/2,540/5,712; real Aris
SPT2319-55 512x512, 1,459 Delaunay vertices, f 0.511: curvature 22.43 -> 15.08 s
(1.49x), log likelihood and figure of merit bit-identical.

Closes #635

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QBeyBLN7ntDChx9v1fmt6M
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Oct 17, 2026
@Jammy2211
Jammy2211 merged commit a847836 into main Oct 17, 2026
3 checks passed
@Jammy2211
Jammy2211 deleted the feature/direct-conv-symmetric branch October 17, 2026 16:26
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: symmetric row-restricted direct_conv curvature kernel (serial numba, large extents)

1 participant