Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@SaitejaUtpala
Copy link
Collaborator

@SaitejaUtpala SaitejaUtpala commented Sep 7, 2021

This PR implements following things

  • vector space of lower triangular matrices
    • geometry
    • tests
  • cholesky space : manifold of lower triangular matrices with positive diagonal elements (as open submanifold of lower triangular matrices)
    • geometry
    • tests
  • Riemannian metric on choleksy space
    • metric
    • tests

@SaitejaUtpala SaitejaUtpala marked this pull request as draft September 7, 2021 05:14
@nguigs
Copy link
Collaborator

nguigs commented Sep 7, 2021

Hi Saiteja!
Great input! In fact the space of lower triangular matrices with positive diag (LT+) is a Lie group, and the vector space of LT matrices is its Lie algebra, so it should be implemented with the additional structure.
What metrics did you have in mind for LT+ ?
It can be embedded with left-invariant metrics, and there is one that coincides with the affine-invariant one on SPD. I have code that checks this.

@SaitejaUtpala
Copy link
Collaborator Author

SaitejaUtpala commented Sep 7, 2021

Hi Saiteja!
Great input! In fact the space of lower triangular matrices with positive diag (LT+) is a Lie group, and the vector space of LT matrices is its Lie algebra, so it should be implemented with the additional structure.
What metrics did you have in mind for LT+ ?
It can be embedded with left-invariant metrics, and there is one that coincides with the affine-invariant one on SPD. I have code that checks this.

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

@nguigs
Copy link
Collaborator

nguigs commented Sep 7, 2021

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?

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

@ninamiolane
Copy link
Collaborator

Wooohoo, thanks for this! As @nguigs mentioned, we should have Cholesky inherits from LieGroup too.

On a minor note, maybe check your docstrings, there are periods missing at the end of descriptions here and there, e.g.:

    @classmethod
    def differential_gram(cls, tanget_vec, base_point):
        """Compute gram matrix of rows  
        Gram_matrix is mapping from point to point.point^{T}. 
        This is diffeomorphism between cholesky space and spd manifold

and at other places.

Otherwise this is awesome, can't wait for the tests.

Copy link
Collaborator

@nguigs nguigs left a 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?

Comment on lines 245 to 308
@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
Copy link
Collaborator

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?

Comment on lines 68 to 72
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
Copy link
Collaborator

@nguigs nguigs Sep 14, 2021

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.

Copy link
Collaborator Author

@SaitejaUtpala SaitejaUtpala Sep 26, 2021

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

Comment on lines 191 to 192
ip_diagonal = gs.einsum("...ii,...ii ,...i->...",
tangent_vec_a, tangent_vec_b, inv_sqrt_diagonal)
Copy link
Collaborator

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.

@nguigs
Copy link
Collaborator

nguigs commented Sep 14, 2021

Maybe the Riemannian metric on SPD could be a PullBack metric @ninamiolane ?

@ythanwerdas
Copy link
Collaborator

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).

@ninamiolane
Copy link
Collaborator

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 LowerTriangularMatrices and LowerTriangularPositiveMatrices, even if it is long: it is more self-explanatory and I am indeed not sure that everybody knows the term CholeskySpace.

Thanks @ythanwerdas for the inputs on the classification of metrics for SPD matrices 🙌

Copy link
Collaborator

@ninamiolane ninamiolane left a 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 _vectorization tests
  • 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!


@classmethod
def inner_product(cls, tangent_vec_a, tangent_vec_b, base_point):
"""Compute the inner product using only strictly lower triangular elements.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adapt the docstring

Copy link
Collaborator

@ninamiolane ninamiolane left a 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):
Copy link
Collaborator

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.
Copy link
Collaborator

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"""
Copy link
Collaborator

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

Copy link
Collaborator

@ninamiolane ninamiolane left a 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.

@SaitejaUtpala
Copy link
Collaborator Author

@ninamiolane ready to merge. deep source is complaining about test files. that is fine though.

Copy link
Collaborator

@ninamiolane ninamiolane left a 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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns
-------
is_triu : array-like, shape=[...,]
Boolean evaluating if the matrix is upper triangular
Copy link
Collaborator

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

@ninamiolane ninamiolane left a 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!

@ninamiolane ninamiolane merged commit 7649949 into geomstats:master Dec 17, 2021
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

Successfully merging this pull request may close these issues.

4 participants