Skip to content

LSMR: return x = 0 instead of NaN when Aᴴb = 0 - #169

Merged
Jutho merged 2 commits into
Jutho:masterfrom
ParadaCarleton:lsmr-zero-rhs
Sep 24, 2026
Merged

Jutho merged 2 commits into
Jutho:masterfrom
ParadaCarleton:lsmr-zero-rhs

Conversation

@ParadaCarleton

@ParadaCarleton ParadaCarleton commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

lssolve with LSMR returns NaNs when b = 0, or more generally when Aᴴb = 0:

julia> using KrylovKit
julia> A = [2.0 1; 0 3; 1 1];
julia> x, info = lssolve((v -> A * v, w -> A' * w), zeros(3));
julia> x, info.converged
([NaN, NaN], 0)

The exact solution is x = 0 in both cases, also with damping λ, since the gradient -Aᴴb of the objective vanishes there. The initialisation divides u by β = ‖b‖ and v by α before the early-return check on ζ̄ = α * β = ‖Aᴴb‖, so that check sees NaN and never fires.

This PR moves the early return before the normalisation, computing ‖Aᴴb‖ directly. It also treats an exactly vanishing ‖Aᴴb‖ as converged, so the case is handled with tol = 0 too. The main loop is unchanged.

I hit this through ImplicitDifferentiation.jl, whose IterativeLeastSquaresSolver calls lssolve on tangents and cotangents, so any zero tangent produced NaN derivatives.

The new testset covers b = 0 and b ≠ 0 with Aᴴb = 0, with and without damping and tol ∈ (0, 1e-8), over the existing wrap modes. It fails 182 of 200 checks on master and passes with this change. The existing lssolve and issue tests still pass locally (Julia 1.13).

The early return compared ‖Aᴴb‖ = α * β with the tolerance only after normalising by β and α, so b = 0 or Aᴴb = 0 divided by zero and returned NaN. Check before normalising; x = 0 then solves the (damped) least-squares problem exactly.
@codecov

codecov Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.50000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 86.65%. Comparing base (6c0cc8b) to head (0653cfc).

Files with missing lines Patch % Lines
src/lssolve/lsmr.jl 87.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #169      +/-   ##
==========================================
- Coverage   88.42%   86.65%   -1.77%     
==========================================
  Files          36       36              
  Lines        3964     3918      -46     
==========================================
- Hits         3505     3395     -110     
- Misses        459      523      +64     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/lssolve/lsmr.jl Outdated
Co-authored-by: Jutho <Jutho@users.noreply.github.com>
@Jutho

Jutho commented Sep 24, 2026

Copy link
Copy Markdown
Owner

Thanks, test failures seem unrelated, but will require me to take a look into this before tagging a new version.

@Jutho
Jutho merged commit 4808454 into Jutho:master Sep 24, 2026
8 of 15 checks passed
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