Example #1
0
 def test_compose(self, n, point_type, point_a, point_b, expected):
     group = SpecialOrthogonal(n, point_type)
     result = group.compose(point_a, point_b)
     self.assertAllClose(result, expected)
Example #2
0
 def test_compose_with_inverse_is_identity(self, space_args):
     group = SpecialOrthogonal(*space_args)
     point = gs.squeeze(group.random_point())
     inv_point = group.inverse(point)
     self.assertAllClose(group.compose(point, inv_point), group.identity)
class TestSpecialOrthogonal(geomstats.tests.TestCase):
    def setUp(self):
        self.n = 2
        self.group = SpecialOrthogonal(n=self.n)
        self.n_samples = 4

    def test_dim(self):
        for n in [2, 3, 4, 5, 6]:
            group = SpecialOrthogonal(n=n)
            result = group.dim
            expected = n * (n - 1) / 2
            self.assertAllClose(result, expected)

    def test_belongs(self):
        theta = gs.pi / 3
        point_1 = gs.array([[gs.cos(theta), - gs.sin(theta)],
                            [gs.sin(theta), gs.cos(theta)]])
        result = self.group.belongs(point_1)
        self.assertTrue(result)

        point_2 = gs.array([[gs.cos(theta), gs.sin(theta)],
                            [gs.sin(theta), gs.cos(theta)]])
        result = self.group.belongs(point_2)
        self.assertFalse(result)

        point = gs.array([point_1, point_2])
        expected = gs.array([True, False])
        result = self.group.belongs(point)
        self.assertAllClose(result, expected)

        point = point_1[0]
        result = self.group.belongs(point)
        self.assertFalse(result)

        point = gs.zeros((2, 3))
        result = self.group.belongs(point)
        self.assertFalse(result)

        point = gs.zeros((2, 2, 3))
        result = self.group.belongs(point)
        self.assertFalse(gs.all(result))

    def test_random_uniform_and_belongs(self):
        point = self.group.random_uniform()
        result = self.group.belongs(point)
        expected = True
        self.assertAllClose(result, expected)

        point = self.group.random_uniform(self.n_samples)
        result = self.group.belongs(point)
        expected = gs.array([True] * self.n_samples)
        self.assertAllClose(result, expected)

    def test_identity(self):
        result = self.group.identity
        expected = gs.eye(self.n)
        self.assertAllClose(result, expected)

    def test_is_in_lie_algebra(self):
        theta = gs.pi / 3
        vec_1 = gs.array([[0., - theta],
                         [theta, 0.]])
        result = self.group.is_tangent(vec_1)
        self.assertTrue(result)

        vec_2 = gs.array([[0., - theta],
                         [theta, 1.]])
        result = self.group.is_tangent(vec_2)
        self.assertFalse(result)

        vec = gs.array([vec_1, vec_2])
        result = self.group.is_tangent(vec)
        expected = gs.array([True, False])
        self.assertAllClose(result, expected)

    def test_is_tangent(self):
        point = self.group.random_uniform()
        theta = 1.
        vec_1 = gs.array([[0., - theta],
                         [theta, 0.]])
        vec_1 = self.group.compose(point, vec_1)
        result = self.group.is_tangent(vec_1, point)
        self.assertTrue(result)

        vec_2 = gs.array([[0., - theta],
                         [theta, 1.]])
        vec_2 = self.group.compose(point, vec_2)
        result = self.group.is_tangent(vec_2, point)
        self.assertFalse(result)

        vec = gs.array([vec_1, vec_2])
        point = gs.array([point, point])
        expected = gs.array([True, False])
        result = self.group.is_tangent(vec, point)
        self.assertAllClose(result, expected)

    def test_to_tangent(self):
        theta = 1.
        vec_1 = gs.array([[0., - theta],
                         [theta, 0.]])
        result = self.group.to_tangent(vec_1)
        expected = vec_1
        self.assertAllClose(result, expected)

        n_samples = self.n_samples
        base_points = self.group.random_uniform(n_samples=n_samples)
        tangent_vecs = self.group.compose(base_points, vec_1)
        result = self.group.to_tangent(tangent_vecs, base_points)
        expected = tangent_vecs
        self.assertAllClose(result, expected)

    def test_projection_and_belongs(self):
        gs.random.seed(4)
        shape = (self.n_samples, self.n, self.n)
        result = helper.test_projection_and_belongs(
            self.group, shape, gs.atol * 100)
        for res in result:
            self.assertTrue(res)

    def test_skew_to_vec_and_back(self):
        group = SpecialOrthogonal(n=4)
        vec = gs.random.rand(group.dim)
        mat = group.skew_matrix_from_vector(vec)
        result = group.vector_from_skew_matrix(mat)
        self.assertAllClose(result, vec)

    def test_parallel_transport(self):
        metric = self.group.bi_invariant_metric
        shape = (self.n_samples, self.group.n, self.group.n)

        results = helper.test_parallel_transport(self.group, metric, shape)
        for res in results:
            self.assertTrue(res)

    def test_metric_left_invariant(self):
        group = self.group
        point = group.random_point()
        tangent_vec = self.group.lie_algebra.basis[0]
        expected = group.bi_invariant_metric.norm(
            tangent_vec)

        translated = group.tangent_translation_map(point)(tangent_vec)
        result = group.bi_invariant_metric.norm(translated)
        self.assertAllClose(result, expected)

    @geomstats.tests.np_and_tf_only
    def test_distance_broadcast(self):
        group = self.group
        point = group.random_point(5)
        result = group.bi_invariant_metric.dist_broadcast(point[:3], point)
        expected = []
        for a in point[:3]:
            expected.append(group.bi_invariant_metric.dist(a, point))
        expected = gs.stack(expected)
        self.assertAllClose(result, expected)
