Status: proposal, not started (2026-10-07).
For one matrix, or a batch smaller than the cores, the CPU path calls
LAPACK’s drivers whole: ssyevd for eigh with vectors, sgesdd for the SVD.
Their divide and conquer (sstedc, sbdsdc) runs on one core. The tridiag
and bidiag backends now use src/divide_conquer.cpp, which runs it on
every core (2.15.0). Call the drivers’ steps one by one in the CPU path too:
ssytrd, tridiagonal_eigensystem, sormtr for eigh, and sgebrd,
bidiagonal_svd, sormbr twice for the SVD, keeping the QR first for tall
matrices as now.
One matrix on an M5 Pro, Accelerate (sweep timings, and the divide and
conquer alone on the tridiagonal of ssytrd and the bidiagonal of sgebrd
of a Gaussian matrix):
| CPU path | its divide and conquer | on every core | |
|---|---|---|---|
| eigh, 1024 | 41 ms | sstedc 12 ms |
3.8 ms |
| eigh, 2048 | 239 ms | 43 ms | 10 ms |
| SVD, 1024 | 78 ms | sbdsdc 28 ms |
7.8 ms |
| SVD, 2048 | 439 ms | 133 ms | 22 ms |
So, if the rest of the driver stays as it is: eigh 1.25x at 1024 and 1.16x at
2048; the SVD 1.34x at both. Above 2048 the GPU backends take one matrix
anyway; below about 1024 tridiag and bidiag are not used, and these are
the calls the CPU path serves.
eigh_cpu for batches below cpu_threads(): query the workspace,
ssytrd, the divide and conquer with cpu_threads() threads, sormtr.
Match ssyevd’s scaling (it scales A when its norm is outside the safe
range; the library already scales every matrix by a power of two, so
this may be moot).svd_cpu likewise: sgebrd, bidiagonal_svd, sormbr("Q") on U and
sormbr("P") on VT, inside the existing QR-first wrapper for tall input.About two days: a day for the two drivers and their workspaces, the rest for tests (the suites’ CPU sections and the structured cases) and the re-measure.
1.15-1.35x for one matrix of 1024-2048 on the CPU path (an estimate: it
assumes ssyevd and sgesdd spend the rest as ssytrd/sormtr and
sgebrd/sormbr would alone). Batches gain only while there are fewer
matrices than cores; lapack_batches already gives each core a matrix.
core::detail::eigh_cpu in src/eigh.mm and svd_cpu in src/svd.mm;
tridiagonal_eigensystem and bidiagonal_svd in src/divide_conquer.h.