Skip to content

Fix: preserve flat FISTA cost dispatch for ND operators - #805

Merged
mrava87 merged 3 commits into
PyLops:devfrom
mikamikasuki:fix-fista-nd-data-cost
Oct 4, 2026
Merged

mrava87 merged 3 commits into
PyLops:devfrom
mikamikasuki:fix-fista-nd-data-cost

Conversation

@mikamikasuki

@mikamikasuki mikamikasuki commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

FISTA computed its data cost through Op @ x, which reshapes output to Op.dimsd and fails against flattened multidimensional data or multiple right-hand sides. Use the solver's existing Opmatvec dispatch for the cost.

Cover ISTA and FISTA with 16 regression cases across real/complex data, single/multiple right-hand sides, and both preallocation modes. Clarify the input layout in both public docstrings and the deblurring tutorial.

Fixes #801.

Validation: pytest pytests/test_sparsity.py — 92 passed; make lint — passed.

AI assistance: Codex authored the fix, documentation, and regression tests.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · 0 duplication

Metric Results
Complexity 0
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 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikamikasuki well spotted and thanks for the PR. I left a few minor comments but overall I think is good (including the new test :))

Comment thread pylops/optimization/sparsity.py
Comment thread pytests/test_sparsity.py
Comment thread pytests/test_sparsity.py Outdated
@mrava87

mrava87 commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

@claude review.

@claude

claude Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Claude finished @mrava87's task in 22s —— View job


Review of PR #805

  • Read the diff against origin/dev
  • Check the fix against ISTA and FISTA in cls_sparsity.py
  • Check whether the review comments from @mrava87 have been addressed

The fix is correct and minimal. FISTA.step computed the data cost with self.Op @ x. That reshapes the result to Op.dimsd, so it breaks against a flat y or an (N, nrhs) y. self.Opmatvec(x) is what the iterations already use (matvec or matmat, depending on the shape of y). ISTA.step doesn't have this problem. It reuses the residual it already computed (cls_sparsity.py:1924), so the one-line change is all the solver needs.

Still open from the earlier review

All of the points below are still unaddressed. The branch has only the one commit.

  1. ista docstring (pylops/optimization/sparsity.py:71). The Data entry in ista still carries the old text. @mrava87 asked for the same clarification there. The two other Data entries (lines 616 and 742) are for other solvers, so they probably don't need it.
  2. Parametrize over ista and fista (pytests/test_sparsity.py). As requested, add @pytest.mark.parametrize("solver", [ista, fista]). The test would pass for ista without a code change, which makes it a useful guard against regressions.
  3. Test name and docstring. The suggested wording is along the lines of "Check that ista/fista can handle nd data with flat models". Rename the test to something like test_ISTA_FISTA_flat_model_nd_data.
  4. Test placement. Move the test below the tests of the same solvers that check for raised errors, e.g. after test_ISTA_FISTA_unknown_threshkind.

Minor points

  • Extra blank line. The new test is followed by three blank lines (see the diff around pytests/test_sparsity.py:366). PEP 8 allows two. ruff format or the linter may flag it.
  • Mutating op.dimsd in the test. op.dimsd = (op.shape[0],) modifies the operator in place to build the reference. It works, but it relies on Op.dimsd being writable and on nothing else caching the old shape. Building a second operator, or wrapping the original with a flat Reshape, would be more robust. If you keep it, add a one-line comment that it is deliberate.
  • Final cost check. assert_array_almost_equal(cost, expected_cost) compares the two runs. Since the reference run uses a flat dimsd, this is fine. You could also assert that cost is finite and non-increasing in the first few iterations as a sanity check, but that is optional.
  • Deblurring tutorial. The added comment is clear. If you want to be thorough, check whether examples/ has other fista calls on a flat model with ND data, for example with SWT2D.

Summary

The core change is good to merge once the four open points above are done. I made no code changes.

@mikamikasuki

Copy link
Copy Markdown
Contributor Author

Added the input-layout clarification to ista, parameterized the regression over ISTA/FISTA, clarified its name/docstring, and moved it below the solver error tests. The flat reference uses a shallow copy of the operator; all 92 sparsity tests and lint pass.

@mrava87 mrava87 changed the title fix: preserve flat FISTA cost dispatch for ND operators Fix: preserve flat FISTA cost dispatch for ND operators Oct 3, 2026
@mrava87 mrava87 added the bug Something isn't working label Oct 3, 2026
@mrava87
mrava87 merged commit 097d368 into PyLops:dev Oct 4, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fista fails with shape mismatch when Op.dims is 1-D and Op.dimsd is N-D

2 participants