class TestSpecialOrthogonal2(geomstats.tests.TestCase):
    def setup_method(self):
        warnings.simplefilter("ignore", category=ImportWarning)
        warnings.simplefilter("ignore", category=UserWarning)

        gs.random.seed(1234)

        self.group = SpecialOrthogonal(n=2, point_type="vector")

        # -- Set attributes
        self.n_samples = 4

    def test_projection(self):
        # Test 2D and nD cases
        rot_mat = gs.eye(2)
        delta = 1e-12 * gs.ones((2, 2))
        rot_mat_plus_delta = rot_mat + delta
        result = self.group.projection(rot_mat_plus_delta)
        expected = rot_mat
        self.assertAllClose(result, expected)

    def test_projection_vectorization(self):
        n_samples = self.n_samples
        mats = gs.ones((n_samples, 2, 2))
        result = self.group.projection(mats)
        self.assertAllClose(gs.shape(result), (n_samples, 2, 2))

    def test_skew_matrix_from_vector(self):
        rot_vec = gs.array([0.9])
        skew_matrix = self.group.skew_matrix_from_vector(rot_vec)
        result = gs.matmul(skew_matrix, skew_matrix)
        diag = gs.array([-0.81, -0.81])
        expected = algebra_utils.from_vector_to_diagonal_matrix(diag)
        self.assertAllClose(result, expected)

    def test_skew_matrix_and_vector(self):
        rot_vec = gs.array([0.8])

        skew_mat = self.group.skew_matrix_from_vector(rot_vec)
        result = self.group.vector_from_skew_matrix(skew_mat)
        expected = rot_vec

        self.assertAllClose(result, expected)

    def test_skew_matrix_from_vector_vectorization(self):
        n_samples = self.n_samples
        rot_vecs = self.group.random_uniform(n_samples=n_samples)
        result = self.group.skew_matrix_from_vector(rot_vecs)

        self.assertAllClose(gs.shape(result), (n_samples, 2, 2))

    def test_random_uniform_shape(self):
        result = self.group.random_uniform()
        self.assertAllClose(gs.shape(result), (self.group.dim, ))

    def test_random_and_belongs(self):
        point = self.group.random_uniform()
        result = self.group.belongs(point)
        expected = True
        self.assertAllClose(result, expected)

    def test_random_and_belongs_vectorization(self):
        n_samples = self.n_samples
        points = self.group.random_uniform(n_samples=n_samples)
        result = self.group.belongs(points)
        expected = gs.array([True] * n_samples)
        self.assertAllClose(result, expected)

    def test_regularize(self):
        angle = 2 * gs.pi + 1
        result = self.group.regularize(gs.array([angle]))
        expected = gs.array([1.0])
        self.assertAllClose(result, expected)

    def test_regularize_vectorization(self):
        n_samples = self.n_samples
        rot_vecs = self.group.random_uniform(n_samples=n_samples)
        result = self.group.regularize(rot_vecs)

        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

    def test_matrix_from_rotation_vector(self):
        angle = gs.pi / 3
        expected = gs.array([[1.0 / 2, -gs.sqrt(3.0) / 2],
                             [gs.sqrt(3.0) / 2, 1.0 / 2]])
        result = self.group.matrix_from_rotation_vector(gs.array([angle]))
        self.assertAllClose(result, expected)

    def test_matrix_from_rotation_vector_vectorization(self):
        n_samples = self.n_samples
        rot_vecs = self.group.random_uniform(n_samples=n_samples)

        rot_mats = self.group.matrix_from_rotation_vector(rot_vecs)

        self.assertAllClose(gs.shape(rot_mats),
                            (n_samples, self.group.n, self.group.n))

    def test_rotation_vector_from_matrix(self):
        angle = 0.12
        rot_mat = gs.array([[gs.cos(angle), -gs.sin(angle)],
                            [gs.sin(angle), gs.cos(angle)]])
        result = self.group.rotation_vector_from_matrix(rot_mat)
        expected = gs.array([0.12])

        self.assertAllClose(result, expected)

    def test_rotation_vector_and_rotation_matrix(self):
        """
        This tests that the composition of
        rotation_vector_from_matrix
        and
        matrix_from_rotation_vector
        is the identity.
        """
        # TODO(nguigs): bring back a 1d representation of SO2
        point = gs.array([0.78])

        rot_mat = self.group.matrix_from_rotation_vector(point)
        result = self.group.rotation_vector_from_matrix(rot_mat)

        expected = point

        self.assertAllClose(result, expected)

    def test_rotation_vector_and_rotation_matrix_vectorization(self):
        rot_vecs = gs.array([[2.0], [1.3], [0.8], [0.03]])

        rot_mats = self.group.matrix_from_rotation_vector(rot_vecs)
        result = self.group.rotation_vector_from_matrix(rot_mats)

        expected = self.group.regularize(rot_vecs)

        self.assertAllClose(result, expected)

    def test_compose(self):
        point_a = gs.array([0.12])
        point_b = gs.array([-0.15])
        result = self.group.compose(point_a, point_b)
        expected = self.group.regularize(gs.array([-0.03]))
        self.assertAllClose(result, expected)

    def test_compose_and_inverse(self):
        angle = 0.986
        point = gs.array([angle])
        inv_point = self.group.inverse(point)
        result = self.group.compose(point, inv_point)
        expected = self.group.identity
        self.assertAllClose(result, expected)

        result = self.group.compose(inv_point, point)
        expected = self.group.identity
        self.assertAllClose(result, expected)

    def test_compose_vectorization(self):
        point_type = "vector"
        self.group.default_point_type = point_type

        n_samples = self.n_samples
        n_points_a = self.group.random_uniform(n_samples=n_samples)
        n_points_b = self.group.random_uniform(n_samples=n_samples)
        one_point = self.group.random_uniform(n_samples=1)

        result = self.group.compose(one_point, n_points_a)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

        result = self.group.compose(n_points_a, one_point)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

        result = self.group.compose(n_points_a, n_points_b)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

    def test_inverse_vectorization(self):
        n_samples = self.n_samples
        points = self.group.random_uniform(n_samples=n_samples)
        result = self.group.inverse(points)

        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

    def test_group_exp(self):
        """
        The Riemannian exp and log are inverse functions of each other.
        This test is the inverse of test_log's.
        """
        rot_vec_base_point = gs.array([gs.pi / 5])
        rot_vec = gs.array([2 * gs.pi / 5])

        expected = gs.array([3 * gs.pi / 5])
        result = self.group.exp(base_point=rot_vec_base_point,
                                tangent_vec=rot_vec)
        self.assertAllClose(result, expected)

    def test_group_exp_vectorization(self):
        n_samples = self.n_samples

        one_tangent_vec = self.group.random_uniform(n_samples=1)
        one_base_point = self.group.random_uniform(n_samples=1)
        n_tangent_vec = self.group.random_uniform(n_samples=n_samples)
        n_base_point = self.group.random_uniform(n_samples=n_samples)

        # Test with the 1 base point, and n tangent vecs
        result = self.group.exp(n_tangent_vec, one_base_point)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

        # Test with the several base point, and one tangent vec
        result = self.group.exp(one_tangent_vec, n_base_point)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

        # Test with the same number n of base point and n tangent vec
        result = self.group.exp(n_tangent_vec, n_base_point)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

    def test_group_log(self):
        """
        The Riemannian exp and log are inverse functions of each other.
        This test is the inverse of test_exp's.
        """
        rot_vec_base_point = gs.array([gs.pi / 5])
        rot_vec = gs.array([2 * gs.pi / 5])

        expected = gs.array([1 * gs.pi / 5])
        result = self.group.log(point=rot_vec, base_point=rot_vec_base_point)
        self.assertAllClose(result, expected)

    def test_group_log_vectorization(self):
        n_samples = self.n_samples

        one_point = self.group.random_uniform(n_samples=1)
        one_base_point = self.group.random_uniform(n_samples=1)
        n_point = self.group.random_uniform(n_samples=n_samples)
        n_base_point = self.group.random_uniform(n_samples=n_samples)

        # Test with the 1 base point, and several different points
        result = self.group.log(n_point, one_base_point)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

        # Test with the several base point, and 1 point
        result = self.group.log(one_point, n_base_point)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

        # Test with the same number n of base point and point
        result = self.group.log(n_point, n_base_point)
        self.assertAllClose(gs.shape(result), (n_samples, self.group.dim))

    def test_group_exp_then_log_from_identity(self):
        """
        Test that the group exponential
        and the group logarithm are inverse.
        Expect their composition to give the identity function.
        """
        tangent_vec = gs.array([0.12])
        result = helper.group_exp_then_log_from_identity(
            group=self.group, tangent_vec=tangent_vec)
        expected = self.group.regularize(tangent_vec)
        self.assertAllClose(result, expected)

    def test_group_log_then_exp_from_identity(self):
        """
        Test that the group exponential
        and the group logarithm are inverse.
        Expect their composition to give the identity function.
        """
        point = gs.array([0.12])
        result = helper.group_log_then_exp_from_identity(group=self.group,
                                                         point=point)
        expected = self.group.regularize(point)
        self.assertAllClose(result, expected)

    def test_group_exp_then_log(self):
        """
        This tests that the composition of
        log and exp gives identity.

        """
        base_point = gs.array([0.12])
        tangent_vec = gs.array([0.35])

        result = helper.group_exp_then_log(group=self.group,
                                           tangent_vec=tangent_vec,
                                           base_point=base_point)

        expected = self.group.regularize_tangent_vec(tangent_vec=tangent_vec,
                                                     base_point=base_point)

        self.assertAllClose(result, expected)

    def test_group_log_then_exp(self):
        """
        This tests that the composition of
        log and exp gives identity.
        """
        base_point = gs.array([0.12])
        point = gs.array([0.35])

        result = helper.group_log_then_exp(group=self.group,
                                           point=point,
                                           base_point=base_point)

        expected = self.group.regularize(point)

        self.assertAllClose(result, expected)
