Ejemplo n.º 1
0
    def test_exp_and_log_from_identity_left_metrics(self):
        """
        Test that the riemannian exponential and the
        riemannian logarithm are inverse.
        Expect their composition to give the identity function.
        """
        # - exp then log
        # For left metric, point and point_small
        result = helper.exp_then_log_from_identity(metric=self.left_metric,
                                                   tangent_vec=self.point_1)
        expected = self.point_1
        self.assertTrue(gs.allclose(result, expected))

        result = helper.exp_then_log_from_identity(
            metric=self.left_metric, tangent_vec=self.point_small)
        expected = self.point_small
        self.assertTrue(gs.allclose(result, expected))

        # - log then exp
        # For left metric, point and point_small
        result = helper.log_then_exp_from_identity(metric=self.left_metric,
                                                   point=self.point_1)
        expected = self.point_1
        self.assertTrue(gs.allclose(result, expected))

        result = helper.log_then_exp_from_identity(metric=self.left_metric,
                                                   point=self.point_small)
        expected = self.point_small
        self.assertTrue(gs.allclose(result, expected))
Ejemplo n.º 2
0
    def test_compose_and_inverse(self):
        # 1. Compose transformation by its inverse on the right
        # Expect the group identity
        rot_vec_1 = self.so3_group.random_uniform()
        mat_1 = self.so3_group.matrix_from_rotation_vector(rot_vec_1)
        inv_mat_1 = self.group.inverse(mat_1)

        result_1 = self.group.compose(mat_1, inv_mat_1)
        expected_1 = self.group.identity

        norm = gs.linalg.norm(expected_1)
        atol = RTOL
        if norm != 0:
            atol = RTOL * norm

        self.assertTrue(
            gs.allclose(result_1, expected_1, atol=atol), '\nresult:\n{}'
            '\nexpected:\n{}'.format(result_1, expected_1))

        # 2. Compose transformation by its inverse on the left
        # Expect the group identity
        rot_vec_2 = self.so3_group.random_uniform()
        mat_2 = self.so3_group.matrix_from_rotation_vector(rot_vec_2)
        inv_mat_2 = self.group.inverse(mat_2)

        result_2 = self.group.compose(inv_mat_2, mat_2)
        expected_2 = self.group.identity

        norm = gs.linalg.norm(expected_2)
        atol = RTOL
        if norm != 0:
            atol = RTOL * norm

        self.assertTrue(gs.allclose(result_2, expected_2, atol=atol))
Ejemplo n.º 3
0
    def test_log_after_exp_with_angles_close_to_pi(
        self, metric, tangent_vec, base_point
    ):
        """
        Test that the Riemannian left exponential and the
        Riemannian left logarithm are inverse.
        Expect their composition to give the identity function.
        """
        group = SpecialEuclidean(3, "vector")
        result = metric.log(metric.exp(tangent_vec, base_point), base_point)

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

        inv_expected = gs.concatenate([-expected[:3], expected[3:6]])

        norm = gs.linalg.norm(expected)
        atol = ATOL
        if norm != 0:
            atol = ATOL * norm

        self.assertTrue(
            gs.allclose(result, expected, atol=atol)
            or gs.allclose(result, inv_expected, atol=atol)
        )
Ejemplo n.º 4
0
    def test_compose(self):
        # 1. Composition by identity, on the right
        # Expect the original transformation
        rot_vec_1 = self.so3_group.random_uniform()
        mat_1 = self.so3_group.matrix_from_rotation_vector(rot_vec_1)

        result_1 = self.group.compose(mat_1, self.group.identity)
        expected_1 = mat_1

        self.assertTrue(gs.allclose(result_1, expected_1))

        # 2. Composition by identity, on the left
        # Expect the original transformation
        rot_vec_2 = self.so3_group.random_uniform()
        mat_2 = self.so3_group.matrix_from_rotation_vector(rot_vec_2)

        result_2 = self.group.compose(self.group.identity, mat_2)
        expected_2 = mat_2

        norm = gs.linalg.norm(expected_2)
        atol = RTOL
        if norm != 0:
            atol = RTOL * norm
        self.assertTrue(
            gs.allclose(result_2, expected_2, atol=atol), '\nresult:\n{}'
            '\nexpected:\n{}'.format(result_2, expected_2))
