@@ -50,16 +50,42 @@ function Base.show(io::IO, tr::LOBPCGTrace)
5050 return
5151end
5252
53- struct LOBPCGResults{T, TL, TR, TX , TI, TTrace <: LOBPCGTrace }
53+ struct LOBPCGResults{TL, TX, T, TR , TI, TM, TB, TTrace <: Union{ LOBPCGTrace, AbstractVector{<:LOBPCGTrace}} }
5454 λ:: TL
5555 X:: TX
56- iterations:: Int
57- residual_norms:: TR
5856 tolerance:: T
59- converged:: Bool
60- maxiter:: TI
57+ residual_norms:: TR
58+ iterations:: TI
59+ maxiter:: TM
60+ converged:: TB
6161 trace:: TTrace
6262end
63+ function EmptyLOBPCGResults (X:: TX , k:: Integer , tolerance, maxiter) where {T, TX<: AbstractMatrix{T} }
64+ blocksize = size (X,2 )
65+ λ = Vector {T} (k)
66+ X = TX (size (X, 1 ), k)
67+
68+ iterations = zeros (Int, ceil (Int, k/ blocksize))
69+ residual_norms = copy (λ)
70+ converged = falses (k)
71+ trace = fill (LOBPCGTrace {Vector{real(T)},Vector{T}} (), k÷ blocksize+ 1 )
72+
73+ return LOBPCGResults (λ, X, tolerance, residual_norms, iterations, maxiter, converged, trace)
74+ end
75+
76+ function Base. append! (r1:: LOBPCGResults , r2:: LOBPCGResults , n1, n2= length (r2. λ))
77+ n = n1 + n2
78+ r1. λ[n1+ 1 : n] .= @view r2. λ[end - n2+ 1 : end ]
79+ r1. residual_norms[n1+ 1 : n] .= @view r2. residual_norms[end - n2+ 1 : end ]
80+ r1. X[:, n1+ 1 : n] .= @view r2. X[:, end - n2+ 1 : end ]
81+
82+ ind = n1 ÷ length (r2. λ) + 1
83+ r1. iterations[ind] = r2. iterations
84+ r1. converged[n1+ 1 : n] .= r2. converged
85+ r1. trace[ind] = r2. trace
86+
87+ return r1
88+ end
6389function Base. show (io:: IO , r:: LOBPCGResults )
6490 first_two (fr) = [x for (i, x) in enumerate (fr)][1 : 2 ]
6591
@@ -79,7 +105,7 @@ function Base.show(io::IO, r::LOBPCGResults)
79105 end
80106 @printf io " * Convergence\n "
81107 @printf io " * Iterations: %s\n " r. iterations
82- @printf io " * Converged: %s\n " r. converged
108+ @printf io " * Converged: %s\n " all ( r. converged)
83109 @printf io " * Iterations limit: %s\n " r. maxiter
84110
85111 return
@@ -112,47 +138,85 @@ function B_mul_X!(b::Blocks{false}, B, n = 0)
112138 return
113139end
114140
115- struct Constraint{T, TVorM<: Union{AbstractVector{T}, AbstractMatrix{T}} , TM<: AbstractMatrix{T} , TC}
141+ mutable struct Constraint{T, TVorM<: Union{AbstractVector{T}, AbstractMatrix{T}} , TM<: AbstractMatrix{T} , TC}
116142 Y:: TVorM
117143 BY:: TVorM
118144 gram_chol:: TC
119145 gramYBV:: TM # to be used in view
120146 tmp:: TM # to be used in view
121147end
122- function Constraint (:: Void , B, X)
148+ struct BWrapper end
149+ struct NotBWrapper end
150+
151+ Constraint (:: Void , B, X) = Constraint (nothing , B, X, BWrapper ())
152+ Constraint (:: Void , B, X, :: NotBWrapper ) = Constraint (nothing , B, X, BWrapper ())
153+ function Constraint (:: Void , B, X, :: BWrapper )
123154 return Constraint {Void, Matrix{Void}, Matrix{Void}, Void} (Matrix {Void} (0 ,0 ), Matrix {Void} (0 ,0 ), nothing , Matrix {Void} (0 ,0 ), Matrix {Void} (0 ,0 ))
124155end
125- function Constraint (Y, B, X)
156+
157+ Constraint (Y, B, X) = Constraint (Y, B, X, BWrapper ())
158+ function Constraint (Y, B, X, :: BWrapper )
126159 T = eltype (X)
127160 if B isa Void
128161 BY = Y
129162 else
130163 BY = similar (Y)
131164 A_mul_B! (BY, B, Y)
132165 end
133- gramYBY = Ac_mul_B (Y, BY)
166+ return Constraint (Y, BY, X, NotBWrapper ())
167+ end
168+ function Constraint (Y, BY, X, :: NotBWrapper )
169+ T = eltype (X)
170+ if Y isa SubArray
171+ gramYBY = @view eye (T, size (Y. parent, 2 ))[1 : size (Y, 2 ), 1 : size (Y, 2 )]
172+ Ac_mul_B! (gramYBY, Y, BY)
173+ gramYBV = @view zeros (T, size (Y. parent, 2 ), size (X, 2 ))[1 : size (Y, 2 ), :]
174+ else
175+ gramYBY = Ac_mul_B (Y, BY)
176+ gramYBV = zeros (T, size (Y, 2 ), size (X, 2 ))
177+ end
134178 realdiag! (gramYBY)
135179 gramYBY_chol = cholfact! (Hermitian (gramYBY))
136- gramYBV = zeros (T, size (Y, 2 ), size (X, 2 ))
137- tmp = similar (gramYBV)
180+ tmp = deepcopy (gramYBV)
138181
139182 return Constraint {eltype(Y), typeof(Y), typeof(gramYBV), typeof(gramYBY_chol)} (Y, BY, gramYBY_chol, gramYBV, tmp)
140183end
141184
185+ function update! (c:: Constraint , X, BX)
186+ sizeY = size (c. Y, 2 )
187+ sizeX = size (X, 2 )
188+ c. Y. parent[:, sizeY+ 1 : sizeY+ sizeX] .= X
189+ if X != = BX
190+ c. BY. parent[:, sizeY+ 1 : sizeY+ sizeX] .= BX
191+ end
192+ sizeY += sizeX
193+ Y = @view c. Y. parent[:, 1 : sizeY]
194+ BY = @view c. BY. parent[:, 1 : sizeY]
195+ c. Y = Y
196+ c. BY = BY
197+ gram_chol = c. gram_chol
198+ new_factors = @view gram_chol. factors. parent[1 : sizeY, 1 : sizeY]
199+ c. gram_chol = typeof (gram_chol)(new_factors, gram_chol. uplo)
200+ c. gramYBV = @view c. gramYBV. parent[1 : sizeY, :]
201+ c. tmp = @view c. tmp. parent[1 : sizeY, :]
202+ return c
203+ end
204+
142205function (constr!:: Constraint{Void} )(X, X_temp)
143206 nothing
144207end
145208
146209function (constr!:: Constraint )(X, X_temp)
147- sizeX = size (X, 2 )
148- sizeY = size (constr!. Y, 2 )
149- gramYBV_view = view (constr!. gramYBV, 1 : sizeY, 1 : sizeX)
150- Ac_mul_B! (gramYBV_view, constr!. BY, X)
151- tmp_view = view (constr!. tmp, 1 : sizeY, 1 : sizeX)
152- A_ldiv_B! (tmp_view, constr!. gram_chol, gramYBV_view)
153- A_mul_B! (X_temp, constr!. Y, tmp_view)
154- @inbounds X .= X .- X_temp
155-
210+ if size (constr!. Y, 2 ) > 0
211+ sizeX = size (X, 2 )
212+ sizeY = size (constr!. Y, 2 )
213+ gramYBV_view = view (constr!. gramYBV, 1 : sizeY, 1 : sizeX)
214+ Ac_mul_B! (gramYBV_view, constr!. BY, X)
215+ tmp_view = view (constr!. tmp, 1 : sizeY, 1 : sizeX)
216+ A_ldiv_B! (tmp_view, constr!. gram_chol, gramYBV_view)
217+ A_mul_B! (X_temp, constr!. Y, tmp_view)
218+ @inbounds X .= X .- X_temp
219+ end
156220 nothing
157221end
158222
@@ -170,7 +234,7 @@ function (precond!::RPreconditioner)(X)
170234 bs = size (X, 2 )
171235 A_ldiv_B! (view (precond!. buffer, :, 1 : bs), precond!. M, X)
172236 # Just returning buffer would be cheaper but struct at call site must be mutable
173- @inbounds X .= view ( precond!. buffer, :, 1 : bs)
237+ @inbounds X .= @ view precond!. buffer[ :, 1 : bs]
174238 nothing
175239end
176240
@@ -379,13 +443,14 @@ LOBPCGIterator(A, X, largest::Bool, P=nothing, C=nothing) = LOBPCGIterator(A, no
379443- `P`: preconditioner of residual vectors, must overload `A_ldiv_B!`;
380444- `C`: constraint to deflate the residual and solution vectors orthogonal
381445 to a subspace; must overload `A_mul_B!`;
382-
383446"""
384447function LOBPCGIterator (A, B, X, largest:: Bool , P= nothing , C= nothing )
385- T = eltype (X)
386- constr! = Constraint (C, B, X)
448+ constr! = Constraint (C, B, X, BWrapper ())
387449 precond! = RPreconditioner (P, X)
388-
450+ return LOBPCGIterator (A, B, X, largest, constr!, precond!)
451+ end
452+ function LOBPCGIterator (A, B, X, largest:: Bool , constr!:: Constraint , precond!:: RPreconditioner )
453+ T = eltype (X)
389454 nev = size (X, 2 )
390455 if B isa Void
391456 XBlocks = Blocks (X, similar (X))
@@ -423,6 +488,35 @@ function LOBPCGIterator(A, B, X, largest::Bool, P=nothing, C=nothing)
423488
424489 return LOBPCGIterator {generalized, T, typeof(A), typeof(B), typeof(λ), typeof(residuals), typeof(λperm), typeof(V), typeof(XBlocks), typeof(ortho!), typeof(precond!), typeof(constr!), typeof(gramABlock), typeof(activeMask), typeof(trace)} (A, B, ritz_values, λperm, λ, V, residuals, largest, XBlocks, tempXBlocks, PBlocks, activePBlocks, RBlocks, activeRBlocks, iteration, currentBlockSize, ortho!, precond!, constr!, gramABlock, gramBBlock, gramA, gramB, activeMask, trace)
425490end
491+ function LOBPCGIterator (A, X, largest:: Bool , nev:: Int , P= nothing , C= nothing )
492+ LOBPCGIterator (A, nothing , X, largest, nev, P, C)
493+ end
494+ function LOBPCGIterator (A, B, X, largest:: Bool , nev:: Int , P= nothing , C= nothing )
495+ T = eltype (X)
496+ n = size (X, 1 )
497+ sizeX = size (X, 2 )
498+ if C isa Void
499+ sizeC = 0
500+ new_C = typeof (X)(n, (nev÷ sizeX)* sizeX)
501+ else
502+ sizeC = size (C,2 )
503+ new_C = typeof (C)(n, sizeC+ (nev÷ sizeX)* sizeX)
504+ new_C[:,1 : sizeC] .= C
505+ end
506+ if B isa Void
507+ new_BC = new_C
508+ else
509+ new_BC = similar (new_C)
510+ end
511+ Y = @view new_C[:, 1 : sizeC]
512+ BY = @view new_BC[:, 1 : sizeC]
513+ if ! (B isa Void)
514+ A_mul_B! (BY, B, Y)
515+ end
516+ constr! = Constraint (Y, BY, X, NotBWrapper ())
517+ precond! = RPreconditioner (P, X)
518+ return LOBPCGIterator (A, B, X, largest, constr!, precond!)
519+ end
426520
427521function ortho_AB_mul_X! (blocks:: Blocks , ortho!, A, B, bs= - 1 )
428522 # Finds BX
@@ -683,10 +777,10 @@ Finds the `nev` extremal eigenvalues and their corresponding eigenvectors satisf
683777
684778- `results`: a `LOBPCGResults` struct. `r.λ` and `r.X` store the eigenvalues and eigenvectors.
685779"""
686- function lobpcg (A, largest:: Bool , nev:: Int = 1 ; kwargs... )
780+ function lobpcg (A, largest:: Bool , nev:: Int ; kwargs... )
687781 lobpcg (A, nothing , largest, nev; kwargs... )
688782end
689- function lobpcg (A, B, largest:: Bool , nev:: Int = 1 ; kwargs... )
783+ function lobpcg (A, B, largest:: Bool , nev:: Int ; kwargs... )
690784 lobpcg (A, B, largest, rand (eltype (A), size (A, 1 ), nev); not_zeros= true , kwargs... )
691785end
692786
@@ -720,13 +814,12 @@ end
720814
721815- `results`: a `LOBPCGResults` struct. `r.λ` and `r.X` store the eigenvalues and eigenvectors.
722816"""
723- function lobpcg (A, largest:: Bool , X0:: Union{AbstractMatrix, AbstractVector} ; kwargs... )
817+ function lobpcg (A, largest:: Bool , X0; kwargs... )
724818 lobpcg (A, nothing , largest, X0; kwargs... )
725819end
726820function lobpcg (A, B, largest, X0;
727821 not_zeros= false , log= false , P= nothing ,
728822 C= nothing , tol= nothing , maxiter= 200 )
729-
730823 X = copy (X0)
731824 T = eltype (X)
732825 n = size (X, 1 )
@@ -776,7 +869,7 @@ function lobpcg!(iterator::LOBPCGIterator; log=false, tol=nothing, maxiter=200,
776869 end
777870 n = size (X, 1 )
778871 sizeX = size (X, 2 )
779- residualTolerance = (tol isa Void) ? (eps (real (T)))^ (real (T)(4 )/ 10 ) : tol
872+ residualTolerance = (tol isa Void) ? (eps (real (T)))^ (real (T)(4 )/ 10 ) : real ( tol)
780873 iterator. iteration[] = 1
781874 while iterator. iteration[] <= maxiter
782875 state = iterator (residualTolerance, log)
@@ -788,7 +881,46 @@ function lobpcg!(iterator::LOBPCGIterator; log=false, tol=nothing, maxiter=200,
788881 end
789882 @inbounds iterator. λ .= view (iterator. ritz_values, 1 : sizeX)
790883
791- results = LOBPCGResults (iterator. λ, X, iterator. iteration[] , iterator. residuals[ 1 : sizeX ], residualTolerance , all ((x)-> (norm (x)<= residualTolerance), view (iterator. residuals, 1 : sizeX)), maxiter , iterator. trace)
884+ results = LOBPCGResults (iterator. λ, X, residualTolerance, iterator. residuals , iterator. iteration[ ], maxiter , all ((x)-> (norm (x)<= residualTolerance), view (iterator. residuals, 1 : sizeX)), iterator. trace)
792885
793886 return results
794887end
888+
889+ function lobpcg (A, largest:: Bool , X0, nev:: Int ; kwargs... )
890+ lobpcg (A, nothing , largest, X0, nev; kwargs... )
891+ end
892+ function lobpcg (A, B, largest:: Bool , X0, nev:: Int ;
893+ not_zeros= false , log= false , P= nothing ,
894+ C= nothing , tol= nothing , maxiter= 200 )
895+ T = eltype (X0)
896+ n = size (X0, 1 )
897+ sizeX = size (X0, 2 )
898+ nev > n && throw (" Number of eigenvectors desired exceeds the row dimension." )
899+
900+ sizeX = min (nev, sizeX)
901+ X = X0[:, 1 : sizeX]
902+ iterator = LOBPCGIterator (A, B, X, largest, nev, C, P)
903+
904+ r = EmptyLOBPCGResults (X, nev, tol, maxiter)
905+ rnext = lobpcg! (iterator, log= log, tol= tol, maxiter= maxiter, not_zeros= not_zeros)
906+ append! (r, rnext, 0 )
907+ converged_x = sizeX
908+ while converged_x < nev
909+ if nev- converged_x < sizeX
910+ cutoff = sizeX- (nev- converged_x)
911+ update! (iterator. constr!, view (iterator. XBlocks. block, :, 1 : cutoff), view (iterator. XBlocks. B_block, :, 1 : cutoff))
912+ X[:, 1 : sizeX- cutoff] .= @view X[:, cutoff+ 1 : sizeX]
913+ rand! (view (X, :, cutoff+ 1 : sizeX))
914+ rnext = lobpcg! (iterator, log= log, tol= tol, maxiter= maxiter, not_zeros= true )
915+ append! (r, rnext, converged_x, sizeX- cutoff)
916+ converged_x += sizeX- cutoff
917+ else
918+ update! (iterator. constr!, iterator. XBlocks. block, iterator. XBlocks. B_block)
919+ rand! (X)
920+ rnext = lobpcg! (iterator, log= log, tol= tol, maxiter= maxiter, not_zeros= true )
921+ append! (r, rnext, converged_x)
922+ converged_x += sizeX
923+ end
924+ end
925+ return r
926+ end
0 commit comments