Skip to content

feat: bound the number of sweeps the SVD spends on one singular value - #220

Closed
tayal-sarthak wants to merge 5 commits into
mljs:mainfrom
tayal-sarthak:svdbound
Closed

feat: bound the number of sweeps the SVD spends on one singular value#220
tayal-sarthak wants to merge 5 commits into
mljs:mainfrom
tayal-sarthak:svdbound

Conversation

@tayal-sarthak

Copy link
Copy Markdown

Closes #70.

Summary

The issue reports a dataset that hangs, with the observation that p never drops below 93. That p is the counter driving the sweep in the singular value decomposition:

let iter = 0;
...
while (p > 0) {
  ...
  iter = iter + 1;

iter is raised on every sweep along with being reset once a singular value settles, yet nothing ever reads it. There is no ceiling anywhere in the loop, so an input the sweep cannot settle keeps it going with no way out. The caller gets no error, no result, and no thread back.

LAPACK bounds the same loop, dbdsqr allowing 6 sweeps per singular value before it reports failure.

The ceiling

A maxIterations option, 100 by default, caps how many sweeps any one singular value gets. Passing it means the sweep is stuck, which is reported:

Error: SVD did not converge after 100 iterations on a single singular value

Choosing the default

Measuring how many sweeps a decomposition that converges takes per singular value, across random matrices:

ceiling 40x25, out of 40 200x150, out of 10
1 40 reported 10 reported
2 40 reported 10 reported
3 37 reported 10 reported
5 none none
10 none none
100 none none

Four sweeps covers every case measured, and the figure does not grow with the size of the input, since the count is spent per singular value rather than over the whole run. A default of 100 therefore sits at roughly 25 times what a decomposition needs, wide enough that a converging input cannot reach it, while a stuck one stops in bounded time instead of running on.

Compatibility

Every decomposition that converges today behaves exactly as before. The only inputs affected are the ones that never finish.

@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.94%. Comparing base (1a4a05a) to head (52c9aec).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #220      +/-   ##
==========================================
+ Coverage   68.88%   68.94%   +0.06%     
==========================================
  Files          49       49              
  Lines        5904     5916      +12     
  Branches     1060     1064       +4     
==========================================
+ Hits         4067     4079      +12     
  Misses       1824     1824              
  Partials       13       13              

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@targos targos closed this Aug 6, 2026
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.

Large dataset caught in an infinite loop

2 participants