Ejemplo n.º 5
0
    def test_squared_dist_is_symmetric(self):
        n_samples = self.n_samples

        point_1 = self.space.random_uniform(n_samples=1)
        point_2 = self.space.random_uniform(n_samples=1)

        sq_dist_1_2 = self.metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = self.metric.squared_dist(point_2, point_1)

        self.assertTrue(gs.allclose(sq_dist_1_2, sq_dist_2_1))

        point_1 = self.space.random_uniform(n_samples=1)
        point_2 = self.space.random_uniform(n_samples=n_samples)

        sq_dist_1_2 = self.metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = self.metric.squared_dist(point_2, point_1)

        self.assertTrue(gs.allclose(sq_dist_1_2, sq_dist_2_1))

        point_1 = self.space.random_uniform(n_samples=n_samples)
        point_2 = self.space.random_uniform(n_samples=1)

        sq_dist_1_2 = self.metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = self.metric.squared_dist(point_2, point_1)

        self.assertTrue(gs.allclose(sq_dist_1_2, sq_dist_2_1))

        point_1 = self.space.random_uniform(n_samples=n_samples)
        point_2 = self.space.random_uniform(n_samples=n_samples)

        sq_dist_1_2 = self.metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = self.metric.squared_dist(point_2, point_1)

        self.assertTrue(gs.allclose(sq_dist_1_2, sq_dist_2_1))
Ejemplo n.º 6
0
    def test_log_vectorization(self):
        n_samples = self.n_samples
        one_base_point = self.space.random_uniform(n_samples=1)
        n_base_point = self.space.random_uniform(n_samples=n_samples)

        one_point = self.space.random_uniform(n_samples=1)
        n_point = self.space.random_uniform(n_samples=n_samples)

        # Test with different points, one base point
        results = self.metric.log(n_point, one_base_point)

        self.assertTrue(
            gs.allclose(results.shape,
                        (n_samples, self.space.n, self.space.n)))

        # Test with the same number of points and base points
        results = self.metric.log(n_point, n_base_point)

        self.assertTrue(
            gs.allclose(results.shape,
                        (n_samples, self.space.n, self.space.n)))

        # Test with the one point and n base points
        results = self.metric.log(one_point, n_base_point)

        self.assertTrue(
            gs.allclose(results.shape,
                        (n_samples, self.space.n, self.space.n)))
Ejemplo n.º 7
0
 def test_rotation_vector_and_rotation_matrix_with_angles_close_to_pi(self, point):
     group = self.space(3, point_type="vector")
     mat = group.matrix_from_rotation_vector(point)
     result = group.rotation_vector_from_matrix(mat)
     expected1 = group.regularize(point)
     expected2 = -1 * expected1
     expected = gs.allclose(result, expected1) or gs.allclose(result, expected2)
     self.assertTrue(expected)
Ejemplo n.º 8
0
 def test_quaternion_and_matrix_with_angles_close_to_pi(self, point):
     group = self.space(3, point_type="vector")
     mat = group.matrix_from_rotation_vector(point)
     quat = group.quaternion_from_matrix(mat)
     result = group.matrix_from_quaternion(quat)
     expected1 = mat
     expected2 = gs.linalg.inv(mat)
     expected = gs.allclose(result, expected1) or gs.allclose(result, expected2)
     self.assertTrue(expected)
Ejemplo n.º 9
0
    def test_quaternion_and_rotation_vector_with_angles_close_to_pi(self, point):
        group = self.space(3, point_type="vector")

        quaternion = group.quaternion_from_rotation_vector(point)
        result = group.rotation_vector_from_quaternion(quaternion)
        expected1 = group.regularize(point)
        expected2 = -1 * expected1
        expected = gs.allclose(result, expected1) or gs.allclose(result, expected2)
        self.assertTrue(expected)
