-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
Support extracting factors from cholfact(::SparseMatrixCSC) #10402
Conversation
sparse(L::Factor) = sparse(Sparse(L)) | ||
function sparse(L::Factor) | ||
A = Sparse(L) | ||
A*A' |
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 would have to check if it is an LDLt or an LLt version of Factor
. I'm sympathetic to changing the behavior of sparse(Factor)
, but then we'd have to consider the permutations. What is returned from this is still not the same as the input because of them.
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.
Ah, thank you, I missed all of those subtleties. If I understand correctly, you're fine with changing it as long as I get the logic right?
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.
Yes. That is correct.
OK, this is a much more comprehensive version. CHOLMOD supports the notion of "combined factors" like This will need some documentation, but I'll write that once we've settled on the functionality. In implementing this, I became a bit bothered by the asymmetries between dense and sparse (e.g., pivoting is on by default for sparse, but not for dense). From an algorithmic standpoint there are some excellent reasons for those choices, but it does mean that code receiving an
or you'll get errors in your results. (If you ignore the fact that I see a
The first seems like the most robust solution, followed by the second. |
That's a serious understatement. Disabling pivoting can be disastrous for performance in the sparse case. I don't like turning it off by default - it appears to be what Matlab does (which is not necessarily a good thing), and would be a bit more consistent, but it's not a very satisfactory way of dealing with this. I see your third item as mandatory, and second as a good idea, regardless of whether or not we decide to do the first. |
Yes, it would be a big performance hit. Moreover, in cases where the main use is F = cholfact(A)
x = F\b then permutation is not a source of error because it's all handled internally. So, I reluctantly agree that we can't disable pivoting by default for the sparse case. Should we conceivably turn it on for the dense case, just so the two are consistent? The problem is that would surely break any existing code that uses Maybe the best bet is to live with the inconsistency, but do items 2 and 3 above, and be very clear about this in the documentation. Curiously, this is an advantage of |
Out of curiosity, does anyone have a sense for the overhead on something like
where |
@@ -576,7 +617,7 @@ for Ti in IndexTypes | |||
d | |||
end | |||
|
|||
function spsolve{Tv<:VTypes}(sys::Integer, F::Factor{Tv,$Ti}, B::Sparse{Tv,$Ti}) | |||
function solve{Tv<:VTypes}(sys::Integer, F::Factor{Tv,$Ti}, B::Sparse{Tv,$Ti}) |
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.
The idea is to match the names in CHOLMOD for the wrappers. Then CHOLMOD can be the documentation for wrappers as well. If we begin to change that it will require documenting all the wrapper function ourself which I think would be the a waste of time.
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 agree there's merit in that, but it would have meant duplicating
Lines 1192 to 1224 in 137b19e
function (\){T,Ti}(L::FactorComponent{T,Ti,:L}, B::Union(Dense,Sparse)) | |
solve(CHOLMOD_L, Factor(L), B) | |
end | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:U}, B::Union(Dense,Sparse)) | |
solve(CHOLMOD_Lt, Factor(L), B) | |
end | |
# Solve PLx = b and L'P'x=b where A = P*L*L'*P' | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:PtL}, B::Union(Dense,Sparse)) | |
F = Factor(L) | |
solve(CHOLMOD_L, F, solve(CHOLMOD_P, F, B)) # Confusingly, CHOLMOD_P solves P'x = b | |
end | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:UP}, B::Union(Dense,Sparse)) | |
F = Factor(L) | |
solve(CHOLMOD_Pt, F, solve(CHOLMOD_Lt, F, B)) | |
end | |
# Solve various equations for A = L*D*L' and A = P*L*D*L'*P' | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:D}, B::Union(Dense,Sparse)) | |
solve(CHOLMOD_D, Factor(L), B) | |
end | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:LD}, B::Union(Dense,Sparse)) | |
solve(CHOLMOD_LD, Factor(L), B) | |
end | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:DU}, B::Union(Dense,Sparse)) | |
solve(CHOLMOD_DLt, Factor(L), B) | |
end | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:PtLD}, B::Union(Dense,Sparse)) | |
F = Factor(L) | |
solve(CHOLMOD_LD, F, solve(CHOLMOD_P, F, B)) | |
end | |
function (\){T,Ti}(L::FactorComponent{T,Ti,:DUP}, B::Union(Dense,Sparse)) | |
F = Factor(L) | |
solve(CHOLMOD_Pt, F, solve(CHOLMOD_DLt, F, B)) | |
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.
It would be great. If you loop through the types and names it is almost the same number of lines of code.
I agree with @tkelman that the default has to be pivoting for sparse matrices. I'm pretty sure the main use of sparse Cholesky is to solve |
OK, I've restored If you're fine with this, then I can add some documentation. However, if you're still thinking about the "bundling" of factors in |
It's a tradeoff between the convenience of special type and the challenge of communicating how the type works and when it should be used. For |
Might be best to let this simmer a bit then, and see how thoughts evolve over time---I agree that the correct path is not obvious. Just to summarize for the benefit of anyone else who wants to chime in:
Is that a fair summary? If not, feel free to edit this post directly. |
A few more than that. Not just binary yes/no are you using pivoting or not, there's also the question of which kind of pivoting you use. Partial? Complete? Rook? Rank-revealing? Bunch-Parlett? Bunch-Kaufman (and there are several variants, A, B, C, D)? Symmetric 1-by-1? Block-restricted versions of these? etc... edit: these would not necessarily need different API's for the outputs, but a Boolean input isn't quite rich enough to ask for different algorithm variants in the function call. Otherwise your summary is very fair. It's a messy, complicated problem space, that is challenging to design generalizable API's for. To slightly reduce the name salad we currently have with |
CC @alanedelman to see if he has any ideas (see two posts up). |
I still like the idea, but This brings us back to this issue because I'm wondering if we should explore the possibility of wrapping |
I kind of like the idea of wrapping it in something a little more informative. An However, the instantiation of the types in the dense and sparse cases is quite different, so I suspect these would have to become abstract/parametric types. |
Noted the reference on the mailing list. I'm not exactly sure where we left this. I guess I still favor the notion of "bundling" factors. @andreasnoack, what are your thoughts? I'm not in a massive rush; the project that needed this is currently on the back burner due to other priorities, but I hope to get back to it within a month or so, so by then it would be good to have a vision. |
I'm on board with the compound factors. |
OK, I'll try to get back to this once I finish #10911. |
Bump. Would be nice to merge this. |
Also supports extracting factors from ldltfact. A wide variety of "unconventional factors," like :PtL, are supported because of the importance of pivoting in sparse factorizations. This also: - changes the behavior of sparse(cholfact(A)) to return the original matrix, just like full(cholfact(A)) for dense matrices *breaking* - Doesn't export transpose(::Sparse, ::Integer) (that seems like an internal interface) - Adds support for ctranspose
Rebased and documentation added. |
Support extracting factors from cholfact(::SparseMatrixCSC)
Good stuff. |
The behavior this is intended to support is:
While I was at it, I noticed a couple of other issues that I thought should be fixed. The most important is that with this pull request,
sparse(cholfact(A))
now returns something equivalent to the original matrix, just likefull(cholfact(A))
does for dense matrices. This is a breaking change, but for consistency I think it seems warranted---it's my impression that the factorization object is supposed to be a representation of the original, not one of the factors.CC @andreasnoack