Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

lobpcg::TruncatedSvd maps non-converged LOBPCG results to Ok, hiding convergence failure

Offen
#420 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Anfängerfreundlichkeit
48/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Aktiv
Tech-Stack
rust
Bereich
api

Rechercherichtung

Start in src/lobpcg/svd.rs at TruncatedSvd::decompose and inspect LobpcgResult handling around lines 162-172, then review the result type and the maxiter setup around line 105. Check src/generate.rs and issue #336 for the separate RNG concern. Done means non-convergence is no longer silently reported as success, with the chosen result API covered by appropriate tests.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Summary

lobpcg::TruncatedSvd::decompose maps a non-converged LOBPCG result onto Ok(..), so callers cannot distinguish a converged decomposition from a failed one and may silently receive wrong singular values.

Version inspected: ndarray-linalg 0.17.0 (source from crates.io).

Where

src/lobpcg/svd.rs:162-172:

match res {
    LobpcgResult::Ok(vals, vecs, _) | LobpcgResult::Err(vals, vecs, _, _) => {
        Ok(TruncatedSvdResult {
            problem: self.problem,
            eigvals: vals,
            eigvecs: vecs,
            ngm: n > m,
        })
    }
    LobpcgResult::NoResult(err) => Err(err),
}

LobpcgResult::Err(..) carries the error as its fourth field and it is dropped on the floor. Returning the partial result is reasonable; giving the caller no way to learn that it is partial is the problem.

Contributing factor: maxiter defaults to problem.len_of(Axis(0)) * 2 (svd.rs:105), which is a small iteration budget for small inputs — exactly where I measured the worst errors in the sibling implementation.

Evidence

I want to be straightforward about what I did and did not run.

Verified by source inspection in ndarray-linalg 0.17.0: the LobpcgResult::Err(..) => Ok(..) mapping above, and the maxiter default.

Not executed against ndarray-linalg: I do not have a LAPACK backend configured locally, so I could not run a reproduction through this crate.

Measured in linfa-linalg 0.2.1, whose lobpcg::TruncatedSvd is the same algorithm with the same structure (Err((_, Some(Lobpcg{..}))) => Ok(..), same 2 * n_samples default, same epsilon * correction * λ_max cutoff). Taking X = U diag(4, 3, 2, 1) Vᵀ with U (8×4) and V (4×4) built from Sylvester–Hadamard columns, so the singular values are exactly [4, 3, 2, 1] by construction:

k=1  returned Ok  sigma=[4.0]                          max rel err=2.220e-16
k=2  returned Ok  sigma=[4.0, 3.0]                     max rel err=4.441e-16
k=3  returned Ok  sigma=[3.94368, 2.67522, 1.477172]   max rel err=2.614e-1   <== WRONG
k=4  returned Ok  sigma=[4.0, 3.0, 2.0, 1.0]           max rel err=2.517e-15

A 26% error reported as success, with neighbouring block sizes exact to machine precision. I would expect the same behaviour here given the shared structure, but I have not confirmed the exact numbers under LAPACK — if that distinction matters to you, treat the code-level finding as the claim and the numbers as indicative.

Filed in parallel as rust-ml/linfa-linalg#20.

Secondary: the result is not reproducible

decompose initialises its starting block with generate::random(..) (svd.rs:132), and generate::random uses thread_rng() (src/generate.rs:36). There is no new_with_rng equivalent, so successive runs of the same program on the same input can land on different subspaces and different component signs. Combined with the silent non-convergence above, that makes the failure intermittent as well as quiet. This overlaps with #336.

Suggested remedies

  1. Surface convergence to the caller — e.g. a converged: bool or the residual norms on TruncatedSvdResult — rather than discarding the error.
  2. Or return Err by default, with the partial result available through an explicit opt-in.
  3. Consider a seedable entry point (new_with_rng) so results are reproducible; linfa-linalg has one.

Glad to put up a PR if you have a preference on direction.

Vorherrschende Sprache
Rust
Sterne
452
Forks
95
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Entwicklungsumgebung

Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus rust-ndarray/ndarray-linalg

Alle Issues in rust-ndarray/ndarray-linalg

Ähnliche Issues

Weitere Issues zu Rust

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.