-
-
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
implement a checkvalid function for sparse matrices and use it in show #22529
Conversation
base/sparse/sparsematrix.jl
Outdated
``` | ||
""" | ||
function Base.isvalid(S::SparseMatrixCSC; full = false) | ||
|
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.
no blank line at start of a block
base/sparse/sparsematrix.jl
Outdated
|
||
if full | ||
# Check colptr increasing | ||
if length(S.colptr) > 1 && !all(i -> S.colptr[i+1] >= S.colptr[i], 1:length(S.colptr)-1) |
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.
would issorted be any faster?
base/sparse/sparsematrix.jl
Outdated
return true | ||
end | ||
|
||
_print_invalid(io, S) = print(io, typeof(S), " with invalid internal representation") |
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.
still worth showing the size
This should verify that the row indices are strictly sorted within each column, possibly under a different kwarg |
Thanks! However to be completely sure we can close #14489 after merging this, we would need to be check that no segfault can happen in other functions for invalid matrices (or at least, that the impact of fixing these crashes on performance would be acceptable). |
8319166
to
d4ccc4e
Compare
|
base/sparse/sparsematrix.jl
Outdated
false | ||
``` | ||
""" | ||
function Base.isvalid(S::SparseMatrixCSC; full = false) |
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 defaulting to only partial checks?
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.
Yeah, perhaps full should be default. I'll change it.
base/sparse/sparsematrix.jl
Outdated
# Check rowval in range and sorted in each column | ||
for col in 1:S.n | ||
nzrang = nzrange(S, col) | ||
l_nzrange = length(nzrang) |
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.
unused variable
base/sparse/sparsematrix.jl
Outdated
ri = S.rowval[r] | ||
(ri <= 0 || ri > S.m) && return false | ||
r == last(nzrang) && break | ||
S.rowval[r+1] <= ri && (println("returning"); return false) |
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.
debugging print left in?
test/sparse/sparse.jl
Outdated
|
||
@testset "isvalid" begin | ||
for x in [sprand(10,5,0.5), sprand(5,10,0.5), spzeros(0,0), spzeros(2,2)] | ||
@show x |
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.
debugging print left in
base/sparse/sparsematrix.jl
Outdated
ri = S.rowval[r] | ||
(ri <= 0 || ri > S.m) && return false | ||
r == last(nzrang) && break | ||
S.rowval[r+1] <= ri && (println("returning"); return false) |
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.
ops
d4ccc4e
to
155e288
Compare
|
9200e9b
to
d35d80b
Compare
base/sparse/sparsematrix.jl
Outdated
|
||
Check if a sparse matrix `S` has a valid internal representation. | ||
If `full` is `false` only O(1) checks are done, otherwise full | ||
O(nnz) checks are performed. |
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.
Should O(1)
and O(nnz)
be marked up somehow?
base/sparse/sparsematrix.jl
Outdated
``` | ||
""" | ||
function Base.isvalid(S::SparseMatrixCSC; full = true) | ||
length(S.colptr) != S.n + 1 && return false |
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 check seems too strict. For explanation, please see #20464 (comment) :).
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.
Thanks @KristofferC! :)
Re. length checks, I advocate checking the set of constraints described in/around #20464 (comment) and no more. Thoughts? :)
Thanks for pointing me to #20464. Will update accordingly. |
d35d80b
to
8e2297d
Compare
Updated. I mimicked a bit the |
base/sparse/sparsematrix.jl
Outdated
``` | ||
""" | ||
function checkvalid(::Type{Bool}, S::SparseMatrixCSC; full = true) | ||
return _checkvalid(S; full = full) == SparseArrayInvalid.VALID |
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.
Invalid.VALID is a messy name 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.
Okay. Please suggest better name / names. SparseArrayValidity
?
base/sparse/sparsematrix.jl
Outdated
Throw an [`ArgumentError`](@ref) if the sparse matrix `S` does not have a valid internal representation. | ||
If `full` is `false` only O(1) checks are done, otherwise full | ||
O(nnz) checks are performed. | ||
``` |
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.
no code 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.
Please elaborate.
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.
Oh, I see now.
|
base/sparse/sparsematrix.jl
Outdated
|
||
|
||
""" | ||
checkvalid(Bool, S::SparseMatrixCSC; full = true) -> Bool |
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.
Perhaps Bool
should be ::Type{Bool}
? I was not certain whether the first argument should be a boolean value or the Bool
type prior to reading the examples. Or do you prefer this signature with the examples to clarify?
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.
Hmm, looking at the docs for checkbounds
:
checkbounds(Bool, A, I...)
Return true if the specified indices I are in bounds for the given array A.
Subtypes of AbstractArray should specialize this method if they need to
provide custom bounds checking behaviors; however, in many cases one can
rely on A's indices and checkindex.
so this is consistent with that. In my opinion ::Type{Bool}
is more clear though. Thoughts?
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.
Whichever you deem best :).
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 isn't right as a signature, it would locally overwrite Bool as a variable name
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.
Pushed a commit that changes this for the pertinent check-methods.
base/sparse/sparsematrix.jl
Outdated
err_str = "S.rowval must be sorted for all column ranges" | ||
else # Should not happen | ||
err_str = "sparse array is invalid" | ||
end |
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.
Beautiful error messages! :) Perhaps the code snippets should be quoted?
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 point. Will update accordingly.
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.
Regarding quoting error messages; do we usually quote things in error message strings? They will not be rendered as markdown and I'm not sure if we use "`" as a convention for code in strings.
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 frequently do, yes
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 was checking e.g. https://github.com/JuliaLang/julia/pull/20464/files#diff-fceaad3480ef8dc3a224be725fa10678R866. Anyway, updated with code quotes.
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.
Beautiful! :) 💯
base/sparse/sparsematrix.jl
Outdated
@@ -167,19 +167,19 @@ function checkvalid(S::SparseMatrixCSC; full = true) | |||
validity = _checkvalid(S; full = full) | |||
validity == SparseArrayValidity.VALID && return | |||
if validity == SparseArrayValidity.COLPTR_LENGTH | |||
err_str = "length of S.colptr must be at least size(S,2) + 1 = $(S.n + 1) but was $(length(S.colptr))" | |||
err_str = "length of `S.colptr` must be at least `size(S,2)` + 1 = $(S.n + 1) but was $(length(S.colptr))" |
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.
would include the + 1 or - 1 in the highlighting
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.
As you wish.
cf968e8
to
2db4ac3
Compare
base/sparse/sparsematrix.jl
Outdated
O(nnz) checks are performed. | ||
|
||
# Examples | ||
|
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.
(Extra empty line under the seemingly just-established convention, but could be fixed in the dedicated PR 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.
lgtm for the touchups! :)
base/sparse/sparsematrix.jl
Outdated
elseif validity == SparseArrayValidity.COLPTR_SORTED | ||
err_str = "`S.colptr` must be sorted" | ||
elseif validity == SparseArrayValidity.ROWVAL_RANGE | ||
err_str = "each element in `S.rowval` must be > 0 and ⩽ `size(S,1)`" |
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.
should use ≤, not \leqslant
Comments addressed |
] | ||
@test SparseArrays._checkvalid(mat; full=full) == err | ||
@test SparseArrays.checkvalid(Bool, mat; full=full) == false | ||
@test_throws ArgumentError SparseArrays.checkvalid(mat; full=full) |
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.
would it be worth adding
if full
@test SparseArrays._checkvalid(mat; full=false) == SparseArrays.SparseArrayValidity.VALID
@test SparseArrays.checkvalid(Bool, mat; full=false) == true
@test SparseArrays.checkvalid(mat; full=false) === nothing
end
for coverage of that case?
It would be nice to revive this one. |
@KristofferC Is it ok to close? |
I think this is still useful (ref https://discourse.julialang.org/t/weird-duplicated-entries-with-different-values-in-sparsematrixcsc/). |
Definitely useful if we can rebase and merge. |
It looks like this PR touches three files. One of those files ( We have moved the SparseArrays stdlib to an external repository. Therefore, for the portion of this PR that modifies the SparseArrays stdlib, can you please:
Thank you! |
SparseArrays.jl is now in its own separate repo. Please open the PR there if still relevant. |
cc @nalimilan, @Sacha0