Skip to content

Commit ce1d466

Browse files
committed
abstol/reltol for IDR(s)
1 parent 0f6e2de commit ce1d466

File tree

2 files changed

+61
-17
lines changed

2 files changed

+61
-17
lines changed

src/idrs.jl

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ export idrs, idrs!
33
using Random
44

55
"""
6-
idrs(A, b; s = 8) -> x, [history]
6+
idrs(A, b; s = 8, kwargs...) -> x, [history]
77
88
Same as [`idrs!`](@ref), but allocates a solution vector `x` initialized with zeros.
99
"""
1010
idrs(A, b; kwargs...) = idrs!(zerox(A,b), A, b; kwargs...)
1111

1212
"""
13-
idrs!(x, A, b; s = 8) -> x, [history]
13+
idrs!(x, A, b; s = 8, kwargs...) -> x, [history]
1414
1515
Solve the problem ``Ax = b`` approximately with IDR(s), where `s` is the dimension of the
1616
shadow space.
@@ -24,7 +24,11 @@ shadow space.
2424
## Keywords
2525
2626
- `s::Integer = 8`: dimension of the shadow space;
27-
- `tol`: relative tolerance;
27+
- `abstol::Real = zero(real(eltype(b)))`,
28+
`reltol::Real = sqrt(eps(real(eltype(b))))`: absolute and relative
29+
tolerance for the stopping condition
30+
`|r_k| / |r_0| ≤ max(reltol * resnorm, abstol)`, where `r_k = A * x_k - b`
31+
is the residual in the `k`th iteration;
2832
- `maxiter::Int = size(A, 2)`: maximum number of iterations;
2933
- `log::Bool`: keep track of the residual norm in each iteration;
3034
- `verbose::Bool`: print convergence information during the iterations.
@@ -41,13 +45,25 @@ shadow space.
4145
- `history`: convergence history.
4246
"""
4347
function idrs!(x, A, b;
44-
s = 8, tol=sqrt(eps(real(eltype(b)))), maxiter=size(A, 2),
45-
log::Bool=false, kwargs...
46-
)
48+
s = 8,
49+
abstol::Real = zero(real(eltype(b))),
50+
reltol::Real = sqrt(eps(real(eltype(b)))),
51+
tol = nothing, # TODO: Deprecations introduced in v0.8
52+
maxiter=size(A, 2),
53+
log::Bool=false,
54+
kwargs...)
4755
history = ConvergenceHistory(partial=!log)
48-
history[:tol] = tol
49-
reserve!(history,:resnorm, maxiter)
50-
idrs_method!(history, x, A, b, s, tol, maxiter; kwargs...)
56+
history[:abstol] = abstol
57+
history[:reltol] = reltol
58+
log && reserve!(history, :resnorm, maxiter)
59+
60+
# TODO: Deprecations introduced in v0.8
61+
if tol !== nothing
62+
Base.depwarn("The keyword argument `tol` is deprecated, use `reltol` instead.", :cg!)
63+
reltol = tol
64+
end
65+
66+
idrs_method!(history, x, A, b, s, abstol, reltol, maxiter; kwargs...)
5167
log && shrink!(history)
5268
log ? (x, history) : x
5369
end
@@ -70,13 +86,14 @@ end
7086
end
7187

7288
function idrs_method!(log::ConvergenceHistory, X, A, C::T,
73-
s::Number, tol::Number, maxiter::Number; smoothing::Bool=false, verbose::Bool=false
89+
s::Number, abstol::Real, reltol::Real, maxiter::Number; smoothing::Bool=false, verbose::Bool=false
7490
) where {T}
7591

7692
verbose && @printf("=== idrs ===\n%4s\t%7s\n","iter","resnorm")
7793
R = C - A*X
7894
normR = norm(R)
79-
iter = 1
95+
iter = 1
96+
tol = max(reltol * normR, abstol)
8097

8198
if smoothing
8299
X_s = copy(X)

test/idrs.jl

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ using IterativeSolvers
22
using Test
33
using Random
44
using LinearAlgebra
5+
using SparseArrays
56

67
@testset "IDR(s)" begin
78

@@ -12,31 +13,31 @@ Random.seed!(1234567)
1213
@testset "Matrix{$T}" for T in (Float32, Float64, ComplexF32, ComplexF64)
1314
A = rand(T, n, n) + n * I
1415
b = rand(T, n)
15-
tol = eps(real(T))
16+
reltol = eps(real(T))
1617

1718
@testset "Without residual smoothing" begin
18-
x, history = idrs(A, b, log=true)
19+
x, history = idrs(A, b, reltol=reltol, log=true)
1920
@test isa(history, ConvergenceHistory)
2021
@test history.isconverged
21-
@test norm(A * x - b) / norm(b) tol
22+
@test norm(A * x - b) / norm(b) reltol
2223
end
2324

2425
# with smoothing
2526
@testset "With residual smoothing" begin
2627
x, history = idrs(A, b; smoothing=true, log=true)
2728
@test history.isconverged
28-
@test norm(A*x - b) / norm(b) tol
29+
@test norm(A*x - b) / norm(b) reltol
2930
end
3031
end
3132

3233
@testset "SparseMatrixCSC{$T, $Ti}" for T in (Float64, ComplexF64), Ti in (Int64, Int32)
3334
A = sprand(T, n, n, 0.5) + n * I
3435
b = rand(T, n)
35-
tol = eps(real(T))
36+
reltol = eps(real(T))
3637

3738
x, history = idrs(A, b, log=true)
3839
@test history.isconverged
39-
@test norm(A * x - b) / norm(b) tol
40+
@test norm(A * x - b) / norm(b) reltol
4041
end
4142

4243
@testset "Maximum number of iterations" begin
@@ -57,4 +58,30 @@ end
5758
@test x_new x
5859
end
5960

61+
@testset "Termination criterion" begin
62+
for T in (Float32, Float64, ComplexF32, ComplexF64)
63+
A = T[ 2 -1 0
64+
-1 2 -1
65+
0 -1 2]
66+
n = size(A, 2)
67+
b = ones(T, n)
68+
x0 = A \ b
69+
perturbation = T[(-1)^i for i in 1:n]
70+
71+
# If the initial residual is small and a small relative tolerance is used,
72+
# many iterations are necessary
73+
x = x0 + sqrt(eps(real(T))) * perturbation
74+
initial_residual = norm(A * x - b)
75+
x, ch = idrs!(x, A, b, log=true)
76+
@test 2 niters(ch) n
77+
78+
# If the initial residual is small and a large absolute tolerance is used,
79+
# no iterations are necessary
80+
x = x0 + 10*sqrt(eps(real(T))) * perturbation
81+
initial_residual = norm(A * x - b)
82+
x, ch = idrs!(x, A, b, abstol=2*initial_residual, reltol=zero(real(T)), log=true)
83+
@test niters(ch) == 0
84+
end
85+
end
86+
6087
end

0 commit comments

Comments
 (0)