Skip to content

Commit 81e7872

Browse files
haampieandreasnoack
authored andcommitted
Fix GMRES memory usage (#131)
* Add improved versions of GMRES and CG * Add preconditioners * Add Hessenberg type * Hessenberg solver * Fix incorrect comment * Benchmark Givens rotation + UpperTriangular vs \ * Rename to Hessenberg * Use UnsafeVectorView when solving the small system * Clean up some * Add Identity preconditioner type * Improve GMRES with specialized functions for preconditioners, unsafe views, and conditional logging * Don't run by default * Some default values for gmres bench * Reduce the number of allocs slightly by solving the least-squares-problem with the Hessenberg matrix in-place * Fix for complex numbers * Move from Vector{Vector{T}} to Matrix{T} using views and make orthogonalization routine reusable * Make the comparison fair and the matrix sparser to ~10 nonzeros per row * Fix a bug for complex numbers * Temporarily remove tests with matrices as preconditioner, since we don't have A_ldiv_B for them at the moment * Add tests for various orthogonalization methods * Fix a problem for complex numbers again * Export Identity * Add tests to runtests.jl * Fix compatibility with Julia 0.5 * Override the current gmres method and move solve! to A_ldiv_B!
1 parent 4e92e2d commit 81e7872

12 files changed

+496
-187
lines changed

benchmark/benchmark-hessenberg.jl

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module HessenbergBench
2+
3+
using IterativeSolvers
4+
using BenchmarkTools
5+
6+
function backslash_versus_givens(; n = 1_000, ms = 10 : 10 : 100)
7+
results = BenchmarkGroup()
8+
results["backslash"] = BenchmarkGroup()
9+
results["givens_qr"] = BenchmarkGroup()
10+
11+
# Example matrix
12+
A = Tridiagonal(fill(-1.5, n - 1), fill(3.0, n), fill(-1.0, n - 1))
13+
14+
# Different sizes of the Hessenberg matrix
15+
for m = ms
16+
println(m)
17+
18+
H = zeros(m + 1, m)
19+
20+
# Create an orthonormal basis for the Krylov subspace
21+
V = rand(n, m + 1)
22+
V[:, 1] /= norm(V[:, 1])
23+
24+
for i = 1 : m
25+
# Expand
26+
V[:, i + 1] = A * V[:, i]
27+
28+
# Orthogonalize
29+
H[1 : i, i] = view(V, :, 1 : i)' * V[:, i + 1]
30+
V[:, i + 1] -= view(V, :, 1 : i) * H[1 : i, i]
31+
32+
# Re-orthogonalize
33+
update = view(V, :, 1 : i)' * V[:, i + 1]
34+
H[1 : i, i] += update
35+
V[:, i + 1] -= view(V, :, 1 : i) * update
36+
37+
# Normalize
38+
H[i + 1, i] = norm(V[:, i + 1])
39+
V[:, i + 1] /= H[i + 1, i]
40+
end
41+
42+
# Fist standard basis vector as rhs
43+
rhs = [i == 1 ? 1.0 : 0.0 for i = 1 : size(H, 1)]
44+
45+
# Run the benchmark
46+
results["givens_qr"][m] = @benchmark IterativeSolvers.solve!(IterativeSolvers.Hessenberg(myH), myRhs) setup = (myH = copy($H); myRhs = copy($rhs))
47+
results["backslash"][m] = @benchmark $H \ $rhs
48+
end
49+
50+
return results
51+
end
52+
53+
end

benchmark/benchmark-linear-systems.jl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,27 @@ function cg(; n = 1_000_000, tol = 1e-6, maxiter::Int = 200)
4141
@benchmark IterativeSolvers.cg!(x0, $A, $b, Pl = $P, maxiter = $maxiter, tol = $tol, log = false) setup=(x0 = copy($initial))
4242
end
4343

44-
end
44+
function indefinite(n)
45+
# Generate an indefinite "hard" matrix
46+
srand(1)
47+
A = speye(n) + sprand(n, n, 5.0 / n)
48+
A = (A + A') / 2
49+
x = ones(n)
50+
b = A * x
51+
52+
A, b
53+
end
54+
55+
function gmres(; n = 100_000, tol = 1e-5, restart::Int = 15, maxiter::Int = 210)
56+
A, b = indefinite(n)
57+
58+
println("Matrix of size ", n, " with ~", nnz(A) / n, " nonzeros per row")
59+
println("Tolerance = ", tol, "; restart = ", restart, "; max #iterations = ", maxiter)
60+
61+
impr = @benchmark IterativeSolvers.improved_gmres($A, $b, tol = $tol, restart = $restart, maxiter = $maxiter, log = false)
62+
old = @benchmark IterativeSolvers.gmres($A, $b, tol = $tol, restart = $restart, maxiter = $maxiter, log = false)
63+
64+
impr, old
65+
end
66+
67+
end

src/IterativeSolvers.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ using SugarBLAS
1010
using Compat
1111

1212
include("common.jl")
13+
include("orthogonalize.jl")
1314
include("krylov.jl")
1415
include("history.jl")
1516

1617
#Specialized factorizations
1718
include("factorization.jl")
19+
include("hessenberg.jl")
1820

1921
#Linear solvers
2022
include("stationary.jl")

src/common.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Base: eltype, length, ndims, real, size, *,
22
A_mul_B!, Ac_mul_B, Ac_mul_B!
33

4-
using LinearMaps
4+
using LinearMaps, Compat
55

6-
export A_mul_B
6+
export A_mul_B, Identity
77

88
#### Type-handling
99
"""
@@ -74,3 +74,10 @@ type PosSemidefException <: Exception
7474
msg :: AbstractString
7575
PosSemidefException(msg::AbstractString="Matrix was not positive semidefinite") = new(msg)
7676
end
77+
78+
# Identity preconditioner
79+
immutable Identity end
80+
81+
Base.:\(::Identity, x) = copy(x)
82+
Base.A_ldiv_B!(::Identity, x) = x
83+
Base.A_ldiv_B!(y, ::Identity, x) = copy!(y, x)

0 commit comments

Comments
 (0)