Skip to content

Conversation

@fredrikekre
Copy link
Member

Still some cleanup to do.

@fredrikekre fredrikekre added the linear algebra Linear algebra label May 31, 2018
@fredrikekre fredrikekre force-pushed the fe/check-or-not-to-check-that-is-the-question branch from db3ed25 to b8aac1f Compare May 31, 2018 09:52
Copy link
Member

@andreasnoack andreasnoack left a comment

Choose a reason for hiding this comment

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

Looks good to me. Only thing I'm wondering is if throw=true is better than check=false.

@fredrikekre
Copy link
Member Author

Stefan pointed out (and I agree) that throw = true looks weird if it does not actually throw (i.e. if the matrix is PD).

Also, should we do the same for CHOLMOD.cholesky[!]? I think that is a trivial extension and would be nice with a consistent interface, but then we should probably do the same for UMFPACK.lu[!] but that seemed a little bit more involved; we basically check issuccess there when we use the factorization. Is it possible to know if the factorization was successful before calling downstream functions in UMFPACK?

@andreasnoack
Copy link
Member

andreasnoack commented May 31, 2018

I don't have strong opinions about the name so let's just stick with check.

It would be great to handle this consistently for the sparse versions as well. For LU, I guess it is a matter of storing the status value in the struct instead of throwing right away in

status = ccall(($num_r, :libumfpack), $itype,
(Ptr{$itype}, Ptr{$itype}, Ptr{Float64}, Ptr{Cvoid}, Ptr{Cvoid},
Ptr{Float64}, Ptr{Float64}),
U.colptr, U.rowval, U.nzval, U.symbolic, tmp,
umf_ctrl, umf_info)
if status != UMFPACK_WARNING_singular_matrix
umferror(status)
end
.

@mbauman
Copy link
Member

mbauman commented May 31, 2018

So to use UMFPACK, we need to first precompute a symbolic factorization and then do the numeric thing. Is it possible for the umfpack_*_numeric to fail when the symbolic one didn't? The docs aren't quite clear on this front — it can return a singular matrix warning, but I'm not sure if that will happen in any cases where it didn't already do so in the symbolic pre-computation.

@andreasnoack
Copy link
Member

andreasnoack commented May 31, 2018

I think the singular warning is only returned in the numerical factorization. The symbolic factorization doesn't fail on structural singularity. Instead of storing the status value, as I suggested in the last comment, we might just make the status != UMFPACK_WARNING_singular_matrix check conditional on !check.

@fredrikekre
Copy link
Member Author

we might just make the status != UMFPACK_WARNING_singular_matrix check conditional on !check.

That means we have to propagate the check kwarg all the way to the function where the ccall happens though, probably better to store status in the struct and do the check "higher up"?

@andreasnoack
Copy link
Member

That means we have to propagate the check kwarg all the way to the function where the ccall happens though

I think you'd only have to add a (positional?) argument to umfpack_numeric! and then, of course, the keyword argument to lu so it's a small change. I think it is simpler than extending the struct.

@fredrikekre fredrikekre force-pushed the fe/check-or-not-to-check-that-is-the-question branch 2 times, most recently from 1e57e83 to e970dd6 Compare June 1, 2018 19:24
@Sacha0
Copy link
Member

Sacha0 commented Jun 2, 2018

(Apologies for review latency; I hope to eke out review time this weekend! :) )

rook pivoting is not used.
When `check = true` the matrix is checked for singularity, and makes sure
the factorization is successful, or else throw an error. When `check = false`
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps slightly more compact "When check = true, an error is thrown if the decomposition fails. When check = false, responsibility for checking the decomposition's validity (via issuccess) lies with the user." ?

end
check && checkpositivedefinite(info)
return C
end
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps slightly simpler?

function cholesky!(A::RealHermSymComplexHerm, ::Val{false}=Val(false); check::Bool = true)
    C, info = _chol!(A.data, A.uplo == 'U' ? UpperTriangular : LowerTriangular)
    check && checkpositivedefinite(info)
    return Cholesky(C.data, A.uplo, info)
end

When `check = true` the matrix will be checked for positive definiteness, and make sure
the factorization was successful, or else throw an error. When `check = false`
the user is responsible to make sure the result is valid, with
[`issuccess`](@ref), before passing the result to downstream functions.
Copy link
Member

Choose a reason for hiding this comment

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

Ref. comment on similar snippet above :).

inv(C::Cholesky{<:BlasFloat,<:StridedMatrix}) = inv!(copy(C))

function inv(C::CholeskyPivoted)
chkfullrank(C)
Copy link
Member

Choose a reason for hiding this comment

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

