Skip to content

Commit 52f0a3d

Browse files
authored
Set off diagonal elements to zero as described in LAWN3 p18 (#105)
This fixes a convergence issue when the trailing diagonal element is zero in the bidiagonal input matrix. Fixes #104
1 parent 8338175 commit 52f0a3d

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

src/svd.jl

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,30 @@ function svdDemmelKahan!(
118118
end
119119

120120
# Recurrence to estimate smallest singular value from LAWN3 Lemma 1
121-
function estimate_σ⁻(dv::AbstractVector, ev::AbstractVector, n1::Integer, n2::Integer)
122-
λ = abs(dv[n2])
123-
B∞ = λ
124-
for j = (n2-1):-1:n1
125-
λ = abs(dv[j]) */+ abs(ev[j])))
126-
B∞ = min(B∞, λ)
127-
end
121+
function estimate_σ⁻!(dv::AbstractVector, ev::AbstractVector, n1::Integer, n2::Integer, tol::Real)
128122

123+
# (4.3) p 18
129124
μ = abs(dv[n1])
130125
B1 = μ
131126
for j = n1:(n2-1)
132127
μ = abs(dv[j+1]) */+ abs(ev[j])))
128+
if abs(ev[j] / μ) < tol
129+
ev[j] = 0
130+
end
133131
B1 = min(B1, μ)
134132
end
135133

134+
# (4.4) p 18
135+
λ = abs(dv[n2])
136+
B∞ = λ
137+
for j = (n2-1):-1:n1
138+
λ = abs(dv[j]) */+ abs(ev[j])))
139+
if abs(ev[j] / λ) < tol
140+
ev[j] = 0
141+
end
142+
B∞ = min(B∞, λ)
143+
end
144+
136145
return min(B∞, B1)
137146
end
138147

@@ -154,7 +163,7 @@ function __svd!(
154163
count = 0
155164

156165
# See LAWN3 page 6 and 22
157-
σ⁻ = estimate_σ⁻(d, e, n1, n2)
166+
σ⁻ = estimate_σ⁻!(d, e, n1, n2, tol)
158167
fudge = n
159168
thresh = tol * σ⁻
160169

@@ -208,7 +217,7 @@ function __svd!(
208217
# current block to determine if it's safe to use shift or if
209218
# the zero shift algorithm is required to maintain high relative
210219
# accuracy
211-
σ⁻ = estimate_σ⁻(d, e, n1, n2)
220+
σ⁻ = estimate_σ⁻!(d, e, n1, n2, tol)
212221
σ⁺ = max(maximum(view(d, n1:n2)), maximum(view(e, n1:(n2-1))))
213222

214223
if fudge * tol * σ⁻ <= eps(σ⁺)

test/svd.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,12 @@ using Test, GenericLinearAlgebra, LinearAlgebra, Quaternions, DoubleFloats
115115
)
116116
@test svdvals(A) svdvals(Complex{Double64}.(A))
117117
end
118+
119+
@testset "Issue 104. Trailing zero in bidiagonal." begin
120+
dv = [-1.8066303423244812, 0.23626846066361504, -1.8244461746384022, 0.3743075843671794, -1.503025651470883, -0.5273978245088017, 6.194053744695789e-75, -1.4816465601202412e-77, -7.05967042009753e-78, -1.8409609384104132e-78, -3.5760859484965067e-78, 1.7012650564461077e-153, -5.106470534144341e-155, 3.6429789846941095e-155, -3.494481025232055e-232, 0.0]
121+
ev = [2.6390728646133144, 1.9554155623906322, 1.9171721320115487, 2.5486042731357257, 1.6188084135207441, -1.2764293576778472, -3.0873284294725004e-77, 1.0815807869027443e-77, -1.0375522364338647e-77, -9.118279619242446e-78, 5.910901980416107e-78, -7.522759136373737e-155, 1.1750163871116314e-154, -2.169544740239464e-155, 2.3352910098001318e-232]
122+
B = Bidiagonal(dv, ev, :U)
123+
F = GenericLinearAlgebra._svd!(copy(B))
124+
@test diag(F.U'*B*F.Vt') F.S rtol=5e-15
125+
end
118126
end

0 commit comments

Comments
 (0)