|
1 | 1 | """ |
2 | 2 | KrylovLinearSolver |
3 | 3 |
|
4 | | -Callable object that can solve linear systems `As = b` and `AS = b` in the same way as the built-in `\\`. |
| 4 | +Callable object that can solve linear systems `Ax = b` and `AX = B` in the same way as the built-in `\\`. |
5 | 5 | Uses an iterative solver from [Krylov.jl](https://github.com/JuliaSmoothOptimizers/Krylov.jl) under the hood. |
6 | 6 |
|
7 | | -# Note |
| 7 | +# Constructor |
8 | 8 |
|
9 | | -This name is not exported, and thus not part of the public API, but it is used in the [`ImplicitFunction`](@ref) constructors. |
10 | | -""" |
11 | | -struct KrylovLinearSolver end |
| 9 | + KrylovLinearSolver(; verbose=true) |
| 10 | +
|
| 11 | +If `verbose` is `true`, the solver logs a warning in case of failure. |
| 12 | +Otherwise it will fail silently, and may return solutions that do not exactly satisfy the linear system. |
| 13 | +
|
| 14 | +# Callable behavior |
12 | 15 |
|
13 | | -""" |
14 | 16 | (::KylovLinearSolver)(A, b::AbstractVector) |
15 | 17 |
|
16 | 18 | Solve a linear system with a single right-hand side. |
17 | | -""" |
18 | | -function (::KrylovLinearSolver)(A, b::AbstractVector) |
19 | | - x, stats = gmres(A, b) |
20 | | - return x |
21 | | -end |
22 | 19 |
|
23 | | -""" |
24 | 20 | (::KrylovLinearSolver)(A, B::AbstractMatrix) |
25 | 21 |
|
26 | 22 | Solve a linear system with multiple right-hand sides. |
27 | 23 | """ |
28 | | -function (::KrylovLinearSolver)(A, B::AbstractMatrix) |
| 24 | +Base.@kwdef struct KrylovLinearSolver |
| 25 | + verbose::Bool = true |
| 26 | +end |
| 27 | + |
| 28 | +function (solver::KrylovLinearSolver)(A, b::AbstractVector) |
| 29 | + x, stats = gmres(A, b) |
| 30 | + if !stats.solved || stats.inconsistent |
| 31 | + solver.verbose && |
| 32 | + @warn "Failed to solve the linear system in the implicit function theorem with `Krylov.gmres`" stats |
| 33 | + end |
| 34 | + return x |
| 35 | +end |
| 36 | + |
| 37 | +function (solver::KrylovLinearSolver)(A, B::AbstractMatrix) |
29 | 38 | # X, stats = block_gmres(A, B) # https://github.com/JuliaSmoothOptimizers/Krylov.jl/issues/854 |
30 | 39 | X = mapreduce(hcat, eachcol(B)) do b |
31 | | - first(gmres(A, b)) |
| 40 | + solver(A, b) |
32 | 41 | end |
33 | 42 | return X |
34 | 43 | end |
@@ -80,6 +89,14 @@ Picks the `lazy` parameter automatically based on the `linear_solver`, using the |
80 | 89 |
|
81 | 90 | Picks the `linear_solver` automatically based on the `lazy` parameter. |
82 | 91 |
|
| 92 | +# Callable behavior |
| 93 | +
|
| 94 | + (implicit::ImplicitFunction)(x::AbstractVector, args...; kwargs...) |
| 95 | +
|
| 96 | +Return `implicit.forward(x, args...; kwargs...)`, which can be either an `AbstractVector` `y` or a tuple `(y, z)`. |
| 97 | +
|
| 98 | +This call makes `y` differentiable with respect to `x`. |
| 99 | +
|
83 | 100 | # Function signatures |
84 | 101 |
|
85 | 102 | There are two possible signatures for `forward` and `conditions`, which must be consistent with one another: |
@@ -122,9 +139,6 @@ struct ImplicitFunction{ |
122 | 139 | conditions_y_backend::B2 |
123 | 140 | end |
124 | 141 |
|
125 | | -""" |
126 | | -
|
127 | | -""" |
128 | 142 | function ImplicitFunction{lazy}( |
129 | 143 | forward::F, |
130 | 144 | conditions::C; |
@@ -163,13 +177,6 @@ function Base.show(io::IO, implicit::ImplicitFunction{lazy}) where {lazy} |
163 | 177 | ) |
164 | 178 | end |
165 | 179 |
|
166 | | -""" |
167 | | - (implicit::ImplicitFunction)(x::AbstractVector, args...; kwargs...) |
168 | | -
|
169 | | -Return `implicit.forward(x, args...; kwargs...)`, which can be either an `AbstractVector` `y` or a tuple `(y, z)`. |
170 | | -
|
171 | | -This call makes `y` differentiable with respect to `x`. |
172 | | -""" |
173 | 180 | function (implicit::ImplicitFunction)(x::AbstractVector, args...; kwargs...) |
174 | 181 | y_or_yz = implicit.forward(x, args...; kwargs...) |
175 | 182 | return y_or_yz |
|
0 commit comments