@@ -50,16 +50,42 @@ function Base.show(io::IO, tr::LOBPCGTrace)
50
50
return
51
51
end
52
52
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}} }
54
54
λ:: TL
55
55
X:: TX
56
- iterations:: Int
57
- residual_norms:: TR
58
56
tolerance:: T
59
- converged:: Bool
60
- maxiter:: TI
57
+ residual_norms:: TR
58
+ iterations:: TI
59
+ maxiter:: TM
60
+ converged:: TB
61
61
trace:: TTrace
62
62
end
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
63
89
function Base. show (io:: IO , r:: LOBPCGResults )
64
90
first_two (fr) = [x for (i, x) in enumerate (fr)][1 : 2 ]
65
91
@@ -79,7 +105,7 @@ function Base.show(io::IO, r::LOBPCGResults)
79
105
end
80
106
@printf io " * Convergence\n "
81
107
@printf io " * Iterations: %s\n " r. iterations
82
- @printf io " * Converged: %s\n " r. converged
108
+ @printf io " * Converged: %s\n " all ( r. converged)
83
109
@printf io " * Iterations limit: %s\n " r. maxiter
84
110
85
111
return
@@ -112,47 +138,85 @@ function B_mul_X!(b::Blocks{false}, B, n = 0)
112
138
return
113
139
end
114
140
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}
116
142
Y:: TVorM
117
143
BY:: TVorM
118
144
gram_chol:: TC
119
145
gramYBV:: TM # to be used in view
120
146
tmp:: TM # to be used in view
121
147
end
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 )
123
154
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 ))
124
155
end
125
- function Constraint (Y, B, X)
156
+
157
+ Constraint (Y, B, X) = Constraint (Y, B, X, BWrapper ())
158
+ function Constraint (Y, B, X, :: BWrapper )
126
159
T = eltype (X)
127
160
if B isa Void
128
161
BY = Y
129
162
else
130
163
BY = similar (Y)
131
164
A_mul_B! (BY, B, Y)
132
165
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
134
178
realdiag! (gramYBY)
135
179
gramYBY_chol = cholfact! (Hermitian (gramYBY))
136
- gramYBV = zeros (T, size (Y, 2 ), size (X, 2 ))
137
- tmp = similar (gramYBV)
180
+ tmp = deepcopy (gramYBV)
138
181
139
182
return Constraint {eltype(Y), typeof(Y), typeof(gramYBV), typeof(gramYBY_chol)} (Y, BY, gramYBY_chol, gramYBV, tmp)
140
183
end
141
184
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
+
142
205
function (constr!:: Constraint{Void} )(X, X_temp)
143
206
nothing
144
207
end
145
208
146
209
function (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
156
220
nothing
157
221
end
158
222
@@ -170,7 +234,7 @@ function (precond!::RPreconditioner)(X)
170
234
bs = size (X, 2 )
171
235
A_ldiv_B! (view (precond!. buffer, :, 1 : bs), precond!. M, X)
172
236
# 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]
174
238
nothing
175
239
end
176
240
@@ -379,13 +443,14 @@ LOBPCGIterator(A, X, largest::Bool, P=nothing, C=nothing) = LOBPCGIterator(A, no
379
443
- `P`: preconditioner of residual vectors, must overload `A_ldiv_B!`;
380
444
- `C`: constraint to deflate the residual and solution vectors orthogonal
381
445
to a subspace; must overload `A_mul_B!`;
382
-
383
446
"""
384
447
function 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 ())
387
449
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)
389
454
nev = size (X, 2 )
390
455
if B isa Void
391
456
XBlocks = Blocks (X, similar (X))
@@ -423,6 +488,35 @@ function LOBPCGIterator(A, B, X, largest::Bool, P=nothing, C=nothing)
423
488
424
489
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)
425
490
end
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
426
520
427
521
function ortho_AB_mul_X! (blocks:: Blocks , ortho!, A, B, bs= - 1 )
428
522
# Finds BX
@@ -683,10 +777,10 @@ Finds the `nev` extremal eigenvalues and their corresponding eigenvectors satisf
683
777
684
778
- `results`: a `LOBPCGResults` struct. `r.λ` and `r.X` store the eigenvalues and eigenvectors.
685
779
"""
686
- function lobpcg (A, largest:: Bool , nev:: Int = 1 ; kwargs... )
780
+ function lobpcg (A, largest:: Bool , nev:: Int ; kwargs... )
687
781
lobpcg (A, nothing , largest, nev; kwargs... )
688
782
end
689
- function lobpcg (A, B, largest:: Bool , nev:: Int = 1 ; kwargs... )
783
+ function lobpcg (A, B, largest:: Bool , nev:: Int ; kwargs... )
690
784
lobpcg (A, B, largest, rand (eltype (A), size (A, 1 ), nev); not_zeros= true , kwargs... )
691
785
end
692
786
@@ -720,13 +814,12 @@ end
720
814
721
815
- `results`: a `LOBPCGResults` struct. `r.λ` and `r.X` store the eigenvalues and eigenvectors.
722
816
"""
723
- function lobpcg (A, largest:: Bool , X0:: Union{AbstractMatrix, AbstractVector} ; kwargs... )
817
+ function lobpcg (A, largest:: Bool , X0; kwargs... )
724
818
lobpcg (A, nothing , largest, X0; kwargs... )
725
819
end
726
820
function lobpcg (A, B, largest, X0;
727
821
not_zeros= false , log= false , P= nothing ,
728
822
C= nothing , tol= nothing , maxiter= 200 )
729
-
730
823
X = copy (X0)
731
824
T = eltype (X)
732
825
n = size (X, 1 )
@@ -776,7 +869,7 @@ function lobpcg!(iterator::LOBPCGIterator; log=false, tol=nothing, maxiter=200,
776
869
end
777
870
n = size (X, 1 )
778
871
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)
780
873
iterator. iteration[] = 1
781
874
while iterator. iteration[] <= maxiter
782
875
state = iterator (residualTolerance, log)
@@ -788,7 +881,46 @@ function lobpcg!(iterator::LOBPCGIterator; log=false, tol=nothing, maxiter=200,
788
881
end
789
882
@inbounds iterator. λ .= view (iterator. ritz_values, 1 : sizeX)
790
883
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)
792
885
793
886
return results
794
887
end
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