Skip to content

Add CuPy GPU backend and phase congruence post-processing - #20

Merged
scottstanie merged 3 commits into
masterfrom
claude/add-cupy-backend-fDOot
Feb 13, 2026
Merged

Add CuPy GPU backend and phase congruence post-processing#20
scottstanie merged 3 commits into
masterfrom
claude/add-cupy-backend-fDOot

Conversation

@scottstanie

Copy link
Copy Markdown
Owner

Summary

This PR adds GPU acceleration support via CuPy and introduces a phase congruence post-processing function to improve unwrapping results.

Key Changes

  • CuPy GPU Backend: Implemented full CuPy-accelerated phase unwrapping with:

    • GPU-optimized gradient and divergence operators
    • CuPy-based p-shrinkage and Laplacian kernel computation
    • DCT/IDCT operations using cupyx.scipy.fft for efficient Fourier-domain solving
    • Automatic fallback with helpful error messages when CuPy is unavailable
  • Phase Congruence Post-Processing: Added make_congruent() function that:

    • Adjusts unwrapped phase to differ from wrapped phase by exact integer multiples of 2π
    • Corrects for ADMM solver ambiguities that don't guarantee congruence
    • Available as a post-processing step via congruent=True flag in unwrap()
  • API Enhancements:

    • Extended unwrap() function with backend parameter supporting 'numpy', 'jax', and 'cupy'
    • Added congruent parameter to enable phase congruence correction
    • Updated CLI with --backend and --congruent options
    • Improved error messages for missing optional dependencies
  • Testing: Added comprehensive test coverage for:

    • CuPy backend functionality and GPU/CPU consistency
    • Phase congruence correctness and quality preservation
    • Import error handling for missing CuPy installation
  • Code Quality:

    • Reformatted __all__ export list for readability
    • Updated module docstrings and imports
    • Added optional dependency declarations in pyproject.toml

https://claude.ai/code/session_01XAyGBPgci1PkE5UpqMDMm9

Add CuPy as an alternate GPU backend alongside JAX. CuPy is a better
fit for this use case since we only need GPU-accelerated FFTs (via
cupyx.scipy.fft.dctn/idctn) without autodiff. The backend is selected
via `backend="cupy"` in the API or `--backend cupy` on the CLI.

Add a `--congruent` flag that post-processes the unwrapped phase so it
differs from the wrapped input by an integer multiple of 2*pi at every
pixel. The ADMM solver doesn't guarantee this property, so
`make_congruent` computes k = round((unwrapped - wrapped) / 2pi) and
returns wrapped + 2*pi*k.

https://claude.ai/code/session_01XAyGBPgci1PkE5UpqMDMm9
Replace the duplicated _*_jax and _*_cupy functions with a single set of
generic helpers (_apply_gradient_x, _apply_gradient_y, _apply_divergence,
_est_wrapped_gradient, _p_shrink, _make_laplace_kernel) that take an xp
array module parameter (np, jnp, or cp).

Both the JAX JIT-compiled step and the CuPy unwrap loop now call the
same generic helpers—jnp is just a Python module constant to JAX's
tracer, so it works transparently with @jax.jit.

The JAX public API functions (est_wrapped_gradient_jax, p_shrink_jax,
make_laplace_kernel_jax) are kept as thin wrappers for backward compat.

https://claude.ai/code/session_01XAyGBPgci1PkE5UpqMDMm9
Drop separate unwrap_jax/unwrap_cupy/JAX wrappers and the numpy
sparse-matrix code path. Now there's one ADMM loop parameterized by
xp (the array module) and a pair of DCT/IDCT callables resolved at
the top of unwrap(). All helper functions (est_wrapped_gradient,
p_shrink, make_laplace_kernel) take xp=np by default.

core.py goes from ~560 lines to ~277.

https://claude.ai/code/session_01XAyGBPgci1PkE5UpqMDMm9
@scottstanie
scottstanie merged commit 61685cb into master Feb 13, 2026
14 checks passed
@scottstanie
scottstanie deleted the claude/add-cupy-backend-fDOot branch February 13, 2026 16:33
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.

2 participants