Ejemplo n.º 10
0
    def test_make_symmetric(self):
        sym_mat = gs.array([[1, 2], [2, 1]])
        result = spd_matrices_space.make_symmetric(sym_mat)
        expected = sym_mat
        self.assertTrue(gs.allclose(result, expected))

        mat = gs.array([[1, 2, 3], [0, 0, 0], [3, 1, 1]])
        result = spd_matrices_space.make_symmetric(mat)
        expected = gs.array([[1, 1, 3], [1, 0, 0.5], [3, 0.5, 1]])
        self.assertTrue(gs.allclose(result, expected))
Ejemplo n.º 11
0
    def test_inner_product_matrix(self):
        base_point = self.group.identity
        result = self.left_metric.inner_product_matrix(base_point=base_point)

        expected = self.left_metric.inner_product_mat_at_identity
        self.assertTrue(gs.allclose(result, expected))

        result = self.right_metric.inner_product_matrix(base_point=base_point)

        expected = self.right_metric.inner_product_mat_at_identity
        self.assertTrue(gs.allclose(result, expected))
Ejemplo n.º 12
0
    def test_compose_regularize_angles_close_to_pi(self, point):
        group = self.space(3, point_type="vector")
        result = group.compose(point, group.identity)
        expected = group.regularize(point)
        inv_expected = -expected
        self.assertTrue(
            gs.allclose(result, expected) or gs.allclose(result, inv_expected))

        result = group.compose(group.identity, point)
        expected = group.regularize(point)
        inv_expected = -expected
        self.assertTrue(
            gs.allclose(result, expected) or gs.allclose(result, inv_expected))
Ejemplo n.º 13
0
    def vector_from_symmetric_matrix_and_symmetric_matrix_from_vector(self):
        sym_mat_1 = gs.array([[1., 0.6, -3.], [0.6, 7., 0.], [-3., 0., 8.]])
        vector_1 = self.space.vector_from_symmetric_matrix(sym_mat_1)
        result_1 = self.space.symmetric_matrix_from_vector(vector_1)
        expected_1 = sym_mat_1

        self.assertTrue(gs.allclose(result_1, expected_1))

        vector_2 = gs.array([1, 2, 3, 4, 5, 6])
        sym_mat_2 = self.space.symmetric_matrix_from_vector(vector_2)
        result_2 = self.space.vector_from_symmetric_matrix(sym_mat_2)
        expected_2 = vector_2

        self.assertTrue(gs.allclose(result_2, expected_2))
Ejemplo n.º 14
0
    def test_group_exp_after_log_with_angles_close_to_pi(
            self, point, base_point):
        """
        This tests that the composition of
        log and exp gives identity.
        """
        # TODO(nguigs): fix this test for tf
        group = self.space(3, point_type="vector")
        result = group.exp(group.log(point, base_point), base_point)
        expected = group.regularize(point)
        inv_expected = -expected

        self.assertTrue(
            gs.allclose(result, expected, atol=5e-3)
            or gs.allclose(result, inv_expected, atol=5e-3))
Ejemplo n.º 15
0
    def test_vector_and_symmetric_matrix_vectorization(self):
        """Test of vectorization."""
        n_samples = 5
        vector = gs.random.rand(n_samples, 6)
        sym_mat = self.space.symmetric_matrix_from_vector(vector)
        result = self.space.vector_from_symmetric_matrix(sym_mat)
        expected = vector

        self.assertTrue(gs.allclose(result, expected))

        vector = self.space.vector_from_symmetric_matrix(sym_mat)
        result = self.space.symmetric_matrix_from_vector(vector)
        expected = sym_mat

        self.assertTrue(gs.allclose(result, expected))
    def test_vector_from_symmetric_matrix_and_symmetric_matrix_from_vector(self):
        """Test for matrix to vector and vector to matrix conversions."""
        sym_mat_1 = gs.array([[1.0, 0.6, -3.0], [0.6, 7.0, 0.0], [-3.0, 0.0, 8.0]])
        vector_1 = self.space.to_vector(sym_mat_1)
        result_1 = self.space.from_vector(vector_1)
        expected_1 = sym_mat_1

        self.assertTrue(gs.allclose(result_1, expected_1))

        vector_2 = gs.array([1, 2, 3, 4, 5, 6])
        sym_mat_2 = self.space.from_vector(vector_2)
        result_2 = self.space.to_vector(sym_mat_2)
        expected_2 = vector_2

        self.assertTrue(gs.allclose(result_2, expected_2))