Example #5
0
 def inner_product_test_data(self):
     group = SpecialOrthogonal(n=3)
     algebra = group.lie_algebra
     tangent_vec_a = algebra.matrix_representation(gs.array([1.0, 0, 2.0]))
     tangent_vec_b = algebra.matrix_representation(gs.array([1.0, 0, 0.5]))
     batch_tangent_vec = algebra.matrix_representation(
         gs.array([[1.0, 0, 2.0], [0, 3.0, 5.0]]))
     smoke_data = [
         dict(
             group=group,
             metric_mat_at_identity=None,
             left_or_right="left",
             tangent_vec_a=tangent_vec_a,
             tangent_vec_b=tangent_vec_b,
             base_point=None,
             expected=4.0,
         ),
         dict(
             group=group,
             metric_mat_at_identity=None,
             left_or_right="left",
             tangent_vec_a=batch_tangent_vec,
             tangent_vec_b=tangent_vec_b,
             base_point=None,
             expected=gs.array([4.0, 5.0]),
         ),
         dict(
             group=group,
             metric_mat_at_identity=None,
             left_or_right="left",
             tangent_vec_a=group.compose(self.point_1_matrix,
                                         tangent_vec_a),
             tangent_vec_b=group.compose(self.point_1_matrix,
                                         tangent_vec_b),
             base_point=self.point_1_matrix,
             expected=4.0,
         ),
         dict(
             group=group,
             metric_mat_at_identity=None,
             left_or_right="left",
             tangent_vec_a=group.compose(self.point_1_matrix,
                                         batch_tangent_vec),
             tangent_vec_b=group.compose(self.point_1_matrix,
                                         tangent_vec_b),
             base_point=self.point_1_matrix,
             expected=gs.array([4.0, 5.0]),
         ),
         dict(
             group=group,
             metric_mat_at_identity=None,
             left_or_right="right",
             tangent_vec_a=group.compose(tangent_vec_a,
                                         self.point_1_matrix),
             tangent_vec_b=group.compose(tangent_vec_b,
                                         self.point_1_matrix),
             base_point=self.point_1_matrix,
             expected=4.0,
         ),
         dict(
             group=group,
             metric_mat_at_identity=None,
             left_or_right="right",
             tangent_vec_a=group.compose(batch_tangent_vec,
                                         self.point_1_matrix),
             tangent_vec_b=group.compose(tangent_vec_b,
                                         self.point_1_matrix),
             base_point=self.point_1_matrix,
             expected=gs.array([4.0, 5.0]),
         ),
     ]
     return self.generate_tests(smoke_data)
