|
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