Skip to content

Improve linalg error messages and coverage reports, round 2 #12434

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

Merged
merged 9 commits into from
Aug 11, 2015

Conversation

kshyatt
Copy link
Contributor

@kshyatt kshyatt commented Aug 2, 2015

I expanded a bunch of functions so that we can see if all branch paths are followed for coverage purposes. I also tried to improve a bunch of error messages, by replacing error with throw(ArgumentErrror()) in relevant spots and improving the text of the message.

@kshyatt kshyatt added the linear algebra Linear algebra label Aug 2, 2015
@@ -35,7 +35,9 @@ end
Bidiagonal(A::AbstractMatrix, isupper::Bool)=Bidiagonal(diag(A), diag(A, isupper?1:-1), isupper)

function getindex{T}(A::Bidiagonal{T}, i::Integer, j::Integer)
(1<=i<=size(A,2) && 1<=j<=size(A,2)) || throw(BoundsError())
if !(1<=i<=size(A,2) && 1<=j<=size(A,2))
return throw(BoundsError())
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does it have a return?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh god. Thanks for the catch. I guess we know this path isn't tested!

@kshyatt kshyatt force-pushed the ksh/errormessages branch from f33fa4a to 04ad48f Compare August 2, 2015 21:53
setindex!(A::LowerTriangular, x, i::Integer, j::Integer) = i >= j ? (A.data[i,j] = x; A) : throw(BoundsError())
setindex!(A::UnitLowerTriangular, x, i::Integer, j::Integer) = i > j ? (A.data[i,j] = x; A) : throw(BoundsError())
function setindex!(A::UpperTriangular, x, i::Integer, j::Integer)
if i <= j
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be:

    i <= j && throw(BoundsError("($i,$j) indices not in upper triangle"))
    A.data[i,j] = x
    return A

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that doesn't fix the coverage reporting issue

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought that had been solved?
I got in trouble for changing the expr && throw's if's, remember? 😀
Even so, changing it to an if, I think it is better to have the errors first, and what you return at the end, instead of the other way around.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIK we are not computing partial coverage on each line yet for Codecov. Until that happens it won't be clear that parts of the line are not covered. Moving the code right of && or || to the next line did not fix it.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, then I hope nobody will complain if I go back to changing things to if's in the string code! 😀 (but I still think the pattern of having the throws first, then the computations, finally return value, is clearer)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be:

    if i > j
       throw(BoundsError(A, i)
   end
    A.data[i,j] = x
    return A

Copy link
Contributor

Choose a reason for hiding this comment

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

You don't think these 4 would be easier to understand as above (but with (i,j) as you did for the second arg to BoundsError)?
Having two things on one line, without the return, now that you've expanded the functions, seems confusing.

@KristofferC
Copy link
Member

Don't we normal try to have error messages without starting capital letter?

Also we should probably be consistent in usage of "should have", "needs a", "must have" in error messages. That can be decided on at some other time though.

@@ -35,7 +35,9 @@ end
Bidiagonal(A::AbstractMatrix, isupper::Bool)=Bidiagonal(diag(A), diag(A, isupper?1:-1), isupper)

function getindex{T}(A::Bidiagonal{T}, i::Integer, j::Integer)
(1<=i<=size(A,2) && 1<=j<=size(A,2)) || throw(BoundsError())
if !(1<=i<=size(A,2) && 1<=j<=size(A,2))
throw(BoundsError())
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this have more information about the subscript(s) that were out of bounds? Would that be BoundsError(A,i,j)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, you'd need to have two separate ones, BoundsError(A,i), or BoundsError(A,j).

Copy link
Contributor

Choose a reason for hiding this comment

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

    if !(1 <= i <= size(A,2))
        throw(BoundsError(A,i))
    elseif !(1 <= j <= size(A,2))
        throw(BoundsError(A,j))
    end

Copy link
Contributor

Choose a reason for hiding this comment

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

I still think this should be addressed.

Copy link
Member

Choose a reason for hiding this comment

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

I think that BoundsError(A,(i,j)) is the right one here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, that would work also, it just shouldn't be left BoundsError() with no information.

@ScottPJones
Copy link
Contributor

Unfortunately, I think all of the ones with BoundsError will be printed badly, because BoundsError expects to get an array and an index.

@ScottPJones
Copy link
Contributor

@KristofferC is correct, with a few exceptions, all of the DimensionError messages start with lower-case.
(If it is the "standard" way of doing error messages, then there are 2 places in multidimensional.jl and all of the ones in reducedim.jl that need to be fixed)

@ScottPJones
Copy link
Contributor

BTW, this is great stuff, and the linalg reorg looks very nice when I did Base.runtests()

@tkelman
Copy link
Contributor

tkelman commented Aug 2, 2015

@carnaval should probably finish #11802

@kshyatt kshyatt force-pushed the ksh/errormessages branch from 04ad48f to e51e0dd Compare August 9, 2015 04:32
@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 9, 2015

I pulled out the strings from the BoundsError throws in triangular.jl. Other than that, does this look ok?

@@ -71,7 +71,7 @@ vecnorm2{T<:BlasFloat}(x::Union{Array{T},StridedVector{T}}) =
function triu!(M::AbstractMatrix, k::Integer)
m, n = size(M)
if (k > 0 && k > n) || (k < 0 && -k > m)
throw(BoundsError())
throw(BoundsError("Requested diagonal, $k, out of bounds in matrix of size ($m,$n)"))
Copy link
Contributor

Choose a reason for hiding this comment

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

These haven't been addressed yet.

Copy link
Member

Choose a reason for hiding this comment

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

I think BoundsError should take an array and index tuple as arguments. You could just use an ArgumentError. It's more flexible.

Copy link
Contributor

Choose a reason for hiding this comment

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

That can cause problems, if there is any code with try/catch expecting the BoundsError
(had to deal with that when I was dealing with trying to improve the messages in AbstractArray)

@andreasnoack
Copy link
Member

I've added a few comments, but only minor things. I think it makes the source more readable which is a nice bonus from your test coverage mission.

SymTridiagonal(A.d, A.dl)
end

function convert(::Type{Diagonal}, A::AbstractTriangular)
full(A) == diagm(diag(A)) || throw(ArgumentError("Matrix cannot be represented as Diagonal"))
if full(A) != diagm(diag(A))
Copy link
Member

Choose a reason for hiding this comment

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

@andreasnoack it seems terribly inefficient to do a full conversion here?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. That is bananas. Allocating three arrays for an operation that doesn't require a single is not efficient. I'll prepare a fix when this is merged.

@kshyatt kshyatt force-pushed the ksh/errormessages branch from e51e0dd to b07fe3e Compare August 10, 2015 21:05
@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 10, 2015

Updated! I added a bunch of right hand side notes to error messages in triangular.jl.

@jakebolewski
Copy link
Member

@kshyatt looks good, a nitpick but maybe stick with the convention that all error messages are lowercased (when appropriate).

@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 10, 2015

I tried to! Did I miss somewhere?

It's not a nitpick - stylistic consistency is important :).

@jakebolewski
Copy link
Member

base/linalg/matmul.jl

@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 10, 2015

CURSES! Can we wait to see if CI passes, and if so, I'll correct that then merge?

@tkelman
Copy link
Contributor

tkelman commented Aug 10, 2015

There's enough of a queue ATM that it wont make much difference if you fix now, the pending jobs will automatically fail fast and if you fix it quickly you'll have the same place in line.

@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 10, 2015

Boss. On the case!

@tkelman
Copy link
Contributor

tkelman commented Aug 10, 2015

matmul's also not the only case with still-uppercase errors, also base/linalg/dense.jl and base/linalg/generic.jl and base/linalg/special.jl and base/linalg/tridiag.jl. And still one unaddressed empty BoundsError() with no more info?

@kshyatt kshyatt force-pushed the ksh/errormessages branch from b07fe3e to f08cd7e Compare August 10, 2015 21:18
@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 10, 2015

Ok! I fixed matmul and I'll take a look at dense. Sorry, everyone.

@kshyatt kshyatt force-pushed the ksh/errormessages branch from f08cd7e to 69de1fd Compare August 10, 2015 21:25
@KristofferC
Copy link
Member

Just a personal remark but I don't like the word need so much in error messages like in right hand side B needs first dimension.... Better is right hand side B must have first dimension.... But I am not a native english speaker so I dunno.

@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 10, 2015

We should open an issue to decide on a common syntax for these messages.

length(rx)==length(ry) || throw(DimensionMismatch())
if length(rx) != length(ry)
throw(DimensionMismatch("length of rx, $(length(rx)), does not equal length of ry, $(length(ry))"))
end
if minimum(rx) < 1 || maximum(rx) > length(x) || minimum(ry) < 1 || maximum(ry) > length(y)
Copy link
Contributor

Choose a reason for hiding this comment

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

This one still has no information in the BoundsError

@ScottPJones
Copy link
Contributor

Lines 163 and 180 in bidiag.jl still have "Size" instead of "size" in DimensionMismatch error.

@ScottPJones
Copy link
Contributor

dense.jl has an empty BoundsError() at line 60.

@kshyatt
Copy link
Contributor Author

kshyatt commented Aug 11, 2015

Did something dumb, fixing now.

@ScottPJones
Copy link
Contributor

I still see the following problems:
Line 53 & 62 of matmul.jl, BoundsError()
Line 120 of bidiag.jl, BoundsError("Matrix...")
Line 163 & 180 of bidiag.jl, DimensionMismatch("Size...")
Line 60 of dense.jl, BoundsError()
Line 18 of diagonal.jl, ArgumentError("Diagonal...)"
Line 443 of generic.jl, BoundsError()
Line 455, 458, 480, 483, 508, of generic.jl, BoundsError("...") Line 486 of generic.jl, would be good to have row and col values. Line 53, 62 of matmul.jl,BoundsError()`

@StefanKarpinski
Copy link
Member

I'm going to merge this once CI passes and then you can submit the fixes you see as a separate PR, ok?

StefanKarpinski added a commit that referenced this pull request Aug 11, 2015
Improve linalg error messages and coverage reports, round 2
@StefanKarpinski StefanKarpinski merged commit b10de59 into master Aug 11, 2015
@StefanKarpinski StefanKarpinski deleted the ksh/errormessages branch August 11, 2015 03:12
@StefanKarpinski
Copy link
Member

Now that it's merged, @ScottPJones, feel free to make whatever fixes seem necessary in a new PR.

@ScottPJones
Copy link
Contributor

@StefanKarpinski Done. There probably needs to be some more coverage tests, because the changes in #12434 would have actually gotten errors from the places where BoundsError() was changed to
BoundsError(string).

julia> throw(BoundsError("foobar"))
ERROR: BoundsError: attempt to access "foobar"

@StefanKarpinski
Copy link
Member

More coverage is always good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
linear algebra Linear algebra
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants