Skip to content

Commit 415e805

Browse files
committed
Add variation to shift strategy as suggested by David Day. Thanks
to Harmen Stoppels for pointing out the issue. Also rename :Wilkinson shift strategy to :Francis since "Wilkinson" seems to be slightly ambiguous in the non-symmetric case. Fixes #29
1 parent c24566d commit 415e805

File tree

2 files changed

+51
-6
lines changed

2 files changed

+51
-6
lines changed

src/eigenGeneral.jl

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ function wilkinson(Hmm, t, d)
7272
end
7373

7474
# We currently absorb extra unsupported keywords in kwargs. These could e.g. be scale and permute. Do we want to check that these are false?
75-
function _schur!(H::HessenbergFactorization{T}; tol = eps(T), debug = false, shiftmethod = :Wilkinson, maxiter = 100*size(H, 1), kwargs...) where T<:Real
75+
function _schur!(H::HessenbergFactorization{T}; tol = eps(T), debug = false, shiftmethod = :Francis, maxiter = 100*size(H, 1), kwargs...) where T<:Real
7676
n = size(H, 1)
7777
istart = 1
7878
iend = n
@@ -122,18 +122,38 @@ function _schur!(H::HessenbergFactorization{T}; tol = eps(T), debug = false, shi
122122
t = iszero(t) ? eps(one(t)) : t # introduce a small pertubation for zero shifts
123123
debug && @printf("block start is: %6d, block end is: %6d, d: %10.3e, t: %10.3e\n", istart, iend, d, t)
124124

125-
if shiftmethod == :Wilkinson
126-
debug && @printf("Double shift with Wilkinson shift! Subdiagonal is: %10.3e, last subdiagonal is: %10.3e\n", HH[iend, iend - 1], HH[iend - 1, iend - 2])
127-
125+
if shiftmethod == :Francis
128126
# Run a bulge chase
129-
doubleShiftQR!(HH, τ, t, d, istart, iend)
127+
if iszero(i % 10)
128+
# Vary the shift strategy to avoid dead locks
129+
# We use a Wilkinson-like shift as suggested in "Sandia technical report 96-0913J: How the QR algorithm fails to converge and how fix it".
130+
131+
debug && @printf("Wilkinson-like shift! Subdiagonal is: %10.3e, last subdiagonal is: %10.3e\n", HH[iend, iend - 1], HH[iend - 1, iend - 2])
132+
_d = t*t - 4d
133+
134+
if _d >= 0
135+
# real eigenvalues
136+
a = t/2
137+
b = sqrt(_d)/2
138+
s = a > Hmm ? a - b : a + b
139+
else
140+
# complex case
141+
s = t/2
142+
end
143+
singleShiftQR!(HH, τ, s, istart, iend)
144+
else
145+
# most of the time use Francis double shifts
146+
147+
debug && @printf("Francis double shift! Subdiagonal is: %10.3e, last subdiagonal is: %10.3e\n", HH[iend, iend - 1], HH[iend - 1, iend - 2])
148+
doubleShiftQR!(HH, τ, t, d, istart, iend)
149+
end
130150
elseif shiftmethod == :Rayleigh
131151
debug && @printf("Single shift with Rayleigh shift! Subdiagonal is: %10.3e\n", HH[iend, iend - 1])
132152

133153
# Run a bulge chase
134154
singleShiftQR!(HH, τ, Hmm, istart, iend)
135155
else
136-
throw(ArgumentError("only support supported shift methods are :Wilkinson (default) and :Rayleigh. You supplied $shiftmethod"))
156+
throw(ArgumentError("only support supported shift methods are :Francis (default) and :Rayleigh. You supplied $shiftmethod"))
137157
end
138158
end
139159
if iend <= 2 break end

test/eigengeneral.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,29 @@ end
2020
end
2121
end
2222

23+
@testset "Convergence in corner cases. Issue 29." begin
24+
function H(n::Int)
25+
H = zeros(2n, 2n)
26+
for i = 1 : 2 : 2n
27+
H[i, i+1] = 1
28+
H[i+1, i] = 1
29+
end
30+
H
31+
end
32+
33+
function E(n::Int)
34+
E = zeros(2n, 2n)
35+
for i = 1 : (n - 1)
36+
E[2i + 1, 2i] = 1
37+
end
38+
E[1, 2n] = 1
39+
E
40+
end
41+
42+
my_matrix(n::Int, η::Float64 = 1e-9) = H(n) .+ η .* E(n)
43+
44+
A = my_matrix(4, 1e-3);
45+
@test sort(GenericLinearAlgebra._eigvals!(GenericLinearAlgebra._schur!(copy(A))), by = t -> (real(t), imag(t))) sort(eigvals(A), by = t -> (real(t), imag(t)))
46+
end
47+
2348
end

0 commit comments

Comments
 (0)