perf: rotation-matrix grid transform + one Grid2D per VectorYX2D (numpy deflections phase 3) - #519
Merged
Merged
Conversation
Build the clockwise rotation from one scalar cos/sin of the angle and apply it as two multiply-adds per coordinate, instead of the polar form's per-pixel sqrt + arctan2 + sin + cos. Algebraically identical (max abs difference 2e-15 on a 15k-point grid); ~7x cheaper on the numpy path, and every transform-decorated profile evaluation pays it once per call. Phase 3 of the numpy-deflections-cpu epic (PyAutoGalaxy#598). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re4JLhTCFnGYeez8oEyM6M
The @to_vector_yx decorator hands the input Grid2D straight into VectorYX2D, which re-converted its values and rebuilt a second Grid2D on every transform-decorated profile evaluation. Reuse the grid when it is already a Grid2D on the same mask (and native storage is not requested); other inputs take the existing conversion path. One Grid2D construction per deflection call instead of two; results unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re4JLhTCFnGYeez8oEyM6M
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
Phase 3 of the
numpy-deflections-cpuepic (PyAutoGalaxy#598) — the shared-geometry lever every@transform-decorated profile pays once per call.geometry_util.transform_grid_2d_to_reference_framebuilds the clockwise rotation from one scalarcos/sinof the angle and applies it as two multiply-adds per coordinate ([y cos a − x sin a, x cos a + y sin a]), instead of the polar form's per-pixelsqrt+arctan2+sin+cos. Algebraically identical (max abs difference 2e-15 on a 15k-point grid); 1.42 ms → 0.21 ms on that grid (~7×).VectorYX2Dreuses theGrid2Dit is handed when it is already paired with the same mask.@to_vector_yxpasses the input grid straight through, and the constructor was re-converting its values and rebuilding a secondGrid2Don every deflection evaluation. OneGrid2Dconstruction per call instead of two; other inputs take the unchanged conversion path.Net on this box (
OMP_NUM_THREADS=1, hst 15,361-pointGrid2D):Isothermal.deflections_yx_2d_from1.95 ms → 0.93 ms with the PyAutoGalaxy hoists from #598 on top. The measurement of record (before/after on hst + euclid for all nine profiles, pins at rtol 1e-6) lands in the autolens_profiling PR of this phase.The rotation is exact where the polar form left round-off: an on-axis point at angle 0 now gives an x-component of exactly
0.0where it was~5e-17. That is what moved one pinned sample in the autolens_profilingstellarcell (relative shift 1.0 on a 1e-17 value) and is re-pinned there with provenance; every other pin held.Merge order: this PR → PyAutoGalaxy#599 (profiles) → autolens_profiling (numbers).
API Changes
No public API change.
transform_grid_2d_to_reference_framereturns the same coordinates;VectorYX2D(values, grid, mask)accepts the same inputs and, whengridis aGrid2Donmask, its.gridis now that object rather than a copy.See full details below.
Test Plan
test_autoarray— 1349 passed, 61 skipped (-n 4); geometry, grids, vectors and decorator tests re-run after each changeruff check/ruff format --check— no new findings in the changed files (both were already format-clean onmain)mainon the hst grid for Isothermal / PowerLaw / NFW / NFWSph / gNFW: max relative difference ≤ 1e-8scripts/lens/deflections/{total,dark,stellar}.pyhst + euclid: every pin held at rtol 1e-6 except the exact-zero sample aboveFull API Changes (for automation & release notes)
Removed
Added
Changed
autoarray.util.geometry.transform_grid_2d_to_reference_frame(grid_2d, centre, angle, xp)— same signature and result; rotation-matrix evaluation (no per-pixelarctan2/sin/cos).autoarray.VectorYX2D.__init__(values, grid, mask, store_native=False)— whengridis aGrid2Dwhose.mask is maskandstore_nativeis False,self.gridisgriditself instead of a re-converted copy.Migration
Generated by the PyAutoLabs agent workflow.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Re4JLhTCFnGYeez8oEyM6M
Generated by Claude Code