Skip to content

Commit 0b6e2b4

Browse files
authored
Merge pull request #175 from fverdugo/matrix_attributes
Release PartitionedSolvers 0.2.2
2 parents b211949 + f8b1554 commit 0b6e2b4

File tree

7 files changed

+152
-18
lines changed

7 files changed

+152
-18
lines changed

PartitionedSolvers/CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@ 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.2.1] - 2025-07-26
9+
## [0.2.2] - 2024-10-03
10+
11+
### Added
12+
13+
- Support for user-defined near nullspace in AMG solver.
14+
- Flag `history` to return solve history in `solve!`.
15+
- Expose iterations for iterative solvers with function `iterations!`.
16+
- Solver traits `uses_nullspace` and `uses_initial_guess`. These allow the user to build the nullspace or reset the initial guess to zero only when needed by the solver.
17+
18+
## [0.2.1] - 2024-07-26
1019

1120
### Added
1221
- Support for PartitionedArrays v0.5.

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.2.1"
4+
version = "0.2.2"
55

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

PartitionedSolvers/src/PartitionedSolvers.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module PartitionedSolvers
22

33
using PartitionedArrays
4+
using PartitionedArrays: val_parameter
45
using SparseArrays
56
using LinearAlgebra
67
using IterativeSolvers
@@ -13,6 +14,9 @@ export AbstractLinearSolver
1314
export linear_solver
1415
export default_nullspace
1516
export nullspace
17+
export uses_nullspace
18+
export uses_initial_guess
19+
export iterations!
1620
include("interfaces.jl")
1721

1822
export lu_solver

