-
-
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
Improve zero checks in sparse and reduce #9325
Conversation
I guess constructing a zero of a type should be comparable in performance to comparing to an integer 0 literal? And there might be some custom types where the former makes sense but the latter doesn't? I've had types where I wanted to put them in sparse matrices and I had to say comparison to zero (or any number) is always false in order for things to work. The appveyor failure is due to #9189 until we can get a new nightly built, not this PR's fault. |
Comparing |
@JeffBezanson has required that we use When would it be wrong to implement As @rfourquet points out: Some types , like |
For sparse arrays, I think that we should consider if we want them to work |
If sparse arrays should work with other types than immutable |
Hmm. This is a bit of a problem. Maybe we need |
As noted above, the reason it uses |
The real issue is that you may want a zero matrix to cound and |
|
I wouldn't be excited to treat sparsity as equivalent to missingness. In my mind, asking for an element of a container with eltype |
Maybe it makes little sense to have sparse arrays for non-numbers that Or maybe the generalisation is just to supply a default value for the |
Note that neither As @ivarne said, the only such comparison that makes sense to write for matrices currently is The other pitfall one can run into is breaking transitivity. Imagine defining |
Wow this was more controversial than I thought it'd be, given it was already done partially but not consistently
It should be free for bitstypes, but I don't know what happens for other types (whether it allocates a fresh zero every time round the loop or it is identifies that it is an invariant)...
... But this suggests it is a problem. Putting it outside the loop is depressingly ugly, but still preferable to the old cold IMO
When that comparison doesn't make sense, or already has another meaning. e.g.
I mean, with this PR we have (probable) complete support for custom types for anything that makes sense. I don't see much point in restricting it to
Maybe, but then you'll need to define
It seems like it mostly works though - these things I fixed are mainly second-order stuff, and there is already chunks of the code that are designed to work with any type (mainly for type stability reasons though rather than a desire to be generic)
I will always push back (as will others) to this idea as I've never seen it in the wild, and it adds even more conceptual overhead to the "structural zeros" situation we are already in.
Thats a good point! I could change the code and add that as test. |
I can't really see how the standard library can be fully generic without having a well defined set of functions that have one single meaning each. |
The
|
Doing sparse matrices generically really demands this. What we're doing now isn't great, we get into unclear quagmires like this. That reminds me that I have an email from @jiahao to respond to. There are different levels of how you want to deal with sparse matrices, structurally and numerically. At the structural stage, if something is given a value, any value, you want it stored explicitly. At the numerical stage, sometimes you want to compare the values against zero and remove them - but that doesn't always make sense. |
I'm going to close this in the interests of tidiness, and delete the branch. Here are the tests that (IMO) should pass but don't, for posterities sake. Maybe we can revisit in the future. # Test proper handling of zeros for user types
immutable SpTestVal
value::Float64
end
(==)(x::SpTestVal,y::SpTestVal) = (x.value == y.value)
Base.zero(x::SpTestVal) = SpTestVal(0)
Base.zero(::Type{SpTestVal}) = SpTestVal(0)
A = sparse([1,2,3],[1,2,3],[SpTestVal(1),SpTestVal(0),SpTestVal(3)])
@test nnz(A) == 2 # zeros should be stripped by sparse
A[2,2] = SpTestVal(0)
@test nnz(A) == 2 # zeros should be stripped by setindex
A = SparseMatrixCSC(3,3,[1,2,3,4],[1,2,3],
[SpTestVal(1.0),SpTestVal(0.0),SpTestVal(3.0)])
@test countnz(A) == 2
r,c,v = findnz(A)
@test length(r) == length(c) == length(v) == 2 |
Just noticed some checks with
0
that don't play nice with custom types. There are probably more of these, but I'm not sure about a systematic way to find them.This is only my second "real" commit I think, so not sure my test code is kosher style-wise.