Skip to content

Commit 7e34171

Browse files
authored
Add deflation to svd algorithm (#108)
This ensures that the estimate for the smallest singular value is correctly updated during the calculations.
1 parent b9370eb commit 7e34171

File tree

2 files changed

+140
-4
lines changed

2 files changed

+140
-4
lines changed

src/svd.jl

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,13 @@ 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, tol::Real)
121+
function estimate_σ⁻!(
122+
dv::AbstractVector,
123+
ev::AbstractVector,
124+
n1::Integer,
125+
n2::Integer,
126+
tol::Real,
127+
)
122128

123129
# (4.3) p 18
124130
μ = abs(dv[n1])
@@ -169,6 +175,24 @@ function __svd!(
169175

170176
if B.uplo === 'U'
171177
while true
178+
@label top
179+
180+
# Deflation check. See LAWN3 p21
181+
for i = n1:n2
182+
if d[i] == 0
183+
debug && println("Deflation! Exact zero in $(i)th diagonal element.")
184+
svdDemmelKahan!(B, n1, n2, U, Vᴴ)
185+
186+
# We have now moved a zero to the end so the problem is one smaller
187+
n2 -= 1
188+
189+
# We can now reestimate the smallest value and set a new threshold
190+
σ⁻ = estimate_σ⁻!(d, e, n1, n2, tol)
191+
fudge = n2 - n1 + 1
192+
thresh = tol * σ⁻
193+
@goto top
194+
end
195+
end
172196

173197
# Search for biggest index for non-zero off diagonal value in e
174198
for n2i = n2:-1:1

test/svd.jl

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,122 @@ using Test, GenericLinearAlgebra, LinearAlgebra, Quaternions, DoubleFloats
117117
end
118118

119119
@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]
120+
dv = [
121+
-1.8066303423244812,
122+
0.23626846066361504,
123+
-1.8244461746384022,
124+
0.3743075843671794,
125+
-1.503025651470883,
126+
-0.5273978245088017,
127+
6.194053744695789e-75,
128+
-1.4816465601202412e-77,
129+
-7.05967042009753e-78,
130+
-1.8409609384104132e-78,
131+
-3.5760859484965067e-78,
132+
1.7012650564461077e-153,
133+
-5.106470534144341e-155,
134+
3.6429789846941095e-155,
135+
-3.494481025232055e-232,
136+
0.0,
137+
]
138+
ev = [
139+
2.6390728646133144,
140+
1.9554155623906322,
141+
1.9171721320115487,
142+
2.5486042731357257,
143+
1.6188084135207441,
144+
-1.2764293576778472,
145+
-3.0873284294725004e-77,
146+
1.0815807869027443e-77,
147+
-1.0375522364338647e-77,
148+
-9.118279619242446e-78,
149+
5.910901980416107e-78,
150+
-7.522759136373737e-155,
151+
1.1750163871116314e-154,
152+
-2.169544740239464e-155,
153+
2.3352910098001318e-232,
154+
]
155+
B = Bidiagonal(dv, ev, :U)
156+
F = GenericLinearAlgebra._svd!(copy(B))
157+
@test diag(F.U' * B * F.Vt') F.S rtol = 5e-15
158+
159+
dv = [
160+
-2.130128478463753,
161+
1.1531468092039445,
162+
-2.847352842043162,
163+
0.6231779022541623,
164+
-1.690093069308479,
165+
-1.1624695467913961,
166+
-2.6642152887216867e-14,
167+
-0.33250510974785286,
168+
-2.2586294525518498,
169+
-1.1141061997716504,
170+
-3.1527435586000423,
171+
-1.823897129321229,
172+
-0.36124507542200524,
173+
-1.077527351579055e-14,
174+
-0.5940127483326197,
175+
-3.250185182454264,
176+
1.3384585640782973,
177+
3.5078636357910748e-16,
178+
-3.6405198891576764e-16,
179+
1.4444960997803543e-16,
180+
-2.7341646772961597e-16,
181+
-1.4813555234291996e-16,
182+
1.975443684819806e-16,
183+
1.6250251794596737e-16,
184+
-1.2910786368068701e-16,
185+
4.4994314760009794e-17,
186+
4.746123492548763e-17,
187+
-8.50145831025358e-17,
188+
-2.7086126595918776e-29,
189+
1.4778381126941581e-31,
190+
8.563148986816008e-33,
191+
-2.576078852735729e-33,
192+
-5.670281645899369e-33,
193+
-4.3644672970128596e-46,
194+
3.038140544755097e-48,
195+
0.0,
196+
]
197+
ev = [
198+
2.1119692536821772,
199+
1.6448724864758517,
200+
-2.9887577094992634,
201+
-2.806523896769826,
202+
0.9686419967280151,
203+
-1.2565901258480143,
204+
-3.154707543364588,
205+
-2.128054620058084,
206+
1.263977392456184,
207+
7.354767862969798e-15,
208+
-0.36808384394360333,
209+
-2.688934874241276,
210+
1.329995154812558,
211+
-3.065722852484613,
212+
-0.6498657781673701,
213+
-0.0512439655384504,
214+
-5.784793952948882e-14,
215+
-3.748937717520342e-16,
216+
-3.451207270993785e-16,
217+
2.0899684974141464e-16,
218+
-2.794129724370907e-16,
219+
-2.2565321108962225e-16,
220+
1.7575656432452187e-16,
221+
1.029754558145647e-16,
222+
-1.5753211255094817e-16,
223+
1.4236049613292231e-16,
224+
-1.26511866970657e-16,
225+
-8.86788043706418e-17,
226+
2.2436351171246806e-30,
227+
-1.5828202903652256e-32,
228+
-1.1811335201359479e-32,
229+
-7.40990609589365e-33,
230+
-4.2582071949325636e-33,
231+
-1.8291280657969477e-46,
232+
1.9436291711597153e-50,
233+
]
122234
B = Bidiagonal(dv, ev, :U)
123235
F = GenericLinearAlgebra._svd!(copy(B))
124-
@test diag(F.U'*B*F.Vt') F.S rtol=5e-15
236+
@test diag(F.U' * B * F.Vt') F.S rtol = 5e-15
125237
end
126238
end

0 commit comments

Comments
 (0)