@@ -102,9 +102,28 @@ function svdDemmelKahan!(B::Bidiagonal{T}, n1, n2, U = nothing, Vᴴ = nothing)
102
102
return B
103
103
end
104
104
105
+ # Recurrence to estimate smallest singular value from LAWN3 Lemma 1
106
+ function estimate_σ⁻ (dv:: AbstractVector , ev:: AbstractVector , n1:: Integer , n2:: Integer )
107
+ λ = abs (dv[n2])
108
+ B∞ = λ
109
+ for j in (n2 - 1 ): - 1 : n1
110
+ λ = abs (dv[j])* (λ/ (λ + abs (ev[j])))
111
+ B∞ = min (B∞, λ)
112
+ end
113
+
114
+ μ = abs (dv[n1])
115
+ B1 = μ
116
+ for j in n1: (n2 - 1 )
117
+ μ = abs (dv[j + 1 ])* (μ* (μ + abs (ev[j])))
118
+ B1 = min (B1, μ)
119
+ end
120
+
121
+ return min (B∞, B1)
122
+ end
123
+
105
124
# The actual SVD solver routine
106
125
# Notice that this routine doesn't adjust the sign and sorts the values
107
- function __svd! (B:: Bidiagonal{T} , U = nothing , Vᴴ = nothing ; tol = eps (T), debug = false ) where T<: Real
126
+ function __svd! (B:: Bidiagonal{T} , U = nothing , Vᴴ = nothing ; tol = 100 eps (T), debug = false ) where T<: Real
108
127
109
128
n = size (B, 1 )
110
129
n1 = 1
@@ -113,22 +132,21 @@ function __svd!(B::Bidiagonal{T}, U = nothing, Vᴴ = nothing; tol = eps(T), deb
113
132
e = B. ev
114
133
count = 0
115
134
135
+ # See LAWN3 page 6 and 22
136
+ σ⁻ = estimate_σ⁻ (d, e, n1, n2)
137
+ fudge = n
138
+ thresh = tol* σ⁻
139
+
116
140
if istriu (B)
117
141
while true
118
142
119
143
# Search for biggest index for non-zero off diagonal value in e
120
144
for n2i = n2: - 1 : 1
121
145
if n2i == 1
122
146
# We are done!
123
-
124
147
return nothing
125
148
else
126
- tolcritTop = tol * abs (d[n2i - 1 ] * d[n2i])
127
-
128
- # debug && println("n2i=", n2i, ", d[n2i-1]=", d[n2i-1], ", d[n2i]=", d[n2i],
129
- # ", e[n2i-1]=", e[n2i-1], ", tolcritTop=", tolcritTop)
130
-
131
- if abs (e[n2i - 1 ]) > tolcritTop
149
+ if abs (e[n2i - 1 ]) > thresh
132
150
n2 = n2i
133
151
break
134
152
end
@@ -137,40 +155,45 @@ function __svd!(B::Bidiagonal{T}, U = nothing, Vᴴ = nothing; tol = eps(T), deb
137
155
138
156
# Search for largest sub-bidiagonal matrix ending at n2
139
157
for _n1 = (n2 - 1 ): - 1 : 1
140
-
141
- if _n1 == 1
158
+ if abs (e[_n1]) < thresh
159
+ n1 = _n1
160
+ break
161
+ elseif _n1 == 1
142
162
n1 = _n1
143
163
break
144
- else
145
- tolcritBottom = tol * abs (d[_n1 - 1 ] * d[_n1])
146
-
147
- # debug && println("n1=", n1, ", d[n1]=", d[n1], ", d[n1-1]=", d[n1-1], ", e[n1-1]", e[n1-1],
148
- # ", tolcritBottom=", tolcritBottom)
149
-
150
- if abs (e[_n1 - 1 ]) < tolcritBottom
151
- n1 = _n1
152
- break
153
- end
154
164
end
155
165
end
156
166
157
- debug && println (" n1=" , n1, " , n2=" , n2, " , d[n1]=" , d[n1], " , d[n2]=" , d[n2], " , e[n1]=" , e[n1])
167
+ debug && println (" n1=" , n1, " , n2=" , n2, " , d[n1]=" , d[n1], " , d[n2]=" , d[n2], " , e[n1]=" , e[n1], " e[n2]= " , e[n2 - 1 ], " thresh= " , thresh )
158
168
159
- # FixMe! Calling the zero shifted version only the first time is adhoc but seems
160
- # to work well. Reexamine analysis in LAWN 3 to improve this later.
161
- if count == 0
169
+
170
+ # See LAWN 3 p 18 and
171
+ # We approximate the smallest and largest singular values of the
172
+ # current block to determine if it's safe to use shift or if
173
+ # the zero shift algorithm is required to maintain high relative
174
+ # accuracy
175
+ σ⁻ = estimate_σ⁻ (d, e, n1, n2)
176
+ σ⁺ = max (maximum (view (d, n1: n2)), maximum (view (e, n1: (n2 - 1 ))))
177
+
178
+ if fudge* tol* σ⁻ <= eps (σ⁺)
162
179
svdDemmelKahan! (B, n1, n2, U, Vᴴ)
163
180
else
164
181
shift = svdvals2x2 (d[n2 - 1 ], d[n2], e[n2 - 1 ])[1 ]
165
- svdIter! (B, n1, n2, shift, U, Vᴴ)
182
+ if shift^ 2 < eps (B. dv[n1]^ 2 )
183
+ # Shift is too small to affect the iteration so just use
184
+ # zero-shift algorithm anyway
185
+ svdDemmelKahan! (B, n1, n2, U, Vᴴ)
186
+ else
187
+ svdIter! (B, n1, n2, shift, U, Vᴴ)
188
+ end
166
189
end
190
+
167
191
count += 1
168
192
debug && println (" count=" , count)
169
193
end
170
194
else
171
195
# Just transpose the matrix
172
- error (" " )
173
- # return _svd!(Bidiagonal(d, e, :U), Vᴴ, U; tol = tol, debug = debug)
196
+ error (" SVD for lower triangular bidiagonal matrices isn't implemented yet." )
174
197
end
175
198
end
176
199
0 commit comments