1
+
2
+ # upper_mul_tri_triview(U, X) == Tridiagonal(U*X) where U is Upper triangular BandedMatrix and X is Tridiagonal
3
+ function upper_mul_tri_triview (U:: BandedMatrix , X:: Tridiagonal )
4
+ T = promote_type (eltype (U), eltype (X))
5
+ n = size (U,1 )
6
+ UX = Tridiagonal (Vector {T} (undef, n- 1 ), Vector {T} (undef, n), Vector {T} (undef, n- 1 ))
7
+
8
+ upper_mul_tri_triview! (UX, U, X)
9
+ end
10
+
11
+ function upper_mul_tri_triview! (UX:: Tridiagonal , U:: BandedMatrix , X:: Tridiagonal )
12
+ n = size (UX,1 )
13
+
14
+
15
+ Xdl, Xd, Xdu = X. dl, X. d, X. du
16
+ UXdl, UXd, UXdu = UX. dl, UX. d, UX. du
17
+
18
+ l,u = bandwidths (U)
19
+
20
+ @assert size (U) == (n,n)
21
+ @assert l ≥ 0
22
+ # Tridiagonal bands can be resized
23
+ @assert length (Xdl)+ 1 == length (Xd) == length (Xdu)+ 1 == length (UXdl)+ 1 == length (UXd) == length (UXdu)+ 1 == n
24
+
25
+ UX, bₖ, aₖ, cₖ, cₖ₋₁ = initiate_upper_mul_tri_triview! (UX, U, X)
26
+ UX, bₖ, aₖ, cₖ, cₖ₋₁ = main_upper_mul_tri_triview! (UX, U, X, 2 : n- 2 , bₖ, aₖ, cₖ, cₖ₋₁)
27
+ finalize_upper_mul_tri_triview! (UX, U, X, n- 1 , bₖ, aₖ, cₖ, cₖ₋₁)
28
+ end
29
+
30
+ # populate first row of UX with UX
31
+
32
+ initiate_upper_mul_tri_triview! (UX, U:: UpperTriangular , X) = initiate_upper_mul_tri_triview! (UX, parent (U), X)
33
+ initiate_upper_mul_tri_triview! (UX, U:: CachedMatrix , X) = initiate_upper_mul_tri_triview! (UX, U. data, X)
34
+ initiate_upper_mul_tri_triview! (UX, U:: Union{AdaptiveCholeskyFactors,AdaptiveQRFactors} , X) = initiate_upper_mul_tri_triview! (UX, U. data. data, X)
35
+
36
+ function initiate_upper_mul_tri_triview! (UX, U:: BandedMatrix , X)
37
+ Xdl, Xd, Xdu = subdiagonaldata (X), diagonaldata (X), supdiagonaldata (X)
38
+ UXdl, UXd, UXdu = UX. dl, UX. d, UX. du
39
+ Udat = U. data
40
+
41
+ l,u = bandwidths (U)
42
+
43
+ k = 1
44
+ aₖ, cₖ = Xd[1 ], Xdl[1 ]
45
+ Uₖₖ, Uₖₖ₊₁, Uₖₖ₊₂ = Udat[u+ 1 ,1 ], Udat[u,2 ], (u > 1 ? Udat[u- 1 ,3 ] : zero (eltype (Udat))) # U[k,k], U[k,k+1], U[k,k+2]
46
+ UXd[1 ] = Uₖₖ* aₖ + Uₖₖ₊₁* cₖ # UX[k,k] = U[k,k]*X[k,k] + U[k,k+1]*X[k+1,k]
47
+ bₖ, aₖ, cₖ, cₖ₋₁ = Xdu[1 ], Xd[2 ], Xdl[2 ], cₖ # X[k,k+1], X[k+1,k+1], X[k+2,k+1], X[k+1,k]
48
+ UXdu[1 ] = Uₖₖ* bₖ + Uₖₖ₊₁* aₖ + Uₖₖ₊₂* cₖ # UX[k,k+1] = U[k,k]*X[k,k+1] + U[k,k+1]*X[k+1,k+1] + U[k,k+1]*X[k+1,k]
49
+
50
+ UX, bₖ, aₖ, cₖ, cₖ₋₁
51
+ end
52
+
53
+ # fills in the rows kr of UX
54
+ main_upper_mul_tri_triview! (UX, U:: UpperTriangular , X, kr, kwds... ) = main_upper_mul_tri_triview! (UX, parent (U), X, kr, kwds... )
55
+
56
+ function main_upper_mul_tri_triview! (UX, U:: Union{CachedMatrix,AdaptiveCholeskyFactors} , X, kr, kwds... )
57
+ resizedata! (U, kr[end ], kr[end ]+ 2 )
58
+ main_upper_mul_tri_triview! (UX, U. data, X, kr, kwds... )
59
+ end
60
+
61
+ function main_upper_mul_tri_triview! (UX, U:: AdaptiveQRFactors , X, kr, kwds... )
62
+ resizedata! (U, kr[end ], kr[end ]+ 2 )
63
+ main_upper_mul_tri_triview! (UX, U. data. data, X, kr, kwds... )
64
+ end
65
+
66
+
67
+ function main_upper_mul_tri_triview! (UX, U:: BandedMatrix , X, kr, bₖ= X[kr[1 ]- 1 ,kr[1 ]], aₖ= X[kr[1 ],kr[1 ]], cₖ= X[kr[1 ]+ 1 ,kr[1 ]], cₖ₋₁= X[kr[1 ],kr[1 ]- 1 ])
68
+ Xdl, Xd, Xdu = subdiagonaldata (X), diagonaldata (X), supdiagonaldata (X)
69
+ UXdl, UXd, UXdu = UX. dl, UX. d, UX. du
70
+ Udat = U. data
71
+ l,u = bandwidths (U)
72
+
73
+ for k = kr
74
+ Uₖₖ, Uₖₖ₊₁, Uₖₖ₊₂ = Udat[u+ 1 ,k], Udat[u,k+ 1 ], (u > 1 ? Udat[u- 1 ,k+ 2 ] : zero (eltype (Udat))) # U[k,k], U[k,k+1], U[k,k+2]
75
+ UXdl[k- 1 ] = Uₖₖ* cₖ₋₁ # UX[k,k-1] = U[k,k]*X[k,k-1]
76
+ UXd[k] = Uₖₖ* aₖ + Uₖₖ₊₁* cₖ # UX[k,k] = U[k,k]*X[k,k] + U[k,k+1]*X[k+1,k]
77
+ bₖ, aₖ, cₖ, cₖ₋₁ = Xdu[k], Xd[k+ 1 ], Xdl[k+ 1 ], cₖ # X[k,k+1], X[k+1,k+1], X[k+2,k+1], X[k+1,k]
78
+ UXdu[k] = Uₖₖ* bₖ + Uₖₖ₊₁* aₖ + Uₖₖ₊₂* cₖ # UX[k,k+1] = U[k,k]*X[k,k+1] + U[k,k+1]*X[k+1,k+1] + U[k,k+2]*X[k+2,k+1]
79
+ end
80
+
81
+ UX, bₖ, aₖ, cₖ, cₖ₋₁
82
+ end
83
+
84
+ # populate rows k and k+1 of UX, assuming we are at the bottom-right
85
+ function finalize_upper_mul_tri_triview! (UX, U, X, k, bₖ, aₖ, cₖ, cₖ₋₁)
86
+ Xdl, Xd, Xdu = X. dl, X. d, X. du
87
+ UXdl, UXd, UXdu = UX. dl, UX. d, UX. du
88
+ Udat = U. data
89
+ l,u = bandwidths (U)
90
+
91
+ Uₖₖ, Uₖₖ₊₁ = Udat[u+ 1 ,k], Udat[u,k+ 1 ] # U[k,k], U[k,k+1]
92
+ UXdl[k- 1 ] = Uₖₖ* cₖ₋₁ # UX[k,k-1] = U[k,k]*X[k,k-1]
93
+ UXd[k] = Uₖₖ* aₖ + Uₖₖ₊₁* cₖ # UX[k,k] = U[k,k]*X[k,k] + U[k,k+1]*X[k+1,k]
94
+ bₖ, aₖ, cₖ₋₁ = Xdu[k], Xd[k+ 1 ], cₖ # X[k,k+1], X[k+1,k+1], X[k+2,k+1], X[k+1,k]
95
+ UXdu[k] = Uₖₖ* bₖ + Uₖₖ₊₁* aₖ # UX[k,k+1] = U[k,k]*X[k,k+1] + U[k,k+1]*X[k+1,k+1] + U[k,k+2]*X[k+2,k+1]
96
+
97
+ k += 1
98
+ Uₖₖ = Udat[u+ 1 ,k] # U[k,k]
99
+ UXdl[k- 1 ] = Uₖₖ* cₖ₋₁ # UX[k,k-1] = U[k,k]*X[k,k-1]
100
+ UXd[k] = Uₖₖ* aₖ # UX[k,k] = U[k,k]*X[k,k] + U[k,k+1]*X[k+1,k]
101
+
102
+ UX
103
+ end
104
+
105
+
106
+ # X*R^{-1} = X*[1/R₁₁ -R₁₂/(R₁₁R₂₂) -R₁₃/R₂₂ …
107
+ # 0 1/R₂₂ -R₂₃/R₃₃
108
+ # 1/R₃₃
109
+
110
+ tri_mul_invupper_triview (X:: Tridiagonal , R:: BandedMatrix ) = tri_mul_invupper_triview! (similar (X, promote_type (eltype (X), eltype (R))), X, R)
111
+
112
+
113
+ function tri_mul_invupper_triview! (Y:: Tridiagonal , X:: Tridiagonal , R:: BandedMatrix )
114
+ n = size (X,1 )
115
+ Xdl, Xd, Xdu = X. dl, X. d, X. du
116
+ Ydl, Yd, Ydu = Y. dl, Y. d, Y. du
117
+
118
+ l,u = bandwidths (R)
119
+
120
+ @assert size (R) == (n,n)
121
+ @assert l ≥ 0 && u ≥ 1
122
+ # Tridiagonal bands can be resized
123
+ @assert length (Xdl)+ 1 == length (Xd) == length (Xdu)+ 1 == length (Ydl)+ 1 == length (Yd) == length (Ydu)+ 1 == n
124
+
125
+ UX, Rₖₖ, Rₖₖ₊₁ = initiate_tri_mul_invupper_triview! (Y, X, R)
126
+ UX, Rₖₖ, Rₖₖ₊₁ = main_tri_mul_invupper_triview! (Y, X, R, 2 : n- 1 , Rₖₖ, Rₖₖ₊₁)
127
+ finalize_tri_mul_invupper_triview! (Y, X, R, n, Rₖₖ, Rₖₖ₊₁)
128
+ end
129
+
130
+ # partially-populate first row of X/R
131
+ # Ydu[k] is updated below
132
+ function initiate_tri_mul_invupper_triview! (Y, X, R:: CachedMatrix )
133
+ resizedata! (R, 1 , 2 )
134
+ initiate_tri_mul_invupper_triview! (Y, X, R. data)
135
+ end
136
+
137
+ function initiate_tri_mul_invupper_triview! (Y, X, R:: Union{AdaptiveCholeskyFactors,AdaptiveQRFactors} )
138
+ resizedata! (R, 1 , 2 )
139
+ initiate_tri_mul_invupper_triview! (Y, X, R. data. data)
140
+ end
141
+
142
+ initiate_tri_mul_invupper_triview! (Y, X, R:: UpperTriangular ) = initiate_tri_mul_invupper_triview! (Y, X, parent (R))
143
+
144
+ function initiate_tri_mul_invupper_triview! (Y, X, R:: BandedMatrix )
145
+ Xdl, Xd, Xdu = X. dl, X. d, X. du
146
+ Ydl, Yd, Ydu = Y. dl, Y. d, Y. du
147
+ Rdat = R. data
148
+
149
+ l,u = bandwidths (R)
150
+
151
+ k = 1
152
+ aₖ,bₖ = Xd[k], Xdu[k]
153
+ Rₖₖ,Rₖₖ₊₁ = Rdat[u+ 1 ,k], Rdat[u,k+ 1 ] # R[1,1], R[1,2]
154
+
155
+ Yd[k] = aₖ/ Rₖₖ
156
+ Ydu[k] = bₖ - aₖ * Rₖₖ₊₁/ Rₖₖ
157
+
158
+ Y, Rₖₖ, Rₖₖ₊₁
159
+ end
160
+
161
+
162
+ # populate rows kr of X/R. Ydu[k] is wrong until next run.
163
+ main_tri_mul_invupper_triview! (Y:: Tridiagonal , X:: Tridiagonal , R:: UpperTriangular , kr, kwds... ) = main_tri_mul_invupper_triview! (Y, X, parent (R), kr, kwds... )
164
+ function main_tri_mul_invupper_triview! (Y:: Tridiagonal , X:: Tridiagonal , R:: Union{AdaptiveCholeskyFactors,CachedMatrix} , kr, kwds... )
165
+ resizedata! (R, kr[end ], kr[end ]+ 1 )
166
+ main_tri_mul_invupper_triview! (Y, X, R. data, kr, kwds... )
167
+ end
168
+
169
+ function main_tri_mul_invupper_triview! (Y:: Tridiagonal , X:: Tridiagonal , R:: AdaptiveQRFactors , kr, kwds... )
170
+ resizedata! (R, kr[end ], kr[end ]+ 1 )
171
+ main_tri_mul_invupper_triview! (Y, X, R. data. data, kr, kwds... )
172
+ end
173
+
174
+ function main_tri_mul_invupper_triview! (Y:: Tridiagonal , X:: Tridiagonal , R:: BandedMatrix , kr, Rₖₖ= R[first (kr)- 1 ,first (kr)- 1 ], Rₖₖ₊₁= R[first (kr)- 1 ,first (kr)])
175
+ Xdl, Xd, Xdu = X. dl, X. d, X. du
176
+ Ydl, Yd, Ydu = Y. dl, Y. d, Y. du
177
+ Rdat = R. data
178
+ l,u = bandwidths (R)
179
+
180
+ for k = kr
181
+ cₖ₋₁,aₖ,bₖ = Xdl[k- 1 ], Xd[k], Xdu[k]
182
+ Ydl[k- 1 ] = cₖ₋₁/ Rₖₖ
183
+ Yd[k] = aₖ- cₖ₋₁* Rₖₖ₊₁/ Rₖₖ
184
+ Ydu[k] = cₖ₋₁/ Rₖₖ
185
+ Rₖₖ,Rₖₖ₊₁,Rₖ₋₁ₖ₊₁,Rₖ₋₁ₖ = Rdat[u+ 1 ,k], Rdat[u,k+ 1 ],(u > 1 ? Rdat[u- 1 ,k+ 1 ] : zero (eltype (Rdat))),Rₖₖ₊₁ # R[k,k], R[k,k+1], R[k-1,k+1]
186
+ Yd[k] /= Rₖₖ
187
+ Ydu[k- 1 ] /= Rₖₖ
188
+ Ydu[k] *= Rₖ₋₁ₖ* Rₖₖ₊₁/ Rₖₖ - Rₖ₋₁ₖ₊₁
189
+ Ydu[k] += bₖ - aₖ * Rₖₖ₊₁ / Rₖₖ
190
+ end
191
+ Y, Rₖₖ, Rₖₖ₊₁
192
+ end
193
+
194
+
195
+ # populate row k of X/R, assuming we are at the bottom-right
196
+ function finalize_tri_mul_invupper_triview! (Y:: Tridiagonal , X:: Tridiagonal , R:: BandedMatrix , k, Rₖₖ= R[k- 1 ,k- 1 ], Rₖₖ₊₁= R[k- 1 ,k])
197
+ Xdl, Xd, Xdu = X. dl, X. d, X. du
198
+ Ydl, Yd, Ydu = Y. dl, Y. d, Y. du
199
+ Rdat = R. data
200
+ l,u = bandwidths (R)
201
+ cₖ₋₁,aₖ = Xdl[k- 1 ], Xd[k]
202
+ Ydl[k- 1 ] = cₖ₋₁/ Rₖₖ
203
+ Yd[k] = aₖ- cₖ₋₁* Rₖₖ₊₁/ Rₖₖ
204
+ Rₖₖ = Rdat[u+ 1 ,k] # R[k,k]
205
+ Yd[k] /= Rₖₖ
206
+ Ydu[k- 1 ] /= Rₖₖ
207
+
208
+ Y
209
+ end
210
+ """
211
+ TridiagonalConjugationData(U, X, V, Y)
212
+
213
+ caches the infinite dimensional Tridiagonal(U*X/V)
214
+ in the tridiagonal matrix `Y`
215
+ """
216
+
217
+ mutable struct TridiagonalConjugationData{T}
218
+ const U:: AbstractMatrix{T}
219
+ const X:: AbstractMatrix{T}
220
+ const V:: AbstractMatrix{T}
221
+
222
+ const UX:: Tridiagonal{T,Vector{T}} # cache Tridiagonal(U*X)
223
+ const Y:: Tridiagonal{T,Vector{T}} # cache Tridiagonal(U*X/V)
224
+
225
+ datasize:: Int
226
+ end
227
+
228
+ function TridiagonalConjugationData (U, X, V)
229
+ T = promote_type (typeof (inv (V[1 , 1 ])), eltype (U), eltype (X)) # include inv so that we can't get Ints
230
+ n_init = 100
231
+ UX = Tridiagonal (Vector {T} (undef, n_init- 1 ), Vector {T} (undef, n_init), Vector {T} (undef, n_init- 1 ))
232
+ Y = Tridiagonal (Vector {T} (undef, n_init- 1 ), Vector {T} (undef, n_init), Vector {T} (undef, n_init- 1 ))
233
+ resizedata! (U, n_init, n_init)
234
+ resizedata! (V, n_init, n_init)
235
+ initiate_upper_mul_tri_triview! (UX, U, X) # fill-in 1st row
236
+ initiate_tri_mul_invupper_triview! (Y, UX, V)
237
+ return TridiagonalConjugationData (U, X, V, UX, Y, 0 )
238
+ end
239
+
240
+
241
+ function TridiagonalConjugationData (U, X)
242
+ C = cache (U)
243
+ TridiagonalConjugationData (C, X, C)
244
+ end
245
+
246
+ copy (data:: TridiagonalConjugationData ) = TridiagonalConjugationData (copy (data. U), copy (data. X), copy (data. V), copy (data. UX), copy (data. Y), data. datasize)
247
+
248
+
249
+ function resizedata! (data:: TridiagonalConjugationData , n)
250
+ n ≤ data. datasize && return data
251
+
252
+ if n ≥ length (data. UX. dl) # Avoid O(n²) growing. Note min(length(dv), length(ev)) == length(ev)
253
+ resize! (data. UX. dl, 2 n)
254
+ resize! (data. UX. d, 2 n + 1 )
255
+ resize! (data. UX. du, 2 n)
256
+
257
+ resize! (data. Y. dl, 2 n)
258
+ resize! (data. Y. d, 2 n + 1 )
259
+ resize! (data. Y. du, 2 n)
260
+ end
261
+
262
+
263
+ if n > data. datasize
264
+ main_upper_mul_tri_triview! (data. UX, data. U, data. X, data. datasize+ 2 : n+ 1 )
265
+ main_tri_mul_invupper_triview! (data. Y, data. UX, data. U, data. datasize+ 2 : n+ 1 ) # need one extra as it updates first row
266
+ data. datasize = n
267
+ end
268
+
269
+ data
270
+ end
271
+
272
+ struct TridiagonalConjugationBand{T} <: LazyVector{T}
273
+ data:: TridiagonalConjugationData{T}
274
+ diag:: Symbol
275
+ end
276
+
277
+ size (P:: TridiagonalConjugationBand ) = (ℵ₀,)
278
+ resizedata! (A:: TridiagonalConjugationBand , n) = resizedata! (A. data, n)
279
+
280
+ function _triconj_getindex (C:: TridiagonalConjugationBand , I)
281
+ resizedata! (C, maximum (I)+ 1 )
282
+ getfield (C. data. Y, C. diag)[I]
283
+ end
284
+
285
+ getindex (A:: TridiagonalConjugationBand , I:: Integer ) = _triconj_getindex (A, I)
286
+ getindex (A:: TridiagonalConjugationBand , I:: AbstractVector ) = _triconj_getindex (A, I)
287
+ getindex (K:: TridiagonalConjugationBand , k:: AbstractInfUnitRange{<:Integer} ) = view (K, k)
288
+ getindex (K:: SubArray{<:Any,1,<:TridiagonalConjugationBand} , k:: AbstractInfUnitRange{<:Integer} ) = view (K, k)
289
+
290
+ copy (A:: TridiagonalConjugationBand ) = A # immutable
291
+
292
+
293
+ const TridiagonalConjugation{T} = Tridiagonal{T, TridiagonalConjugationBand{T}}
294
+ const SymTridiagonalConjugation{T} = SymTridiagonal{T, TridiagonalConjugationBand{T}}
295
+ function TridiagonalConjugation (R, X, Y... )
296
+ data = TridiagonalConjugationData (R, X, Y... )
297
+ Tridiagonal (TridiagonalConjugationBand (data, :dl ), TridiagonalConjugationBand (data, :d ), TridiagonalConjugationBand (data, :du ))
298
+ end
299
+
300
+ function SymTridiagonalConjugation (R, X, Y... )
301
+ data = TridiagonalConjugationData (R, X, Y... )
302
+ SymTridiagonal (TridiagonalConjugationBand (data, :d ), TridiagonalConjugationBand (data, :du ))
303
+ end
0 commit comments