Skip to content

Commit 79b8953

Browse files
authored
Convert lower to upper bidgiagonal in _svd! and _svdvals! (#158)
This is done by running a single pass of givens rotations from the left while also updating the U matrix. For svdvals!, the uplo field is simply flipped as the singular values of the transpose are the same.
1 parent ec4784b commit 79b8953

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "GenericLinearAlgebra"
22
uuid = "14197337-ba66-59df-a3e3-ca00e7dcff7a"
3-
version = "0.3.17"
3+
version = "0.3.18"
44

55
[deps]
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

src/svd.jl

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function svdIter!(
7171
d[n2] = -G.s * ei1 + G.c * di1
7272

7373
else
74-
throw(ArgumentError("lower bidiagonal version not implemented yet"))
74+
throw(ArgumentError("please convert to upper bidiagonal"))
7575
end
7676

7777
return B
@@ -254,6 +254,7 @@ function __svd!(
254254
end
255255

256256
function _svdvals!(B::Bidiagonal{T}; tol = eps(T)) where {T<:Real}
257+
B = Bidiagonal(B.dv, B.ev, :U)
257258
__svd!(B, tol = tol)
258259
return sort(abs.(diag(B)), rev = true)
259260
end
@@ -283,12 +284,31 @@ function _sort_and_adjust!(U, s, Vᴴ)
283284
return nothing
284285
end
285286

287+
# Convert a lower Bidiagonal to an upper by running a single pass
288+
# of givens rotations from the left. A noop if the Bidiagnoal is
289+
# already upper.
290+
function _lower_to_upper!(B::Bidiagonal, U::Matrix)
291+
if istriu(B)
292+
return B
293+
end
294+
for i in 1:length(B.ev)
295+
G, r = givens(B.dv[i], B.ev[i], i, i + 1)
296+
B.dv[i] = r
297+
B.ev[i] = G.s * B.dv[i + 1]
298+
B.dv[i + 1] = G.c * B.dv[i + 1]
299+
rmul!(U, G')
300+
end
301+
return Bidiagonal(B.dv, B.ev, :U)
302+
end
303+
286304
function _svd!(B::Bidiagonal{T}; tol = eps(T)) where {T<:Real}
287305
n = size(B, 1)
288306

289307
U = Matrix{T}(I, n, n)
290308
Vᴴ = Matrix{T}(I, n, n)
291309

310+
B = _lower_to_upper!(B, U)
311+
292312
__svd!(B, U, Vᴴ, tol = tol)
293313

294314
s = diag(B)

test/svd.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,4 +266,12 @@ using Test, GenericLinearAlgebra, LinearAlgebra, Quaternions, DoubleFloats
266266
@test svdvals(BigFloat[0 0; 1 -1]) [sqrt(2), 0]
267267
@test svdvals(BigFloat[1 0 0; 0 0 0; 0 1 -1]) [sqrt(2), 1, 0]
268268
end
269+
270+
@testset "Lower Bidiagonal matrices. Issue 157" begin
271+
B = Bidiagonal(randn(4), randn(3), :L)
272+
@test GenericLinearAlgebra._svdvals!(copy(B)) GenericLinearAlgebra._svdvals!(copy(B'))
273+
U, s, V = GenericLinearAlgebra._svd!(copy(B))
274+
@test B U * Diagonal(s) * V'
275+
@test_throws ArgumentError("please convert to upper bidiagonal") GenericLinearAlgebra.svdIter!(B, 1, size(B, 1), 1.0)
276+
end
269277
end

0 commit comments

Comments
 (0)