Closed bob-carpenter closed 10 years ago
Moving this discussion from stan-dev; questions are mine, answers are Ben's:
Q: I pushed a branch from develop that has everything stubbed out that we'll need to add a Cholesky factor of correlation matrices type:
feature/corr-cholesky-type
Sorry there's not an issue, but I started doing this on the plane w/o an internet connection. Is there a way to change the name of a branch?
A:
git branch -m
Q: What we need to add is:
A: read_corr_L
already does the transformation from CPCs to L
I just pushed factor_L
which does the transformation from L to CPCs
We already have the infrastructure in place to transform CPCs to or from the unconstrained space
Q: Do I need to do anything more in transform.hpp?
A: We also need a density for L such that LL' is LKJ(eta).
Q: Does this also need to allow rectangular sizes?
A: I suppose, but we can do the square ones first.
Q: And are there constraints on the rectangular sizes for the ordinary Cholesky factors for symmetric, positive definite matrices?
A: At least as many rows as there are columns
feature/issue-413-cholesky-corr-type
Why is there a cov_matrix_free_lkj()
function in prob/transforms.hpp
? It's not getting used anywhere I can see in src/stan
.
Should we have cholesky_corr_free
(perhaps via factor_L
) throws an exception if L
is not a Cholesky factor for a correlation matrix?
This is another example of a function that's being called only from our own code when we know it will work because it's going to operate on a variable of type cholesky_corr
.
@bgoodri Why go through an array in factor_L
the body of which is L.diagonal().array().inverse().diagonal()
?
For a large matrix, verifying that the rows of L are normalized would be somewhat expensive for an internal function. I think L.diagonal() is an expression template for a vector, which doesn't have an .inverse() method. Maybe that is wrong, but in any event, .array() and .matrix() are no-ops.
I think cov_matrix_free_lkj()
is left over from the days when the mapping from a covariance matrix to the unbounded space first decomposed the covariance matrix into a diagonal matrix of standard deviations and a correlation matrix, which were separately mapped to the unbounded space. Now that the primitive of a covariance matrix is just a Cholesky factor, I don't think cov_matrix_free_lkj()
is needed
It's not technically a no-op --- it's an expression template and hence requires a constructor call, which requires a bit of stack-based storage (not heap, so no malloc penalty). The indirection in calls through the expression template should be inlineable away, though.
I'm not sure about whether the expression template for .diagonal() supports .inverse() --- it's the Wild West with template specializations in C++!
On 12/7/13, 6:14 PM, bgoodri wrote:
For a large matrix, verifying that the rows of L are normalized would be somewhat expensive for an internal function. I think L.diagonal() is an expression template for a vector, which doesn't have an .inverse() method. Maybe that is wrong, but in any event, .array() and .matrix() are no-ops.
It inherits from MatrixBase so .inverse() for something not square yields an error novel
#include<Eigen/Dense>
#include<iostream>
int main() {
Eigen::Matrix3d m = Eigen::Matrix3d::Random();
std::cout << m.diagonal().inverse() << std::endl;
return 0;
}
Ben
On Sat, Dec 7, 2013 at 8:53 PM, Bob Carpenter notifications@github.comwrote:
It's not technically a no-op --- it's an expression template and hence requires a constructor call, which requires a bit of stack-based storage (not heap, so no malloc penalty). The indirection in calls through the expression template should be inlineable away, though.
I'm not sure about whether the expression template for .diagonal() supports .inverse() --- it's the Wild West with template specializations in C++!
- Bob
On 12/7/13, 6:14 PM, bgoodri wrote:
For a large matrix, verifying that the rows of L are normalized would be somewhat expensive for an internal function. I think L.diagonal() is an expression template for a vector, which doesn't have an .inverse() method. Maybe that is wrong, but in any event, .array() and .matrix() are no-ops.
— Reply to this email directly or view it on GitHubhttps://github.com/stan-dev/stan/issues/413#issuecomment-30072859 .
@bgoodri Could you add a test for factor_L
in transform.hpp? I can't get it instantiated:
src/stan/prob/transform.hpp:118:54: error: no member named 'diagonal' in
'Eigen::ArrayBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_inverse_op<double>, const
Eigen::ArrayWrapper<const Eigen::Diagonal<const Eigen::Matrix<double, -1, -1, 0, -1, -1>, 0> > >
>'
= L * L.diagonal().array().inverse().array().diagonal();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
src/stan/prob/transform.hpp:1499:7: note: in instantiation of function template specialization
'stan::prob::factor_L<double>' requested here
factor_L(cpcs,L);
^
src/stan/io/writer.hpp:407:13: note: in instantiation of function template specialization
'stan::prob::cholesky_corr_free<double>' requested here
= stan::prob::cholesky_corr_free(y);
Also, what's the right drill w.r.t. Git here? I can probably stub things out to where they don't work, but at least they'll compile. Should I do that and push it?
We can worry about efficiency later -- I can't even get it to compile.
I have everything else compiling now, but am blocked on how to get the factor_L thing working. (In my branch, I've just stubbed out the bit that won't compile.)
Here's the minimal example of the expression you're trying to evaluate in factor_L() in prob/transform.hpp:
#include <Eigen/Dense>
int main() {
Eigen::MatrixXd L(2,2);
L << 1, 0, 0, 1;
Eigen::MatrixXd foo = L * ( L.diagonal().array().inverse().diagonal() );
}
It produces this error:
$ clang++ -I ~/stan/lib/eigen_3.2.0/ test.cpp
test.cpp:6:62: error: no member named 'diagonal' in 'Eigen::CwiseUnaryOp<Eigen::internal::scalar_inverse_op<double>, const
Eigen::ArrayWrapper<Eigen::Diagonal<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 0> > >'
Eigen::MatrixXd foo = L * ( L.diagonal().array().inverse().diagonal() );
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
1 error generated.
I fixed it. It needed to be asDiagonal() rather than diagonal() and with a vector that inherits from MatrixBase rather than ArrayBase. The test I added might conflict with your unpushed stuff but it should be easy to harmonize it.
Thanks. I'll merge and give it a go.
On 12/8/13, 9:43 AM, bgoodri wrote:
I fixed it. It needed to be asDiagonal() rather than diagonal() and with a vector that inherits from MatrixBase rather than ArrayBase. The test I added might conflict with your unpushed stuff but it should be easy to harmonize it.
— Reply to this email directly or view it on GitHub https://github.com/stan-dev/stan/issues/413#issuecomment-30082895.
I've already started a branch:
and what remains is:
Unit testing's going to be a big hurdle here because nothing that came before has proper unit tests.
I have a question about whether we want to do the following, and if so if there's a requirement that M < N or something like that (for this and covariance matrix factors, which we'll rename):