From 91d8b97d47492fb6f5f12073ba92393e761f87ed Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 18:19:37 +0000 Subject: [PATCH 1/2] Defer the eager scipy.sparse and scipy.spatial imports (~280 ms) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `import autoarray` drops from 464.4 ms to 183.7 ms (medians of 15 runs, Python 3.13, dev extras) — a 281 ms saving. The filed task named `derivative_util.py:30`'s module-scope `from scipy.sparse import csr_matrix` as the target, on the evidence that `scipy.sparse` costs ~0.11 s of every import. Deferring it changed nothing, because `scipy.sparse` was never being imported from there: autoarray/__init__.py:80 -> inversion/mesh/mesh_geometry/delaunay.py:2 import scipy.spatial -> scipy/spatial/__init__.py:111 from ._kdtree import * -> scipy/spatial/_kdtree.py:4 from ._ckdtree import cKDTree `scipy.spatial` (134 ms) pulls `scipy.sparse` (154 ms) in transitively, so the csr_matrix import was riding on a subtree that was already paid for. Deferring `scipy.spatial` as well is what actually removes both, and is required to meet the task's own acceptance criterion. Changes: - `inversion/mesh/mesh_geometry/delaunay.py` — drop the module-scope `import scipy.spatial`. Two of its three use sites already had local imports; only `voronoi_neighbors_from` needed one added, so this finishes a deferral that had been started and left half-done. - `operators/derivative_util.py`, `operators/coarse_interp_util.py` — move `from scipy.sparse import csr_matrix` into the four functions that use it. No longer load-bearing for the import time on its own, but it keeps `scipy.sparse` off the import path independently of what `scipy.spatial` happens to pull in. Every use site is inside a function, so a plain local import suffices — no module-level cache as in `transformer.py:_load_nufftax()`, which needed one only because unpickled instances in multiprocessing workers never re-run `__init__`. Function-local imports run on every call and hit `sys.modules` after the first. Verified: `python -X importtime -c "import autoarray"` shows neither `scipy.sparse` nor `scipy.spatial`. Suites green — autoarray 1179 passed, autogalaxy 1103 passed / 1 skipped, autolens 532 passed / 1 skipped. --- .../inversion/mesh/mesh_geometry/delaunay.py | 2 +- autoarray/operators/coarse_interp_util.py | 3 ++- autoarray/operators/derivative_util.py | 11 ++++++++--- .../arrays/files/array/output_test/array.fits | Bin 5760 -> 5760 bytes 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/autoarray/inversion/mesh/mesh_geometry/delaunay.py b/autoarray/inversion/mesh/mesh_geometry/delaunay.py index eadbbfbd6..093fa6172 100644 --- a/autoarray/inversion/mesh/mesh_geometry/delaunay.py +++ b/autoarray/inversion/mesh/mesh_geometry/delaunay.py @@ -1,5 +1,4 @@ import numpy as np -import scipy.spatial from typing import Tuple from autonerves import cached_property @@ -147,6 +146,7 @@ def neighbors(self) -> Neighbors: The neighbors of a Voronoi mesh are computed using the `ridge_points` attribute of the scipy `Voronoi` object, as described in the method `voronoi_neighbors_from`. """ + import scipy.spatial delaunay = scipy.spatial.Delaunay(self.mesh_grid_xy) diff --git a/autoarray/operators/coarse_interp_util.py b/autoarray/operators/coarse_interp_util.py index e9477babc..58c9b3a60 100644 --- a/autoarray/operators/coarse_interp_util.py +++ b/autoarray/operators/coarse_interp_util.py @@ -17,7 +17,6 @@ """ import numpy as np -from scipy.sparse import csr_matrix from autoarray import exc from autoarray import numba_util @@ -242,6 +241,8 @@ def coarse_interp_matrix_from( A ``scipy.sparse.csr_matrix`` of shape [n_unmasked_fine_pixels, n_unmasked_coarse_pixels]. """ + from scipy.sparse import csr_matrix + mask_itp_box = np.asarray(mask_itp_box) if np.count_nonzero(~mask_itp_box) == 0: raise exc.MeshException( diff --git a/autoarray/operators/derivative_util.py b/autoarray/operators/derivative_util.py index 62bf96471..b32606949 100644 --- a/autoarray/operators/derivative_util.py +++ b/autoarray/operators/derivative_util.py @@ -27,7 +27,6 @@ """ import numpy as np -from scipy.sparse import csr_matrix from autoarray import exc from autoarray import numba_util @@ -297,9 +296,11 @@ def derivative_1st_operators_from(mask, pixel_scale: float = 1.0): ------- The (Hy, Hx) operators as ``scipy.sparse.csr_matrix``. """ + from scipy.sparse import csr_matrix + mask, diff_types = _diff_types_of_cleaned_mask_from(mask) - rows_hx, cols_hx, data_hx, rows_hy, cols_hy, data_hy = ( - derivative_1st_triplets_from(mask, diff_types, dpix=pixel_scale) + rows_hx, cols_hx, data_hx, rows_hy, cols_hy, data_hy = derivative_1st_triplets_from( + mask, diff_types, dpix=pixel_scale ) n_unmasked = np.count_nonzero(~mask) @@ -443,6 +444,8 @@ def derivative_2nd_operators_from(mask, pixel_scale: float = 1.0): ------- The (Hyy, Hxx) operators as ``scipy.sparse.csr_matrix``. """ + from scipy.sparse import csr_matrix + mask, diff_types = _diff_types_of_cleaned_mask_from(mask) rows_hxx, cols_hxx, data_hxx, rows_hyy, cols_hyy, data_hyy = ( derivative_2nd_triplets_from(mask, diff_types, dpix=pixel_scale) @@ -574,6 +577,8 @@ def forward_difference_operators_from( ------- The (Hy, Hx) operators as ``scipy.sparse.csr_matrix``. """ + from scipy.sparse import csr_matrix + if max_order not in (1, 2, 3, 4): raise ValueError(f"max_order must be in 1..4, got {max_order}") diff --git a/test_autoarray/structures/arrays/files/array/output_test/array.fits b/test_autoarray/structures/arrays/files/array/output_test/array.fits index d028d2d18597d94ca2d84236941cc1f8e37672aa..0cff0a8f7db90d3ded28c644cd66e3791627feeb 100644 GIT binary patch delta 21 ccmZqBZP49tfoZb>vjWFt2j+my4%`mh08bhQN&o-= delta 77 zcmZqBZP49tfr&HN*U`tv#WBQoVxx$jn}WVVK%`@6h<`j-JRT_F80;DntdN*ol3A9j ckXWKnUX)pqs!)=do4WZllPbq%2W|&$0JQWNkpKVy From 528f802310760ba9109640840318c2f207443a77 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 18:19:49 +0000 Subject: [PATCH 2/2] Revert test-output artifact swept into the previous commit `test_autoarray/.../output_test/array.fits` is a tracked file that the test suite rewrites when it runs. It is unrelated to the import deferral and was picked up by `git add -A`; this restores it to its state on main. --- .../arrays/files/array/output_test/array.fits | Bin 5760 -> 5760 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test_autoarray/structures/arrays/files/array/output_test/array.fits b/test_autoarray/structures/arrays/files/array/output_test/array.fits index 0cff0a8f7db90d3ded28c644cd66e3791627feeb..d028d2d18597d94ca2d84236941cc1f8e37672aa 100644 GIT binary patch delta 77 zcmZqBZP49tfr&HN*U`tv#WBQoVxx$jn}WVVK%`@6h<`j-JRT_F80;DntdN*ol3A9j ckXWKnUX)pqs!)=do4WZllPbq%2W|&$0JQWNkpKVy delta 21 ccmZqBZP49tfoZb>vjWFt2j+my4%`mh08bhQN&o-=