Example #6
0
class TestSpecialOrthogonal(geomstats.tests.TestCase):
    def setUp(self):
        self.n = 2
        self.group = SpecialOrthogonal(n=self.n)
        self.n_samples = 4

    def test_belongs(self):
        theta = gs.pi / 3
        point_1 = gs.array([[gs.cos(theta), -gs.sin(theta)],
                            [gs.sin(theta), gs.cos(theta)]])
        result = self.group.belongs(point_1)
        expected = True
        self.assertAllClose(result, expected)

        point_2 = gs.array([[gs.cos(theta), gs.sin(theta)],
                            [gs.sin(theta), gs.cos(theta)]])
        result = self.group.belongs(point_2)
        expected = False
        self.assertAllClose(result, expected)

        point = gs.array([point_1, point_2])
        expected = gs.array([True, False])
        result = self.group.belongs(point)
        self.assertAllClose(result, expected)

    def test_random_uniform_and_belongs(self):
        point = self.group.random_uniform()
        result = self.group.belongs(point)
        expected = True
        self.assertAllClose(result, expected)

        point = self.group.random_uniform(self.n_samples)
        result = self.group.belongs(point)
        expected = gs.array([True] * self.n_samples)
        self.assertAllClose(result, expected)

    def test_identity(self):
        result = self.group.identity
        expected = gs.eye(self.n)
        self.assertAllClose(result, expected)

    def test_is_in_lie_algebra(self):
        theta = gs.pi / 3
        vec_1 = gs.array([[0., -theta], [theta, 0.]])
        result = self.group.is_tangent(vec_1)
        expected = True
        self.assertAllClose(result, expected)

        vec_2 = gs.array([[0., -theta], [theta, 1.]])
        result = self.group.is_tangent(vec_2)
        expected = False
        self.assertAllClose(result, expected)

        vec = gs.array([vec_1, vec_2])
        expected = gs.array([True, False])
        result = self.group.is_tangent(vec)
        self.assertAllClose(result, expected)

    def test_is_tangent(self):
        point = self.group.random_uniform()
        theta = 1.
        vec_1 = gs.array([[0., -theta], [theta, 0.]])
        vec_1 = self.group.compose(point, vec_1)
        result = self.group.is_tangent(vec_1, point)
        expected = True
        self.assertAllClose(result, expected)

        vec_2 = gs.array([[0., -theta], [theta, 1.]])
        vec_2 = self.group.compose(point, vec_2)
        result = self.group.is_tangent(vec_2, point)
        expected = False
        self.assertAllClose(result, expected)

        vec = gs.array([vec_1, vec_2])
        point = gs.array([point, point])
        expected = gs.array([True, False])
        result = self.group.is_tangent(vec, point)
        self.assertAllClose(result, expected)

    def test_to_tangent(self):
        theta = 1.
        vec_1 = gs.array([[0., -theta], [theta, 0.]])
        result = self.group.to_tangent(vec_1)
        expected = vec_1
        self.assertAllClose(result, expected)

        n_samples = self.n_samples
        base_points = self.group.random_uniform(n_samples=n_samples)
        tangent_vecs = self.group.compose(base_points, vec_1)
        result = self.group.to_tangent(tangent_vecs, base_points)
        expected = tangent_vecs
        self.assertAllClose(result, expected)

    def test_projection_and_belongs(self):
        gs.random.seed(3)
        group = SpecialOrthogonal(n=4)
        mat = gs.random.rand(4, 4)
        point = group.projection(mat)
        result = group.belongs(point)
        self.assertTrue(result)

        mat = gs.random.rand(2, 4, 4)
        point = group.projection(mat)
        result = group.belongs(point, atol=1e-4)
        self.assertTrue(gs.all(result))

    def test_skew_to_vec_and_back(self):
        group = SpecialOrthogonal(n=4)
        vec = gs.random.rand(group.dim)
        mat = group.skew_matrix_from_vector(vec)
        result = group.vector_from_skew_matrix(mat)
        self.assertAllClose(result, vec)
