Skip to content

Add DBDSVDMR3: MRRR-based bidiagonal SVD (Golub-Kahan TGK) with DBDSDC safety fallback - #1361

Draft
saisuryadv wants to merge 3 commits into
Reference-LAPACK:masterfrom
saisuryadv:dbdsvr-mrrr-bidiagonal-svd
Draft

Add DBDSVDMR3: MRRR-based bidiagonal SVD (Golub-Kahan TGK) with DBDSDC safety fallback#1361
saisuryadv wants to merge 3 commits into
Reference-LAPACK:masterfrom
saisuryadv:dbdsvr-mrrr-bidiagonal-svd

Conversation

@saisuryadv

@saisuryadv saisuryadv commented Aug 13, 2026

Copy link
Copy Markdown

Update (naming): per review, the driver is now DBDSVDMR3 (was DBDSVR) and the computational routine DBDSVDMR3_WORK (was DBDSVDMR3); the battery below was re-run after the rename with identical results.

Add DBDSVDMR3: an MRRR-based bidiagonal SVD driver

Summary

DBDSVDMR3 computes the SVD of an n-by-n bidiagonal matrix by the MRRR algorithm applied to the Golub-Kahan tridiagonal, with the same argument list as DBDSVDX (plus LWORK/LIWORK) and a built-in safety net: every output is audited for nonfiniteness and, on audit or nonzero INFO, inputs are restored and DBDSDC recomputes, with the execution path reported in IWORK(2) (1 native / 2 fallback-on-INFO / 3 fallback-on-audit). Motivation: DBDSVDX is 7-228x slower than DBDSVDMR3 on a 16-variety battery and returns unorthogonalized vectors with INFO=0 on clustered spectra (ratios to 2.2e14); DBDSDC remains the deflation-friendly workhorse, and DBDSVDMR3 complements it with the best worst-case time of the four solvers tested.

Integration pattern (mirrors the DBDSVDX integration)

  • SRC/: dbdsvdmr3.f (driver), dbdsvdmr3_work.f, dbdtgk.f, dlar1v_tgk.f, dlarrf_tgk.f, dlarrv_tgk.f, dlarrb_tgk.f (bundled bisection renamed from DLARRB - its extended signature collides with SRC/dlarrb.f; linking the stock routine segfaults).
  • SRC/Makefile, SRC/CMakeLists.txt: DLASRC lists extended.
  • TESTING/EIG/dchkbd.f: tests 35-49, an exact programmatic mirror of the DBDSVDX tests 20-34 (RANGE='A','I','V' x residual, U/VT orthogonality, ordering, values-vs-vectors agreement).
  • TESTING/EIG/derrbd.f: 12 error-exit checks.

Validation on current master (svd.in)

  • All tests for DBD routines passed the threshold ( 14820 tests run)
  • All tests for DBD drivers passed the threshold ( 14820 tests run)
  • All tests for DBD routines passed the threshold ( 14820 tests run)
  • All tests for DBD drivers passed the threshold ( 14820 tests run)
  • All tests for DBD routines passed the threshold ( 14820 tests run)
  • All tests for DBD drivers passed the threshold ( 14820 tests run)
  • All tests for DBD routines passed the threshold ( 14820 tests run)
  • All tests for DBD drivers passed the threshold ( 14820 tests run)
  • All tests for DBD routines passed the threshold ( 14820 tests run)
  • All tests for DBD drivers passed the threshold ( 14820 tests run) - includes the 15 new DBDSVDMR3 tests across all sizes/types.
  • DBD routines passed the tests of the error exits ( 55 tests done) - includes the 12 new checks.

Accuracy on a harder 16-variety battery (separate DCHKBSVR harness)

Sizes 2-100, DBDT04/DORT01 in n.ulp units, threshold 20; identical 240-case RANGE='A' basis; DBDSVDMR3/DBDSVDX additionally exercised on I/V modes:

Method n exact-0 share share > 20 p50 p90 p99 max
DBDSVDMR3 (ours) 240 6% 2.1% 0.20 6.38 25.76 30.20
DBDSDC 240 45% 0.0% 0.01 0.76 1.41 1.53
DBDSVDX 240 32% 0.0% 0.03 0.91 3.41 7.80
MR3GK (Willems & Lang) 240 44% 0.0% 0.02 1.66 4.65 14.50

DBDSVDMR3: 1195/1200 residuals below threshold; the exceedances (max 30.2, i.e. <=1.6x threshold) are confined to Cholesky-lifted geometric spectra where the construction fuses ~80% of sigma into one 1e-13-tight cluster (child-representation selection in dlarrf_tgk; fix path = block factorizations, validated externally). DBDSVDX on the same battery fails variety 8 at up to 2.2e14 with INFO=0 in its I/V modes. Wilkinson-class zero-diagonal inputs route to fallback path 3 by design.

Performance (same battery; ratios are the reliable objects)

N=2000, ms per call (unpinned VM; median 39% absolute drift measured, 11% on ratios; a pinned EPYC 9454 confirms all rankings and reaches 65x over DBDSDC on Clement at n=3000):

