Skip to content

Commit

Permalink
IDR(s) as iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
mschauer committed Aug 3, 2023
1 parent a545182 commit b94a23d
Showing 1 changed file with 133 additions and 81 deletions.
214 changes: 133 additions & 81 deletions src/idrs.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export idrs, idrs!

import Base: iterate
using Printf
using Random

"""
Expand Down Expand Up @@ -50,8 +51,8 @@ function idrs!(x, A, b;
Pl = Identity(),
abstol::Real = zero(real(eltype(b))),
reltol::Real = sqrt(eps(real(eltype(b)))),
maxiter=size(A, 2),
log::Bool=false,
maxiter = size(A, 2),
log::Bool = false,
kwargs...)
history = ConvergenceHistory(partial=!log)
history[:abstol] = abstol
Expand All @@ -72,33 +73,58 @@ end
nt = norm(t)
ts = dot(t,s)
rho = abs(ts/(nt*ns))
om = ts/(nt*nt)
omega = ts/(nt*nt)
if rho < angle
om = om*convert(typeof(om),angle)/rho
omega = omega*convert(typeof(omega),angle)/rho
end
om
omega
end

function idrs_method!(log::ConvergenceHistory, X, A, C::T,
mutable struct IDRSIterable
X
A
s
Pl
abstol
reltol
maxiter
smoothing
verbose
R
X_s
R_s
T_s
normR
tol
Z
P
U
G
Q
V
M
f
c
omega
log
end
function idrs_iterable!(log::ConvergenceHistory, X, A, C::T,
s::Number, Pl::precT, abstol::Real, reltol::Real, maxiter::Number; smoothing::Bool=false, verbose::Bool=false
) where {T, precT}

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

if smoothing
X_s = copy(X)
R_s = copy(R)
T_s = zero(R)
else
X_s = nothing
R_s = nothing
T_s = nothing
end

if normR <= tol # Initial guess is a good enough solution
setconv(log, 0<=normR<tol)
return X
end

Z = zero(C)

Expand All @@ -112,76 +138,106 @@ function idrs_method!(log::ConvergenceHistory, X, A, C::T,
f = zeros(eltype(C),s)
c = zeros(eltype(C),s)

om::eltype(C) = 1
while normR > tol && iter maxiter
for i in 1:s
f[i] = dot(P[i], R)
end
for k in 1:s
nextiter!(log,mvps=1)
omega::eltype(C) = 1
IDRSIterable(X, A, s, Pl, abstol, reltol, maxiter, smoothing, verbose,
R, X_s, R_s, T_s, normR, tol, Z, P, U, G, Q, V, M, f, c, omega, log)
end

# Solve small system and make v orthogonal to P

c = LowerTriangular(M[k:s,k:s])\f[k:s]
V .= c[1] .* G[k]
Q .= c[1] .* U[k]
function idrs_method!(log::ConvergenceHistory, X, A, C::T,
s::Number, Pl::precT, abstol::Real, reltol::Real, maxiter::Number; smoothing::Bool=false, verbose::Bool=false
) where {T, precT}

for i = k+1:s
V .+= c[i-k+1] .* G[i]
Q .+= c[i-k+1] .* U[i]
end
verbose && @printf("=== idrs ===\n%4s\t%4s\t%7s\n", "iter", "step", "resnorm")

# Compute new U[:,k] and G[:,k], G[:,k] is in space G_j
V .= R .- V
iterable = idrs_iterable!(log, X, A, C, s, Pl, abstol, reltol, maxiter; smoothing, verbose)

normR = reduce((_,r) -> r, iterable; init=iterable.normR)

# Preconditioning
ldiv!(Pl, V)
verbose && @printf("\n")
iterable.X
end

U[k] .= Q .+ om .* V
mul!(G[k], A, U[k])
function iterate(it::IDRSIterable, (iter, step) = (1, 1))
X, A, s, Pl, R, X_s, R_s, T_s, Z, P, U, G, Q, V, M, f, c =
it.X, it.A, it.s, it.Pl, it.R, it.X_s, it.R_s, it.T_s, it.Z, it.P, it.U, it.G, it.Q, it.V, it.M, it.f, it.c

if it.normR < it.tol || iter > it.maxiter
setconv(it.log, 0 <= it.normR < it.tol)

# Bi-orthogonalise the new basis vectors
if it.smoothing
copyto!(X, X_s)
end
return nothing
end

for i in 1:k-1
alpha = dot(P[i],G[k])/M[i,i]
G[k] .-= alpha .* G[i]
U[k] .-= alpha .* U[i]
if step in 1:s
if step == 1
for i in 1:s
f[i] = dot(P[i], R)
end
end
k = step
nextiter!(it.log, mvps=1)

# New column of M = P'*G (first k-1 entries are zero)
# Solve small system and make v orthogonal to P

for i in k:s
M[i,k] = dot(P[i],G[k])
end
c = LowerTriangular(M[k:s,k:s])\f[k:s]
V .= c[1] .* G[k]
Q .= c[1] .* U[k]

# Make r orthogonal to q_i, i = 1..k
for i = k+1:s
V .+= c[i-k+1] .* G[i]
Q .+= c[i-k+1] .* U[i]
end

beta = f[k]/M[k,k]
R .-= beta .* G[k]
X .+= beta .* U[k]
# Compute new U[:,k] and G[:,k], G[:,k] is in space G_j
V .= R .- V

normR = norm(R)
if smoothing
T_s .= R_s .- R
# Preconditioning
ldiv!(Pl, V)

gamma = dot(R_s, T_s)/dot(T_s, T_s)
U[k] .= Q .+ it.omega .* V
mul!(G[k], A, U[k])

R_s .-= gamma .* T_s
X_s .-= gamma .* (X_s .- X)
# Bi-orthogonalise the new basis vectors

normR = norm(R_s)
end
push!(log, :resnorm, normR)
verbose && @printf("%3d\t%1.2e\n",iter,normR)
if normR < tol || iter == maxiter
setconv(log, 0<=normR<tol)
return X
end
if k < s
f[k+1:s] .-= beta*M[k+1:s,k]
end
iter += 1
for i in 1:k-1
alpha = dot(P[i], G[k])/M[i,i]
G[k] .-= alpha .* G[i]
U[k] .-= alpha .* U[i]
end

# New column of M = P'*G (first k-1 entries are zero)

for i in k:s
M[i,k] = dot(P[i], G[k])
end

# Make r orthogonal to q_i, i = 1..k

beta = f[k]/M[k,k]
R .-= beta .* G[k]
X .+= beta .* U[k]

it.normR = norm(R)
if it.smoothing
T_s .= R_s .- R

gamma = dot(R_s, T_s)/dot(T_s, T_s)

R_s .-= gamma .* T_s
X_s .-= gamma .* (X_s .- X)

it.normR = norm(R_s)
end
push!(it.log, :resnorm, it.normR)
it.verbose && @printf("%3d\t%3d\t%1.2e\n", iter, step, it.normR)
if k < s
f[k+1:s] .-= beta*M[k+1:s,k]
end
return it.normR, (iter + 1, step + 1)
elseif step == s + 1

# Now we have sufficient vectors in G_j to compute residual in G_j+1
# Note: r is already perpendicular to P so v = r
Expand All @@ -191,29 +247,25 @@ function idrs_method!(log::ConvergenceHistory, X, A, C::T,
ldiv!(Pl, V)

mul!(Q, A, V)
om = omega(Q, R)
R .-= om .* Q
X .+= om .* V
it.omega = omega(Q, R)
R .-= it.omega .* Q
X .+= it.omega .* V

normR = norm(R)
if smoothing
it.normR = norm(R)
if it.smoothing
T_s .= R_s .- R

gamma = dot(R_s, T_s)/dot(T_s, T_s)

R_s .-= gamma .* T_s
X_s .-= gamma .* (X_s .- X)

normR = norm(R_s)
it.normR = norm(R_s)
end
iter += 1
nextiter!(log, mvps=1)
push!(log, :resnorm, normR)
nextiter!(it.log, mvps=1)
push!(it.log, :resnorm, it.normR)
it.verbose && @printf("%3d\t%3d\t%1.2e\n", iter, step, it.normR)
return it.normR, (iter + 1, 1)
end
if smoothing
copyto!(X, X_s)
end
verbose && @printf("\n")
setconv(log, 0<=normR<tol)
X
end

0 comments on commit b94a23d

Please sign in to comment.