-
Notifications
You must be signed in to change notification settings - Fork 275
Cholesky space #1142
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 space #1142
Conversation
|
Hi Saiteja! |
Hey @nguigs . yup LT+ is a lie group. The metric is constructed by imposing different kinds of inner products on strictly lower part and diagonal elements (this metric doesn't have name). this is actually bi-invariant metric Then this metric is push forwarded to SPD space, this is called Log Cholesky metric . Log cholesky metric has lots of nice properties and is kind of best of two worlds (Log euclidean, Affine Invariant ). It has closed form expression for Frechet mean and easily computable expressions for parallel trasnport, R-log , R-exp maps . So, I don't think this is equivalent to Affine Invariant Metric? here is the paper : https://arxiv.org/abs/1908.09326 |
Only the left-invariant metric with 2 on the diagonal and 1 on other coefficients is equivalent to AI metric when pushed to SPD. The others are different. This is good to test the implementation |
|
Wooohoo, thanks for this! As @nguigs mentioned, we should have On a minor note, maybe check your docstrings, there are periods missing at the end of descriptions here and there, e.g.: and at other places. Otherwise this is awesome, can't wait for the tests. |
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.
Good start!
I think we should discuss the naming though. Firstly, I'm not sure the naming Cholesky space is justified and well known enough, maybe we should stick to something more informative (PositiveLowerTriangular?).
This is even more the case for the metrics. I think the one you are implementing is called Log-Cholesky, and we should be precise because we can implement other ones such as Euclidean-Cholesky, LogEuclidean-Cholesky, and invariant metrics.
@ythanwerdas what do you think?
| @classmethod | ||
| def is_diagonal(cls, mat, atol=gs.atol): | ||
| """Check if a matrix is square and diagonal. | ||
| Parameters | ||
| ---------- | ||
| mat : array-like, shape=[..., n, n] | ||
| Matrix. | ||
| atol : float | ||
| Absolute tolerance. | ||
| Optional, default: backend atol. | ||
| Returns | ||
| ------- | ||
| is_diagonal : array-like, shape=[...,] | ||
| Boolean evaluating if the matrix is square and diagonal. | ||
| """ | ||
| is_square = cls.is_square(mat) | ||
| if not gs.all(is_square): | ||
| return False | ||
| diagonal_mat = from_vector_to_diagonal_matrix(cls.diagonal(mat)) | ||
| is_diagonal = gs.all( | ||
| gs.isclose(mat, diagonal_mat, atol=atol), axis=(-2, -1)) | ||
| return is_diagonal |
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 does this appear in this PR?
geomstats/geometry/cholesky.py
Outdated
| vec_diag = gs.exp(gs.diagonal(point, axis1 = -2, axis2 = -1)) | ||
| diag = gs.vec_to_diag(vec_diag) | ||
| strictly_lower_triangular = Matrices.to_lower_triangular(point) | ||
| projection = diag + strictly_lower_triangular | ||
| return projection |
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.
Ideally, the projection should minimize the Frobenius norm. This is tricky as we have an open set here, but one property that must be verified for a projection function p is p(p(x))=p(x) for all x, i.e. p(x)=x if x is already in the manifold.
This is not the case here, so maybe only do the projection if point does not already belong to LT+, or use epsilon to floor negative values of the diagonal.
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.
@nguigs nice catch! I forgot we should we have p(p(x))=x. I am using abs to make sure this happens
geomstats/geometry/cholesky.py
Outdated
| ip_diagonal = gs.einsum("...ii,...ii ,...i->...", | ||
| tangent_vec_a, tangent_vec_b, inv_sqrt_diagonal) |
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 think our torch and tf einsum don't work with 3 inputs, but you can use tangent_vec_b * inv_sqrt_diagonal or two lines instead.
|
Maybe the Riemannian metric on SPD could be a PullBack metric @ninamiolane ? |
|
Dear all, let me give you an overview of Riemannian metrics on SPD matrices based on the Cholesky decomposition to help you decide the names. First of all, Saiteja and Nicolas don't speak about the same Lie group structure. For Nicolas, the internal law is the matrix multiplication. For Saiteja, following Zhenhua Lin, the Lie group structure is a direct product of Lie groups: additive on the strict lower triangular matrix and multiplicative on the diagonal. By the way, it is even a vector space structure. Otherwise said, there is a diffeomorphism from LT^+(n) to the vector space LT(n) which is identity on the off-diagonal part and logarithm on the diagonal part. I am preparing a paper on left-invariant metrics on the multiplicative Lie group LT^+(n), I will update this comment with the preprint as soon as it is available. I call Lie-Cholesky metrics the pullbacks of these metrics onto SPD matrices. Zhenhua Lin calls log-Cholesky the metric Saiteja is implementing in this PR. Some people use directly the Euclidean metric on LT^+(n) and the pullback onto SPD matrices has been called "Cholesky metric" (see chapter 3 of Riemannian Geometric Statistics in Medical Image Analysis). It could be called Euclidean-Cholesky to avoid confusions. Another vector space parameterization is given by the matrix logarithm which sends diffeomorphically LT^+(n) onto LT(n) (see this paper). This is also geodesically complete of course. The pullback onto SPD matrices could be called log-Euclidean-Cholesky to avoid confusions again. I don't have opinion on the naming of the space, Cholesky or PositiveLowerTriangular have different advantages. One last comment if I may, from a modelling point of view, I wouldn't say that log-Cholesky is better than log-Euclidean and affine-invariant since it is not invariant under orthogonal transformations and not even under permutations. It means that changing the order of the axes (representing your signals for example if your SPD matrices are covariance matrices) would change the statistical analysis. This property depends on the application but in many cases, we would like the analysis to be independent under orthogonal transformations (at least). |
|
Yes, this metric should inherit from the PullbackMetric, while still overwriting most methods: if we can use closed forms instead of automatic differentiation the results will be better. I agree with having Thanks @ythanwerdas for the inputs on the classification of metrics for SPD matrices 🙌 |
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.
Very nice, I think we will be able to merge this great PR today 🎉 High-level comments:
- I have important comments/questions on the structure of the algebraic tools in the backends, see inlines.
- Some tests do not include tests on minibatch, aka
_vectorizationtests - DeepSource is failing (there's not much to do, though)
- Can you make a pass on all the docstrings?
- Some docstrings are not right (I believed you copy pasted something but then didn't edit it)
- Some words have uppercase in the docstrings:
- cholesky -> Cholesky
- spd -> SPD
- Some "." are missing here and there.
Thank you very much for this!
tests/tests_geomstats/test_positive_lower_triangular_matrices.py
Outdated
Show resolved
Hide resolved
|
|
||
| @classmethod | ||
| def inner_product(cls, tangent_vec_a, tangent_vec_b, base_point): | ||
| """Compute the inner product using only strictly lower triangular elements. |
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.
Adapt the docstring
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.
Almost there! A few cosmetic comments to address (e.g. see my previous code review comments on the docstrings' cleanup).
Will be merged very soon! 🎉
| return tf.tile(x_reshape, multiples) | ||
|
|
||
|
|
||
| def vec_to_diag(vec): |
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.
Put on top of the file as, see:
|
|
||
| @classmethod | ||
| def inner_product(cls, tangent_vec_a, tangent_vec_b, base_point): | ||
| """Compute the inner product using only strictly lower triangular elements. |
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 copy-pasting has had a problem)
| @@ -0,0 +1,291 @@ | |||
| """Unit tests for Positive lower triangular matrices""" | |||
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.
and double space between lower and triangular
tests/tests_geomstats/test_positive_lower_triangular_matrices.py
Outdated
Show resolved
Hide resolved
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.
Moving to "request changes" to clean up docstrings and address other minor comments. Excellent work, looking forward to merge.
|
@ninamiolane ready to merge. deep source is complaining about test files. that is fine though. |
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.
@SaitejaUtpala there are still some comments to be addressed + can you look at how this integrates with the PR #1232 merged two days ago? Someone needed triu, and we didn't want to wait until the Cholesky PR is merged thus it got merged. Thank you very much!
| return gs.tril_to_vec(mat) | ||
|
|
||
| def projection(self, point): | ||
| """Make a square matrix lower triangular. |
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.
geomstats/geometry/matrices.py
Outdated
| Returns | ||
| ------- | ||
| is_triu : array-like, shape=[...,] | ||
| Boolean evaluating if the matrix is upper triangular |
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.
|
|
||
| @staticmethod | ||
| def gram(point): | ||
| """Compute gram matrix of rows |
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.
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.
Fantastic, thank you very much!
This PR implements following things