numerics 0.1.0
Loading...
Searching...
No Matches
svd.cpp
Go to the documentation of this file.
1/// @file svd/svd.cpp
2/// @brief SVD dispatcher + randomized truncated SVD.
3///
4/// One-sided Jacobi SVD
5///
6/// Apply Givens rotations G to the columns of A from the right until the
7/// columns are mutually orthogonal. Each rotation zeros (A^T*A)[p,q]:
8///
9/// Given col_p and col_q of the working matrix A:
10/// alpha = col_p * col_p, beta = col_q * col_q, gamma = col_p * col_q
11/// zeta = (beta - alpha) / (2gamma)
12/// t = sign(zeta) / (|zeta| + sqrt(1 + zeta^2))
13/// c = 1/sqrt(1+t^2), s = c*t
14///
15/// Randomized SVD
16///
17/// Halko, Martinsson, Tropp (2011) "Finding Structure with Randomness".
18///
19/// Backend routing:
20/// Backend::lapack -> backends::lapack::svd (LAPACKE_dgesdd,
21/// divide-and-conquer) everything else -> backends::seq::svd (one-sided
22/// Jacobi)
23
24#include "linalg/svd/svd.hpp"
26#include "backends/seq/impl.hpp"
27#include "backends/lapack/impl.hpp"
28
29namespace num {
30
31SVDResult svd(const Matrix& A_in, Backend backend, real tol, idx max_sweeps) {
32 switch (backend) {
33 case Backend::lapack:
34 return backends::lapack::svd(A_in);
35 default:
36 return backends::seq::svd(A_in, tol, max_sweeps);
37 }
38}
39
40// Randomized truncated SVD -- Halko, Martinsson, Tropp (2011)
41//
42// Steps:
43// 1. Draw Omega in R^{nx(k+p)} (Gaussian random sketch)
44// 2. Y = A * Omega
45// 3. Q, _ = QR(Y) (orthonormal basis for approx. range of A)
46// 4. B = Q^T * A (project to small k-dimensional subspace)
47// 5. U~, Sigma, V^T = svd(B) (cheap: B is (k+p)xn, small)
48// 6. U = Q * U~ (lift back to full dimension)
49
51 idx k,
52 Backend backend,
53 idx oversampling,
54 Rng* rng) {
55 const idx m = A.rows(), n = A.cols();
56 if (k == 0 || k > std::min(m, n))
57 throw std::invalid_argument("svd_truncated: k out of range");
58
59 const idx l = k + oversampling;
60
61 Rng local_rng;
62 if (!rng)
63 rng = &local_rng;
64
65 // 1. Gaussian sketch matrix Omega in R^{nxl}
66 Matrix Omega(n, l);
67 for (idx j = 0; j < l; ++j)
68 for (idx i = 0; i < n; ++i)
69 Omega(i, j) = rng_normal(rng, 0.0, 1.0);
70
71 // 2. Y = A * Omega (m x l)
72 Matrix Y(m, l, 0.0);
73 matmul(A, Omega, Y, backend);
74
75 // 3. Q = QR(Y).Q (m x m, orthonormal columns)
76 QRResult qr_res = qr(Y);
77 const Matrix& Q = qr_res.Q;
78
79 // 4. B = Q^T * A (l x n)
80 Matrix B(l, n, 0.0);
81 for (idx i = 0; i < l; ++i)
82 for (idx kk = 0; kk < m; ++kk) {
83 const real q_ki = Q(kk, i);
84 for (idx j = 0; j < n; ++j)
85 B(i, j) += q_ki * A(kk, j);
86 }
87
88 // 5. SVD of B (small: l x n)
89 SVDResult small = svd(B, backend);
90
91 // 6. U = Q * U~[:, 0..k-1] (m x k)
92 Matrix U(m, k, 0.0);
93 for (idx j = 0; j < k; ++j)
94 for (idx i = 0; i < m; ++i)
95 for (idx ii = 0; ii < l; ++ii)
96 U(i, j) += Q(i, ii) * small.U(ii, j);
97
98 Vector S(k);
99 for (idx i = 0; i < k; ++i)
100 S[i] = small.S[i];
101
102 Matrix Vt(k, n, 0.0);
103 for (idx i = 0; i < k; ++i)
104 for (idx j = 0; j < n; ++j)
105 Vt(i, j) = small.Vt(i, j);
106
107 return {U, S, Vt, 0, true};
108}
109
110} // namespace num
Dense row-major matrix with optional GPU storage.
Definition matrix.hpp:12
constexpr idx rows() const noexcept
Definition matrix.hpp:24
constexpr idx cols() const noexcept
Definition matrix.hpp:25
SVDResult svd(const Matrix &A)
Definition svd.cpp:15
SVDResult svd(const Matrix &A, real tol, idx max_sweeps)
Definition svd.cpp:11
SVDResult svd_truncated(const Matrix &A, idx k, Backend backend=default_backend, idx oversampling=10, Rng *rng=nullptr)
Randomized truncated SVD – top-k singular triplets.
Definition svd.cpp:50
double real
Definition types.hpp:10
Backend
Selects which backend handles a linalg operation.
Definition policy.hpp:19
@ lapack
LAPACKE – industry-standard factorizations, SVD, eigen.
QRResult qr(const Matrix &A, Backend backend=lapack_backend)
QR factorization of an mxn matrix A (m >= n) via Householder reflections.
Definition qr.cpp:15
std::size_t idx
Definition types.hpp:11
SVDResult svd(const Matrix &A, Backend backend=lapack_backend, real tol=1e-12, idx max_sweeps=100)
Full SVD of an mxn matrix.
Definition svd.cpp:31
real rng_normal(Rng *r, real mean, real stddev)
Normal (Gaussian) sample with given mean and standard deviation.
Definition math.hpp:296
void matmul(const Matrix &A, const Matrix &B, Matrix &C, Backend b=default_backend)
C = A * B.
Definition matrix.cpp:95
QR factorization via Householder reflections.
Result of a QR factorization: A = Q * R.
Definition qr.hpp:18
Matrix Q
mxm orthogonal
Definition qr.hpp:19
Seeded pseudo-random number generator (Mersenne Twister). Pass a pointer to rng_* functions to draw s...
Definition math.hpp:281
Result of a Singular Value Decomposition: A = U * diag(S) * V^T.
Definition svd.hpp:41
Matrix Vt
rxn right singular vectors (rows orthonormal)
Definition svd.hpp:44
Matrix U
mxr left singular vectors (columns orthonormal)
Definition svd.hpp:42
Vector S
r singular values in descending order
Definition svd.hpp:43
Singular Value Decomposition – dense and randomized truncated.