Ejemplo n.º 17
0
    def vector_and_symmetric_matrix_vectorization(self):
        n_samples = self.n_samples
        vector = gs.random.rand(n_samples, 6)
        sym_mat = self.space.symmetric_matrix_from_vector(vector)
        result = self.space.vector_from_symmetric_matrix(sym_mat)
        expected = vector

        self.assertTrue(gs.allclose(result, expected))

        sym_mat = self.space.random_uniform(n_samples)
        vector = self.space.vector_from_symmetric_matrix(sym_mat)
        result = self.space.symmetric_matrix_from_vector(vector)
        expected = sym_mat

        self.assertTrue(gs.allclose(result, expected))
Ejemplo n.º 18
0
    def log(self, point, base_point=None):
        """Compute the group logarithm of `point` relative to `base_point`.

        Parameters
        ----------
        point : array-like, shape=[..., {dim, [n, n]}]
            Point.
        base_point : array-like, shape=[..., {dim, [n, n]}]
            Base point.
            Optional, defaults to identity if None.

        Returns
        -------
        tangent_vec : array-like, shape=[..., {dim, [n, n]}]
            Group logarithm.
        """
        # TODO (ninamiolane): Build a standalone decorator that *only*
        # deals with point_type None and base_point None
        identity = self.get_identity(point_type=self.default_point_type)
        if base_point is None:
            base_point = identity

        point = self.regularize(point)
        base_point = self.regularize(base_point)

        if gs.allclose(base_point, identity):
            result = self.log_from_identity(point)
        else:
            result = self.log_not_from_identity(point, base_point)
        return result
Ejemplo n.º 19
0
    def exp(self, tangent_vec, base_point=None):
        """Compute the group exponential at `base_point` of `tangent_vec`.

        Parameters
        ----------
        tangent_vec : array-like, shape=[..., {dim, [n, n]}]
            Tangent vector at base point.
        base_point : array-like, shape=[..., {dim, [n, n]}]
            Base point.
            Optional, default: self.identity

        Returns
        -------
        result : array-like, shape=[..., {dim, [n, n]}]
            Group exponential.
        """
        identity = self.get_identity()

        if base_point is None:
            base_point = identity
        base_point = self.regularize(base_point)

        if gs.allclose(base_point, identity):
            result = self.exp_from_identity(tangent_vec)
        else:
            result = self.exp_not_from_identity(tangent_vec, base_point)
        return result
Ejemplo n.º 20
0
    def test_expm_and_logm_vectorization(self):
        point = gs.array([[[2., 0., 0.], [0., 3., 0.], [0., 0., 4.]],
                          [[1., 0., 0.], [0., 5., 0.], [0., 0., 6.]]])
        result = gs.linalg.expm(gs.linalg.logm(point))
        expected = point

        self.assertTrue(gs.allclose(result, expected))
Ejemplo n.º 21
0
    def test_logm(self):
        point = gs.array([[2., 0., 0.], [0., 3., 0.], [0., 0., 4.]])
        result = gs.linalg.logm(point)
        expected = gs.array([[0.693147180, 0., 0.], [0., 1.098612288, 0.],
                             [0., 0., 1.38629436]])

        self.assertTrue(gs.allclose(result, expected))
