-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
in-place minres #269
in-place minres #269
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great PR !!!
if you want to rebase :
|
23bd4d6
to
b9bfbed
Compare
Codecov Report
@@ Coverage Diff @@
## master #269 +/- ##
==========================================
+ Coverage 96.96% 97.09% +0.13%
==========================================
Files 32 33 +1
Lines 3491 3516 +25
==========================================
+ Hits 3385 3414 +29
+ Misses 106 102 -4
Continue to review full report at Codecov.
|
@geoffroyleconte You were right, we need both |
@dpo It's fine for me. What do you think about it ? |
src/krylov_solvers.jl
Outdated
- r1 | ||
- r2 | ||
- w1 | ||
- w2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn’t seem important/useful to document since the user is never supposed to touch this structure. I would remove lines 9-13 and add comments inside the struct to guide the developer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user may need to access x
no? And maybe other parameters if we create the same struct for other Krylov solver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x
is always returned by a Krylov method and it's already a pointer to a vector inside a KrylovSolver
.
test/test_minres.jl
Outdated
resid = norm(r) / norm(b) | ||
@printf("MINRES: Relative residual: %8.1e\n", resid) | ||
@test(resid ≤ minres_tol) | ||
@test(stats.solved) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to add a test showing that minres!(A, b, solver)
does not allocate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not possible yet because there are still allocs done with the Residuals and Aresiduals vectors (see #272) . Even after the PR there will still be allocs because we create empty vectors for Residuals and Aresiduals and we do not fill them.
I think we need to separate cleanly the Minres storage from the stats structure. I think x should be in the stats structure so that the user never needs to look into the solver private storage. We should have an option to not accumulate the arrays of rNorms and ArNorms and be able to check that when that option is turned on, the solver doesn’t allocate. I would also put the stats structure inside the solver storage and return it at the end. |
If x is in the stats structure, we will need to add it in the arguments of minres! . Do you mean something like |
Can you rebase your branch Geoffroy ? |
Store the stats structure inside MinresSolver and x inside the stats. Then just return the stats instead of (x, stats). If the operators are preallocated, it should be possible to remove all allocations. |
78b3f83
to
fdf61bc
Compare
@dpo It will break every code that use |
I don’t think so. If you want, you can return (stats.x, stats) for the time being. What will break? At any rate, that’s what version numbers are for. Overall I think it’s an improvement.
I think the objective of this should be to remove allocations. What I’m saying is that if history = false and the operators preallocate, we should be able to have no allocations in the solver itself. |
|
||
may be used in order to create these vectors. | ||
""" | ||
mutable struct MinresSolver{T, S} <: KrylovSolver{T, S} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mutable
is not required here.
fdf61bc
to
97f8dfd
Compare
@dpo , with @amontoison we think that it might be wise to keep this PR as it is for now, and to focus on removing the Residuals and Aresiduals in another PR. The ultimate goal is, as you said, to remove all allocations with |
That’s a different topic. We’re just doing this for MINRES for now. Generic stats can come later (maybe). |
Yes, sure. But if you want to add |
Sure, let’s duplicate SimpleStats to make one just for MINRES for now. This is our proof of concept. It’s not that difficult. No need to implement show at this point. The main point is: can we get rid of all allocations in the second call? |
@geoffroyleconte |
Yes, it will be the case for MINRES (and all methods that do not require A'). We just need to pass a We should create the |
Let’s do it so @geoffroyleconte can use it in his code. |
@geoffroyleconte |
d037b3d
to
a2a2e77
Compare
@dpo @amontoison can we merge this if I check that the Julia version is 1.5 for the allocs test with |
I didn’t realize that you simply deactivated the test for Julia ≤ 1.5. That’s ok I guess. |
Also it looks like the coverage went down. I think we just need to call the variants in the tests: A = dense matrix, b = sparse vector, etc. |
@geoffroyleconte Could you deactivate the MINRES allocation test for Julia ≤ 1.5 as @amontoison did? The tests should pass with Julia 1.3. |
test/test_variants.jl
Outdated
solver = eval(Symbol(uppercasefirst(string(fn))[1:end-1], "Solver"))(A, b) | ||
@eval $fn($solver, $A, $b) | ||
@eval $fn($solver, $transpose($A), $b) | ||
@eval $fn($solver, $adjoint($A), $b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the annotations in variants.jl
to see which are not covered by the current tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an issue when b
is a SparseVector
, I did not find how to fix it. But anyway the function converts b
to a Vector
so this is not really an issue, the user just has to give a Vector
instead of a SparseVector
. All these issues will be fixed when we change LinearOperators
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand, but what we’re trying to fix now is coverage. What’s the problem with SparseVector?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have to give a PreallocatedLinearOperator that has a preallocated vector that we can keep track of so that the in-place version works correctly, I suggest we remove the variants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverage is completely separate from the in-place solver. We need to test the variants simply to ensure that they are callable and behave correctly. It's understood that they will allocate. But allocations are not what we're testing. If you're having an issue with SparseVector
s, then it's an indication that there's a bug and we should fix it.
Could you paste the error here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no issue with minres
, only with minres!
. It looks like the coverage is increased. We are loosing time on minor issues that will be fixed with the changes that will be made on LinearOperators.jl. We should say that for now the user has to use PreallocatedLinearOperators. It is actually the only way he can avoid allocations with the current implementation. I can add this to the documentation if needed.
Here is the error:
minres! ERROR: LoadError: LoadError: TypeError: in typeassert, expected SparseVector{Float32,Int32}, got a value of type Array{Float32,1} Stacktrace: [1] *(::PreallocatedLinearOperator{Float32}, ::SparseVector{Float32,Int32}) at C:\Users\Geoffroy Leconte\.julia\packages\LinearOperators\qFko7\src\operations.jl:7 [2] minres!(::MinresSolver{Float32,SparseVector{Float32,Int32}}, ::PreallocatedLinearOperator{Float32}, ::Array{Float32,1}; M::opEye, λ::Float32, atol::Float32, rtol::Float32, ratol
I added annotations so that the user is forced to use I can raise an issue to deal with |
src/krylov_solvers.jl
Outdated
@@ -22,7 +23,7 @@ mutable struct MinresSolver{T, S} <: KrylovSolver{T, S} | |||
stats :: SimpleStats{T} | |||
end | |||
|
|||
function MinresSolver(A, b :: AbstractVector{T}; window :: Int=5) where T <: AbstractFloat | |||
function MinresSolver(A :: PreallocatedLinearOperator{T}, b :: Vector{T}; window :: Int=5) where T <: AbstractFloat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot use anymore minres
on GPU :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the annotation should go in minres!()
, not here. Would that also break the GPU?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
b
must be an AbstractVector{T}
to keep support with CuVector{T}
. (GPU storage).
The parametrization of A is not needed too : https://juliasmoothoptimizers.github.io/Krylov.jl/dev/matrix-free/
But one thing should be explained somewhere, if the user want to use minres!
, he should wrap itselft A::AbstractMatrix in a PreallocatedLinearOperator. It's only done automatically with minres
.
If the user already uses its linear operator (LinearOperators.jl
, LinearMaps.jl
, ...) he doesn't need to do anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I removed annotations and documented that the user has to use PreallocatedLinearOperators to avoid allocations.
bd5f056
to
edf0608
Compare
Great! Thank you! |
@amontoison