SparseFFT#

class pygrog.operator.SparseFFT(grid_shape=None, image_shape=None, indices=None, weights=None, smaps=None, device=None, *, plan=None, toeplitz=None)[source]#

Bases: SolveMixin

Sparse FFT / IFFT operator with coil combination.

Accepts either a pre-built plan (from fft_plan()) or raw arrays. When a plan is provided, sorted indices, sqrt-weights, and permutation arrays are reused directly; otherwise they are computed from the raw indices / weights arguments.

Parameters:
  • plan (SimpleNamespace | None) – Pre-built plan from GrogInterpolator.fft_plan(). If given, grid_shape, image_shape, indices, and weights are ignored.

  • grid_shape (tuple[int, ...] | None) – Oversampled Cartesian k-space grid, e.g. (nz, ny, nx).

  • image_shape (tuple[int, ...] | None) – Target image shape (center-crop), e.g. (nz, ny, nx).

  • indices (array-like | None) – Flat grid indices (n_samples,) int64.

  • weights (array-like | None) – Density-compensation weights (n_samples,) float32. sqrt(weights) is applied in both directions.

  • smaps (torch.Tensor | None) – (n_coils, *image_shape) sensitivity maps. None → RSS.

  • device (str | torch.device | None) – Compute device. When 'cuda' with CPU data, dual-stream pipelining is enabled.

  • toeplitz (bool | None, optional) – Use Toeplitz embedding (PSF on grid_shape) for the self-adjoint operator normal(). None → auto: enabled on CPU, disabled on CUDA (matches pygrog.utils.nlinv() policy).

Methods

__init__

adjoint

Sparse k-space to image.

forward

Image to sparse k-space.

normal

Self-adjoint application: A^H A image.

solve

Solve \(\arg\min_x \|A x - b\|^2 + \lambda^2 \|x\|^2\).

adjoint(sparse_kspace)[source]#

Sparse k-space to image.

Accepted input layouts (with optional leading *B batch and, for stacked plans, leading *S stack axes inserted between batch and single-frame dims):

  • (*B, *S, n_coils, *natural_shape)

  • (*B, *S, n_coils, n_samples) (legacy / flat form)

Output: (*B, *S, *image_shape) if smaps are set (SENSE-combined), else (*B, *S, n_coils, *image_shape).

Note

This function uses torch internally, and will convert all its array argument to torch tensors, but will respect the device they are allocated on. The outputs will be converted back to the original array module and device.

forward(image)[source]#

Image to sparse k-space.

Accepted input layouts (with optional leading *B batch and, for stacked plans, leading *S stack axes):

  • (*B, *S, *image_shape) if smaps are set

  • (*B, *S, n_coils, *image_shape) otherwise

Output: (*B, *S, n_coils, *natural_shape).

Note

This function uses torch internally, and will convert all its array argument to torch tensors, but will respect the device they are allocated on. The outputs will be converted back to the original array module and device.

normal(image)[source]#

Self-adjoint application: A^H A image.

When self.toeplitz is True, uses a pre-computed PSF on grid_shape (built lazily on first call) and applies pad / FFT / PSF / IFFT / crop per coil. Otherwise dispatches to a fused forward(adjoint(.)) helper that skips the inv_perm (in adjoint) and sort_perm (in forward) round- trip — the intermediate sparse k-space is kept in sorted order end-to-end (“sort-once” optimisation).

Parameters:

image (torch.Tensor) – Same shape as the output of forward().

Returns:

Same shape as input.

Return type:

torch.Tensor

Note

This function uses torch internally, and will convert all its array argument to torch tensors, but will respect the device they are allocated on. The outputs will be converted back to the original array module and device.