Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

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

Đang mở
#420 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
rust
Lĩnh vực
api

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.

Ngôn ngữ chính
Rust
Star
452
Fork
95
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của rust-ndarray/ndarray-linalg

Tất cả issue của rust-ndarray/ndarray-linalg

Issue tương tự

Thêm issue về Rust

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.