-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
A_ldiv_B!(a, b) writes over b or not depending on type of a #10787
Comments
It's a misnomer in the Umfpack interface, which is what is used for solving square, non-Hermitian, sparse systems. The Whether or not this is a bug depends on how strongly you interpret the |
I should add that, as far as I know, there is no mutating solver in Umfpack, so the only way you could get mutating behavior in Julia is to allocate a vector or matrix for the solution, solve the system, then copy the solution back into the right hand side. |
I think a no-method error would be preferable in cases where a mutating operation is not available, rather than trying to mimic an in-place operation by allocating and copying. |
I'm not sure. Let's say you wrote an algorithm using the updating versions
for increased efficiency. Wouldn't you still want it to work for other
cases, even though you can't get at the same efficency?
Btw if there is no mutating solve in umfpack, maybe Tim Davis would be
sympathetic to adding one? But I guess it's not as useful if it's only in
new releases.
|
Having the in-place version perform slower and allocate [as much or] more memory than the standard case defeats the purpose of having it at all. If you want code to be generic and not every type can implement an updating operation, then you should probably be using the conventional operation. If you want the highest possible performance, your code would need to be aware of the types it's operating on, use in-place for types where it is faster, or the standard form when an in-place operation is not available. Yes it would be ideal if every single type supported in-place operations and they would always be the higher-performance option, then the copying operation would be always be a trivial generic wrapper around the in-place version. But this is not currently the case. edit: The current situation of having an in-place operator that isn't actually in-place is semantically confusing, but at least doesn't incur a performance cost due to extra copying. So maybe it's acceptable for now? |
@tkelman That's a tough call. You may want your algorithm to be as fast as possible for types that support in-place operations, and still work (even if less efficiently) for other types. The alternatives are 1) the function fails plainly when given a type that doesn't support in-place operation, or 2) the developer checks for the existence of the in-place method for the type, and falls back to the copying more generic function. But I agree that |
The semantics would of course still have to be to do the update in place.
|
Personally, I expect some homogeneity in the A_op_B methods. It feels dangerous if you try to write a general method for matrices and you get different outputs depending on the representation you chose for the matrix. I think that there are two possible choices:
Keeping the current situation feels like it can lead to very subtle bugs in user code. |
Manual mutation and incurring the associated performance penalty might be preferable to a no-method error, but then you have a more subtle performance discrepancy that depends on the input types. |
We do provide generic fallbacks for some Btw had anyone timed this to see how much efficiency is actually lost in this case? |
I always read
Similarly you don't really lose anything by writing:
but the documentation says clearly you don't need to. |
In general I agree that the I also seem to remember from a previous discussion that always assigning the return value back to the corresponding variable might make some optimizations harder for the compiler. |
Not sure how much it matters, but in Python it seems that methods that operate inplace usually do not return anything, for example If this is good or not, I am not sure. Many times students write something similar to: def sort_thingy(thingy)
return thingy.sort() and get confused when they get |
Agreed that @KristofferC, I think it's better to return something, that way you can do |
For the explicit reassignment version only, it sounds like, but... I'm a bit worried about |
The performance cost I was talking about was for assigning the return value
of a mutating function back to the original variable - the compiler might
not always be able to realize that it is a noop. But I don't think we
should encourage that style anyway.
Python is kind of purist when it comes to returning None (python nothing)
from mutating functions, to avoid hiding the side effects. But in practice,
chaining can be pretty useful. I think our case is slightly easier at least
thanks to the visually distinguishable exclamation mark.
|
The problem was that A_ldiv_B! does not update B in case A is a sparse lufact: JuliaLang/julia#10787 Sparse coloring does not work yet.
+1. It's a source of bug. It also makes it harder to understand which operations really allocate in place. |
Deprecate A_ldiv_B!(SparseMatrixCSC, StridedVecOrMat) thereby fixing #10787
I close this now, see #13496 |
Is this intended?
The text was updated successfully, but these errors were encountered: