@@ -73,6 +73,7 @@ def data_vector_via_psf_weighted_data_from(
7373 cols : np .ndarray , # (nnz,) int32 source pixel index
7474 vals : np .ndarray , # (nnz,) float64 mapping weights incl sub_fraction
7575 S : int , # number of source pixels
76+ xp = np ,
7677) -> np .ndarray :
7778 r"""
7879 Returns the data vector `D` from the `psf_weighted_data` matrix (see `psf_weighted_data_from`), which encodes the
@@ -96,7 +97,16 @@ def data_vector_via_psf_weighted_data_from(
9697 The values of the sparse mapping matrix triplet representation, which map the image pixels to source pixels.
9798 S
9899 The number of source pixels.
100+ xp
101+ The array module: `np` scatter-adds with `np.bincount` (no JAX import, so this runs without
102+ JAX installed); `jax.numpy` uses `jax.ops.segment_sum`. The triplets must be masked (see
103+ `mapper_util.sparse_triplets_from(pix_sizes_for_sub=...)`) so every column is non-negative.
99104 """
105+ if xp is np :
106+ w = np .asarray (psf_weighted_data )[np .asarray (rows )] # (nnz,)
107+ contrib = np .asarray (vals ) * w # (nnz,)
108+ return np .bincount (np .asarray (cols ), weights = contrib , minlength = S )[:S ] # (S,)
109+
100110 from jax .ops import segment_sum
101111
102112 w = psf_weighted_data [rows ] # (nnz,)
@@ -284,7 +294,32 @@ def mapped_reconstructed_operated_data_via_sparse_operator_from(
284294 vals , # (nnz,)
285295 fft_index_for_masked_pixel ,
286296 data_shape : int , # y_shape * x_shape
297+ xp = np ,
287298):
299+ """
300+ Returns the slim image `A s` of a reconstruction `s` mapped through a mapper's sparse mapping
301+ operator `A`, whose COO triplets `(rows, cols, vals)` index rows on the rectangular FFT grid
302+ (`Mapper.sparse_triplets_curvature`).
303+
304+ The scatter-add is performed on the rectangular grid of `data_shape` and the masked pixels are
305+ then gathered via `fft_index_for_masked_pixel`. With `xp=np` it uses `np.bincount` and imports
306+ no JAX, so it runs without JAX installed; with `xp=jax.numpy` it uses `jax.ops.segment_sum`.
307+ """
308+ num_segments = data_shape [0 ] * data_shape [1 ]
309+
310+ if xp is np :
311+ reconstruction = np .asarray (reconstruction , dtype = np .float64 )
312+ rows = np .asarray (rows , dtype = np .int64 )
313+ cols = np .asarray (cols , dtype = np .int64 )
314+ vals = np .asarray (vals , dtype = np .float64 )
315+
316+ contrib = vals * reconstruction [cols ] # (nnz,)
317+ image_rect = np .bincount (rows , weights = contrib , minlength = num_segments )[
318+ :num_segments
319+ ] # (M_rect,)
320+
321+ return image_rect [np .asarray (fft_index_for_masked_pixel )] # (M_pix,)
322+
288323 import jax .numpy as jnp
289324 from jax .ops import segment_sum
290325
@@ -294,9 +329,7 @@ def mapped_reconstructed_operated_data_via_sparse_operator_from(
294329 vals = jnp .asarray (vals , dtype = jnp .float64 )
295330
296331 contrib = vals * reconstruction [cols ] # (nnz,)
297- image_rect = segment_sum (
298- contrib , rows , num_segments = data_shape [0 ] * data_shape [1 ]
299- ) # (M_rect,)
332+ image_rect = segment_sum (contrib , rows , num_segments = num_segments ) # (M_rect,)
300333
301334 image_slim = image_rect [fft_index_for_masked_pixel ] # (M_pix,)
302335 return image_slim
0 commit comments