PartitionedSolvers/src/amg.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,8 @@ function amg(;
789789
update! = amg_update!
790790
solve! = amg_solve!
791791
finalize! = amg_finalize!
792-
linear_solver(;setup,update!,solve!,finalize!)
792+
uses_nullspace = Val(true)
793+
linear_solver(;setup,update!,solve!,finalize!,uses_nullspace)
793794
end
794795

795796
function amg_setup(x,A,b,::Nothing,amg_params)
@@ -939,4 +940,4 @@ function amg_finalize!(setup)
939940
end
940941
coarse_solver_setup = setup.coarse_level.coarse_solver_setup
941942
finalize!(coarse_solver_setup)
942-
end
943+
end

PartitionedSolvers/src/interfaces.jl

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11

2+
abstract type AbstractType end
3+
function Base.show(io::IO,data::AbstractType)
4+
print(io,"PartitionedSolvers.$(nameof(typeof(data)))(…)")
5+
end
6+
27
function default_nullspace(A)
38
T = eltype(A)
49
[ones(T,size(A,2))]
@@ -10,29 +15,51 @@ function default_nullspace(A::PSparseMatrix)
1015
[ pones(T,col_partition) ]
1116
end
1217

13-
abstract type AbstractLinearSolver end
18+
abstract type AbstractLinearSolver <: AbstractType end
1419

1520
function linear_solver(;
1621
setup,
1722
solve!,
1823
update!,
1924
finalize! = ls_setup->nothing,
25+
step! = nothing,
26+
uses_nullspace = Val(false),
27+
uses_initial_guess = Val(true),
28+
returns_history = Val(false),
2029
)
21-
LinearSolver(setup,solve!,update!,finalize!)
30+
if step! === nothing
31+
step! = (x,ls_setup,b,options,step=0) -> begin
32+
if step !=0
33+
return nothing
34+
end
35+
x = solve!(x,ls_setup,b,options)
36+
x,step+1
37+
end
38+
end
39+
traits = LinearSolverTraits(uses_nullspace,uses_initial_guess,returns_history)
40+
LinearSolver(setup,solve!,update!,finalize!,step!,traits)
2241
end
2342

24-
struct LinearSolver{A,B,C,D} <: AbstractLinearSolver
43+
struct LinearSolverTraits{A,B,C} <: AbstractType
44+
uses_nullspace::A
45+
uses_initial_guess::B
46+
returns_history::C
47+
end
48+
49+
struct LinearSolver{A,B,C,D,E,F} <: AbstractLinearSolver
2550
setup::A
2651
solve!::B
2752
update!::C
2853
finalize!::D
54+
step!::E
55+
traits::F
2956
end
3057

3158
function linear_solver(s::LinearSolver)
3259
s
3360
end
3461

35-
struct Preconditioner{A,B}
62+
struct Preconditioner{A,B} <: AbstractType
3663
solver::A
3764
solver_setup::B
3865
end
@@ -45,6 +72,18 @@ function nullspace(options)
4572
options.nullspace
4673
end
4774

75+
function uses_nullspace(a::LinearSolver)
76+
val_parameter(a.traits.uses_nullspace)
77+
end
78+
79+
function uses_initial_guess(a::LinearSolver)
80+
val_parameter(a.traits.uses_initial_guess)
81+
end
82+
83+
function returns_history(a::LinearSolver)
84+
val_parameter(a.traits.returns_history)
85+
end
86+
4887
function setup(solver::LinearSolver,x,A,b;kwargs...)
4988
options = setup_options(;kwargs...)
5089
solver_setup = solver.setup(x,A,b,options)
@@ -57,18 +96,30 @@ function update!(P::Preconditioner,A;kwargs...)
5796
P
5897
end
5998

60-
function solve_options(;zero_guess=false)
61-
options = (;zero_guess)
99+
function solve_options(;zero_guess=false,history=Val(false))
100+
options = (;zero_guess,history)
62101
end
63102

64103
function solve!(x,P::Preconditioner,b;kwargs...)
65104
options = solve_options(;kwargs...)
66-
P.solver.solve!(x,P.solver_setup,b,options)
67-
x
105+
next = P.solver.solve!(x,P.solver_setup,b,options)
106+
if returns_history(P.solver)
107+
x,log = next
108+
else
109+
x = next
110+
log = nothing
111+
end
112+
if val_parameter(options.history) == true
113+
return x, log
114+
else
115+
return x
116+
end
68117
end
69118

70119
function LinearAlgebra.ldiv!(x,P::Preconditioner,b)
71-
fill!(x,zero(eltype(x)))
120+
if uses_initial_guess(P.solver)
121+
fill!(x,zero(eltype(x)))
122+
end
72123
solve!(x,P,b;zero_guess=true)
73124
x
74125
end
@@ -77,3 +128,31 @@ function finalize!(P::Preconditioner)
77128
P.solver.finalize!(P.solver_setup)
78129
end
79130

131+
function iterations!(x,P::Preconditioner,b;kwargs...)
132+
options = solve_options(;kwargs...)
133+
params = (;options,x,P,b)
134+
LinearSolverIterator(params)
135+
end
136+
137+
struct LinearSolverIterator{A} <: AbstractType
138+
params::A
139+
end
140+
141+
function Base.iterate(a::LinearSolverIterator)
142+
P = a.params.P
143+
options = a.params.options
144+
b = a.params.b
145+
x = a.params.x
146+
next = P.solver.step!(x,P.solver_setup,b,options)
147+
next
148+
end
149+
150+
function Base.iterate(a::LinearSolverIterator,state)
151+
P = a.params.P
152+
options = a.params.options
153+
b = a.params.b
154+
x = a.params.x
155+
next = P.solver.step!(x,P.solver_setup,b,options,state)
156+
next
157+
end
158+

PartitionedSolvers/src/smoothers.jl

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ function lu_solver()
33
setup(x,op,b,options) = lu(op)
44
update!(state,op,options) = lu!(state,op)
55
solve!(x,P,b,options) = ldiv!(x,P,b)
6-
linear_solver(;setup,solve!,update!)
6+
uses_initial_guess = Val(false)
7+
linear_solver(;setup,solve!,update!,uses_initial_guess)
78
end
89

910
function jacobi_correction()
1011
setup(x,op,b,options) = dense_diag!(similar(b),op)
1112
update!(state,op,options) = dense_diag!(state,op)
1213
function solve!(x,state,b,options)
1314
x .= state .\ b
15+
x
1416
end
15-
linear_solver(;setup,update!,solve!)
17+
uses_initial_guess = Val(false)
18+
linear_solver(;setup,update!,solve!,uses_initial_guess)
1619
end
1720

1821
function richardson(solver;iters,omega=1)
@@ -39,13 +42,27 @@ function richardson(solver;iters,omega=1)
3942
ldiv!(dx,P,r)
4043
x .-= omega .* dx
4144
end
42-
(;iters)
45+
x, (;iters)
46+
end
47+
function step!(x,state,b,options,step=0)
48+
if step == iters
49+
return nothing
50+
end
51+
(r,dx,P,A_ref) = state
52+
A = A_ref[]
53+
dx .= x
54+
mul!(r,A,dx)
55+
r .-= b
56+
ldiv!(dx,P,r)
57+
x .-= omega .* dx
58+
x,step+1
4359
end
4460
function finalize!(state)
4561
(r,dx,P,A_ref) = state
4662
PartitionedSolvers.finalize!(P)
4763
end
48-
linear_solver(;setup,update!,solve!,finalize!)
64+
returns_history = Val(true)
65+
linear_solver(;setup,update!,solve!,finalize!,step!,returns_history)
4966
end
5067

5168
function jacobi(;kwargs...)
@@ -122,7 +139,7 @@ function local_solver_options(A,options)
122139
end
123140
end
124141

125-
struct AdditiveSchwarzSetup{A}
142+
struct AdditiveSchwarzSetup{A} <: AbstractType
126143
local_setups::A
127144
end
128145

PartitionedSolvers/test/smoothers_tests.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ tol = 1.e-8
2424
update!(S,2*A)
2525
solve!(y,S,b)
2626
@test norm(y-x/2)/norm(x/2) < tol
27+
28+
istep = Ref(0)
29+
for y in iterations!(y,S,b)
30+
isa(y,AbstractVector)
31+
istep[] += 1
32+
end
33+
@test istep[] == 1
34+
35+
y2,hist = solve!(y,S,b;history=true)
36+
@test y2 === y
37+
@test hist === nothing
38+
2739
finalize!(S)
2840

2941
solver = linear_solver(LinearAlgebra.lu)
@@ -59,6 +71,18 @@ tol = 1.e-8
5971
update!(S,2*A)
6072
solve!(y,S,b)
6173
@test norm(y-x/2)/norm(x/2) < tol
74+
75+
y,hist = solve!(y,S,b;history=true)
76+
@test hist.iters == 1000
77+
78+
istep = Ref(0)
79+
y .= 0
80+
for y in iterations!(y,S,b)
81+
isa(y,AbstractVector)
82+
istep[] += 1
83+
end
84+
@test norm(y-x/2)/norm(x/2) < tol
85+
@test istep[] == 1000
6286
finalize!(S)
6387

6488
solver = additive_schwarz(lu_solver())

0 commit comments

Comments
 (0)