Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

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

Ouverte
#420 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
48/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
Active
Stack technique
rust
Domaine
api

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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.

Langage dominant
Rust
Étoiles
452
Forks
95
Métriques de merge des PR
Aucune PR mergée en 30 j

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de rust-ndarray/ndarray-linalg

Toutes les issues de rust-ndarray/ndarray-linalg

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.