Skip to content

Commit d03b40a

Browse files
committed
Add in-place Krylov methods
1 parent ac55536 commit d03b40a

36 files changed

+1715
-449
lines changed

docs/src/api.md

+31-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,36 @@ Krylov.AdjointStats
1111
## Solver Types
1212

1313
```@docs
14-
Krylov.KrylovSolver
15-
Krylov.MinresSolver
14+
KrylovSolver
15+
MinresSolver
16+
CgSolver
17+
CrSolver
18+
SymmlqSolver
19+
CgLanczosSolver
20+
CgLanczosShiftSolver
21+
MinresQlpSolver
22+
DqgmresSolver
23+
DiomSolver
24+
UsymlqSolver
25+
UsymqrSolver
26+
TricgSolver
27+
TrimrSolver
28+
TrilqrSolver
29+
CgsSolver
30+
BicgstabSolver
31+
BilqSolver
32+
QmrSolver
33+
BilqrSolver
34+
CglsSolver
35+
CrlsSolver
36+
CgneSolver
37+
CrmrSolver
38+
LslqSolver
39+
LsqrSolver
40+
LsmrSolver
41+
LnlqSolver
42+
CraigSolver
43+
CraigmrSolver
1644
```
1745

1846
## Utilities
@@ -22,6 +50,7 @@ Krylov.roots_quadratic
2250
Krylov.sym_givens
2351
Krylov.to_boundary
2452
Krylov.vec2str
53+
Krylov.ktypeof
2554
Krylov.kzeros
2655
Krylov.kones
2756
```

src/bicgstab.jl

+18-12
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# Alexis Montoison, <alexis.montoison@polymtl.ca>
1414
# Montréal, October 2020.
1515

16-
export bicgstab
16+
export bicgstab, bicgstab!
1717

1818
"""
1919
(x, stats) = bicgstab(A, b::AbstractVector{T}; c::AbstractVector{T}=b,
@@ -41,9 +41,14 @@ This implementation allows a left preconditioner `M` and a right preconditioner
4141
* H. A. van der Vorst, *Bi-CGSTAB: A fast and smoothly converging variant of Bi-CG for the solution of nonsymmetric linear systems*, SIAM Journal on Scientific and Statistical Computing, 13(2), pp. 631--644, 1992.
4242
* G. L.G. Sleijpen and D. R. Fokkema, *BiCGstab(ℓ) for linear equations involving unsymmetric matrices with complex spectrum*, Electronic Transactions on Numerical Analysis, 1, pp. 11--32, 1993.
4343
"""
44-
function bicgstab(A, b :: AbstractVector{T}; c :: AbstractVector{T}=b,
45-
M=opEye(), N=opEye(), atol :: T=eps(T), rtol :: T=eps(T),
46-
itmax :: Int=0, verbose :: Int=0, history :: Bool=false) where T <: AbstractFloat
44+
function bicgstab(A, b :: AbstractVector{T}; kwargs...) where T <: AbstractFloat
45+
solver = BicgstabSolver(A, b)
46+
bicgstab!(solver, A, b; kwargs...)
47+
end
48+
49+
function bicgstab!(solver :: BicgstabSolver{T,S}, A, b :: AbstractVector{T}; c :: AbstractVector{T}=b,
50+
M=opEye(), N=opEye(), atol :: T=eps(T), rtol :: T=eps(T),
51+
itmax :: Int=0, verbose :: Int=0, history :: Bool=false) where {S, T <: AbstractFloat}
4752

4853
n, m = size(A)
4954
m == n || error("System must be square")
@@ -56,18 +61,19 @@ function bicgstab(A, b :: AbstractVector{T}; c :: AbstractVector{T}=b,
5661

5762
# Check type consistency
5863
eltype(A) == T || error("eltype(A) ≠ $T")
64+
ktypeof(b) == S || error("ktypeof(b) ≠ $S")
65+
ktypeof(c) == S || error("ktypeof(c) ≠ $S")
5966
MisI || (eltype(M) == T) || error("eltype(M) ≠ $T")
6067
NisI || (eltype(N) == T) || error("eltype(N) ≠ $T")
6168

62-
# Determine the storage type of b
63-
S = typeof(b)
64-
6569
# Set up workspace.
66-
x = kzeros(S, n) # x₀
67-
s = kzeros(S, n) # s₀
68-
v = kzeros(S, n) # v₀
69-
r = copy(M * b) # r₀
70-
p = copy(r) # p₁
70+
x, s, v, r, p = solver.x, solver.s, solver.v, solver.r, solver.p
71+
72+
x .= zero(T) # x₀
73+
s .= zero(T) # s₀
74+
v .= zero(T) # v₀
75+
r .= (M * b) # r₀
76+
p .= r # p₁
7177

7278
α = one(T) # α₀
7379
ω = one(T) # ω₀

src/bilq.jl

+19-13
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# Alexis Montoison, <alexis.montoison@polymtl.ca>
1111
# Montreal, February 2019.
1212

13-
export bilq
13+
export bilq, bilq!
1414

1515
"""
1616
(x, stats) = bilq(A, b::AbstractVector{T}; c::AbstractVector{T}=b,
@@ -29,9 +29,14 @@ when it exists. The transfer is based on the residual norm.
2929
3030
* A. Montoison and D. Orban, *BiLQ: An Iterative Method for Nonsymmetric Linear Systems with a Quasi-Minimum Error Property*, SIAM Journal on Matrix Analysis and Applications, 41(3), pp. 1145--1166, 2020.
3131
"""
32-
function bilq(A, b :: AbstractVector{T}; c :: AbstractVector{T}=b,
33-
atol :: T=eps(T), rtol :: T=eps(T), transfer_to_bicg :: Bool=true,
34-
itmax :: Int=0, verbose :: Int=0, history :: Bool=false) where T <: AbstractFloat
32+
function bilq(A, b :: AbstractVector{T}; kwargs...) where T <: AbstractFloat
33+
solver = BilqSolver(A, b)
34+
bilq!(solver, A, b; kwargs...)
35+
end
36+
37+
function bilq!(solver :: BilqSolver{T,S}, A, b :: AbstractVector{T}; c :: AbstractVector{T}=b,
38+
atol :: T=eps(T), rtol :: T=eps(T), transfer_to_bicg :: Bool=true,
39+
itmax :: Int=0, verbose :: Int=0, history :: Bool=false) where {S, T <: AbstractFloat}
3540

3641
n, m = size(A)
3742
m == n || error("System must be square")
@@ -40,15 +45,17 @@ function bilq(A, b :: AbstractVector{T}; c :: AbstractVector{T}=b,
4045

4146
# Check type consistency
4247
eltype(A) == T || error("eltype(A) ≠ $T")
48+
ktypeof(b) == S || error("ktypeof(b) ≠ $S")
49+
ktypeof(c) == S || error("ktypeof(c) ≠ $S")
4350

4451
# Compute the adjoint of A
4552
Aᵀ = A'
4653

47-
# Determine the storage type of b
48-
S = typeof(b)
54+
# Set up workspace.
55+
uₖ₋₁, uₖ, vₖ₋₁, vₖ, x, d̅ = solver.uₖ₋₁, solver.uₖ, solver.vₖ₋₁, solver.vₖ, solver.x, solver.
4956

5057
# Initial solution x₀ and residual norm ‖r₀‖.
51-
x = kzeros(S, n)
58+
x .= zero(T)
5259
bNorm = @knrm2(n, b) # ‖r₀‖
5360
bNorm == 0 && return (x, SimpleStats(true, false, [bNorm], T[], "x = 0 is a zero-residual solution"))
5461

@@ -64,16 +71,15 @@ function bilq(A, b :: AbstractVector{T}; c :: AbstractVector{T}=b,
6471
bᵗc = @kdot(n, b, c) # ⟨b,c⟩
6572
bᵗc == 0 && return (x, SimpleStats(false, false, [bNorm], T[], "Breakdown bᵀc = 0"))
6673

67-
# Set up workspace.
6874
βₖ = (abs(bᵗc)) # β₁γ₁ = bᵀc
6975
γₖ = bᵗc / βₖ # β₁γ₁ = bᵀc
70-
vₖ₋₁ = kzeros(S, n) # v₀ = 0
71-
uₖ₋₁ = kzeros(S, n) # u₀ = 0
72-
vₖ = b / βₖ # v₁ = b / β₁
73-
uₖ = c / γₖ # u₁ = c / γ₁
76+
vₖ₋₁ .= zero(T) # v₀ = 0
77+
uₖ₋₁ .= zero(T) # u₀ = 0
78+
vₖ .= b ./ βₖ # v₁ = b / β₁
79+
uₖ .= c ./ γₖ # u₁ = c / γ₁
7480
cₖ₋₁ = cₖ = -one(T) # Givens cosines used for the LQ factorization of Tₖ
7581
sₖ₋₁ = sₖ = zero(T) # Givens sines used for the LQ factorization of Tₖ
76-
= kzeros(S, n) # Last column of D̅ₖ = Vₖ(Qₖ)ᵀ
82+
.= zero(T) # Last column of D̅ₖ = Vₖ(Qₖ)ᵀ
7783
ζₖ₋₁ = ζbarₖ = zero(T) # ζₖ₋₁ and ζbarₖ are the last components of z̅ₖ = (L̅ₖ)⁻¹β₁e₁
7884
ζₖ₋₂ = ηₖ = zero(T) # ζₖ₋₂ and ηₖ are used to update ζₖ₋₁ and ζbarₖ
7985
δbarₖ₋₁ = δbarₖ = zero(T) # Coefficients of Lₖ₋₁ and L̅ₖ modified over the course of two iterations

src/bilqr.jl

+22-15
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# Alexis Montoison, <alexis.montoison@polymtl.ca>
1111
# Montreal, July 2019.
1212

13-
export bilqr
13+
export bilqr, bilqr!
1414

1515
"""
1616
(x, t, stats) = bilqr(A, b::AbstractVector{T}, c::AbstractVector{T};
@@ -32,9 +32,14 @@ BiCG point, when it exists. The transfer is based on the residual norm.
3232
3333
* A. Montoison and D. Orban, *BiLQ: An Iterative Method for Nonsymmetric Linear Systems with a Quasi-Minimum Error Property*, SIAM Journal on Matrix Analysis and Applications, 41(3), pp. 1145--1166, 2020.
3434
"""
35-
function bilqr(A, b :: AbstractVector{T}, c :: AbstractVector{T};
36-
atol :: T=eps(T), rtol :: T=eps(T), transfer_to_bicg :: Bool=true,
37-
itmax :: Int=0, verbose :: Int=0, history :: Bool=false) where T <: AbstractFloat
35+
function bilqr(A, b :: AbstractVector{T}, c :: AbstractVector{T}; kwargs...) where T <: AbstractFloat
36+
solver = BilqrSolver(A, b)
37+
bilqr!(solver, A, b, c; kwargs...)
38+
end
39+
40+
function bilqr!(solver :: BilqrSolver{T,S}, A, b :: AbstractVector{T}, c :: AbstractVector{T};
41+
atol :: T=eps(T), rtol :: T=eps(T), transfer_to_bicg :: Bool=true,
42+
itmax :: Int=0, verbose :: Int=0, history :: Bool=false) where {S, T <: AbstractFloat}
3843

3944
n, m = size(A)
4045
m == n || error("Systems must be square")
@@ -44,19 +49,21 @@ function bilqr(A, b :: AbstractVector{T}, c :: AbstractVector{T};
4449

4550
# Check type consistency
4651
eltype(A) == T || error("eltype(A) ≠ $T")
52+
ktypeof(b) == S || error("ktypeof(b) ≠ $S")
53+
ktypeof(c) == S || error("ktypeof(c) ≠ $S")
4754

4855
# Compute the adjoint of A
4956
Aᵀ = A'
5057

51-
# Determine the storage type of b
52-
S = typeof(b)
58+
# Set up workspace.
59+
uₖ₋₁, uₖ, vₖ₋₁, vₖ, x, t, d̅, wₖ₋₃, wₖ₋₂ = solver.uₖ₋₁, solver.uₖ, solver.vₖ₋₁, solver.vₖ, solver.x, solver.t, solver.d̅, solver.wₖ₋₃, solver.wₖ₋₂
5360

5461
# Initial solution x₀ and residual norm ‖r₀‖ = ‖b - Ax₀‖.
55-
x = kzeros(S, n) # x₀
62+
x .= zero(T) # x₀
5663
bNorm = @knrm2(n, b) # rNorm = ‖r₀‖
5764

5865
# Initial solution t₀ and residual norm ‖s₀‖ = ‖c - Aᵀt₀‖.
59-
t = kzeros(S, n) # t₀
66+
t .= zero(T) # t₀
6067
cNorm = @knrm2(n, c) # sNorm = ‖s₀‖
6168

6269
iter = 0
@@ -76,21 +83,21 @@ function bilqr(A, b :: AbstractVector{T}, c :: AbstractVector{T};
7683
# Set up workspace.
7784
βₖ = (abs(bᵗc)) # β₁γ₁ = bᵀc
7885
γₖ = bᵗc / βₖ # β₁γ₁ = bᵀc
79-
vₖ₋₁ = kzeros(S, n) # v₀ = 0
80-
uₖ₋₁ = kzeros(S, n) # u₀ = 0
81-
vₖ = b / βₖ # v₁ = b / β₁
82-
uₖ = c / γₖ # u₁ = c / γ₁
86+
vₖ₋₁ .= zero(T) # v₀ = 0
87+
uₖ₋₁ .= zero(T) # u₀ = 0
88+
vₖ .= b ./ βₖ # v₁ = b / β₁
89+
uₖ .= c ./ γₖ # u₁ = c / γ₁
8390
cₖ₋₁ = cₖ = -one(T) # Givens cosines used for the LQ factorization of Tₖ
8491
sₖ₋₁ = sₖ = zero(T) # Givens sines used for the LQ factorization of Tₖ
85-
= kzeros(S, n) # Last column of D̅ₖ = Vₖ(Qₖ)ᵀ
92+
.= zero(T) # Last column of D̅ₖ = Vₖ(Qₖ)ᵀ
8693
ζₖ₋₁ = ζbarₖ = zero(T) # ζₖ₋₁ and ζbarₖ are the last components of z̅ₖ = (L̅ₖ)⁻¹β₁e₁
8794
ζₖ₋₂ = ηₖ = zero(T) # ζₖ₋₂ and ηₖ are used to update ζₖ₋₁ and ζbarₖ
8895
δbarₖ₋₁ = δbarₖ = zero(T) # Coefficients of Lₖ₋₁ and L̅ₖ modified over the course of two iterations
8996
ψbarₖ₋₁ = ψₖ₋₁ = zero(T) # ψₖ₋₁ and ψbarₖ are the last components of h̅ₖ = Qₖγ₁e₁
9097
norm_vₖ = bNorm / βₖ # ‖vₖ‖ is used for residual norm estimates
9198
ϵₖ₋₃ = λₖ₋₂ = zero(T) # Components of Lₖ₋₁
92-
wₖ₋₃ = kzeros(S, n) # Column k-3 of Wₖ = Uₖ(Lₖ)⁻ᵀ
93-
wₖ₋₂ = kzeros(S, n) # Column k-2 of Wₖ = Uₖ(Lₖ)⁻ᵀ
99+
wₖ₋₃ .= zero(T) # Column k-3 of Wₖ = Uₖ(Lₖ)⁻ᵀ
100+
wₖ₋₂ .= zero(T) # Column k-2 of Wₖ = Uₖ(Lₖ)⁻ᵀ
94101
τₖ = zero(T) # τₖ is used for the dual residual norm estimate
95102

96103
# Stopping criterion.

src/cg.jl

+16-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# Dominique Orban, <dominique.orban@gerad.ca>
1414
# Salt Lake City, UT, March 2015.
1515

16-
export cg
16+
export cg, cg!
1717

1818

1919
"""
@@ -37,10 +37,15 @@ with `n = length(b)`.
3737
3838
* M. R. Hestenes and E. Stiefel, *Methods of conjugate gradients for solving linear systems*, Journal of Research of the National Bureau of Standards, 49(6), pp. 409--436, 1952.
3939
"""
40-
function cg(A, b :: AbstractVector{T};
41-
M=opEye(), atol :: T=eps(T), rtol :: T=eps(T),
42-
itmax :: Int=0, radius :: T=zero(T), linesearch :: Bool=false,
43-
verbose :: Int=0, history :: Bool=false) where T <: AbstractFloat
40+
function cg(A, b :: AbstractVector{T}; kwargs...) where T <: AbstractFloat
41+
solver = CgSolver(A, b)
42+
cg!(solver, A, b; kwargs...)
43+
end
44+
45+
function cg!(solver :: CgSolver{T,S}, A, b :: AbstractVector{T};
46+
M=opEye(), atol :: T=eps(T), rtol :: T=eps(T),
47+
itmax :: Int=0, radius :: T=zero(T), linesearch :: Bool=false,
48+
verbose :: Int=0, history :: Bool=false) where {S, T <: AbstractFloat}
4449

4550
linesearch && (radius > 0) && error("`linesearch` set to `true` but trust-region radius > 0")
4651

@@ -50,16 +55,16 @@ function cg(A, b :: AbstractVector{T};
5055

5156
# Check type consistency
5257
eltype(A) == T || error("eltype(A) ≠ $T")
58+
ktypeof(b) == S || error("ktypeof(b) ≠ $S")
5359
isa(M, opEye) || (eltype(M) == T) || error("eltype(M) ≠ $T")
5460

55-
# Determine the storage type of b
56-
S = typeof(b)
61+
# Set up workspace.
62+
x, r, p = solver.x, solver.r, solver.p
5763

58-
# Initial state.
59-
x = kzeros(S, n)
60-
r = copy(b)
64+
x .= zero(T)
65+
r .= b
6166
z = M * r
62-
p = copy(z)
67+
p .= z
6368
γ = @kdot(n, r, z)
6469
γ == 0 && return x, SimpleStats(true, false, [zero(T)], T[], "x = 0 is a zero-residual solution")
6570

0 commit comments

Comments
 (0)