Skip to content

Commit 5f4f09d

Browse files
authored
Polish the API for workspace accessors (#1000)
1 parent 241593c commit 5f4f09d

File tree

5 files changed

+96
-90
lines changed

5 files changed

+96
-90
lines changed

docs/src/custom_workspaces.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,14 +438,14 @@ We now solve the system $Ax = b$ using `minres` with our preconditioner:
438438

439439
```@example block-arrays
440440
using Krylov
441-
import Krylov: solution, niterations
441+
import Krylov: solution, iteration_count
442442
443443
kc = KrylovConstructor(b)
444444
workspace = MinresWorkspace(kc)
445445
minres!(workspace, A, b; M=P)
446446
447447
x = solution(workspace)
448-
niter = niterations(workspace)
448+
niter = iteration_count(workspace)
449449
```
450450

451451
This example demonstrates how `BlockArrays.jl` and `Krylov.jl` can be effectively combined to solve structured saddle point systems.

docs/src/generic_interface.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ They allow to build Krylov workspaces and call both in-place and out-of-place va
66

77
```@docs
88
krylov_workspace
9-
krylov_solve!
109
krylov_solve
10+
krylov_solve!
1111
```
1212

13+
The section on [workspace accessors](@ref workspace-accessors) describes how to retrieve the solution, statistics, and other results from a workspace after calling `krylov_solve!`.
14+
1315
## Examples
1416

15-
```julia
16-
using Krylov, Random
17+
```@example op_interface
18+
using Krylov, SparseArrays, LinearAlgebra
1719
1820
# Define a symmetric positive definite matrix A and a right-hand side vector b
1921
n = 1000
@@ -29,16 +31,16 @@ for method in (:cg, :cr, :car)
2931
end
3032
```
3133

32-
```julia
33-
using Krylov, Random
34+
```@example ip_interface
35+
using Krylov, SparseArrays, LinearAlgebra
3436
3537
# Define a square nonsymmetric matrix A and a right-hand side vector b
3638
n = 100
3739
A = sprand(n, n, 0.05) + I
3840
b = rand(n)
3941
4042
# In-place interface
41-
for method in (:bicgstab, :gmres)
43+
for method in (:bicgstab, :gmres, :qmr)
4244
# Create a workspace for the Krylov method
4345
workspace = krylov_workspace(Val(method), A, b)
4446
@@ -56,13 +58,18 @@ for method in (:bicgstab, :gmres)
5658
println("Convergence of $method: ", solved)
5759
5860
# Display the number of iterations
59-
niter = Krylov.niterations(workspace)
61+
niter = Krylov.iteration_count(workspace)
6062
println("Number of iterations for $method: ", niter)
6163
6264
# Display the elapsed timer
6365
timer = Krylov.elapsed_time(workspace)
6466
println("Elapsed time for $method: ", timer, " seconds")
6567
68+
# Display the number of operator-vector products with A and A'
69+
nAprod = Krylov.Aprod_count(workspace)
70+
nAtprod = Krylov.Atprod_count(workspace)
71+
println("Number of operator-vector products with A and A' for $method: ", (nAprod, nAtprod))
72+
6673
println()
6774
end
6875
```

docs/src/inplace.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ lsqr_workspace = LsqrWorkspace(m, n, CuVector{Float32})
4545
lsqr!(lsqr_workspace, A4, b4)
4646
```
4747

48-
## Workspace accessors
48+
## [Workspace accessors](@id workspace-accessors)
4949

5050
In-place solvers update the workspace, from which solutions and statistics can be retrieved.
5151
The following functions are available for post-solve analysis.
@@ -55,14 +55,13 @@ These functions are not exported and must be accessed using the prefix `Krylov.`
5555
```@docs
5656
Krylov.results
5757
Krylov.solution
58-
Krylov.nsolution
5958
Krylov.statistics
6059
Krylov.elapsed_time
61-
Krylov.niterations
6260
Krylov.issolved
63-
Krylov.Aprod
64-
Krylov.Atprod
65-
Krylov.Bprod
61+
Krylov.solution_count
62+
Krylov.iteration_count
63+
Krylov.Aprod_count
64+
Krylov.Atprod_count
6665
```
6766

6867
## Examples

src/workspace_accessors.jl

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,81 +2,84 @@
22
solution(workspace)
33
44
Return the solution(s) stored in the `workspace`.
5+
56
Optionally you can specify which solution you want to recover,
67
`solution(workspace, 1)` returns `x` and `solution(workspace, 2)` returns `y`.
78
"""
89
function solution end
910

1011
"""
11-
nsolution(workspace)
12+
statistics(workspace)
1213
13-
Return the number of outputs of `solution(workspace)`.
14+
Return the statistics stored in `workspace`.
1415
"""
15-
function nsolution end
16+
function statistics end
1617

1718
"""
18-
statistics(workspace)
19+
results(workspace)
1920
20-
Return the statistics stored in `workspace`.
21+
Return a tuple containing the solution(s) and the statistics associated with `workspace`.
22+
This allows retrieving the output arguments of an out-of-place method from an in-place method.
23+
24+
For example, instead of `x, stats = cg(A, b)`, you can use:
25+
```julia
26+
workspace = CgWorkspace(A, b)
27+
cg!(workspace, A, b)
28+
x, stats = results(workspace)
29+
```
2130
"""
22-
function statistics end
31+
function results end
2332

2433
"""
2534
issolved(workspace)
2635
2736
Return a boolean indicating whether the Krylov method associated with `workspace` has succeeded.
37+
38+
For the Krylov methods [`bilqr`](@ref) and [`trilqr`](@ref), you can use `issolved_primal(workspace)`
39+
and `issolved_dual(workspace)` to separately check whether the solver has converged on the primal or dual system.
2840
"""
2941
function issolved end
3042

3143
"""
32-
niterations(workspace)
44+
elapsed_time(workspace)
3345
34-
Return the number of iterations performed by the Krylov method associated with `workspace`.
46+
Return the elapsed time (in seconds) during the last call to the Krylov method associated with `workspace`.
3547
"""
36-
function niterations end
48+
function elapsed_time end
3749

3850
"""
39-
Aprod(workspace)
51+
solution_count(workspace)
4052
41-
Return the number of operator-vector products with `A` performed by the Krylov method associated with `workspace`.
53+
Return the number of outputs of `solution(workspace)`.
4254
"""
43-
function Aprod end
55+
function solution_count end
4456

4557
"""
46-
Atprod(workspace)
58+
iteration_count(workspace)
4759
48-
Return the number of operator-vector products with `A'` performed by the Krylov method associated with `workspace`.
49-
"""
50-
function Atprod end
60+
Return the number of iterations performed by the Krylov method associated with `workspace`.
5161
62+
The number of iterations alone is not a reliable basis for comparing different Krylov methods,
63+
since the work performed in each iteration can vary significantly.
64+
For a fairer performance comparison, use the total number of operator-vector products with `A` and `A'` (see [Aprod_count](@ref) and [Atprod_count](@ref)).
5265
"""
53-
Bprod(workspace)
66+
function iteration_count end
5467

55-
Return the number of operator-vector products with `B` performed by the Krylov method associated with `workspace`.
5668
"""
57-
function Bprod end
69+
Aprod_count(workspace)
5870
59-
"""
60-
elapsed_time(workspace)
71+
Return the number of operator-vector products with `A` performed by the Krylov method associated with `workspace`.
6172
62-
Return the elapsed time (in seconds) during the last call to the Krylov method associated with `workspace`.
73+
This function can also be used to determine the number of operator-vector products with `B` in [`gpmr`](@ref), since it is the same as for `A`.
6374
"""
64-
function elapsed_time end
75+
function Aprod_count end
6576

6677
"""
67-
results(workspace)
78+
Atprod_count(workspace)
6879
69-
Return a tuple containing the solution(s) and the statistics associated with `workspace`.
70-
This allows retrieving the output arguments of an out-of-place method from an in-place method.
71-
72-
For example, instead of `x, stats = cg(A, b)`, you can use:
73-
```julia
74-
workspace = CgWorkspace(A, b)
75-
cg!(workspace, A, b)
76-
x, stats = results(workspace)
77-
```
80+
Return the number of operator-vector products with `A'` performed by the Krylov method associated with `workspace`.
7881
"""
79-
function results end
82+
function Atprod_count end
8083

8184
"""
8285
warm_start!(workspace, x0)
@@ -128,13 +131,10 @@ for (KS, fun, nsol, nA, nAt, warm_start) in [
128131
@eval begin
129132
elapsed_time(workspace :: $KS) = workspace.stats.timer
130133
statistics(workspace :: $KS) = workspace.stats
131-
niterations(workspace :: $KS) = workspace.stats.niter
132-
Aprod(workspace :: $KS) = $nA * workspace.stats.niter
133-
Atprod(workspace :: $KS) = $nAt * workspace.stats.niter
134-
if $KS == GpmrWorkspace
135-
Bprod(workspace :: $KS) = workspace.stats.niter
136-
end
137-
nsolution(workspace :: $KS) = $nsol
134+
solution_count(workspace :: $KS) = $nsol
135+
iteration_count(workspace :: $KS) = workspace.stats.niter
136+
Aprod_count(workspace :: $KS) = $nA * workspace.stats.niter
137+
Atprod_count(workspace :: $KS) = $nAt * workspace.stats.niter
138138
if $nsol == 1
139139
solution(workspace :: $KS) = workspace.x
140140
solution(workspace :: $KS, p :: Integer) = (p == 1) ? solution(workspace) : error("solution(workspace) has only one output.")
@@ -187,10 +187,10 @@ for (KS, fun, nsol, nA, nAt, warm_start) in [
187187
@eval begin
188188
elapsed_time(workspace :: $KS) = workspace.stats.timer
189189
statistics(workspace :: $KS) = workspace.stats
190-
niterations(workspace :: $KS) = workspace.stats.niter
191-
Aprod(workspace :: $KS) = $nA * workspace.stats.niter
192-
Atprod(workspace :: $KS) = $nAt * workspace.stats.niter
193-
nsolution(workspace :: $KS) = $nsol
190+
solution_count(workspace :: $KS) = $nsol
191+
iteration_count(workspace :: $KS) = workspace.stats.niter
192+
Aprod_count(workspace :: $KS) = $nA * workspace.stats.niter
193+
Atprod_count(workspace :: $KS) = $nAt * workspace.stats.niter
194194
if $nsol == 1
195195
solution(workspace :: $KS) = workspace.X
196196
solution(workspace :: $KS, p :: Integer) = (p == 1) ? solution(workspace) : error("solution(workspace) has only one output.")

test/test_interface.jl

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -154,22 +154,22 @@ function test_krylov_workspaces(FC; krylov_constructor::Bool=false)
154154
@inferred krylov_solve(Val(method), A, b)
155155
@inferred krylov_solve!(workspace, A, b)
156156
end
157-
niter = niterations(workspace)
158-
@test Aprod(workspace) == (method (:cgs, :bicgstab) ? 2 * niter : niter)
159-
@test Atprod(workspace) == (method (:bilq, :qmr) ? niter : 0)
157+
niter = iteration_count(workspace)
158+
@test Aprod_count(workspace) == (method (:cgs, :bicgstab) ? 2 * niter : niter)
159+
@test Atprod_count(workspace) == (method (:bilq, :qmr) ? niter : 0)
160160
@test solution(workspace) === workspace.x
161-
@test nsolution(workspace) == 1
161+
@test solution_count(workspace) == 1
162162
end
163163

164164
if method (:cgne, :crmr, :lnlq, :craig, :craigmr)
165165
@inferred krylov_solve(Val(method), Au, c)
166166
@inferred krylov_solve!(workspace, Au, c)
167-
niter = niterations(workspace)
168-
@test Aprod(workspace) == niter
169-
@test Atprod(workspace) == niter
167+
niter = iteration_count(workspace)
168+
@test Aprod_count(workspace) == niter
169+
@test Atprod_count(workspace) == niter
170170
@test solution(workspace, 1) === workspace.x
171-
@test nsolution(workspace) == (method (:cgne, :crmr) ? 1 : 2)
172-
(nsolution(workspace) == 2) && (@test solution(workspace, 2) == workspace.y)
171+
@test solution_count(workspace) == (method (:cgne, :crmr) ? 1 : 2)
172+
(solution_count(workspace) == 2) && (@test solution(workspace, 2) == workspace.y)
173173
end
174174

175175
if method (:cgls, :crls, :lslq, :lsqr, :lsmr, :cgls_lanczos_shift)
@@ -180,22 +180,22 @@ function test_krylov_workspaces(FC; krylov_constructor::Bool=false)
180180
@inferred krylov_solve(Val(method), Ao, b)
181181
@inferred krylov_solve!(workspace, Ao, b)
182182
end
183-
niter = niterations(workspace)
184-
@test Aprod(workspace) == niter
185-
@test Atprod(workspace) == niter
183+
niter = iteration_count(workspace)
184+
@test Aprod_count(workspace) == niter
185+
@test Atprod_count(workspace) == niter
186186
@test solution(workspace) === workspace.x
187-
@test nsolution(workspace) == 1
187+
@test solution_count(workspace) == 1
188188
end
189189

190190
if method (:bilqr, :trilqr)
191191
@inferred krylov_solve(Val(method), A, b, b)
192192
@inferred krylov_solve!(workspace, A, b, b)
193-
niter = niterations(workspace)
194-
@test Aprod(workspace) == niter
195-
@test Atprod(workspace) == niter
193+
niter = iteration_count(workspace)
194+
@test Aprod_count(workspace) == niter
195+
@test Atprod_count(workspace) == niter
196196
@test solution(workspace, 1) === workspace.x
197197
@test solution(workspace, 2) === workspace.y
198-
@test nsolution(workspace) == 2
198+
@test solution_count(workspace) == 2
199199
@test issolved_primal(workspace)
200200
@test issolved_dual(workspace)
201201
end
@@ -208,13 +208,13 @@ function test_krylov_workspaces(FC; krylov_constructor::Bool=false)
208208
@inferred krylov_solve(Val(method), Au, c, b)
209209
@inferred krylov_solve!(workspace, Au, c, b)
210210
end
211-
niter = niterations(workspace)
212-
@test Aprod(workspace) == niter
213-
method != :gpmr && (@test Atprod(workspace) == niter)
214-
method == :gpmr && (@test Bprod(workspace) == niter)
211+
niter = iteration_count(workspace)
212+
@test Aprod_count(workspace) == niter
213+
method != :gpmr && (@test Atprod_count(workspace) == niter)
214+
method == :gpmr && (@test Atprod_count(workspace) == 0)
215215
@test solution(workspace, 1) === workspace.x
216216
@test solution(workspace, 2) === workspace.y
217-
@test nsolution(workspace) == 2
217+
@test solution_count(workspace) == 2
218218
end
219219

220220
if method (:usymlq, :usymqr)
@@ -225,11 +225,11 @@ function test_krylov_workspaces(FC; krylov_constructor::Bool=false)
225225
@inferred krylov_solve(Val(method), Ao, b, c)
226226
@inferred krylov_solve!(workspace, Ao, b, c)
227227
end
228-
niter = niterations(workspace)
229-
@test Aprod(workspace) == niter
230-
@test Atprod(workspace) == niter
228+
niter = iteration_count(workspace)
229+
@test Aprod_count(workspace) == niter
230+
@test Atprod_count(workspace) == niter
231231
@test solution(workspace) === workspace.x
232-
@test nsolution(workspace) == 1
232+
@test solution_count(workspace) == 1
233233
end
234234

235235
@test niter > 0
@@ -262,11 +262,11 @@ function test_block_krylov_workspaces(FC)
262262
B = 5 * B
263263
@inferred krylov_solve(Val(method), A, B)
264264
@inferred krylov_solve!(workspace, A, B)
265-
niter = niterations(workspace)
266-
@test Aprod(workspace) == niter
267-
@test Atprod(workspace) == 0
265+
niter = iteration_count(workspace)
266+
@test Aprod_count(workspace) == niter
267+
@test Atprod_count(workspace) == 0
268268
@test solution(workspace) === workspace.X
269-
@test nsolution(workspace) == 1
269+
@test solution_count(workspace) == 1
270270
@test niter > 0
271271
@test statistics(workspace) === workspace.stats
272272
@test issolved(workspace)

0 commit comments

Comments
 (0)