-
-
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
De-eval-ify vectorized unary functions over SparseMatrixCSCs, and then transition them to compact broadcast syntax #17265
Conversation
eval(Multimedia, quote | ||
export @MIME | ||
macro MIME(s) | ||
Base.warn_once("@MIME(\"\") is deprecated, use MIME\"\" instead.") |
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.
wrong conflict resolution 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.
Good catch. Fixed? Thanks!
Messed things up a bit while addressing comments. Should be in order again now. Thanks! |
needs rebase |
Thanks for the ping! Rebased. |
@@ -793,6 +793,19 @@ function transpose(x) | |||
return x | |||
end | |||
|
|||
# Deprecate vectorized unary functions over sparse matrices in favor of compact broadcast syntax (#17265). |
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 won't be deprecating these in 0.5, move after the "to be deprecated in 0.6"
Rebased for 0.6. Thanks! |
# Operations that map both zeros and nonzeros to zeros, yielding a dense matrix | ||
""" | ||
Takes unary function `f` that maps both zeros and nonzeros to nonzeros, and returns a new | ||
`Matrix{TvB}` `B` effectively generated by applying `f` to every entry in `A`. |
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.
why "effectively" ?
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.
Due to the B = fill(f(zero(Tv)), size(A))
, this method calls f
only once rather than once for each zero in A
. Would make a difference if e.g. f
has side effects.
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.
worth writing that down in the docstring?
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.
Good call. Clarified in docstring. Thanks!
ready to merge? |
Looks like a good candidate for backporting as well for 0.5.x. |
No it isn't, it's a whole bunch of deprecations. |
d380f1a
to
57b032b
Compare
Rebased resolving deprecation conflict. Best! |
@Sacha0 sorry we frequently do a bad job of merging your (always impeccably well-done) PR's before they hit conflicts. Rebase? |
No worries! Your time is much better spent elsewhere at the moment. Also thanks for the kind words! Related question: Though master is technically 0.6-dev at this point, I imagine that prior to the actual 0.5 release it's advantageous to keep master as close as possible to 0.5.x? That is, I imagine holding noncritical PRs targeting 0.6 till 0.5 is out the door makes life easier? If so, apologies for bothering you with noncritical PRs targeting 0.6 recently, and I'll hold bumps / non-bugfix work till 0.5 is out. Thanks and best! |
It's fine actually, as long as things aren't a huge risk of causing non-trivial conflicts with bugfixes that need backporting. 0.5 is most likely only one more RC away from final, and we need to get moving on 0.6 just as much as we need to get 0.5 final done. |
…higher order functions and multiple dispatch to displace eval. Fixes some apparent type instabilities.
…act broadcast syntax, accordingly revise and expand the associated tests, and add deprecations for the vectorized syntax.
57b032b
to
bd7da66
Compare
Thanks for reviewing / merging! |
I wonder if we should have a more general function that does function broadcast{T<:Number}(f::Function, A::AbstractSparseArray{T})
fzero = f(zero(T))
if fzero == zero(fzero)
... broadcast to sparse array, operating f only on nonzero elements ...
else
.... broadcast to dense array, though as an optimization we could just use fzero for the zero elements ... or throw an error?
end
end This assumes |
Would the sketch above be type unstable? Would a version parametric on the function type recover type stability? Best! |
@Sacha0, the problem is that it assumes I guess we could use traits for this, but they wouldn't help much for anonymous functions that are constructed during loop fusion. |
Edit: Ref. #16285 and #11474.
This PR's first commit revises the implementation of vectorized unary functions over
SparseMatrixCSC
s, leveraging higher order functions to displace a set of macros andeval
s. Regarding performance, see below.This PR's second commit then transitions those vectorized unary functions over
SparseMatrixCSC
s to compact broadcast syntax, accordingly revises the associated tests, expands those tests, and then adds deprecations for the vectorized calls.Question: Both the existing code and that in this PR separate unary functions into three classes (with disjoint logic): (1) unary functions that map zeros to zeros and may map nonzeros to zeros; (2) unary functions that map zeros to zeros and nonzeros to nonzeros; and (3) unary functions that map both zeros and nonzeros to nonzeros. In the first class, when a nonzero in the original sparse matrix miraculously maps to exact zero under, e.g.,
sin
, the implementation expunges that entry. This behavior seems like a holdover from the aggressive-stored-zero-expunging era, now inconsistent with behavior elsewhere. Perhaps classes one and two should be merged? Merging those two classes would enable some code reduction and might increase the performance of operations presently falling under class one (by eliminating a branch in an inner loop, and enabling@simd
decoration of that inner loop). Thoughts?Perf
With the exception of
real
andimag
, for functions in the first class the existing and new implementations perform similarly or slightly favor the new implementation. The new implementation seems to resolve a type instability or so withreal
andimag
, significantly improving performance: Wherereal
is the existing implementation andho_real
this PR's, this benchfor
presmat = smallC
yieldsand for
presmat = largeC
yieldsFor functions in the second class, this PR's implementation exhibits significantly better performance on small matrices and somewhat better on large matrices, e.g. for the bench above with
presmat = smallA
, comparingexpm1
andho_expm1
yieldsand for
presmat = largeA
This PR's implementation also appears to resolve a type instability or so with
abs
andabs2
, e.g. comparingabs2
andho_abs2
forpresmat = smallC
the above bench yieldsand for
presmat = largeC
For functions in the third class, performance differences are within the noise. Best!