-
Notifications
You must be signed in to change notification settings - Fork 13
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
[WIP] cholesky #44
[WIP] cholesky #44
Conversation
I will try out your branch and see I can resolve the errors. |
return istriu(A) && istriu(B) | ||
end | ||
|
||
function getproperty(C::KroneckerCholesky, d::Symbol) |
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 fixed an error here by changing it into
function getproperty(C::KroneckerCholesky, d::Symbol)
Cfactors = getfield(C, :factors)
Cuplo = getfield(C, :uplo)
info = getfield(C, :info)
Cuplo != 'U' && throw(NotImplementedError(""))
if d == :U
return UpperTriangular(Cfactors)
elseif d == :L
return LowerTriangular(copy(Cfactors'))
#return LowerTriangular(Cuplo === char_uplo(d) ? Cfactors : copy(Cfactors'))
elseif d == :UL
return (Cuplo === 'U' ? UpperTriangular(Cfactors) : LowerTriangular(Cfactors))
else
return getfield(C, d)
end
end
I also needed my own version of copy
which provides shallow copies of Kronecker products. This gives the right answer.
return size(B, 1) * logdet_A + size(A, 1) * logdet_B | ||
end | ||
|
||
function \(C::KroneckerCholesky, x::AbstractVecOrMat) |
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 am not sure this is correct. If I understand it correctly, the main performance of Cholesky decomposition originates from the fact that it is easy to solve a triangular system. The vec trick kind of destroys this structure...
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. I admit that I hadn't really thought very hard about this when writing it, but I'm pretty sure that you can use the vec trick to compute backsolves. Note that
vec(inv(L2) X inv(L1)) = (inv(L1) ⊗ inv(L2)) vec(X) = inv(L1 ⊗ L2) vec(X)
so we should be able to implement backsolving with kronecker matrices efficiently provided that the individual backsolves are efficient.
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.
So you would leave it as is for the moment?
You're right. I shouldn't have been doing the above. The cholesky factorisation of a kronecker product is the kronecker product of the cholesky factors though, which is what I would ultimately like to exploit. Probably requires some care to make this work correctly. |
K2::KroneckerPower{T2, N}) where {T1, T2, N} | ||
function Base.:*( | ||
K1::KroneckerPower{T1, TA1, N}, | ||
K2::KroneckerPower{T1, TA2, N}, |
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 do you require that both Kronecker factors have the same eltype
T1
? I don't think that's necessary.
|
||
function cholesky(A::AbstractKroneckerProduct; check=true) | ||
P, Q = getmatrices(A) | ||
chol_P, chol_Q = cholesky(P; check=true), cholesky(Q; check=true) |
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 this be
chol_P, chol_Q = cholesky(P; check=check), cholesky(Q; check=check)
? Otherwise, the kwarg doesn't enter anywhere.
|
||
function UpperTriangular(C::AbstractKroneckerProduct) | ||
A, B = getmatrices(C) | ||
return UpperTriangular(A) ⊗ UpperTriangular(B) |
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.
UpperTriangular
is the constructor of the UpperTriangular
type. So I guess this should return an object of that type, and you may wish to consider returning
UpperTriangular(UpperTriangular(A) ⊗ UpperTriangular(B))
? Otherwise, subsequent code will not benefit from upper-triangularizing an AbstractKroneckerProduct
, it will be "invisible" from the type point of view.
Closing in favour of #50 |
A first attempt at implementing the cholesky factorisation for Kronecker matrices, will close #10 if completed. Attempting to implement this has highlighted a few aspects of the codebase that we really should sort out:
GeneralizedKroneckerProduct <: AbstractMatrix{Number}
- this was bad causes type stability issues. If you don't parametriseGeneralisedKroneckerProduct{T}
, you wind up constructing things likeCholesky{Number, ...}
. This required quite a few changes throughout the codebase. Seems to work fine (tests pass), but of course I might have missed something. This also seems to resolve an issue whereby attempting to displayUpperTriangular(d)
for someKroneckerProduct
d
threw an error.UpperTriangular
andLowerTriangular
. ForCholesky
stuff to really work, we need this to work. The approach I've taken here is to cheat and makeUpperTriangular
of anAbstractKroneckerProduct
return anAbstractKroneckerProduct
ofUpperTriangular
matrices. While this makes sense mathematically I'm not sure that it's a great move semantically. It's also been causing some stack overflow errors that I've not managed to track down.I also took the (highly opinionated) liberty of renaming the files in
test
so that they don't begin with the wordtest
- this word being redundant as they're in thetest
folder. Please feel free to suggest that I revert this :)Let me know what you think :)