Skip to content

Commit 52a8258

Browse files
committed
Initial infrasctructure for preconditioners
1 parent ea29705 commit 52a8258

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

src/KKT/KKT.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ include("test.jl")
107107
include("lapack.jl")
108108
include("cholmod.jl")
109109
include("ldlfact.jl")
110-
include("krylov.jl")
110+
include("Krylov/krylov.jl")
111111

112112
"""
113113
default_options(Tv)

src/KKT/Krylov/jacobi.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
struct JacobiPreconditioner{T, Tv} <: AbstractPreconditioner{T}
2+
d::Tv
3+
4+
JacobiPreconditioner(d::Tv) where{T, Tv<:AbstractVector{T}} = new{T, Tv}(d)
5+
end
6+
7+
op(P::JacobiPreconditioner) = Diagonal(P.d)
8+
9+
# Code for Jacobi preconditioners
10+
function update_preconditioner(kkt::KrylovSPDSolver{T, F, Tv, Ta, Tp}) where{T, F, Tv, Ta<:SparseMatrixCSC, Tp<:JacobiPreconditioner{T, Tv}}
11+
12+
A = kkt.A
13+
d = kkt.P.d
14+
15+
# S = A (Θ⁻¹ + Rp)⁻¹ A' + Rd, so its diagonal writes
16+
# S[i, i] = Σ_j=1..n D[j, j] * A[i, j] ^2,
17+
# where D = (Θ⁻¹ + Rp)⁻¹
18+
19+
_d = one(T) ./ (kkt.θ .+ kkt.regP)
20+
21+
rows = rowvals(A)
22+
vals = nonzeros(A)
23+
m, n = size(A)
24+
25+
d .= zero(T)
26+
27+
for j = 1:n
28+
_a = zero(T)
29+
dj = _d[j]
30+
for i in nzrange(A, j)
31+
row = rows[i]
32+
a_ij = vals[i]
33+
34+
d[row] += dj * a_ij ^2
35+
end
36+
end
37+
38+
# I think putting this afterwards is more numerics-friendly
39+
d .+= kkt.regD
40+
41+
# Invert
42+
d .\= one(T)
43+
44+
return nothing
45+
end

src/KKT/krylov.jl renamed to src/KKT/Krylov/krylov.jl

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,17 @@ where `S`, `ξ` and `dy` are the normal equations system's
3838
left- and right-hand side, and solution vector, respectively.
3939
`S` may take the form of a matrix, or of a suitable linear operator.
4040
"""
41-
mutable struct KrylovSPDSolver{T, F, Tv, Ta} <: AbstractKrylovSolver{T}
41+
mutable struct KrylovSPDSolver{T, F, Tv, Ta, Tp} <: AbstractKrylovSolver{T}
4242
m::Int
4343
n::Int
4444

4545
f::F # Krylov function
4646
atol::T # absolute tolerance
4747
rtol::T # relative tolerance
4848

49+
P::Tp # Preconditioner
50+
nitertot::Int # Total number of Krylov iterations
51+
4952
# Problem data
5053
A::Ta # Constraint matrix
5154
θ::Tv # scaling
@@ -54,14 +57,26 @@ mutable struct KrylovSPDSolver{T, F, Tv, Ta} <: AbstractKrylovSolver{T}
5457

5558
function KrylovSPDSolver(f::Function, A::Ta;
5659
atol::T=eps(T)^(3 // 4),
57-
rtol::T=eps(T)^(3 // 4)
60+
rtol::T=eps(T)^(3 // 4),
61+
preconditioner::Symbol=:Identity
5862
) where{T, Ta <: AbstractMatrix{T}}
5963
F = typeof(f)
6064
m, n = size(A)
6165

62-
return new{T, F, Vector{T}, Ta}(
66+
if preconditioner == :Jacobi
67+
P = JacobiPreconditioner(ones(T, m))
68+
elseif preconditioner == :Identity
69+
P = IdentityPreconditioner()
70+
else
71+
@error "Unknown preconditioner: $preconditioner, using identity instead"
72+
P = IdentityPreconditioner()
73+
end
74+
75+
return new{T, F, Vector{T}, Ta, typeof(P)}(
6376
m, n,
6477
f, atol, rtol,
78+
P,
79+
0,
6580
A, ones(T, n), ones(T, n), ones(T, m)
6681
)
6782
end
@@ -101,6 +116,9 @@ function update!(
101116
kkt.regP .= regP
102117
kkt.regD .= regD
103118

119+
# Update Jacobi preconditioner
120+
update_preconditioner(kkt)
121+
104122
return nothing
105123
end
106124

@@ -137,17 +155,22 @@ function solve!(
137155
end
138156
)
139157

158+
opM = op(kkt.P)
159+
# @info typeof(opM) extrema(kkt.P.d)
160+
140161
# Solve normal equations
141-
_dy, stats = kkt.f(opS, ξ_, atol=kkt.atol, rtol=kkt.rtol)
142-
dy .= _dy
162+
_dy, stats = kkt.f(opS, ξ_, M = opM, atol=kkt.atol, rtol=kkt.rtol)
143163

144-
# Recover dx
164+
# Book-keeping
165+
kkt.nitertot += length(stats.residuals) - 1
166+
167+
# Recover dy, dx
168+
dy .= _dy
145169
dx .= D * (kkt.A' * dy - ξd)
146170

147171
return nothing
148172
end
149173

150-
151174
# ==============================================================================
152175
# KrylovSIDSolver:
153176
# ==============================================================================
@@ -424,4 +447,7 @@ function solve!(
424447
dy .= _dy
425448

426449
return nothing
427-
end
450+
end
451+
452+
# Code for pre-conditioners
453+
include("preconditioners.jl")

src/KKT/Krylov/preconditioners.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
abstract type AbstractPreconditioner{T} end
2+
3+
update_preconditioner(::AbstractKKTSolver) = nothing
4+
5+
struct IdentityPreconditioner end
6+
7+
op(::IdentityPreconditioner) = LO.opEye()
8+
9+
include("jacobi.jl")

0 commit comments

Comments
 (0)