@@ -92,23 +92,9 @@ function ql_hessenberg!(B::InfBandedMatrix{TT}; kwds...) where TT
9292 QLHessenberg (_BandedMatrix (H, ℵ₀, l, 1 ), Vcat ( LowerHessenbergQ (F. Q). q, F∞. q))
9393end
9494
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-
10095getL (Q:: QL , :: NTuple{2,InfiniteCardinal{0}} ) = LowerTriangular (Q. factors)
10196getL (Q:: QLHessenberg , :: NTuple{2,InfiniteCardinal{0}} ) = LowerTriangular (Q. factors)
10297
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
11298
11399function materialize! (M:: Lmul{<:QLPackedQLayout{<:BandedColumns},<:PaddedLayout} )
114100 A,B = M. A,M. B
@@ -123,7 +109,7 @@ function materialize!(M::Lmul{<:QLPackedQLayout{<:BandedColumns},<:PaddedLayout}
123109 D = Afactors. data
124110 for k = 1 : ∞
125111 ν = k
126- allzero = k > nzzeros (B, 1 ) ? true : false
112+ allzero = k > last ( colsupport (B) ) ? true : false
127113 for j = 1 : nB
128114 vBj = B[k,j]
129115 for i = max (1 ,ν- u): k- 1
@@ -157,7 +143,7 @@ function materialize!(M::Lmul{<:AdjQLPackedQLayout{<:BandedColumns},<:PaddedLayo
157143 l,u = bandwidths (Afactors)
158144 D = Afactors. data
159145 @inbounds begin
160- for k = nzzeros (B, 1 )+ u: - 1 : 1
146+ for k = last ( colsupport (B) )+ u: - 1 : 1
161147 ν = k
162148 for j = 1 : nB
163149 vBj = B[k,j]
@@ -175,15 +161,6 @@ function materialize!(M::Lmul{<:AdjQLPackedQLayout{<:BandedColumns},<:PaddedLayo
175161 B
176162end
177163
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)
187164
188165
189166function blocktailiterate (c,a,b, d= c, e= a)
@@ -246,7 +223,7 @@ function lmul!(adjA::AdjointQtype{<:Any,<:QLPackedQ{<:Any,<:InfBlockBandedMatrix
246223 l = 2 l+ 1
247224 u = 2 u+ 1
248225 @inbounds begin
249- for k = nzzeros (B, 1 )+ u: - 1 : 1
226+ for k = last ( colsupport (B) )+ u: - 1 : 1
250227 ν = k
251228 for j = 1 : nB
252229 vBj = B[k,j]
@@ -290,7 +267,7 @@ function materialize!(M::MatLdivVec{<:TriangularLayout{'L','N',BandedColumns{Per
290267 throw (DimensionMismatch (" second dimension of left hand side A, $n , and length of right hand side b, $(length (b)) , must be equal" ))
291268 end
292269 data = triangulardata (A)
293- nz = nzzeros (b, 1 )
270+ nz = last ( colsupport (b) )
294271 @inbounds for j in 1 : n
295272 iszero (data[j,j]) && throw (SingularException (j))
296273 bj = b[j] = data[j,j] \ b[j]
@@ -333,8 +310,6 @@ function _ql(::SymTridiagonalLayout, ::NTuple{2,OneToInf{Int}}, A, args...; kwds
333310 ql (_BandedMatrix (Hcat (dat, [ev∞,d∞,ev∞] * Ones {T} (1 ,∞)), ℵ₀, 1 , 1 ), args... ; kwds... )
334311end
335312
336-
337-
338313# TODO : This should be redesigned as ql(BandedMatrix(A))
339314# But we need to support dispatch on axes
340315function _ql (:: TridiagonalLayout , :: NTuple{2,OneToInf{Int}} , A, args... ; kwds... )
@@ -378,3 +353,169 @@ function LazyBandedMatrices._SymTridiagonal(::Tuple{TriangularLayout{'L', 'N', P
378353 ev = [A[k,k+ 1 ] for k= 1 : m- 1 ]
379354 SymTridiagonal ([dv; Fill (dv[end ],∞)], [ev; Fill (ev[end ],∞)])
380355end
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