Skip to content

Commit f167f73

Browse files
authored
Merge pull request #150 from fverdugo/solver_interface
Solver interface
2 parents bdf5984 + 09409f1 commit f167f73

File tree

9 files changed

+222
-208
lines changed

9 files changed

+222
-208
lines changed

PartitionedSolvers/CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ All notable changes to this project will be documented in this file.
66
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
77
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9-
## [0.1.0] - Unreleased
9+
## [0.2.0] - Unreleased
10+
11+
### Changed
12+
13+
- Linear solver interface.
14+
15+
## [0.1.0]
1016

1117
### Added
1218

PartitionedSolvers/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PartitionedSolvers"
22
uuid = "11b65f7f-80ac-401b-9ef2-3db765482d62"
33
authors = ["Francesc Verdugo <[email protected]>"]
4-
version = "0.1.0"
4+
version = "0.2.0"
55

66
[deps]
77
IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153"

PartitionedSolvers/src/PartitionedSolvers.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@ using LinearAlgebra
66

77
export setup
88
export solve!
9-
export setup!
9+
export update!
1010
export finalize!
1111
export AbstractLinearSolver
1212
export linear_solver
13-
export attach_nullspace
1413
export default_nullspace
15-
export preconditioner
16-
export matrix
1714
export nullspace
1815
include("interfaces.jl")
1916

