Skip to content

Commit 4eed112

Browse files
authored
Simplify svd code now that upper bidiagonal matrices can be processed (#159)
1 parent 79b8953 commit 4eed112

File tree

2 files changed

+12
-31
lines changed

2 files changed

+12
-31
lines changed

src/svd.jl

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ function svdDemmelKahan!(
111111
d[n2] = h * Gold.c
112112

113113
else
114-
throw(ArgumentError("lower bidiagonal version not implemented yet"))
114+
throw(ArgumentError("please convert to upper bidiagonal"))
115115
end
116116

117117
return B
@@ -248,8 +248,7 @@ function __svd!(
248248
iteration += 1
249249
end
250250
else
251-
# Just transpose the matrix
252-
error("SVD for lower triangular bidiagonal matrices isn't implemented yet.")
251+
throw(ArgumentError("please convert to upper bidiagonal"))
253252
end
254253
end
255254

@@ -288,7 +287,7 @@ end
288287
# of givens rotations from the left. A noop if the Bidiagnoal is
289288
# already upper.
290289
function _lower_to_upper!(B::Bidiagonal, U::Matrix)
291-
if istriu(B)
290+
if B.uplo === 'U'
292291
return B
293292
end
294293
for i in 1:length(B.ev)
@@ -647,38 +646,18 @@ function LinearAlgebra.svd!(
647646
# Convert the input matrix A to bidiagonal form and return a BidiagonalFactorization object
648647
BF = bidiagonalize!(A)
649648

650-
# The location of the super/sub-diagonal of the bidiagonal matrix depends on the aspect ratio of the input. For tall and square matrices, the bidiagonal matrix is upper whereas it is lower for wide input matrices as illustrated below. The 'O' entries indicate orthogonal (unitary) matrices.
651-
652-
# A = Q_l * B * Q_r^H
653-
654-
# |x x x| = |O O O| |x x | |O O O|
655-
# |x x x| |O O O|*| x x|*|O O O|
656-
# |x x x| |O O O| | x| |O O O|
657-
# |x x x| |O O O|
658-
# |x x x| |O O O|
659-
660-
# |x x x x x| = |O O O| |x | |O O O O O|
661-
# |x x x x x| |O O O|*|x x |*|O O O O O|
662-
# |x x x x x| |O O O| | x x| |O O O O O|
663-
664-
_B = BF.bidiagonal
665-
B = _B.uplo === 'U' ? _B : Bidiagonal(_B.dv, _B.ev, :U)
649+
B = BF.bidiagonal
666650

667651
# Compute the SVD of the bidiagonal matrix B
668652
F = _svd!(B, tol = tol)
669653

670654
# Form the matrices U and Vᴴ by combining the singular vector matrices of the bidiagonal SVD with the Householder reflectors from the bidiagonal factorization.
671-
if _B.uplo === 'U'
672-
U = Matrix{T}(I, m, full ? m : n)
673-
U[1:n, 1:n] = F.U
674-
lmul!(BF.leftQ, U)
675-
Vᴴ = F.Vt * BF.rightQ'
676-
else
677-
U = BF.leftQ * F.V
678-
Vᴴ = Matrix{T}(I, full ? n : m, n)
679-
Vᴴ[1:m, 1:m] = F.U'
680-
rmul!(Vᴴ, BF.rightQ')
681-
end
655+
U = Matrix{T}(I, m, full ? m : min(m, n))
656+
U[1:min(m, n), 1:min(m, n)] = F.U
657+
lmul!(BF.leftQ, U)
658+
Vᴴ = Matrix{T}(I, full ? n : min(m, n), n)
659+
Vᴴ[1:min(m, n), 1:min(m, n)] = F.Vt
660+
rmul!(Vᴴ, BF.rightQ')
682661

683662
s = F.S
684663

test/svd.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,5 +273,7 @@ using Test, GenericLinearAlgebra, LinearAlgebra, Quaternions, DoubleFloats
273273
U, s, V = GenericLinearAlgebra._svd!(copy(B))
274274
@test B U * Diagonal(s) * V'
275275
@test_throws ArgumentError("please convert to upper bidiagonal") GenericLinearAlgebra.svdIter!(B, 1, size(B, 1), 1.0)
276+
@test_throws ArgumentError("please convert to upper bidiagonal") GenericLinearAlgebra.svdDemmelKahan!(B, 1, size(B, 1), 1.0)
277+
@test_throws ArgumentError("please convert to upper bidiagonal") GenericLinearAlgebra.__svd!(B)
276278
end
277279
end

0 commit comments

Comments
 (0)