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

Cholesky Decomposition Fails for Larger Matrixes #7

Closed
pindash opened this issue Jun 8, 2017 · 10 comments
Closed

Cholesky Decomposition Fails for Larger Matrixes #7

pindash opened this issue Jun 8, 2017 · 10 comments

Comments

@pindash
Copy link

pindash commented Jun 8, 2017

A simple test case:
a:500 500#250000?1.0
a:.qml.mm[a;flip a]
.qml.mchol[a]

In particular I get a matrix full of 0n for larger matrix

A simple solution I came up with borrows from J software's implementation of Cholesky. found here:
http://code.jsoftware.com/wiki/Essays/Cholesky_Decomposition

Here is the code I used which recursively calculates the cholesky for larger matrices using smaller matrices
The Code assumes upper triangular Cholesky: I added this function to .qml
.qml.mchollarge:{[m] $[100>l:count m;
.qml.mchol[m];
[a:.5*l;
A:m[b;b:til l-floor[a]];
B:m[c:ceiling[a]+til l-ceiling[a];b];
C:m[c;c];
L0:.qml.mchollarge A;
L1:.qml.mchollarge C-.qml.mm[T: .qml.mm[B;.qml.minv A];flip B];
Z:(count first L3;count L3:flip .qml.mm[T;L0])#0f;
(l;l)#raze (L0,'L3),(Z,'L1)]]};

@pindash
Copy link
Author

pindash commented Jun 9, 2017

Hey Sorry, after trying to track down the error. It might be simply that my virtual machine that I'm using is screwing up the IEEE 754 floating point standard.

@pindash
Copy link
Author

pindash commented Jun 9, 2017

The issue has to do with unlucky picking of Floating point numbers. Apparently, there is a difference between how Linux (rhel specifically) and windows interact with Lapack. The solution that works well is to simply multiply the matrix by some scaling value before applying the cholesky this shifts the floating point representation and will usually cause the matrix decompose nicely.
here is the code that closes the issue:
.qml.pmchol:{[m] $[0<sum over null r:.qml.mchol[m];.qml.pmchol[p*m]%sqrt[p:first 2+1?10];r]};

@pindash pindash closed this as completed Jun 9, 2017
@zholos
Copy link
Owner

zholos commented Jun 9, 2017

For me the test case works both on Linux (Debian) and Windows. If you're linking to system LAPACK on RHEL (i.e. not using ./configure --build-blas), then perhaps the difference is due to different LAPACK versions.

@pindash
Copy link
Author

pindash commented Jun 9, 2017 via email

@zholos
Copy link
Owner

zholos commented Jun 10, 2017

You can attach the kdb file with the matrix (i.e. `:a set a) here if you like.

I think it's probably a numerical problem, but it could also be an issue with how LAPACK is compiled on different machines (e.g. different compiler flags), so I'd like to investigate.

@pindash
Copy link
Author

pindash commented Jun 12, 2017

Pretty sure it is a numerical problem, but it behaves differently on RHEL and Windows.
SpecCovMat.zip

@zholos
Copy link
Owner

zholos commented Jun 15, 2017

Thanks! .qml.mchol fails on this matrix for me too (on Debian). I think the matrix is just too big for double precision:

q).qml.mdet 203#'203#a
0w

I also tried using the recursive Cholesky function in LAPACK (dpotrf2 instead of dpotrf), which I think is the same as your recursive q code at the top, but that also fails.

@pindash
Copy link
Author

pindash commented Jun 15, 2017

The way I solved it for my matrix is I added the following:
.qml.pmchol:{[m;p] $[0<sum over null r:.qml.mchol[p*m];.qml.pmchol[m;first 1+1?100];r%sqrt[p]]};
For some reason multiplying by a small number will shift the matrix to be cholesky compatible. You can check if it works for you in debian. it's obviously an ugly solution.

Thanks again,

@zholos
Copy link
Owner

zholos commented Jun 16, 2017

Found the problem. This submatrix is not positive-definite (if that's a covariance matrix, you have perfect correlation between two variables):

q)a[202 203;202 203]
78.62156 77.39634
77.39634 76.1902 
q).qml.mdet a[202 203;202 203]
0f

Thus, the full matrix isn't positive-definite either, and .qml.mchol returns null as expected.

Fiddling around with a scaling factor will make it positive-definite numerically, kind of like:

q).qml.mchol (1 2;2 4)
 
 
q).qml.mchol (1 2;2 4)*1.000001
1 2.000001    
0 2.980232e-08

Dropping either of those variables works: .qml.mchol (a _202)_'202

I guess .qml.mchol does work on matrices that large after all.

@pindash
Copy link
Author

pindash commented Jun 20, 2017

I did that as well, but I don't think it actually has an eigen value of zero. I think it is just very close to zero:
https://www.wolframalpha.com/input/?i=upper+triangular+matrix+%7B%7B78.62156,+77.39634%7D,+%7B77.39634,+76.1902%7D%7D&lk=2

I guess how you treat matrixes that are close to being semi positive definite instead of positive definite is a question.

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

No branches or pull requests

2 participants