Ty Variety DBDSVDMR3 (ours) DBDSDC DBDSVDX MR3GK (Willems & Lang)
1 zero 39.0 3.1 12.3 5.1
2 identity 50.7 6.4 16.5 5.2
3 arith bidiag 296.5 3,451.0† 27,200.0† 8,691.4†
4 geom bidiag 255.6 206.3 23,634.0† 2,968.5†
5 log-dist 88.8 41.2 25,042.0† 287.6
6 arith tri-chol 700.7 1,665.4† 8,585.4† 8,102.7†
7 geom tri-chol 1,124.1† 177.8 19,765.0† 3,276.3†
8 clust tri-chol 85.3 35.0 18.4 17.0
9 arith sqrt-ovfl 278.3 3,715.1† 27,154.0† 8,899.9†
10 arith sqrt-unfl 352.0 3,466.9† 28,675.0† 8,537.3†
11 arith diag 75.5 6.1 15.4 5.0
12 geom diag 72.2 5.9 16.0 5.0
13 clust diag 59.4 6.3 15.0 5.0
14 diag sqrt-ovfl 74.0 7.5 16.3 5.0
15 diag sqrt-unfl 70.7 5.8 19.6 5.0
16 SPD geom-chol 830.6 292.2 20,374.0† 4,169.3†

Pooled t/n^2 percentiles over 80 (variety, size) cases:

Method p25 p50 p75 p90 max
DBDSVDMR3 (ours) 8.6 18.7 63.8 176.5 281.0
DBDSDC 1.6 4.9 83.9 288.3 928.8
DBDSVDX 5.7 390.4 1,389.9 5,139.6 7,168.8
MR3GK (Willems & Lang) 1.3 38.8 1,237.0 1,955.9 2,241.7

DBDSVDMR3 wins exactly the deflation-free spectra (9.8-13.4x over DBDSDC at n=2000), concedes the deflation-friendly ones (2.2-6.3x), has the smallest maximum of any solver, and the best suite total (2.9x over DBDSDC at n=2000, growing with n).

Known limitations / review questions

Double precision only (SBDSVDMR3 to follow); RANGE='I'/'V' currently post-filters a full computation (index pushdown into dlarrv_tgk is the planned follow-up); the two clustered-spectrum exceedance classes above; LAPACKE bindings not included; the fallback introduces a dependency on DBDSDC.

…afety fallback

Same argument list as DBDSVDX plus LWORK/LIWORK. Engine: dqds values,
MRRR vector tree adapted from the DSTEGR lineage (dlarrv/dlar1v/dlarrf
_tgk variants), bundled bounded-progress bisection renamed DLARRB_TGK
to avoid the signature collision with SRC/dlarrb.f. Wrapper audits all
outputs for nonfiniteness and falls back to DBDSDC on audit or error,
reporting the path in IWORK(2).
Tests 35-49 mirror the DBDSVDX tests 20-34 (RANGE='A','I','V' x
residual, U/VT orthogonality, ordering, values-vs-vectors agreement).
derrbd gains 12 corresponding error-exit checks. svd.in on master:
all DBD ratios pass the threshold; error exits 55/55.
@mgates3

mgates3 commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Interesting approach to an SVD with MRRR.

I think names bdsvr and bdsvdmr3 are confusing. If users are looking for an SVD with MRRR, they will likely find the low-level bdsvdmr3 and could miss that the high-level bdsvr is even an SVD. The archaic 6-char limit produced some inscrutable abbreviations; let's not perpetuate the trend. (Note confusion with gesvj and gejsv, which have rather unfortunate names; gesvdj or gesvd_jacobi would be better.)

I'm not sure the best way to distinguish them, but I think both should start bdsvd. I would probably use something like bdsvdmr3 for the high-level driver (currently bdsvr) and bdsvdmr3_work for the low-level computational routine (currently bdsvdmr3). There's not really an LAPACK naming convention for high-level vs. low-level routines. Or bdsvdmrrr or bdsvd_mrrr; the 3 saves only 1 char and is less recognizable.

If the "classic" SVD with MRRR -- which has had numerical stability issues, hence never made it to LAPACK -- were ever added to LAPACK, would it replace these names, or how would it be distinguished? Something to consider.

…SVDMR3_WORK

Addresses mgates3's naming comment: both routines now start bdsvd so
the driver is discoverable as an SVD, with the driver/worker split via
the _work suffix he suggested. Testers, error-exit strings, and build
lists updated; svd.in battery and error exits revalidated.
@saisuryadv

Copy link
Copy Markdown
Author

Thanks @mgates3 — agreed on all points, and I've adopted exactly the pair you suggested. The routines are now:

  • DBDSVRDBDSVDMR3 (high-level driver)
  • DBDSVDMR3DBDSVDMR3_WORK (computational routine)

so both start bdsvd and the driver is discoverable as an SVD. The internal MRRR kernels keep their dlarr*_tgk names, which describe the Golub–Kahan adaptation rather than user-facing functionality. The testers, error-exit strings (derrbd now checks DBDSVDMR3), and both build lists were updated, and the full svd.in battery was re-run after the rename: all DBD ratios pass the threshold across all five data sets, error exits 55/55. PR title and description updated to match.

On your forward-compatibility question: the driver is engine-agnostic — its interface (the DBDSVDX argument list plus LWORK/LIWORK) makes no commitment to how the decomposition is computed. If a "classic" structure-preserving MRRR SVD were added later, the cleanest path would be replacing or augmenting _WORK behind the same DBDSVDMR3 name, since the accuracy characteristics would only improve; if the community preferred both engines exposed, a distinguishing suffix on the worker level keeps the single driver name intact. Happy to adjust further if the team prefers bdsvdmrrr spelled out.

@saisuryadv saisuryadv changed the title Add DBDSVR: MRRR-based bidiagonal SVD (Golub-Kahan TGK) with DBDSDC safety fallback Add DBDSVDMR3: MRRR-based bidiagonal SVD (Golub-Kahan TGK) with DBDSDC safety fallback Aug 19, 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.

2 participants