Ejemplo n.º 22
0
    def log(self, point, base_point=None, point_type=None):
        """Compute the group logarithm of `point` relative to `base_point`.

        Parameters
        ----------
        point : array-like, shape=[n_samples, {dim,[n,n]}]
        base_point : array-like, shape=[n_samples, {dim,[n,n]}]
        point_type : str, {'vector', 'matrix'}

        Returns
        -------
        tangent_vec : array-like, shape=[n_samples, {dim,[n,n]}]
        """
        # TODO(ninamiolane): Build a standalone decorator that *only*
        # deals with point_type None and base_point None
        if point_type is None:
            point_type = self.default_point_type
        identity = self.get_identity(point_type=point_type)
        if base_point is None:
            base_point = identity

        point = self.regularize(point, point_type=point_type)
        base_point = self.regularize(base_point, point_type=point_type)

        if gs.allclose(base_point, identity):
            result = self.log_from_identity(point, point_type=point_type)
        else:
            result = self.log_not_from_identity(point, base_point, point_type)
        return result
Ejemplo n.º 23
0
    def group_log(self, point, base_point=None, point_type=None):
        """
        Compute the group logarithm at point base_point
        of the point point.
        """
        if point_type is None:
            point_type = self.default_point_type

        identity = self.get_identity(point_type=point_type)
        identity = self.regularize(identity, point_type=point_type)
        if base_point is None:
            base_point = identity
        base_point = self.regularize(base_point, point_type=point_type)
        if gs.allclose(base_point, identity):
            return self.group_log_from_identity(point, point_type=point_type)

        point = self.regularize(point, point_type=point_type)

        jacobian = self.jacobian_translation(point=base_point,
                                             left_or_right='left',
                                             point_type=point_type)
        point_near_id = self.compose(self.inverse(base_point),
                                     point,
                                     point_type=point_type)
        group_log_from_id = self.group_log_from_identity(point=point_near_id,
                                                         point_type=point_type)

        group_log = gs.einsum('ij,ijk->ik', group_log_from_id,
                              gs.transpose(jacobian, axes=(0, 2, 1)))

        assert group_log.ndim == 2
        return group_log
Ejemplo n.º 24
0
    def test_group_log_and_exp(self):
        point_1 = 5 * gs.eye(4)
        group_log_1 = spd_matrices_space.group_log(point_1)
        result_1 = spd_matrices_space.group_exp(group_log_1)
        expected_1 = point_1

        self.assertTrue(gs.allclose(result_1, expected_1))
Ejemplo n.º 25
0
 def test_inner_product_matrix_and_its_inverse(self):
     inner_prod_mat = self.left_diag_metric.inner_product_mat_at_identity
     inv_inner_prod_mat = gs.linalg.inv(inner_prod_mat)
     result = gs.matmul(inv_inner_prod_mat, inner_prod_mat)
     expected = gs.eye(self.group.dimension)
     expected = gs.to_ndarray(expected, to_ndim=3, axis=0)
     self.assertTrue(gs.allclose(result, expected))
Ejemplo n.º 26
0
    def _iterate_once(self, current_median, X, weights, lr):
        """Compute a single iteration of Weiszfeld Algorithm.

        Parameters
        ----------
        current_median : array-like, shape={representation shape}
            current median.
        X : array-like, shape=[..., {representation shape}]
            data for which geometric has to be found.
        weights : array-like, shape=[N]
            weights for weighted sum.
        lr : float
            learning rate for the current iteration.

        Returns
        -------
        updated_median: array-like, shape={representation shape}
            updated median after single iteration.
        """
        def _scalarmul(scalar, array):
            if gs.ndim(array) == 2:
                return scalar[:, None] * array

            return scalar[:, None, None] * array

        dists = self.metric.dist(current_median, X)

        if gs.allclose(dists, 0.0):
            return current_median

        logs = self.metric.log(X, current_median)
        mul = gs.divide(weights, dists, ignore_div_zero=True)
        v_k = gs.sum(_scalarmul(mul, logs), axis=0) / gs.sum(mul)
        updated_median = self.metric.exp(lr * v_k, current_median)
        return updated_median
