Skip to content
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

Closed
wants to merge 7 commits into from

Conversation

KristofferC
Copy link
Member

@KristofferC KristofferC commented Jun 25, 2017

@KristofferC KristofferC added the sparse Sparse arrays label Jun 25, 2017
```
"""
function Base.isvalid(S::SparseMatrixCSC; full = false)

Copy link
Contributor

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


if full
# Check colptr increasing
if length(S.colptr) > 1 && !all(i -> S.colptr[i+1] >= S.colptr[i], 1:length(S.colptr)-1)
Copy link
Contributor

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?

return true
end

_print_invalid(io, S) = print(io, typeof(S), " with invalid internal representation")
Copy link
Contributor

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

@tkelman
Copy link
Contributor

tkelman commented Jun 25, 2017

This should verify that the row indices are strictly sorted within each column, possibly under a different kwarg

@nalimilan
Copy link
Member

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).

@KristofferC KristofferC force-pushed the kc/sparse_check branch 2 times, most recently from 8319166 to d4ccc4e Compare June 25, 2017 15:12
@KristofferC
Copy link
Member Author

  • Added a verification for rowindices in a column
  • Added size when printing invalid matrices
  • Removed closing statement of issue from first post.

false
```
"""
function Base.isvalid(S::SparseMatrixCSC; full = false)
Copy link
Contributor

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?

Copy link
Member Author

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.

# Check rowval in range and sorted in each column
for col in 1:S.n
nzrang = nzrange(S, col)
l_nzrange = length(nzrang)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused variable

ri = S.rowval[r]
(ri <= 0 || ri > S.m) && return false
r == last(nzrang) && break
S.rowval[r+1] <= ri && (println("returning"); return false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debugging print left in?


@testset "isvalid" begin
for x in [sprand(10,5,0.5), sprand(5,10,0.5), spzeros(0,0), spzeros(2,2)]
@show x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debugging print left in

ri = S.rowval[r]
(ri <= 0 || ri > S.m) && return false
r == last(nzrang) && break
S.rowval[r+1] <= ri && (println("returning"); return false)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ops

@KristofferC
Copy link
Member Author

  • Changed full to true by default
  • Some other minor cleanups


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.
Copy link
Member

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?

```
"""
function Base.isvalid(S::SparseMatrixCSC; full = true)
length(S.colptr) != S.n + 1 && return false
Copy link
Member

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) :).

Copy link
Member

@Sacha0 Sacha0 left a 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? :)

@KristofferC
Copy link
Member Author

Thanks for pointing me to #20464. Will update accordingly.

@KristofferC KristofferC changed the title implement an isvalid function for sparse matrices and use it in show implement a checkvalid function for sparse matrices and use it in show Jun 27, 2017
@KristofferC
Copy link
Member Author

Updated. I mimicked a bit the checkbounds style where the code can either throw an exception or return true / false if a Type{Bool} is given as first argument.

```
"""
function checkvalid(::Type{Bool}, S::SparseMatrixCSC; full = true)
return _checkvalid(S; full = full) == SparseArrayInvalid.VALID
Copy link
Contributor

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

Copy link
Member Author

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?

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.
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no code here...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please elaborate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see now.

@KristofferC
Copy link
Member Author

  • Updated name of module encapsulating enum as well as removed unwanted code block from a docstring.



"""
checkvalid(Bool, S::SparseMatrixCSC; full = true) -> Bool
Copy link
Member

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?

Copy link
Member Author

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whichever you deem best :).

Copy link
Contributor

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

Copy link
Member Author

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.

err_str = "S.rowval must be sorted for all column ranges"
else # Should not happen
err_str = "sparse array is invalid"
end
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we frequently do, yes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@Sacha0 Sacha0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful! :) 💯

@@ -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))"
Copy link
Contributor

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you wish.

O(nnz) checks are performed.

# Examples

Copy link
Member

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.)

Copy link
Member

@Sacha0 Sacha0 left a 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! :)

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)`"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use ≤, not \leqslant

@KristofferC
Copy link
Member Author

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)
Copy link
Contributor

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?

@ViralBShah
Copy link
Member

It would be nice to revive this one.

@ViralBShah
Copy link
Member

@KlausC implemented much of this in b32c1b8. I think all we need is a checkvalid wrapper.

@ViralBShah
Copy link
Member

@KristofferC Is it ok to close?

@KristofferC
Copy link
Member Author

@ViralBShah
Copy link
Member

Definitely useful if we can rebase and merge.

@DilumAluthge
Copy link
Member

It looks like this PR touches three files. One of those files (base/abstractarray.jl) is in Base. The remaining two files are part of the SparseArrays stdlib.

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:

  1. Remove the SparseArrays changes from this PR.
  2. Open a new PR against https://github.com/JuliaLang/SparseArrays.jl with the SparseArrays changes.

Thank you!

@DilumAluthge DilumAluthge added arrays [a, r, r, a, y, s] and removed sparse Sparse arrays labels Jan 14, 2022
@ViralBShah
Copy link
Member

SparseArrays.jl is now in its own separate repo. Please open the PR there if still relevant.

@ViralBShah ViralBShah closed this Jan 17, 2022
@ViralBShah ViralBShah added the sparse Sparse arrays label Jan 17, 2022
@DilumAluthge DilumAluthge deleted the kc/sparse_check branch January 18, 2022 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arrays [a, r, r, a, y, s] sparse Sparse arrays
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants