This site is version 0.0.1. Most of the code on this site is drafted by an agent and needs review. I apologize for the AI-speak, we are working on rewriting it!
viv-lang.org

Notebooks · lib/svd

The singular value decomposition, by one-sided Jacobi

A = U S V^T, with U and V orthonormal and S diagonal and non-negative. This is the decomposition that answers what a matrix does to the unit sphere, what its rank is when the answer is not a whole number, and which directions of its input it barely notices.

The temptation is to get it from eig_sym(A^T A): the eigenvectors are V and the eigenvalues are the squares of the singular values. That works, and it is wrong for the small ones, because squaring the matrix squares its condition number and each singular value comes back with about half the digits it should have. The last test measures it on a matrix built to have singular values 1, 10−3, 10−6, 10−9, 1e-12. Relative error in each, one-sided Jacobi against the squared route:

1       1.1e-15     1.2e-15
1e-3    7.4e-15     5.1e-12
1e-6    8.5e-12     2.0e-6
1e-9    3.0e-8      0.34
1e-12   1.8e-5      1.0

The squared route has lost a third of the fourth value and the whole of the fifth, which it returns as zero. Some of what Jacobi loses further down that column is the test matrix rather than the method: writing Q1 diag(s) Q2^T into double precision already perturbs a singular value of 1e-12 relative to a largest of 1.

One-sided Jacobi does it differently. Take pairs of columns of A and rotate each pair until the two are orthogonal, which is a 2 by 2 eigenvalue problem with a closed form. Sweep over all pairs, repeat, and the columns converge to mutually orthogonal vectors. Their lengths are the singular values and their directions are U; the accumulated rotations are V. Nothing is ever squared except inside a single 2 by 2, so the small singular values keep their digits.

A must have at least as many rows as columns. For a wide matrix, decompose its transpose and swap U and V.

Used with import svd.

Look inside this program

  • Atlas

    The program’s map: every function and which calls which.

  • There’s no recorded run of this program yet.

Shift+Enter in a cell runs it and moves to the next. Running a cell runs every cell above it too, as one program.

[1]lines 43–310