@@ -92,23 +92,9 @@ function ql_hessenberg!(B::InfBandedMatrix{TT}; kwds...) where TT
92
92
QLHessenberg (_BandedMatrix (H, ℵ₀, l, 1 ), Vcat ( LowerHessenbergQ (F. Q). q, F∞. q))
93
93
end
94
94
95
- getindex (Q:: QLPackedQ{T,<:InfBandedMatrix{T}} , i:: Int , j:: Int ) where T =
96
- (Q' * [Zeros {T} (i- 1 ); one (T); Zeros {T} (∞)])[j]'
97
- getindex (Q:: QLPackedQ{<:Any,<:InfBandedMatrix} , I:: AbstractVector{Int} , J:: AbstractVector{Int} ) =
98
- [Q[i,j] for i in I, j in J]
99
-
100
95
getL (Q:: QL , :: NTuple{2,InfiniteCardinal{0}} ) = LowerTriangular (Q. factors)
101
96
getL (Q:: QLHessenberg , :: NTuple{2,InfiniteCardinal{0}} ) = LowerTriangular (Q. factors)
102
97
103
- # number of structural non-zeros in axis k
104
- nzzeros (A:: AbstractArray , k) = size (A,k)
105
- nzzeros (:: Zeros , k) = 0
106
- nzzeros (B:: Vcat , k) = sum (size .(B. args[1 : end - 1 ],k))
107
- nzzeros (B:: CachedArray , k) = max (B. datasize[k], nzzeros (B. array,k))
108
- function nzzeros (B:: AbstractMatrix , k)
109
- l,u = bandwidths (B)
110
- k == 1 ? size (B,2 ) + l : size (B,1 ) + u
111
- end
112
98
113
99
function materialize! (M:: Lmul{<:QLPackedQLayout{<:BandedColumns},<:PaddedLayout} )
114
100
A,B = M. A,M. B
@@ -123,7 +109,7 @@ function materialize!(M::Lmul{<:QLPackedQLayout{<:BandedColumns},<:PaddedLayout}
123
109
D = Afactors. data
124
110
for k = 1 : ∞
125
111
ν = k
126
- allzero = k > nzzeros (B, 1 ) ? true : false
112
+ allzero = k > last ( colsupport (B) ) ? true : false
127
113
for j = 1 : nB
128
114
vBj = B[k,j]
129
115
for i = max (1 ,ν- u): k- 1
@@ -157,7 +143,7 @@ function materialize!(M::Lmul{<:AdjQLPackedQLayout{<:BandedColumns},<:PaddedLayo
157
143
l,u = bandwidths (Afactors)
158
144
D = Afactors. data
159
145
@inbounds begin
160
- for k = nzzeros (B, 1 )+ u: - 1 : 1
146
+ for k = last ( colsupport (B) )+ u: - 1 : 1
161
147
ν = k
162
148
for j = 1 : nB
163
149
vBj = B[k,j]
@@ -175,15 +161,6 @@ function materialize!(M::Lmul{<:AdjQLPackedQLayout{<:BandedColumns},<:PaddedLayo
175
161
B
176
162
end
177
163
178
- function _lmul_cache (A:: Union{AbstractMatrix{T},AbstractQ{T}} , x:: AbstractVector{S} ) where {T,S}
179
- TS = promote_op (matprod, T, S)
180
- lmul! (A, cache (convert (AbstractVector{TS},x)))
181
- end
182
-
183
- (* )(A:: QLPackedQ{T,<:InfBandedMatrix} , x:: AbstractVector ) where {T} = _lmul_cache (A, x)
184
- (* )(A:: AdjointQtype{T,<:QLPackedQ{T,<:InfBandedMatrix}} , x:: AbstractVector ) where {T} = _lmul_cache (A, x)
185
- (* )(A:: QLPackedQ{T,<:InfBandedMatrix} , x:: LazyVector ) where {T} = _lmul_cache (A, x)
186
- (* )(A:: AdjointQtype{T,<:QLPackedQ{T,<:InfBandedMatrix}} , x:: LazyVector ) where {T} = _lmul_cache (A, x)
187
164
188
165
189
166
function blocktailiterate (c,a,b, d= c, e= a)
@@ -246,7 +223,7 @@ function lmul!(adjA::AdjointQtype{<:Any,<:QLPackedQ{<:Any,<:InfBlockBandedMatrix
246
223
l = 2 l+ 1
247
224
u = 2 u+ 1
248
225
@inbounds begin
249
- for k = nzzeros (B, 1 )+ u: - 1 : 1
226
+ for k = last ( colsupport (B) )+ u: - 1 : 1
250
227
ν = k
251
228
for j = 1 : nB
252
229
vBj = B[k,j]
@@ -290,7 +267,7 @@ function materialize!(M::MatLdivVec{<:TriangularLayout{'L','N',BandedColumns{Per
290
267
throw (DimensionMismatch (" second dimension of left hand side A, $n , and length of right hand side b, $(length (b)) , must be equal" ))
291
268
end
292
269
data = triangulardata (A)
293
- nz = nzzeros (b, 1 )
270
+ nz = last ( colsupport (b) )
294
271
@inbounds for j in 1 : n
295
272
iszero (data[j,j]) && throw (SingularException (j))
296
273
bj = b[j] = data[j,j] \ b[j]
@@ -333,8 +310,6 @@ function _ql(::SymTridiagonalLayout, ::NTuple{2,OneToInf{Int}}, A, args...; kwds
333
310
ql (_BandedMatrix (Hcat (dat, [ev∞,d∞,ev∞] * Ones {T} (1 ,∞)), ℵ₀, 1 , 1 ), args... ; kwds... )
334
311
end
335
312
336
-
337
-
338
313
# TODO : This should be redesigned as ql(BandedMatrix(A))
339
314
# But we need to support dispatch on axes
340
315
function _ql (:: TridiagonalLayout , :: NTuple{2,OneToInf{Int}} , A, args... ; kwds... )
@@ -378,3 +353,169 @@ function LazyBandedMatrices._SymTridiagonal(::Tuple{TriangularLayout{'L', 'N', P
378
353
ev = [A[k,k+ 1 ] for k= 1 : m- 1 ]
379
354
SymTridiagonal ([dv; Fill (dv[end ],∞)], [ev; Fill (ev[end ],∞)])
380
355
end
356
+
357
+ # ##
358
+ # Experimental adaptive finite section QL
359
+ # ##
360
+ mutable struct AdaptiveQLTau{T} <: AbstractCachedVector{T}
361
+ data:: Vector{T}
362
+ M:: AbstractMatrix{T}
363
+ datasize:: Integer
364
+ tol:: Real
365
+ AdaptiveQLTau {T} (D, M, N:: Integer , tol) where T = new {T} (D, M, N, tol)
366
+ end
367
+ mutable struct AdaptiveQLFactors{T} <: AbstractCachedMatrix{T}
368
+ data:: BandedMatrix{T}
369
+ M:: AbstractMatrix{T}
370
+ datasize:: Tuple{Int, Int}
371
+ tol:: Real
372
+ AdaptiveQLFactors {T} (D, M, N:: Tuple{Int, Int} , tol) where T = new {T} (D, M, N, tol)
373
+ end
374
+
375
+ size (:: AdaptiveQLFactors ) = (ℵ₀, ℵ₀)
376
+ size (:: AdaptiveQLTau ) = (ℵ₀, )
377
+
378
+ # adaptive QL accepts optional tolerance
379
+ function ql (A:: InfBandedMatrix{T} , tol = eps (float (real (T)))) where T
380
+ factors, τ = initialadaptiveQLblock (A, tol)
381
+ QL (AdaptiveQLFactors {T} (factors, A, size (factors), tol),AdaptiveQLTau {T} (τ, A, length (τ), tol))
382
+ end
383
+
384
+ # Computes the initial data for the finite section based QL decomposition
385
+ function initialadaptiveQLblock (A:: AbstractMatrix{T} , tol) where T
386
+ maxN = 10000 # Prevent runaway loop
387
+ j = 50 # We initialize with a 50 × 50 block that is adaptively expanded
388
+ Lerr = one (real (T))
389
+ N = j
390
+ checkinds = max (1 ,j- bandwidth (A,1 )- bandwidth (A,2 ))
391
+ @inbounds Ls = ql (A[checkinds: N,checkinds: N]). L[2 : j- checkinds+ 1 ,2 : j- checkinds+ 1 ]
392
+ @inbounds while Lerr > tol
393
+ # compute QL for small finite section and large finite section
394
+ Ll = ql (A[checkinds: 2 N,checkinds: 2 N]). L[2 : j- checkinds+ 1 ,2 : j- checkinds+ 1 ]
395
+ # compare bottom right sections and stop if desired level of convergence achieved
396
+ Lerr = norm (Ll- Ls,2 )
397
+ if N == maxN
398
+ error (" Reached max. iterations in adaptive QL without convergence to desired tolerance." )
399
+ end
400
+ Ls = Ll
401
+ N = 2 * N
402
+ end
403
+ F = ql (A[1 : (N÷ 2 ),1 : (N÷ 2 )])
404
+ return (F. factors[1 : 50 ,1 : 50 ], F. τ[1 : 50 ])
405
+ end
406
+
407
+ # Resize and filling functions for cached implementation
408
+ function resizedata! (K:: AdaptiveQLFactors , nm... )
409
+ nm = maximum (nm)
410
+ νμ = K. datasize[1 ]
411
+ if nm > νμ
412
+ olddata = copy (K. data)
413
+ K. data = similar (K. data, nm, nm)
414
+ K. data[axes (olddata)... ] = olddata
415
+ inds = νμ:nm
416
+ cache_filldata! (K, inds)
417
+ K. datasize = size (K. data)
418
+ end
419
+ K
420
+ end
421
+
422
+ function resizedata! (K:: AdaptiveQLTau , nm... )
423
+ nm = maximum (nm)
424
+ νμ = K. datasize
425
+ if nm > νμ
426
+ resize! (K. data,nm)
427
+ cache_filldata! (K, νμ:nm )
428
+ K. datasize = size (K. data,1 )
429
+ end
430
+ K
431
+ end
432
+
433
+ function cache_filldata! (A:: AdaptiveQLFactors{T} , inds:: UnitRange{Int} ) where T
434
+ j = maximum (inds)
435
+ maxN = 1000 * j # Prevent runaway loop
436
+ Lerr = one (real (T))
437
+ N = j
438
+ checkinds = max (1 ,j- bandwidth (A. M,1 )- bandwidth (A. M,2 ))
439
+ @inbounds Ls = ql (A. M[checkinds: N,checkinds: N]). L[2 : j- checkinds+ 1 ,2 : j- checkinds+ 1 ]
440
+ @inbounds while Lerr > A. tol
441
+ # compute QL for small finite section and large finite section
442
+ Ll = ql (A. M[checkinds: 2 N,checkinds: 2 N]). L[2 : j- checkinds+ 1 ,2 : j- checkinds+ 1 ]
443
+ # compare bottom right sections and stop if desired level of convergence achieved
444
+ Lerr = norm (Ll- Ls,2 )
445
+ if N == maxN
446
+ error (" Reached max. iterations in adaptive QL without convergence to desired tolerance." )
447
+ end
448
+ Ls = Ll
449
+ N = 2 * N
450
+ end
451
+ A. data = ql (A. M[1 : (N÷ 2 ),1 : (N÷ 2 )]). factors[1 : j,1 : j]
452
+ end
453
+
454
+ function cache_filldata! (A:: AdaptiveQLTau{T} , inds:: UnitRange{Int} ) where T
455
+ j = maximum (inds)
456
+ maxN = 1000 * j
457
+ Lerr = one (real (T))
458
+ N = j
459
+ checkinds = max (1 ,j- bandwidth (A. M,1 )- bandwidth (A. M,2 ))
460
+ @inbounds Ls = ql (A. M[checkinds: N,checkinds: N]). L[2 : j- checkinds+ 1 ,2 : j- checkinds+ 1 ]
461
+ @inbounds while Lerr > A. tol
462
+ # compute QL for small finite section and large finite section
463
+ Ll = ql (A. M[checkinds: 2 N,checkinds: 2 N]). L[2 : j- checkinds+ 1 ,2 : j- checkinds+ 1 ]
464
+ # compare bottom right sections and stop if desired level of convergence achieved
465
+ Lerr = norm (Ll- Ls,2 )
466
+ if N == maxN
467
+ error (" Reached max. iterations in adaptive QL without convergence to desired tolerance." )
468
+ end
469
+ Ls = Ll
470
+ N = 2 * N
471
+ end
472
+ A. data = ql (A. M[1 : (N÷ 2 ),1 : (N÷ 2 )]). τ[1 : j]
473
+ end
474
+
475
+ # TODO : adaptively build L*b using caching and forward-substitution
476
+ * (L:: LowerTriangular{T, AdaptiveQLFactors{T}} , b:: LayoutVector ) where T = ApplyArray (* , L, b)
477
+
478
+ MemoryLayout (:: AdaptiveQLFactors ) = LazyBandedLayout ()
479
+ bandwidths (F:: AdaptiveQLFactors ) = bandwidths (F. data)
480
+
481
+ # Q = \\prod_{i=1}^{\\min(m,n)} (I - \\tau_i v_i v_i^T)
482
+ getindex (Q:: QLPackedQ{T,<:AdaptiveQLFactors{T}} , i:: Int , j:: Int ) where T =
483
+ (Q' * [Zeros {T} (i- 1 ); one (T); Zeros {T} (∞)])[j]'
484
+ getindex (Q:: QLPackedQ{<:Any,<:AdaptiveQLFactors} , I:: AbstractVector{Int} , J:: AbstractVector{Int} ) =
485
+ [Q[i,j] for i in I, j in J]
486
+ getindex (Q:: QLPackedQ{<:Any,<:AdaptiveQLFactors} , I:: Int , J:: UnitRange{Int} ) =
487
+ [Q[i,j] for i in I, j in J]
488
+ getindex (Q:: QLPackedQ{<:Any,<:AdaptiveQLFactors} , I:: UnitRange{Int} , J:: Int ) =
489
+ [Q[i,j] for i in I, j in J]
490
+
491
+ materialize! (M:: Lmul{<:QLPackedQLayout{<:LazyLayout},<:PaddedLayout} ) = ApplyArray (* ,M. A,M. B)
492
+
493
+ function materialize! (M:: Lmul{<:AdjQLPackedQLayout{<:LazyLayout},<:PaddedLayout} )
494
+ adjA,B = M. A,M. B
495
+ A = parent (adjA)
496
+ mA, nA = size (A. factors)
497
+ mB, nB = size (B,1 ), size (B,2 )
498
+ if mA != mB
499
+ throw (DimensionMismatch (" matrix A has dimensions ($mA ,$nA ) but B has dimensions ($mB , $nB )" ))
500
+ end
501
+ Afactors = A. factors
502
+ l,u = bandwidths (Afactors)
503
+ l = 2 l+ 1
504
+ u = 2 u+ 1
505
+ @inbounds begin
506
+ for k = last (colsupport (B))+ u: - 1 : 1
507
+ for j = 1 : nB
508
+ vBj = B[k,j]
509
+ for i = max (1 ,k- u): k- 1
510
+ vBj += conj (Afactors[i,k])* B[i,j]
511
+ end
512
+ vBj = conj (A. τ[k])* vBj
513
+ B[k,j] -= vBj
514
+ for i = max (1 ,k- u): k- 1
515
+ B[i,j] -= Afactors[i,k]* vBj
516
+ end
517
+ end
518
+ end
519
+ end
520
+ B
521
+ end
0 commit comments