Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

オープン
#420 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
rust
領域
api

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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.

主要言語
Rust
スター
452
フォーク
95
PR マージ指標
30日以内にマージされた PR はありません

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

rust-ndarray/ndarray-linalg のほかの issue

rust-ndarray/ndarray-linalg の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。