Skip to content

Fix: preserve feasible inputs in L1 ball projection - #268

Merged
mrava87 merged 2 commits into
PyLops:devfrom
mikamikasuki:fix-l1-ball-interior-projection
Oct 3, 2026
Merged

mrava87 merged 2 commits into
PyLops:devfrom
mikamikasuki:fix-l1-ball-interior-projection

Conversation

@mikamikasuki

Copy link
Copy Markdown
Contributor

L1BallProj always projected onto the simplex boundary, so an input already inside the L1 ball was changed. For example, projecting [0.1, -0.2] with radius 1 returned approximately [0.45, -0.55] instead of the input.

Return feasible inputs unchanged before applying the existing boundary projection, and document the complete piecewise formula. Add regressions for real and complex interior, boundary and zero vectors, and the corresponding dual proximal operator.

Validation: 54 projection tests pass; all Ruff checks and strict mypy checks pass. An independent sorting-based reference agrees with 1,000 real and complex interior/exterior projections. The full suite has 275 passing tests and one complex64 bilinear tolerance failure, which also occurs on the clean base revision (253 passing tests).

AI assistance: Codex generated the fix, tests and this description.

@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
Contributor

Choose a reason for hiding this comment

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

@mikamikasuki well spotted. Just a few minor improvements on the tests docstrings, then I think this is good to go.

Comment thread pytests/test_projection.py Outdated
Comment thread pytests/test_projection.py
@mrava87

mrava87 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

@claude review.

@claude

claude Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

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


Review of PR #268

The fix is correct and minimal. Projecting a point already in the ball now returns it unchanged. The docstring now gives the full piecewise formula, and it also fixes the old Simplex(x) to Simplex(|x|). I didn't run the tests myself. The review is based on the diff.

Suggestions

  1. Aliasing (pyproximal/projection/L1.py:57-58). return x returns the caller's array, not a copy. Callers that later modify the result in place would silently modify their input. ball.prox(x, tau) has the same aliasing. Solvers usually rebind rather than mutate, so this is probably fine, and it avoids a copy. It would be worth a one-line note in the docstring, or you could return x.copy(). assert_array_equal(x, original) only checks that the projection didn't mutate its input. It doesn't catch aliasing.
  2. Array backend (pyproximal/projection/L1.py:57). np.sum(np.abs(x)) is written for numpy, as the rest of the method is. If cupy support is wanted here, use get_array_module(x). This is the same as before the PR, so it's optional.
  3. Tests, docstrings requested by @mrava87.
    • test_L1Ball_feasible_inputs (pytests/test_projection.py:164): change to Check that the projection returns the input as already in the ball.
    • test_L1Ball_complex_interior (pytests/test_projection.py:177): it has no docstring. Add a similar one, e.g. Check that complex inputs already in the ball are returned unchanged.
  4. Boundary case (minor). The feasible-input test has [1.0, 0.0], which sits exactly on the boundary at radius 1, so it covers <=. The PR description also mentions complex boundary and zero vectors. Zero is covered. A complex boundary case such as [0.5j, 0.5] would be a small addition.

I have nothing else to flag. Once the docstrings are updated, I think this is good to go.

@mrava87 mrava87 changed the title fix: preserve feasible inputs in L1 ball projection Fix: preserve feasible inputs in L1 ball projection Oct 3, 2026
@mrava87 mrava87 added the bug Something isn't working label Oct 3, 2026
@mrava87
mrava87 merged commit 094e673 into PyLops:dev Oct 3, 2026
16 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.

2 participants