I feel like we can afford the vowel in check 😄. Perhaps some day...

:($(esc(info)) == 0 ? $(esc(A)) : throw(SingularException($(esc(info)))))
end
checkpositivedefinite(info) = info == 0 || throw(PosDefException(info))
checknonsingular(info) = info == 0 || throw(SingularException(info))
Copy link
Member

Choose a reason for hiding this comment

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

👍

Copy link
Member

Choose a reason for hiding this comment

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

👍

return convert(S, det(UpperTriangular(A)))
end
return det(lu(A))
return det(lu(A; check = false))
Copy link
Member

Choose a reason for hiding this comment

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

Does this check = false belong 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.

Yes, otherwise we throw, and det deals with failed factorizations:

issuccess(F) || return zero(T)

AA = similar(A, S)
copyto!(AA, A)
F = lu!(AA, Val(false))
F = lu!(AA, Val(false); check = false) # ?
Copy link
Member

Choose a reason for hiding this comment

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

Re. the # ?, looks sound in combination with the downstream logic.

end
F = bunchkaufman(R; check = false)
@test sprint(show, "text/plain", F) == "Failed factorization of type $(typeof(F))"
end
Copy link
Member

@Sacha0 Sacha0 Jun 3, 2018

Choose a reason for hiding this comment

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

Do these tests preserve all that can/should be preserved from the block removed above? If so, carry on :). (Edit: E.g. eltype combinations.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, should hit all relevant code paths.

Hermitian{T,SparseMatrixCSC{T,SuiteSparse_long}}};
shift = 0.0) where {T<:Real} =
cholesky!(F, Sparse(A); shift = shift)
shift = 0.0, check::Bool = true) where {T<:Real} =
Copy link
Member

Choose a reason for hiding this comment

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

Though the indentation was off before, perhaps indent this part of the signature to match the preceding part?

function LinearAlgebra.issuccess(lu::UmfpackLU)
U, status = umfpack_numeric!(lu, false)
return status == UMFPACK_OK
end
Copy link
Member

Choose a reason for hiding this comment

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

I haven't worked through the umfpack_numeric! logic, but presume that calling this issuccess method on a completed UmfpackLU will not result in an additional numerical decomposition phase?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was wondering the same when I wrote this, my tests suggested it was an quick return, but I tried again now (with larger matrices) and that does not seem to be the case... Might have to store status in the struct after all!

Copy link
Member

@andreasnoack andreasnoack Jun 3, 2018

Choose a reason for hiding this comment

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

Browsed through the source and indeed it doesn't look like it is returning early if the factorization is already computed so storing the status is probably the way to go. UMFPACK stores an estimate of the reciprocal condition number and this number is used to determine singularity but I don't think we have a way to extract that estimate.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done; I think the diff is smaller for this implementation as well.

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.

Looks great! Wonderful to cleanup to the use-sites :). Much thanks @fredrikekre!

Caveat: I did not examine the logic for the sparse decompositions carefully.

@fredrikekre fredrikekre force-pushed the fe/check-or-not-to-check-that-is-the-question branch 2 times, most recently from 30b7db2 to 112731f Compare June 4, 2018 06:37
@fredrikekre fredrikekre force-pushed the fe/check-or-not-to-check-that-is-the-question branch from 112731f to 6238946 Compare June 5, 2018 12:20
@fredrikekre fredrikekre force-pushed the fe/check-or-not-to-check-that-is-the-question branch from 6238946 to fa6f586 Compare June 7, 2018 06:16
@fredrikekre fredrikekre closed this Jun 7, 2018
@fredrikekre fredrikekre reopened this Jun 7, 2018
@StefanKarpinski
Copy link
Member

FreeBSD failure is OOM; Windows failures are timeouts. Do we have reason to be suspicious of this PR on non-Linux platforms? It does pass on macOS at least, so it's fine on at least two different OSes.

@fredrikekre
Copy link
Member Author

It passed on FreeBSD before the rebase as well.

@StefanKarpinski
Copy link
Member

Ok, good to go then?

@andreasnoack andreasnoack merged commit 37d70a5 into master Jun 7, 2018
@andreasnoack andreasnoack deleted the fe/check-or-not-to-check-that-is-the-question branch June 7, 2018 20:20
haampie pushed a commit to haampie/julia that referenced this pull request Jun 9, 2018
* check = (true|false) for LinearAlgebra.cholesky[!]

* check = (true|false) for LinearAlgebra.lu[!]

* check = (true|false) for LinearAlgebra.bunchkaufman[!]

* check = (true|false) for CHOLMOD.cholesky[!] and CHOLMOD.ldlt[!]

* check = (true|false) for UMFPACK.lu
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.

6 participants