Example #7
0
class TestSpecialOrthogonal(geomstats.tests.TestCase):
    def setUp(self):
        self.n = 2
        self.group = SpecialOrthogonal(n=self.n)
        self.n_samples = 4

    def test_belongs(self):
        theta = gs.pi / 3
        point_1 = gs.array([[gs.cos(theta), -gs.sin(theta)],
                            [gs.sin(theta), gs.cos(theta)]])
        result = self.group.belongs(point_1)
        expected = True
        self.assertAllClose(result, expected)

        point_2 = gs.array([[gs.cos(theta), gs.sin(theta)],
                            [gs.sin(theta), gs.cos(theta)]])
        result = self.group.belongs(point_2)
        expected = False
        self.assertAllClose(result, expected)

        point = gs.array([point_1, point_2])
        expected = gs.array([True, False])
        result = self.group.belongs(point)
        self.assertAllClose(result, expected)

    def test_random_uniform_and_belongs(self):
        point = self.group.random_uniform()
        result = self.group.belongs(point)
        expected = True
        self.assertAllClose(result, expected)

        point = self.group.random_uniform(self.n_samples)
        result = self.group.belongs(point)
        expected = gs.array([True] * self.n_samples)
        self.assertAllClose(result, expected)

    def test_identity(self):
        result = self.group.identity
        expected = gs.eye(self.n)
        self.assertAllClose(result, expected)

    def test_is_in_lie_algebra(self):
        theta = gs.pi / 3
        vec_1 = gs.array([[0., -theta], [theta, 0.]])
        result = self.group.is_tangent(vec_1)
        expected = True
        self.assertAllClose(result, expected)

        vec_2 = gs.array([[0., -theta], [theta, 1.]])
        result = self.group.is_tangent(vec_2)
        expected = False
        self.assertAllClose(result, expected)

        vec = gs.array([vec_1, vec_2])
        expected = gs.array([True, False])
        result = self.group.is_tangent(vec)
        self.assertAllClose(result, expected)

    def test_is_tangent(self):
        point = self.group.random_uniform()
        theta = 1.
        vec_1 = gs.array([[0., -theta], [theta, 0.]])
        vec_1 = self.group.compose(point, vec_1)
        result = self.group.is_tangent(vec_1, point, atol=1e-6)
        expected = True
        self.assertAllClose(result, expected)

        vec_2 = gs.array([[0., -theta], [theta, 1.]])
        vec_2 = self.group.compose(point, vec_2)
        result = self.group.is_tangent(vec_2, point, atol=1e-6)
        expected = False
        self.assertAllClose(result, expected)

        vec = gs.array([vec_1, vec_2])
        point = gs.array([point, point])
        expected = gs.array([True, False])
        result = self.group.is_tangent(vec, point, atol=1e-6)
        self.assertAllClose(result, expected)

    def test_to_tangent(self):
        theta = 1.
        vec_1 = gs.array([[0., -theta], [theta, 0.]])
        result = self.group.to_tangent(vec_1)
        expected = vec_1
        self.assertAllClose(result, expected)

        n_samples = self.n_samples
        base_points = self.group.random_uniform(n_samples=n_samples)
        tangent_vecs = self.group.compose(base_points, vec_1)
        result = self.group.to_tangent(tangent_vecs, base_points)
        expected = tangent_vecs
        self.assertAllClose(result, expected)