I am not accustomed to having to worry about numerical accuracy in my coding. However, I'm quickly realizing that I really should be.
I've learned about log_sum_exp trick, and I've been trying to compute things in log-space to avoid numerical underflow. (Any other general tips would be appreciated!)
My main question is: what do I need to know about high-dimensional symmetric matrices? I'd like to compute log determinants and the such. I'd also like to compute quadratic forms. (Presumably, there's a smart way to compute these without inverting the matrix?)
I'm seeing that Stan seems so use the LDLT Factor. Is this what I should read up on?
Thanks very much in advance,
Alp
P.S. This whole discussion began as I realized my algorithms were only stable until dimension = 5. I think this is because Eigen has closed-form implementations of things like determinants up to that dimension. (I may be wrong.) Because when I go to dimension = 6, I seem to lose a lot of numerical stability.
--
You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Both of your responses were very helpful. I will switch to LDL' form then.
In the meantime, if anyone else has any tricks like the "log_sum_exp", please feel free to share!
Cheers,
Alp
Thanks for the all the help.
Would you guys mind looking over the attached PDF? I think I've figured out how to do log abs determinants and quadratic forms. (Please do let me know if I got something wrong.) But I'm a bit confused by a trace that shows up in the inverse Wishart distribution.
Cheers,
Alp
The quadratic form can be cleaned up a bit,
LLT<MatrixXd> L = H.selfadjointView<Eigen::Lower>().ldlt();
Eigen::VectorXd y = L.solve(x);
quad = x.squaredNorm();
The trace is a tricker one and I'm surprised more people don't write it out more efficiently. Calling trace will be O(N^{3}) because of the intermediate matrix multiplication, but you can actually do it in O(N^{2}). In components,
Tr[A . B] = \sum_{ij} A_{ij} B_{ji} = A_{i-} B_{-i}
In other words, the trace is the inner product of the ith row of A with the ith column of B (or the other way around, it doesn't matter) summed over i.
Cheers,
Alp
Sorry. I should be clearer. (BTW: I appreciate all the help guys -- this is immensely useful.)
I have A_old at iteration t-1. It is in LDLT form.
I have computed it's gradient. Call it G. I have a closed-form expression for it.
I want to compute A_new at iteration t in LDLT form.
Currently, it seems like I need to do something like
A_new = LDLT<MatrixXd>(A_old.reconstructedMatrix() + G);
I guess what I'm asking is: there's no "trick" to avoid that LDLT, right?
Marcus: that makes sense. I came to a similar conclusion by looking at what Eigen offered for the LDLT class.
Ben: that's a really good point. However, I missed the subtlety about pivoting. Do I need to keep track of pivoting if I'm using "reconstrucedMatrix()" too?