-
Notifications
You must be signed in to change notification settings - Fork 0
/
AMRVW_algorithm.jl
213 lines (145 loc) · 5.16 KB
/
AMRVW_algorithm.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
## Main algorithm of AMRVW
## This follows that given in the paper very closely
## should trace algorithm better with `verbose`
function AMRVW_algorithm!(state::AbstractQRRotatorFactorization)
m = eltype(state.QF) <: Real ? 2 : 1
AMRVW_algorithm!(state, m)
end
function AMRVW_algorithm!(state::AbstractQRRotatorFactorization, m)
QF, RF = state.QF, state.RF
S = eltype(QF)
T = real(S)
# set counters
n = length(QF.Q)
ctr = AMRVW_Counter(0, 1, n, IT_COUNT, n-1)
# set up storage
storage = make_storage(QF, m)
A = storage.A # cleanup
EIGS = zeros(Complex{T}, n+1)
it_max = 20*n
kk = 0
check_deflation(state, ctr)
while kk <= it_max
if ctr.stop_index <= 0
break
end
check_deflation(state, ctr)
##show_status(state, ctr)
kk += 1
## Delta is number of rotators in piece being considered
## m must be greater than delta-1 to run a bulge step
k = ctr.stop_index
delta = ctr.stop_index - ctr.zero_index ## number of rotators in Q factorization
if delta == 1
diagonal_block!(A, QF, RF, k, k+1)
e1::Complex{T}, e2::Complex{T} = eigen_values(A)
EIGS[k] = e1
EIGS[k+1] = e2
# can finish up if near end
if ctr.stop_index == 2
diagonal_block!(A, QF, RF, 1, 2)
e1 = A[1,1]
EIGS[1] = e1
break
end
ctr.stop_index = ctr.zero_index - 1
ctr.zero_index = 0
ctr.start_index = 1
check_deflation(state, ctr)
ctr.stop_index <= 0 && break
elseif delta <= 0
diagonal_block!(A, QF, RF, k, k+1)
e1, e2 = A[1,1], A[2,2] # 0s off diagonal
if ctr.stop_index == 1
# finish up
EIGS[1], EIGS[2] = e1, e2
ctr.stop_index = 0
break
end
EIGS[k+1] = e2
ctr.stop_index = ctr.zero_index - 1
ctr.stop_index <= 0 && break
ctr.zero_index = 0
ctr.start_index = 1
check_deflation(state, ctr)
elseif m > 2 && m >= delta - 1
## When finding shifts we find m eigenvalues from some other means
## so here we find the eigvals
δ, Δ = ctr.start_index, ctr.stop_index
diagonal_block!(A, QF, RF, δ, Δ+1)
es = _eigvals(view(A,1:Δ-δ+2,1:Δ-δ+2))
for (ind, ev) in enumerate(es)
EIGS[δ+ind-1] = ev
end
if δ == 2
# finish up
diagonal_block!(A, QF, RF, 1, 2)
e1 = A[1,1] # δ == 2 means first rotator a diagonal, so product will be diagonal in 1:2x1:2 block
EIGS[1] = e1
break
end
ctr.zero_index = 0
ctr.start_index = 1
ctr.stop_index = δ - 2
ctr.stop_index <= 0 && break
check_deflation(state, ctr)
else
bulge_step(QF, RF, storage, ctr, m)
ctr.it_count -= 1
end
end
LinearAlgebra.sorteig!(EIGS)
EIGS
end
##################################################
## A container for our counters
mutable struct AMRVW_Counter
zero_index::Int # this should be dropped, it is just start_index-1
start_index::Int
stop_index::Int
it_count::Int # count on use of random rotators
tr::Int # count for simple_passthrough
end
function make_counter(state)
n = length(state.QF.Q)
AMRVW_Counter(0, 1, n, 0, n-1)
end
##################################################
## Used to create storage based on Qfactorization type
make_storage(state::QRFactorization) = make_storage(state.QF, eltype(state) <: Complex ? 1 : 2)
function make_storage(QF::QFactorization{T,S,V}, m) where {T, S, V}
A = zeros(S, 4, 4)
VU = Vector{Rotator{T, S}}(undef, m) # Ascending Chain
limb = DescendingChain(copy(QF.Q.x[1:(m-1)]))
(A=A, VU=VU, limb=limb)
end
function make_storage(QF::QFactorizationTwisted{T,S, Vt, PVt}, m) where {T, S, Vt, PVt}
A = zeros(S, max(4, m+2), max(4, m+2))
VU = Vector{Rotator{T, S}}(undef, m) # Ascending Chain
limb = TwistedChain(copy(QF.Q.x[1:(m-1)]), copy(QF.Q.pv[1:(m-2)]))
(A=A, VU=VU, limb=limb)
end
##################################################
## Deflation
## when a Q[k] matrix becomes a diagonal matrix, we deflate.
## This is checked by the sine term being basically 0.
function check_deflation(state::AbstractQRRotatorFactorization, ctr)
QF = state.QF
tol = eps(real(eltype(QF)))
for k in ctr.stop_index:-1:ctr.start_index
c, s = vals(QF.Q[k])
if abs(s) <= tol
deflate(QF, k, ctr)
ctr.zero_index = k # points to a matrix Q[k] either
ctr.start_index = k + 1
ctr.it_count = 15 # reset counter
return
end
end
end
## Find eigenvalues from factorization
function eigvals(state::AbstractQRRotatorFactorization)
es = AMRVW_algorithm!(copy(state))
LinearAlgebra.sorteig!(es)
es
end