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

Bug: using a non-diagonal metric matrix at identity yields the same geodesics every time #1884

Open
psarahdactyl opened this issue Sep 5, 2023 · 4 comments
Labels

Comments

@psarahdactyl
Copy link

psarahdactyl commented Sep 5, 2023

Describe the bug

I am using an InvariantMetric equipped on SO3 to compute a geodesic between two points. Besides not being able to equip the metric using the function geometry.manifold.Manifold.equip_with_metric from here, if I set the metric_mat_at_identity to a matrix with non-zero off-diagonal values, I get the same geodesic no matter what the values are.

Steps/Code to Reproduce

import os
os.environ["GEOMSTATS_BACKEND"] = "autograd"
import geomstats

import numpy as np

import geomstats.backend as gs
from geomstats.algebra_utils import from_vector_to_diagonal_matrix
from geomstats.geometry.invariant_metric import InvariantMetric
from geomstats.geometry.special_orthogonal import SpecialOrthogonal

a = np.linspace(0.001, 30., num=5)
from itertools import combinations, permutations, product

SO3 = SpecialOrthogonal(n=3, point_type="matrix")

rot1 = gs.eye(3)
rot2 = SO3.random_point()

alpha = 2.
beta = 3.

# print(rot1, rot2)
times = gs.arange(0.0, 1.0, 0.1)

mats = []
for triplet in set(product(set(a),repeat = 3)):
#     print("triplet", triplet)
    gamma = triplet[0]
    delta = triplet[1]
    xi = triplet[2]
    
    # here i am fixing alpha and beta and just setting the off-diagonal values
    if gamma != 0 and delta != 0 and xi != 0:
        # when the metric mat is this, my geodesics are the same every time
        metric_mat = gs.array([
             [1., gamma, delta],
             [gamma, alpha, xi],
             [delta, xi, beta]])
    else:
        # when the metric mat is this, things work as expected
        metric_mat = from_vector_to_diagonal_matrix(gs.array([1, alpha, beta]))

    metric_kwargs = {
        "metric_mat_at_identity": metric_mat,
        "left": True,
    }

    SO3_metric_from_z = InvariantMetric( 
        space=SO3, metric_mat_at_identity=metric_mat, left=True
    )

    # doesn't work, get error "TypeError: '_InvariantMetricMatrix' object is not callable"
#     SO3.equip_with_metric(SO3_metric_from_z, **metric_kwargs)

    SO3.metric = SO3_metric_from_z

    # so here i just call the geodesic function directly from the metric instead of the group, 
    # bc i don't know if the group was properly equipped from the above line
    points_mat = SO3_metric_from_z.geodesic(initial_point=rot1, end_point=rot2)(times)
    print(points_mat[3]) # these are the exact same for each loop iteration
    print("loc", id(points_mat)) # showing myself that they're different locations in memory
    mats.append(points_mat)

Expected Behaviour

I expect different geodesics to be produced from different metrics.

Actual Behaviour

I get the same geodesic every iteration.

If I try to equip the metric with this line

SO3.equip_with_metric(SO3_metric_from_z, **metric_kwargs)

I get this error:

---> 48     SO3_loop.equip_with_metric(Metric=SO3_metric_from_z, **metric_kwargs)


File ~/Library/Python/3.10/lib/python/site-packages/geomstats/geometry/manifold.py:83, in Manifold.equip_with_metric(self, Metric, **metric_kwargs)
     80     else:
     81         Metric = out
---> 83 self.metric = Metric(self, **metric_kwargs)

TypeError: '_InvariantMetricMatrix' object is not callable

Your environment

Geomstats' latest master branch (2.7.0)
MacOS but coding in a jupyter notebook
Python 3.10.2
@luisfpereira
Copy link
Collaborator

@psarahdactyl, following the code flow, the reason for the independence of the geodesics is the way inner_product_at_identity is implemented: if the metric matrix is not diagonal, then this inner product is given by the Frobenius product of the two tangent vectors, i.e. it makes no use of the metric matrix, hence the independence.

@nguigs, @ninamiolane, is this the expected behavior?

@ninamiolane
Copy link
Collaborator

Thanks for the quick answer! No, that is not the expected behavior.

Paper: https://arxiv.org/pdf/2103.01585.pdf.
I don't see anything in the theory of @nguigs 's paper that would require a diagonal metric matrix.
However, I note that @nguigs only experiments with for a diagonal metric matrix in section 4.3.

If possible: let's see if we can use @nguigs 's code for non-diagonal metric matrix?
In the meantime, the expected behavior should be that an error message ("not implemented") is returned if the matrix is not diagonal.

@nguigs
Copy link
Collaborator

nguigs commented Sep 6, 2023

The theory indeed should work in general, but the implementation is for diagonal metric only because of reshape_metric_matrix that is used to easily compute the inner product:

tan_b = tangent_vec_b * self.reshaped_metric_matrix

@luisfpereira
Copy link
Collaborator

To extend to non-diagonal matrices we simply need to get the basis representation from the Lie algebra and perform the "normal" computations, right @nguigs? Is there any other part of the code that needs to be updated?

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

No branches or pull requests

4 participants