@@ -59,14 +59,15 @@ _no_preconditioner(::IdentityOperator) = true
59
59
_no_preconditioner (:: UniformScaling ) = true
60
60
_no_preconditioner (_) = false
61
61
62
- function init_cacheval (alg:: SimpleGMRES{false} , args... ; kwargs... )
63
- return _init_cacheval (Val (false ), alg, args... ; kwargs... )
62
+ _norm2 (x) = norm (x, 2 )
63
+ _norm2 (x, dims) = .√ (sum (abs2, x; dims))
64
+
65
+ function init_cacheval (alg:: SimpleGMRES{UDB} , args... ; kwargs... ) where {UDB}
66
+ return _init_cacheval (Val (UDB), alg, args... ; kwargs... )
64
67
end
65
68
66
- # TODO : We can check if `A` is a block diagonal matrix with uniformly sized square blocks
67
- # and use the specialized dispatch
68
69
function _init_cacheval (:: Val{false} , alg:: SimpleGMRES , A, b, u, Pl, Pr, maxiters:: Int ,
69
- abstol, :: Any , :: Bool , :: OperatorAssumptions ; zeroinit = true )
70
+ abstol, :: Any , :: Bool , :: OperatorAssumptions ; zeroinit = true , kwargs ... )
70
71
if zeroinit
71
72
return SimpleGMRESCache {false} (0 , 0 , maxiters, alg. blocksize, zero (eltype (u)),
72
73
similar (b, 0 , 0 ), similar (b, 0 , 0 ), u, similar (b, 0 ), similar (b, 0 ),
@@ -75,6 +76,7 @@ function _init_cacheval(::Val{false}, alg::SimpleGMRES, A, b, u, Pl, Pr, maxiter
75
76
76
77
@assert _no_preconditioner (Pl)&& _no_preconditioner (Pr) " Preconditioning not supported! Use KrylovJL_GMRES instead."
77
78
N = LinearAlgebra. checksquare (A)
79
+ @assert N == length (b) " The size of `A` and `b` must match."
78
80
T = eltype (u)
79
81
M = min (maxiters, alg. restart)
80
82
ϵ = eps (T)
@@ -87,7 +89,7 @@ function _init_cacheval(::Val{false}, alg::SimpleGMRES, A, b, u, Pl, Pr, maxiter
87
89
88
90
mul! (@view (Q[:, 1 ]), A, u, T (- 1 ), T (0 )) # r0 <- A u
89
91
axpy! (T (1 ), b, @view (Q[:, 1 ])) # r0 <- r0 - b
90
- β = norm (@view (Q[:, 1 ]), 2 )
92
+ β = _norm2 (@view (Q[:, 1 ]))
91
93
Q[:, 1 ] ./= β
92
94
93
95
x = u
@@ -100,6 +102,45 @@ function _init_cacheval(::Val{false}, alg::SimpleGMRES, A, b, u, Pl, Pr, maxiter
100
102
β, abstol)
101
103
end
102
104
105
+ function _init_cacheval (:: Val{true} , alg:: SimpleGMRES , A, b, u, Pl, Pr, maxiters:: Int ,
106
+ abstol, :: Any , :: Bool , :: OperatorAssumptions ; zeroinit = true ,
107
+ blocksize = alg. blocksize)
108
+ if zeroinit
109
+ return SimpleGMRESCache {true} (0 , 0 , maxiters, alg. blocksize, zero (eltype (u)),
110
+ similar (b, 0 , 0 , 0 ), similar (b, 0 , 0 , 0 ), u, similar (b, 0 ), similar (b, 0 , 0 ),
111
+ A, b, similar (b, 0 , 0 ), abstol)
112
+ end
113
+
114
+ @assert _no_preconditioner (Pl)&& _no_preconditioner (Pr) " Preconditioning not supported! Use KrylovJL_GMRES instead."
115
+ N = LinearAlgebra. checksquare (A)
116
+ @assert mod (N, blocksize)== 0 " The blocksize must divide the size of the matrix."
117
+ @assert N== length (b) " The size of `A` and `b` must match."
118
+ T = eltype (u)
119
+ M = min (maxiters, alg. restart)
120
+ ϵ = eps (T)
121
+ bsize = N ÷ blocksize
122
+
123
+ # Initialize the Cache
124
+ # # Use `b` since `A` might be an operator
125
+ Q = similar (b, blocksize, M + 1 , bsize)
126
+ H = similar (b, M + 1 , M, bsize)
127
+ fill! (H, zero (T))
128
+
129
+ mul! (vec (@view (Q[:, 1 , :])), A, u, T (- 1 ), T (0 )) # r0 <- A u
130
+ axpy! (T (1 ), b, vec (@view (Q[:, 1 , :]))) # r0 <- r0 - b
131
+ β = _norm2 (@view (Q[:, 1 , :]), 1 )
132
+ Q[:, 1 , :] ./= β
133
+
134
+ x = u
135
+ r = similar (b)
136
+ βe₁ = similar (b, M + 1 , bsize)
137
+ fill! (βe₁, 0 )
138
+ βe₁[1 , :] .= vec (β) # Avoid the scalar indexing error
139
+
140
+ return SimpleGMRESCache {true} (M, N, maxiters, blocksize, ϵ, Q, H, x, r, βe₁, A, b,
141
+ β, abstol)
142
+ end
143
+
103
144
default_alias_A (:: SimpleGMRES , :: Any , :: Any ) = false
104
145
default_alias_b (:: SimpleGMRES , :: Any , :: Any ) = false
105
146
@@ -111,25 +152,25 @@ function SciMLBase.solve!(cache::LinearCache, alg::SimpleGMRES; kwargs...)
111
152
cache. cacheval = solver
112
153
cache. isfresh = false
113
154
end
114
- return SciMLBase. solve! (cache. cacheval)
155
+ return SciMLBase. solve! (cache. cacheval, cache )
115
156
end
116
157
117
- function SciMLBase. solve! (cache:: SimpleGMRESCache{false, T} ) where {T}
158
+ function SciMLBase. solve! (cache:: SimpleGMRESCache{false, T} ,
159
+ lincache:: LinearCache ) where {T}
118
160
@unpack M, N, maxiters, ϵ, Q, H, x, r, βe₁, A, b, β, abstol = cache
119
- norm2 = Base. Fix2 (norm, 2 )
120
161
res_norm = β
121
162
122
163
# FIXME : The performance for this is quite bad when compared to the KrylovJL_GMRES
123
164
# version
124
- for _ in 1 : (maxiters ÷ M + 1 )
165
+ for _ in 1 : (( maxiters ÷ M) + 1 )
125
166
for j in 1 : M
126
167
Qⱼ₊₁ = @view (Q[:, j + 1 ])
127
168
mul! (Qⱼ₊₁, A, @view (Q[:, j])) # Q(:,j+1) <- A Q(:, j)
128
169
for i in 1 : j
129
170
H[i, j] = dot (@view (Q[:, i]), Qⱼ₊₁)
130
171
axpy! (- H[i, j], @view (Q[:, i]), Qⱼ₊₁)
131
172
end
132
- H[j + 1 , j] = norm2 (Qⱼ₊₁)
173
+ H[j + 1 , j] = _norm2 (Qⱼ₊₁)
133
174
H[j + 1 , j] > ϵ && (Qⱼ₊₁ ./= H[j + 1 , j])
134
175
135
176
# FIXME : Figure out a way to avoid the allocation
@@ -140,10 +181,10 @@ function SciMLBase.solve!(cache::SimpleGMRESCache{false, T}) where {T}
140
181
mul! (x, @view (Q[:, 1 : j]), y)
141
182
mul! (r, A, x, T (- 1 ), T (0 ))
142
183
axpy! (T (1 ), b, r)
143
- res_norm = norm2 (r)
184
+ res_norm = _norm2 (r)
144
185
145
186
if res_norm < abstol
146
- return SciMLBase. build_linear_solution (nothing , x, r, nothing ;
187
+ return SciMLBase. build_linear_solution (lincache . alg , x, r, lincache ;
147
188
retcode = ReturnCode. Success)
148
189
end
149
190
end
@@ -153,6 +194,6 @@ function SciMLBase.solve!(cache::SimpleGMRESCache{false, T}) where {T}
153
194
fill! (H, zero (T))
154
195
end
155
196
156
- return SciMLBase. build_linear_solution (nothing , x, r, nothing ;
197
+ return SciMLBase. build_linear_solution (lincache . alg , x, r, lincache ;
157
198
retcode = ReturnCode. MaxIters)
158
199
end
0 commit comments