PartitionedSolvers/src/amg.jl

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,7 @@ function smoothed_aggregation(;
287287
tentative_prolongator = tentative_prolongator_for_laplace,
288288
repartition_threshold = 2000,
289289
)
290-
function coarsen(operator)
291-
A = matrix(operator)
292-
B = nullspace(operator)
290+
function coarsen(A,B)
293291
diagA = dense_diag(A)
294292
node_to_aggregate, aggregates = aggregate(A,diagA;epsilon)
295293
n_nullspace_vecs = length(B)
@@ -299,14 +297,11 @@ function smoothed_aggregation(;
299297
R = transpose(P)
300298
Ac,cache = rap(R,A,P;reuse=true)
301299
Ac,Bc,R,P,cache,repartition_threshold = enhance_coarse_partition(A,Ac,Bc,R,P,cache,repartition_threshold)
302-
coarse_operator = attach_nullspace(Ac,Bc)
303-
coarse_operator,R,P,cache
300+
Ac,Bc,R,P,cache
304301
end
305-
function coarsen!(operator,coarse_operator,R,P,cache)
306-
A = matrix(operator)
307-
Ac = matrix(coarse_operator)
302+
function coarsen!(A,Ac,R,P,cache)
308303
rap!(Ac,R,A,P,cache)
309-
coarse_operator,R,P,cache
304+
Ac,R,P,cache
310305
end
311306
(coarsen, coarsen!)
312307
end
@@ -341,14 +336,18 @@ function amg(;
341336
fine_params=amg_fine_params(),
342337
coarse_params=amg_coarse_params(),)
343338
amg_params = (;fine_params,coarse_params)
344-
setup(x,O,b) = amg_setup(x,O,b,amg_params)
345-
setup! = amg_setup!
339+
setup(x,O,b,options) = amg_setup(x,O,b,nullspace(options),amg_params)
340+
update! = amg_update!
346341
solve! = amg_solve!
347342
finalize! = amg_finalize!
348-
linear_solver(;setup,setup!,solve!,finalize!)
343+
linear_solver(;setup,update!,solve!,finalize!)
349344
end
350345

351-
function amg_setup(x,operator,b,amg_params)
346+
function amg_setup(x,A,b,::Nothing,amg_params)
347+
B = default_nullspace(A)
348+
amg_setup(x,A,b,B,amg_params)
349+
end
350+
function amg_setup(x,A,b,B,amg_params)
352351
fine_params = amg_params.fine_params
353352
coarse_params = amg_params.coarse_params
354353
(;coarse_solver,coarse_size) = coarse_params
@@ -358,11 +357,10 @@ function amg_setup(x,operator,b,amg_params)
358357
return nothing
359358
end
360359
(;pre_smoother,pos_smoother,coarsening,cycle) = fine_level
361-
pre_setup = setup(pre_smoother)(x,operator,b)
362-
pos_setup = setup(pos_smoother)(x,operator,b)
360+
pre_setup = setup(pre_smoother,x,A,b)
361+
pos_setup = setup(pos_smoother,x,A,b)
363362
coarsen, _ = coarsening
364-
coarse_operator,R,P,coarse_operator_setup = coarsen(operator)
365-
Ac = matrix(coarse_operator)
363+
Ac,Bc,R,P,Ac_setup = coarsen(A,B)
366364
nc = size(Ac,1)
367365
if nc <= coarse_size
368366
done = true
@@ -373,20 +371,21 @@ function amg_setup(x,operator,b,amg_params)
373371
e = similar(x)
374372
ec = similar(e,axes(Ac,2))
375373
ec2 = similar(e,axes(P,2)) # TODO
376-
level_setup = (;R,P,r,rc,rc2,e,ec,ec2,operator,coarse_operator,pre_setup,pos_setup,coarse_operator_setup)
374+
level_setup = (;R,P,r,rc,rc2,e,ec,ec2,A,B,Ac,Bc,pre_setup,pos_setup,Ac_setup)
377375
x = ec
378376
b = rc
379-
operator = coarse_operator
377+
A = Ac
378+
B = Bc
380379
level_setup
381380
end
382381
n_fine_levels = count(i->i!==nothing,fine_levels)
383382
nlevels = n_fine_levels+1
384-
coarse_solver_setup = setup(coarse_solver)(x,operator,b)
383+
coarse_solver_setup = setup(coarse_solver,x,A,b)
385384
coarse_level = (;coarse_solver_setup)
386385
(;nlevels,fine_levels,coarse_level,amg_params)
387386
end
388387

389-
function amg_solve!(x,setup,b)
388+
function amg_solve!(x,setup,b,options)
390389
level=1
391390
amg_cycle!(x,setup,b,level)
392391
x
@@ -395,16 +394,14 @@ end
395394
function amg_cycle!(x,setup,b,level)
396395
amg_params = setup.amg_params
397396
if level == setup.nlevels
398-
coarse_solver = amg_params.coarse_params.coarse_solver
399397
coarse_solver_setup = setup.coarse_level.coarse_solver_setup
400-
return solve!(coarse_solver)(x,coarse_solver_setup,b)
398+
return solve!(x,coarse_solver_setup,b)
401399
end
402400
level_params = amg_params.fine_params[level]
403401
level_setup = setup.fine_levels[level]
404-
(;pre_smoother,pos_smoother,cycle) = level_params
405-
(;R,P,r,rc,rc2,e,ec,ec2,operator,coarse_operator,pre_setup,pos_setup) = level_setup
406-
solve!(pre_smoother)(x,pre_setup,b)
407-
A = matrix(operator)
402+
(;cycle) = level_params
403+
(;R,P,r,rc,rc2,e,ec,ec2,A,Ac,pre_setup,pos_setup) = level_setup
404+
solve!(x,pre_setup,b)
408405
mul!(r,A,x)
409406
r .= b .- r
410407
mul!(rc2,R,r)
@@ -414,28 +411,29 @@ function amg_cycle!(x,setup,b,level)
414411
ec2 .= ec
415412
mul!(e,P,ec2)
416413
x .+= e
417-
solve!(pos_smoother)(x,pos_setup,b)
414+
solve!(x,pos_setup,b)
418415
x
419416
end
420417

421-
function amg_statistics(setup)
418+
function amg_statistics(P::Preconditioner)
422419
# Taken from: An Introduction to Algebraic Multigrid, R. D. Falgout, April 25, 2006
423420
# Grid complexity is the total number of grid points on all grids divided by the number
424421
# of grid points on the fine grid. Operator complexity is the total number of nonzeroes in the linear operators
425422
# on all grids divided by the number of nonzeroes in the fine grid operator
423+
setup = P.solver_setup
426424
nlevels = setup.nlevels
427425
level_rows = zeros(Int,nlevels)
428426
level_nnz = zeros(Int,nlevels)
429427
for level in 1:(nlevels-1)
430428
level_setup = setup.fine_levels[level]
431-
(;operator,) = level_setup
432-
level_rows[level] = size(matrix(operator),1)
433-
level_nnz[level] = nnz(matrix(operator))
429+
(;A,) = level_setup
430+
level_rows[level] = size(A,1)
431+
level_nnz[level] = nnz(A)
434432
end
435433
level_setup = setup.fine_levels[nlevels-1]
436-
(;coarse_operator) = level_setup
437-
level_rows[end] = size(matrix(coarse_operator),1)
438-
level_nnz[end] = nnz(matrix(coarse_operator))
434+
(;Ac) = level_setup
435+
level_rows[end] = size(Ac,1)
436+
level_nnz[end] = nnz(Ac)
439437
nnz_total = sum(level_nnz)
440438
rows_total = sum(level_rows)
441439
level_id = collect(1:nlevels)
@@ -461,23 +459,22 @@ end
461459
amg_cycle!(args...)
462460
end
463461

464-
function amg_setup!(setup,operator)
462+
function amg_update!(setup,A,options)
465463
amg_params = setup.amg_params
466464
nlevels = setup.nlevels
467465
for level in 1:(nlevels-1)
468466
level_params = amg_params.fine_params[level]
469467
level_setup = setup.fine_levels[level]
470-
(;coarsening,pre_smoother,pos_smoother) = level_params
468+
(;coarsening) = level_params
471469
_, coarsen! = coarsening
472-
(;R,P,operator,coarse_operator,coarse_operator_setup,pre_setup,pos_setup) = level_setup
473-
setup!(pre_smoother)(pre_setup,operator)
474-
setup!(pos_smoother)(pos_setup,operator)
475-
coarsen!(operator,coarse_operator,R,P,coarse_operator_setup)
476-
operator = coarse_operator
470+
(;R,P,A,Ac,Ac_setup,pre_setup,pos_setup) = level_setup
471+
update!(pre_setup,A)
472+
update!(pos_setup,A)
473+
coarsen!(A,Ac,R,P,Ac_setup)
474+
A = Ac
477475
end
478-
coarse_solver = amg_params.coarse_params.coarse_solver
479476
coarse_solver_setup = setup.coarse_level.coarse_solver_setup
480-
setup!(coarse_solver)(coarse_solver_setup,operator)
477+
update!(coarse_solver_setup,A)
481478
setup
482479
end
483480

@@ -487,14 +484,12 @@ function amg_finalize!(setup)
487484
for level in 1:(nlevels-1)
488485
level_params = amg_params.fine_params[level]
489486
level_setup = setup.fine_levels[level]
490-
(;pre_smoother,pos_smoother) = level_params
491487
(;pre_setup,pos_setup) = level_setup
492-
finalize!(pre_smoother)(pre_setup)
493-
finalize!(pos_smoother)(pos_setup)
488+
finalize!(pre_setup)
489+
finalize!(pos_setup)
494490
end
495-
coarse_solver = amg_params.coarse_params.coarse_solver
496491
coarse_solver_setup = setup.coarse_level.coarse_solver_setup
497-
finalize!(coarse_solver)(coarse_solver_setup)
492+
finalize!(coarse_solver_setup)
498493
nothing
499494
end
500495

PartitionedSolvers/src/interfaces.jl

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,4 @@
11

2-
function attach_nullspace(A,ns)
3-
MatrixWithNullspace(A,ns)
4-
end
5-
6-
struct MatrixWithNullspace{A,B}
7-
matrix::A
8-
nullspace::B
9-
end
10-
matrix(a::MatrixWithNullspace) = a.matrix
11-
nullspace(a::MatrixWithNullspace) = a.nullspace
12-
13-
matrix(a) = a
14-
nullspace(a) = default_nullspace(a)
15-
162
function default_nullspace(A)
173
T = eltype(A)
184
[ones(T,size(A,2))]
@@ -29,46 +15,61 @@ abstract type AbstractLinearSolver end
2915
function linear_solver(;
3016
setup,
3117
solve!,
32-
setup!,
18+
update!,
3319
finalize! = ls_setup->nothing,
3420
)
35-
LinearSolver(setup,solve!,setup!,finalize!)
21+
LinearSolver(setup,solve!,update!,finalize!)
3622
end
3723

3824
struct LinearSolver{A,B,C,D} <: AbstractLinearSolver
3925
setup::A
4026
solve!::B
41-
setup!::C
27+
update!::C
4228
finalize!::D
4329
end
4430

45-
setup(solver::LinearSolver) = solver.setup
46-
setup!(solver::LinearSolver) = solver.setup!
47-
solve!(solver::LinearSolver) = solver.solve!
48-
finalize!(solver::LinearSolver) = solver.finalize!
49-
5031
struct Preconditioner{A,B}
5132
solver::A
5233
solver_setup::B
5334
end
5435

55-
function preconditioner(solver,x,A,b)
56-
solver_setup = setup(solver)(x,A,b)
36+
function setup_options(;nullspace=nothing)
37+
options = (;nullspace)
38+
end
39+
40+
function nullspace(options)
41+
options.nullspace
42+
end
43+
44+
function setup(solver::LinearSolver,x,A,b;kwargs...)
45+
options = setup_options(;kwargs...)
46+
solver_setup = solver.setup(x,A,b,options)
5747
Preconditioner(solver,solver_setup)
5848
end
5949

60-
function preconditioner!(P::Preconditioner,A)
61-
setup!(P.solver)(P.solver_setup,A)
50+
function update!(P::Preconditioner,A;kwargs...)
51+
options = setup_options(;kwargs...)
52+
P.solver.update!(P.solver_setup,A,options)
6253
P
6354
end
6455

56+
function solve_options(;zero_guess=false)
57+
options = (;zero_guess)
58+
end
59+
60+
function solve!(x,P::Preconditioner,b;kwargs...)
61+
options = solve_options(;kwargs...)
62+
P.solver.solve!(x,P.solver_setup,b,options)
63+
x
64+
end
65+
6566
function LinearAlgebra.ldiv!(x,P::Preconditioner,b)
6667
fill!(x,zero(eltype(x)))
67-
solve!(P.solver)(x,P.solver_setup,b)
68+
solve!(x,P,b;zero_guess=true)
6869
x
6970
end
7071

7172
function finalize!(P::Preconditioner)
72-
PartitionedSolvers.finalize!(P.solver)(P.solver_setup)
73+
P.solver.finalize!(P.solver_setup)
7374
end
7475

0 commit comments

Comments
 (0)