Ejemplo n.º 27
0
    def is_tangent(self, vector, base_point=None, atol=ATOL):
        """Check whether the vector is tangent at base_point.

        Parameters
        ----------
        vector : array-like, shape=[..., dim_embedding]
            Vector.
        base_point : array-like, shape=[..., dim_embedding]
            Point in the Lie group.

        Returns
        -------
        is_tangent : bool
            Boolean denoting if vector is a tangent vector at the base point.
        """
        if base_point is None:
            base_point = self.identity

        if gs.allclose(base_point, self.identity):
            tangent_vec_at_id = vector
        else:
            tangent_vec_at_id = self.compose(
                self.inverse(base_point), vector)
        is_tangent = self._is_in_lie_algebra(tangent_vec_at_id, atol)
        return is_tangent
Ejemplo n.º 28
0
    def test_exp_and_log_and_projection_to_tangent_space_general_case(self):
        """Test Log and Exp.

        Test that the Riemannian exponential
        and the Riemannian logarithm are inverse.

        Expect their composition to give the identity function.

        NB: points on the n-dimensional sphere are
        (n+1)-D vectors of norm 1.
        """
        # Riemannian Exp then Riemannian Log
        # General case
        # NB: Riemannian log gives a regularized tangent vector,
        # so we take the norm modulo 2 * pi.
        base_point = gs.array([0.0, -3.0, 0.0, 3.0, 4.0])
        base_point = base_point / gs.linalg.norm(base_point)

        vector = gs.array([3.0, 2.0, 0.0, 0.0, -1.0])
        vector = self.space.to_tangent(vector=vector, base_point=base_point)

        exp = self.metric.exp(tangent_vec=vector, base_point=base_point)
        result = self.metric.log(point=exp, base_point=base_point)

        expected = vector
        norm_expected = gs.linalg.norm(expected)
        regularized_norm_expected = gs.mod(norm_expected, 2 * gs.pi)
        expected = expected / norm_expected * regularized_norm_expected

        # The Log can be the opposite vector on the tangent space,
        # whose Exp gives the base_point
        are_close = gs.allclose(result, expected)
        norm_2pi = gs.isclose(gs.linalg.norm(result - expected), 2 * gs.pi)
        self.assertTrue(are_close or norm_2pi)
Ejemplo n.º 29
0
def rotate_points(points, end_point):
    """Apply to points the rotation from north_pole to end_point.

    A QR decomposition is used to find the rotation that maps the north pole
    (1, 0,...,0) to the end_point, then this rotation is applied to the
    input points.

    Parameters
    ----------
    points : array-like, shape=[..., n]
        Points to rotate.
    end_point : array-like, shape=[n, ]
        Point to parametrise the rotation.

    Returns
    -------
    rotated_points : array-like, shape=[..., n]
        Points after the rotation.
    """
    n = end_point.shape[0]
    base_point = gs.array([1.0] + [0] * (n - 1))
    embedded = gs.concatenate([end_point[None, :], gs.zeros((n - 1, n))])
    norm = gs.linalg.norm(end_point)
    q, _ = gs.linalg.qr(gs.transpose(embedded) / norm)
    new_points = gs.matmul(points[None, :], gs.transpose(q)) * norm
    if not gs.allclose(gs.matmul(q, base_point[:, None])[:, 0], end_point):
        new_points = -new_points
    return new_points[0]
Ejemplo n.º 30
0
    def exp(self, tangent_vec, base_point=None, point_type=None):
        """Compute the group exponential at `base_point` of `tangent_vec`.

        Parameters
        ----------
        tangent_vec : array-like, shape=[n_samples, {dim,[n,n]}]
        base_point : array-like, shape=[n_samples, {dim,[n,n]}]
            default: self.identity
        point_type : str, {'vector', 'matrix'}
            default: the default point type
            the type of the point

        Returns
        -------
        result : array-like, shape=[n_samples, {dim,[n,n]}]
            The exponentiated tangent vector
        """
        if point_type is None:
            point_type = self.default_point_type
        identity = self.get_identity(point_type=point_type)

        if base_point is None:
            base_point = identity
        base_point = self.regularize(base_point, point_type=point_type)

        if gs.allclose(base_point, identity):
            result = self.exp_from_identity(tangent_vec, point_type=point_type)
        else:
            result = self.exp_not_from_identity(
                tangent_vec, base_point, point_type)
        return result