Skip to content

Feat: added Downsample2D operator - #794

Merged
mrava87 merged 3 commits into
PyLops:devfrom
mrava87:feat-downsample
Aug 30, 2026
Merged

Feat: added Downsample2D operator#794
mrava87 merged 3 commits into
PyLops:devfrom
mrava87:feat-downsample

Conversation

@mrava87

@mrava87 mrava87 commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

This PR adds a new Claude skill called newop that can be used to ask Claude to create a PyLops operator from a detailed mathematical description and/or a plain implementation of forward/adjoint.

It is stress-tested with a rather popular operator, namely a downsampling operator for images called Downsample2D. The first implementation is created from the following prompt:

❯ Create a new operator in signalprocessing called Downsample2D that implements 2d downsampling as the combination
  of gaussian filtering and subsampling in both directions.

and slightly refined to match PyLops standards (mostly in the way parameters are checked and test suite).

@mrava87 mrava87 self-assigned this Aug 30, 2026
@mrava87 mrava87 added the enhancement New feature or request label Aug 30, 2026
@mrava87

mrava87 commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator Author

@claude review.

@claude

claude Bot commented Aug 30, 2026

Copy link
Copy Markdown

Claude finished @mrava87's task in 2m 39s —— View job


Review of feat-downsample

  • Gather context (diff, changed files)
  • Review pylops/signalprocessing/downsample2d.py
  • Review tests pytests/test_downsample.py
  • Review example examples/plot_downsample.py
  • Review skill files and misc changes (radon2d/radon3d, AIPOLICY.md, tutorials/ctscan.py deletion)
  • Post review feedback

Overall this is a clean, well-tested addition. Downsample2D follows the existing operator conventions closely (dims/dimsd handling, @reshaped, dottest coverage, real+complex parametrization, scipy cross-check, and an inversion round-trip). A few things worth a look before merging:

1. Unrelated/unexplained deletion of tutorials/ctscan.py (167 lines)
This PR removes the entire CT-scan tutorial, but nothing in the title/description explains why, and it isn't referenced anywhere else in the diff as being replaced or moved. Since the tutorial used Radon2D with a custom callable kind (the same feature this PR touches in radon2d.py/radon3d.py), it's worth double-checking this wasn't an accidental deletion rather than an intentional removal. If intentional, please note the reason in the PR description.

2. Scope creep: Radon2D/Radon3D callable-kind type-hint fix + new tests
pylops/signalprocessing/radon2d.py/radon3d.py change the kind type hint to Literal[...] | Callable, and pytests/test_radon.py adds two new tests (test_Radon2D_unknown_kind, test_Radon2D_callable_kind). The runtime already supported callable(kind) before this PR, so this is a legitimate, low-risk fix — but it's unrelated to "add Downsample2D operator." Consider splitting into its own PR/commit for a cleaner history, or at least mention it in the PR description.

3. Missing .. versionadded:: directive
Downsample2D's docstring (pylops/signalprocessing/downsample2d.py:30-139) doesn't include a .. versionadded:: 2.9.0 tag, even though this is a brand-new operator and the newly-added newop skill itself calls this out as a required step ("Add .. versionadded:: <next release> to the class docstring for a brand-new operator"). Other operators (e.g. bilinear.py, convolve2d.py) consistently include this.

4. _matvec/_rmatvec call the private Cop._matvec/Cop._rmatvec instead of public Cop.matvec/Cop.rmatvec (downsample2d.py:227, :235)
Other composite operators in the codebase that wrap a sub-operator (e.g. sliding2d.py) invoke the wrapped operator via its public matvec()/rmatvec(). Calling the private methods directly bypasses LinearOperator's @count instrumentation (nmatvec/nrmatvec) on the inner Convolve2D operator, so Dop.Cop.nmatvec would silently stay at 0 even though it's actually being invoked internally. Minor, but worth aligning with convention unless the private call was intentional for a small perf win.

5. Minor: no validation of duplicate axes
axes=(0, 0) (or two values that normalize to the same axis, e.g. (-2, 0) with dims of length 2) isn't rejected in __init__ (downsample2d.py:158-162); it will silently apply the same factor twice via axes.index(ax). Low priority since this mirrors the effort put into validating factors/sigma, but a quick len(set(axes)) != 2 check would close the gap.

Nothing above blocks the core Downsample2D correctness — the math, dot-test coverage, and scipy cross-check all look solid. Items 1 and 2 are the ones I'd want clarified before merge since they touch files outside the operator's own scope.

Note: I was not able to execute pytest/make lint in this sandbox (command execution requires approval that isn't available in this context), so the above is a static read-through, not a verified test run.

@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 2 high · 2 medium

Alerts:
⚠ 4 issues (≤ 0 issues of at least minor severity)

Results:
4 new issues

Category Results
Security 2 high
Complexity 2 medium

View in Codacy

🟢 Metrics 0 duplication

Metric Results
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@mrava87
mrava87 merged commit ceed5da into PyLops:dev Aug 30, 2026
23 of 24 checks passed
@mrava87
mrava87 deleted the feat-downsample branch August 30, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant