1
1
using Printf
2
+ import BlockDiagonals: BlockDiagonal
3
+ import BlockDiagonals
2
4
import Base: iterate
3
- import LinearAlgebra: UpperTriangular
5
+ import LinearAlgebra: UpperTriangular, UpperHessenberg
4
6
5
7
"""
6
8
LookAheadLanczosDecompOptions
@@ -71,21 +73,23 @@ mutable struct LookAheadLanczosDecomp{OpT, OptT, VecT, MatT, ElT, ElRT}
71
73
γ:: Vector{ElRT}
72
74
73
75
# Eq. 2.13
74
- D:: Matrix{ElT}
76
+ D:: BlockDiagonal{ElT, Matrix{ElT} }
75
77
# Eq. 3.14
76
- E:: Matrix{ElT}
78
+ E:: BlockDiagonal{ElT, Matrix{ElT} }
77
79
# Defined after Eq. 5.1
78
- F:: Matrix{ElT}
80
+ F:: BlockDiagonal{ElT, Matrix{ElT} }
79
81
F̃lastcol:: Vector{ElT}
80
82
# Eq. 5.1
81
83
G:: Vector{ElT}
82
84
# Eq. 3.11
83
85
H:: Vector{ElT}
84
86
85
87
# Eq. 3.9
88
+ # need to keep previous columns of U for G checks
86
89
U:: UpperTriangular{ElT, Matrix{ElT}}
87
- L:: Matrix{ElT}
88
-
90
+ # need to keep previous columns of L for H checks
91
+ L:: UpperHessenberg{ElT, Matrix{ElT}}
92
+
89
93
# Indices tracking location in block and sequence
90
94
n:: Int
91
95
k:: Int
@@ -173,16 +177,16 @@ function LookAheadLanczosDecomp(
173
177
γ = Vector {real(elT)} (undef, 1 )
174
178
γ[1 ] = 1.0
175
179
176
- D = Matrix {elT} (undef, 0 , 0 )
177
- E = Matrix {elT} (undef, 0 , 0 )
180
+ D = BlockDiagonal {elT, Matrix{elT}} ( Vector {Matrix{elT}} () )
181
+ E = BlockDiagonal {elT, Matrix{elT}} ( Vector {Matrix{elT}} () )
178
182
G = Vector {elT} ()
179
183
H = Vector {elT} ()
180
184
181
- F = Matrix {elT} (undef, 0 , 0 )
185
+ F = BlockDiagonal {elT, Matrix{elT}} ( Vector {Matrix{elT}} () )
182
186
F̃lastcol = Vector {elT} ()
183
187
184
188
U = UpperTriangular (Matrix {elT} (undef, 0 , 0 ))
185
- L = Matrix {elT} (undef, 0 , 0 )
189
+ L = UpperHessenberg ( Matrix {elT} (undef, 0 , 0 ) )
186
190
187
191
# Alg 5.2.0
188
192
n = 1
@@ -241,6 +245,34 @@ _VW_block_size(ld) = ld.n+1 - ld.nl[ld.l]
241
245
_VW_prev_block_size (ld) = ld. nl[ld. l] - ld. nl[max (1 , ld. l- 1 )]
242
246
_is_block_small (ld, n) = n < ld. opts. max_block_size
243
247
248
+ """
249
+ _grow_last_block!(A, Bcol, Brow, Bcorner)
250
+
251
+ Grows the last block in-place in `A` by appending the column `Bcol`, the row `Brow`, and the corner element `Bcorner`. `Bcol` and `Brow` are automatically truncated to match the size of the grown block
252
+ """
253
+ function _grow_last_block! (A:: BlockDiagonal{T, TM} , Bcol, Brow, Bcorner) where {T, TM}
254
+ n = BlockDiagonals. nblocks (A)
255
+ b = BlockDiagonals. blocks (A)
256
+ s = size (last (b), 1 )
257
+ b[n] = TM ([
258
+ b[n] Bcol[end - s+ 1 : end ]
259
+ Brow[:, end - s+ 1 : end ] Bcorner
260
+ ])
261
+ return A
262
+ end
263
+
264
+ """
265
+ _start_new_block!(A, B)
266
+
267
+ Appends a new block to the end of `A` with `B`
268
+ """
269
+ function _start_new_block! (A:: BlockDiagonal{T, TM} , B) where {T, TM}
270
+ push! (BlockDiagonals. blocks (A), TM (fill (only (B), 1 , 1 )))
271
+ return A
272
+ end
273
+
274
+ Base. size (B:: BlockDiagonals.BlockDiagonal ) = sum (first∘ size, BlockDiagonals. blocks (B), init= 0 ), sum (last∘ size, BlockDiagonals. blocks (B), init= 0 )
275
+
244
276
start (:: LookAheadLanczosDecomp ) = 1
245
277
done (ld:: LookAheadLanczosDecomp , iteration:: Int ) = iteration ≥ ld. opts. max_iter
246
278
function iterate (ld:: LookAheadLanczosDecomp , n:: Int = start (ld))
@@ -288,7 +320,7 @@ function _update_PQ_sequence!(ld)
288
320
if ! innerp
289
321
# Alg. 5.2.8
290
322
_update_pq_regular! (ld)
291
- _mv_pq ! (ld)
323
+ _matvec_pq ! (ld)
292
324
# Alg. 5.2.9
293
325
_update_Gn! (ld)
294
326
innerp = inner_ok && _check_G (ld)
@@ -306,19 +338,19 @@ function _update_PQ_sequence!(ld)
306
338
# Alg. 5.2.11
307
339
isverbose (ld) && @info " Inner P-Q construction, second G check"
308
340
_update_pq_inner! (ld)
309
- _mv_pq ! (ld, true )
341
+ _matvec_pq ! (ld, true )
310
342
end
311
343
else
312
344
# Alg. 5.2.11
313
345
isverbose (ld) && @info " Inner P-Q construction, first G check"
314
346
_update_pq_inner! (ld)
315
- _mv_pq ! (ld)
347
+ _matvec_pq ! (ld)
316
348
end
317
349
else
318
350
# Alg. 5.2.11
319
351
isverbose (ld) && @info " Inner P-Q construction, singular E check"
320
352
_update_pq_inner! (ld)
321
- _mv_pq ! (ld)
353
+ _matvec_pq ! (ld)
322
354
end
323
355
ld. innerp = innerp
324
356
return ld
@@ -397,20 +429,16 @@ function _update_D!(ld)
397
429
# Alg. 5.2.1
398
430
# Eq. 5.2:
399
431
# F[n-1] = Wt[n-1]V[n]L[n-1] = D[n-1]L[1:n-1, 1:n-1] + l[n, n-1]D[1:n-1, n][0 ... 0 1]
400
- # => D[1:end-1, end] = (F[:, end] - (D_prev L[1:end-1, 1: end]))[:, end] / ρ
432
+ # => D[1:end-1, end] = (F[:, end] - (D_prev L[1:end-1, end])) / ρ
401
433
# Eq. 3.15, (D Γ)ᵀ = (D Γ)
402
434
# D[n, n] = wtv
403
435
404
- # TODO : closed block
405
- if isone (ld. n)
406
- ld. D = fill (ld. wtv, 1 , 1 )
436
+ if isone (ld. n) || _VW_block_size (ld) == 1
437
+ _start_new_block! (ld. D, ld. wtv)
407
438
else
408
- D_lastcol = (ld. F[:, end ] - (ld. D * ld. L[1 : end - 1 , :])[:, end ]) / ld. ρ
409
- D_lastrow = D_lastcol * ld. γ[end ] ./ ld. γ[1 : end - 1 ]
410
- ld. D = [
411
- ld. D D_lastcol
412
- transpose (D_lastrow) ld. wtv
413
- ]
439
+ D_lastcol = (ld. F[:, end ] - (ld. D * ld. L[1 : end - 1 , end ])) / ld. ρ
440
+ D_lastrow = transpose (D_lastcol * ld. γ[end ] ./ ld. γ[1 : end - 1 ])
441
+ _grow_last_block! (ld. D, D_lastcol, D_lastrow, ld. wtv)
414
442
end
415
443
return ld
416
444
end
@@ -433,14 +461,17 @@ function _update_Flastrow!(ld)
433
461
# Eq. 5.2 (w/ indices advanced):
434
462
# F_{n} = D_{n}L[1:n, 1:n] + l[n+1, n]D_{n}[1:n, n+1][0 ... 0 1]
435
463
# TODO : block
436
- if ! isone (ld. n) # We only need to do this if we are constructing a block
464
+ if isone (ld. n)
465
+ _start_new_block! (ld. F, 0.0 )
466
+ else
437
467
Flastrow = reshape (ld. D[end : end , :] * ld. L, :)
438
468
ld. F̃lastcol = Flastrow .* ld. γ[1 : end - 1 ] ./ ld. γ[end ]
439
469
# we are not able to fill in the last column yet, so we fill with zero
440
- ld. F = [
441
- ld. F fill (0.0 , size (ld. F, 1 ))
442
- transpose (Flastrow) 0.0
443
- ]
470
+ if _VW_block_size (ld) == 1
471
+ _grow_last_block! (ld. F, fill (0.0 , size (ld. F, 1 )), transpose (Flastrow), 0.0 )
472
+ else
473
+ _grow_last_block! (ld. F, fill (0.0 , size (ld. F, 1 )), transpose (Flastrow), 0.0 )
474
+ end
444
475
end
445
476
end
446
477
@@ -453,6 +484,7 @@ function _update_U!(ld, innerp)
453
484
idx_offset = 0
454
485
# TODO
455
486
# we only store the entries from mk[kstar] to n-1
487
+
456
488
ld. U = UpperTriangular (
457
489
[
458
490
ld. U fill (0.0 , n- 1 , 1 )
@@ -547,7 +579,7 @@ function _update_pq_inner!(ld)
547
579
return ld
548
580
end
549
581
550
- function _mv_pq ! (ld, retry= false )
582
+ function _matvec_pq ! (ld, retry= false )
551
583
# Common part of Alg. 5.2.8, Alg. 5.2.11
552
584
# if retry, then this means we have already added data to the vectors, but our
553
585
# inner block check failed, so we overwrite what he have. This is the case if
@@ -580,16 +612,13 @@ function _update_E!(ld)
580
612
# 5.2.14
581
613
n = ld. n
582
614
583
- if isone (ld. n)
584
- ld. E = fill ( ld. qtAp, 1 , 1 )
615
+ if isone (ld. n) || _PQ_block_size (ld) == 1
616
+ _start_new_block! ( ld. E, ld. qtAp)
585
617
else
586
618
ΓUtinvΓ = ld. γ .* transpose (ld. U) ./ transpose (ld. γ)
587
- Elastrow = (ΓUtinvΓ \ ld. F[1 : n, 1 : n- 1 ])[n, :]
619
+ Elastrow = (ΓUtinvΓ[ end , end ] \ ld. F[n : n, 1 : n- 1 ] - ΓUtinvΓ[ end : end , 1 : end - 1 ] * ld . E)
588
620
Elastcol = (Elastrow .* ld. γ[1 : n- 1 ] ./ ld. γ[n])
589
- ld. E = [
590
- ld. E Elastcol
591
- transpose (Elastrow) ld. qtAp
592
- ]
621
+ _grow_last_block! (ld. E, Elastcol, Elastrow, ld. qtAp)
593
622
end
594
623
return ld
595
624
end
@@ -608,7 +637,7 @@ function _update_Flastcol!(ld)
608
637
ΓUtinvΓ = ld. γ .* transpose (ld. U) ./ transpose (ld. γ)
609
638
# length n, ld.F_lastrow of length n-1
610
639
if isone (n)
611
- ld. F = fill ( ΓUtinvΓ[end , end ] * ld. E[end , end ], 1 , 1 )
640
+ ld. F[ 1 , 1 ] = ΓUtinvΓ[end , end ] * ld. E[end , end ]
612
641
else
613
642
ld. F[:, end ] .= ΓUtinvΓ * ld. E[:, end ]
614
643
end
@@ -625,14 +654,19 @@ function _update_L!(ld, innerv)
625
654
Llastcol[block_start: block_end] .= ld. D[block_start: block_end, block_start: block_end] \ ld. F[block_start: block_end, end ]
626
655
end
627
656
if ! innerv
657
+ @show ld. D
628
658
Llastcol[nl[l]: end ] .= ld. D[nl[l]: end , nl[l]: end ] \ ld. F[nl[l]: end , end ]
629
659
end
630
660
if isone (n)
631
- ld. L = reshape ([Llastcol[1 ]
661
+ ld. L = UpperHessenberg (
662
+ reshape ([Llastcol[1 ]
632
663
0.0 ], 2 , 1 )
664
+ )
633
665
else
634
- ld. L = [ld. L Llastcol
635
- fill (0.0 , 1 , n)]
666
+ ld. L = UpperHessenberg (
667
+ [ld. L Llastcol
668
+ fill (0.0 , 1 , n)]
669
+ )
636
670
end
637
671
return ld
638
672
end
0 commit comments