Ejemplo n.º 1
0
    def test_belongs(self):
        theta = gs.pi / 3
        point_1 = gs.array(
            [
                [gs.cos(theta), -gs.sin(theta), 2.0],
                [gs.sin(theta), gs.cos(theta), 3.0],
                [0.0, 0.0, 1.0],
            ]
        )
        result = self.group.belongs(point_1)
        self.assertTrue(result)

        point_2 = gs.array(
            [
                [gs.cos(theta), -gs.sin(theta), 2.0],
                [gs.sin(theta), gs.cos(theta), 3.0],
                [0.0, 0.0, 0.0],
            ]
        )
        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))
        self.assertAllClose(result.shape, (2,))
Ejemplo n.º 2
0
    def extrinsic_to_intrinsic_coords(self, point_extrinsic):
        """Convert from extrinsic to intrinsic coordinates.

        Parameters
        ----------
        point_extrinsic : array-like, shape=[..., dim + 1]
            Point in the embedded manifold in extrinsic coordinates,
            i. e. in the coordinates of the embedding manifold.

        Returns
        -------
        point_intrinsic : array-like, shape=[..., dim]
            Point in intrinsic coordinates.
        """
        belong_point = self.belongs(point_extrinsic)
        if not gs.all(belong_point):
            raise NameError("Point that does not belong to the hyperboloid "
                            "found")
        return\
            Hyperbolic.change_coordinates_system(point_extrinsic,
                                                 'extrinsic',
                                                 'intrinsic')
Ejemplo n.º 3
0
    def test_log_is_tangent(self, connection_args, space, point, base_point,
                            is_tangent_atol):
        """Check that the connection logarithm gives a tangent vector.

        Parameters
        ----------
        connection_args : tuple
            Arguments to pass to constructor of the connection.
        space : Manifold
            Manifold where connection is defined.
        point : array-like
            Point on the manifold.
        base_point : array-like
            Point on the manifold.
        is_tangent_atol : float
            Absolute tolerance for the is_tangent function.
        """
        connection = self.connection(*connection_args)
        log = connection.log(gs.array(point), gs.array(base_point))
        result = gs.all(
            space.is_tangent(log, gs.array(base_point), is_tangent_atol))
        self.assertAllClose(result, gs.array(True))
    def belongs(self, point):
        """Evaluate if a point belongs to the manifold of Dirichlet distributions.

        Check that point defines parameters for a Dirichlet distributions,
        i.e. belongs to the positive quadrant of the Euclidean space.

        Parameters
        ----------
        point : array-like, shape=[..., dim]
            Point to be checked.

        Returns
        -------
        belongs : array-like, shape=[...,]
            Boolean indicating whether point represents a Dirichlet
            distribution.
        """
        point_dim = point.shape[-1]
        belongs = point_dim == self.dim
        belongs = gs.logical_and(
            belongs, gs.all(gs.greater(point, 0.), axis=-1))
        return belongs
Ejemplo n.º 5
0
    def permute(self, graph_to_permute, permutation):
        r"""Permutation action applied to graph observation.

        Parameters
        ----------
        graph_to_permute : array-like, shape=[..., n, n]
            Input graphs to be permuted.
        permutation: array-like, shape=[..., n]
            Node permutations where in position i we have the value j meaning
            the node i should be permuted with node j.

        Returns
        -------
        graphs_permuted : array-like, shape=[..., n, n]
            Graphs permuted.
        """
        nodes = self.nodes
        single_graph = len(graph_to_permute.shape) < 3
        if single_graph:
            graph_to_permute = [graph_to_permute]
            permutation = [permutation]
        result = []
        for i, p in enumerate(permutation):
            if gs.all(gs.array(nodes) == gs.array(p)):
                result.append(graph_to_permute[i])
            else:
                gtype = graph_to_permute[i].dtype
                permutation_matrix = gs.array_from_sparse(
                    data=gs.ones(nodes, dtype=gtype),
                    indices=list(zip(list(range(nodes)), p)),
                    target_shape=(nodes, nodes),
                )
                result.append(
                    self.adjmat.mul(
                        permutation_matrix,
                        graph_to_permute[i],
                        gs.transpose(permutation_matrix),
                    ))
        return result[0] if single_graph else gs.array(result)
Ejemplo n.º 6
0
    def test_is_diagonal(self):
        base_point = gs.array([[1., 2., 3.], [0., 0., 0.], [3., 1., 1.]])
        result = self.space.is_diagonal(base_point)
        expected = False
        self.assertAllClose(result, expected)

        diagonal = gs.eye(3)
        result = self.space.is_diagonal(diagonal)
        self.assertTrue(result)

        base_point = gs.stack([base_point, diagonal])
        result = self.space.is_diagonal(base_point)
        expected = gs.array([False, True])
        self.assertAllClose(result, expected)

        base_point = gs.stack([diagonal] * 2)
        result = self.space.is_diagonal(base_point)
        self.assertTrue(gs.all(result))

        base_point = gs.reshape(gs.arange(6), (2, 3))
        result = self.space.is_diagonal(base_point)
        self.assertTrue(~result)
Ejemplo n.º 7
0
    def equal(mat_a, mat_b, atol=TOLERANCE):
        """Test if matrices a and b are close.

        Parameters
        ----------
        mat_a : array-like, shape=[..., dim1, dim2]
            Matrix.
        mat_b : array-like, shape=[..., dim2, dim3]
            Matrix.
        atol : float
            Tolerance.
            Optional, default: 1e-5.

        Returns
        -------
        eq : array-like, shape=[...,]
            Boolean evaluating if the matrices are close.
        """
        is_vectorized = \
            (gs.ndim(gs.array(mat_a)) == 3) or (gs.ndim(gs.array(mat_b)) == 3)
        axes = (1, 2) if is_vectorized else (0, 1)
        return gs.all(gs.isclose(mat_a, mat_b, atol=atol), axes)
Ejemplo n.º 8
0
    def spherical_to_extrinsic(self, point_spherical):
        """Convert point from spherical to extrinsic coordinates.

        Convert from the spherical coordinates in the hypersphere
        to the extrinsic coordinates in Euclidean space.
        Spherical coordinates are defined from the north pole, i.e. that
        angles [0., 0.] correspond to point [0., 0., 1.].
        Only implemented in dimension 2.

        Parameters
        ----------
        point_spherical : array-like, shape=[..., dim]
            Point on the sphere, in spherical coordinates.

        Returns
        -------
        point_extrinsic : array_like, shape=[..., dim + 1]
            Point on the sphere, in extrinsic coordinates in Euclidean space.
        """
        if self.dim != 2:
            raise NotImplementedError(
                "The conversion from spherical coordinates"
                " to extrinsic coordinates is implemented"
                " only in dimension 2."
            )

        theta = point_spherical[..., 0]
        phi = point_spherical[..., 1]

        point_extrinsic = gs.stack(
            [gs.sin(theta) * gs.cos(phi), gs.sin(theta) * gs.sin(phi), gs.cos(theta)],
            axis=-1,
        )

        if not gs.all(self.belongs(point_extrinsic)):
            raise ValueError("Points do not belong to the manifold.")

        return point_extrinsic
Ejemplo n.º 9
0
    def vector_from_symmetric_matrix(self, mat):
        """
        Convert the symmetric part of a symmetric matrix
        into a vector.
        """
        mat = gs.to_ndarray(mat, to_ndim=3)
        assert gs.all(self.embedding_manifold.is_symmetric(mat))
        mat = self.embedding_manifold.make_symmetric(mat)

        _, mat_dim, _ = mat.shape
        vec_dim = int(mat_dim * (mat_dim + 1) / 2)
        vec = gs.zeros(vec_dim)

        idx = 0
        for i in range(mat_dim):
            for j in range(i + 1):
                if i == j:
                    vec[idx] = mat[j, j]
                else:
                    vec[idx] = mat[j, i]
                idx += 1

        return vec
Ejemplo n.º 10
0
    def test_geodesic_and_belongs(self):
        n_geodesic_points = 10
        initial_point = self.space.random_uniform(2)
        vector = gs.array([[2.0, 0.0, -1.0, -2.0, 1.0]] * 2)
        initial_tangent_vec = self.space.to_tangent(vector=vector,
                                                    base_point=initial_point)
        geodesic = self.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        t = gs.linspace(start=0.0, stop=1.0, num=n_geodesic_points)
        points = geodesic(t)
        result = gs.stack([self.space.belongs(pt) for pt in points])
        self.assertTrue(gs.all(result))

        initial_point = initial_point[0]
        initial_tangent_vec = initial_tangent_vec[0]
        geodesic = self.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        points = geodesic(t)
        result = self.space.belongs(points)
        expected = gs.array(n_geodesic_points * [True])
        self.assertAllClose(expected, result)
Ejemplo n.º 11
0
    def belongs(self, point, point_type=None):
        """Test if a point belongs to the manifold.

        Parameters
        ----------
        point : array-like, shape=[..., {dim, [dim_2, dim_2]}]
            Point.
        point_type : str, {'vector', 'matrix'}
            Representation of point.
            Optional, default: None.

        Returns
        -------
        belongs : array-like, shape=[...,]
            Boolean evaluating if the point belongs to the manifold.
        """
        if point_type is None:
            point_type = self.default_point_type
        geomstats.errors.check_parameter_accepted_values(
            point_type, 'point_type', ['vector', 'matrix'])

        if point_type == 'vector':
            intrinsic = self.metric.is_intrinsic(point)
            belongs = self._iterate_over_manifolds('belongs', {'point': point},
                                                   intrinsic)
            belongs = gs.stack(belongs, axis=1)

        else:
            belongs = gs.stack([
                space.belongs(point[:, i])
                for i, space in enumerate(self.manifolds)
            ],
                               axis=1)

        belongs = gs.all(belongs, axis=1)
        belongs = gs.to_ndarray(belongs, to_ndim=2, axis=1)
        return belongs
Ejemplo n.º 12
0
    def belongs(self, point, point_type=None):
        """Test if a point belongs to the manifold.

        Parameters
        ----------
        point : array-like, shape=[n_samples, dim]
                           or shape=[n_samples, dim_2, dim_2]
            Point.
        point_type : str, {'vector', 'matrix'}
            Representation of point.

        Returns
        -------
        belongs : array-like, shape=[n_samples, 1]
            Array of booleans evaluating if the corresponding points
            belong to the manifold.
        """
        if point_type is None:
            point_type = self.default_point_type
        if point_type == 'vector':
            point = gs.to_ndarray(point, to_ndim=2)
            intrinsic = self.metric._is_intrinsic(point)
            belongs = self._iterate_over_manifolds('belongs', {'point': point},
                                                   intrinsic)
            belongs = gs.hstack(belongs)

        elif point_type == 'matrix':
            point = gs.to_ndarray(point, to_ndim=3)
            belongs = gs.stack([
                space.belongs(point[:, i])
                for i, space in enumerate(self.manifolds)
            ],
                               axis=1)

        belongs = gs.all(belongs, axis=1)
        belongs = gs.to_ndarray(belongs, to_ndim=2, axis=1)
        return belongs
Ejemplo n.º 13
0
    def spherical_to_extrinsic(self, point_spherical):
        """Convert point from spherical to extrinsic coordinates.

        Convert from the spherical coordinates in the hypersphere
        to the extrinsic coordinates in Euclidean space.
        Only implemented in dimension 2.

        Parameters
        ----------
        point_spherical : array-like, shape=[..., dim]
            Point on the sphere, in spherical coordinates.

        Returns
        -------
        point_extrinsic : array_like, shape=[..., dim + 1]
            Point on the sphere, in extrinsic coordinates in Euclidean space.
        """
        if self.dim != 2:
            raise NotImplementedError(
                'The conversion from spherical coordinates'
                ' to extrinsic coordinates is implemented'
                ' only in dimension 2.')

        theta = point_spherical[..., 0]
        phi = point_spherical[..., 1]

        point_extrinsic = gs.stack([
            gs.sin(theta) * gs.cos(phi),
            gs.sin(theta) * gs.sin(phi),
            gs.cos(theta)
        ],
                                   axis=-1)

        if not gs.all(self.belongs(point_extrinsic)):
            raise ValueError('Points do not belong to the manifold.')

        return point_extrinsic
Ejemplo n.º 14
0
    def test_kendall_sectional_curvature(self):
        """Sectional curvature of Kendall shape space is larger than 1.

        The sectional curvature always increase by taking the quotient in a
        Riemannian submersion. Thus, it should larger in kendall shape space
        thane the sectional curvature of the pre-shape space which is 1 as it
        a hypersphere.
        The sectional curvature is computed here with the generic
        directional_curvature and sectional curvature methods.
        """
        space = self.space
        metric = self.shape_metric
        n_samples = 4 * self.k_landmarks * self.m_ambient
        base_point = self.space.random_point(1)

        vec_a = gs.random.rand(n_samples, self.k_landmarks, self.m_ambient)
        tg_vec_a = space.to_tangent(space.center(vec_a), base_point)
        hor_a = space.horizontal_projection(tg_vec_a, base_point)

        vec_b = gs.random.rand(n_samples, self.k_landmarks, self.m_ambient)
        tg_vec_b = space.to_tangent(space.center(vec_b), base_point)
        hor_b = space.horizontal_projection(tg_vec_b, base_point)

        tidal_force = metric.directional_curvature(hor_a, hor_b, base_point)

        numerator = metric.inner_product(tidal_force, hor_a, base_point)
        denominator = (
            metric.inner_product(hor_a, hor_a, base_point)
            * metric.inner_product(hor_b, hor_b, base_point)
            - metric.inner_product(hor_a, hor_b, base_point) ** 2
        )
        condition = ~gs.isclose(denominator, 0.0)
        kappa = numerator[condition] / denominator[condition]
        kappa_direct = metric.sectional_curvature(hor_a, hor_b, base_point)[condition]
        self.assertAllClose(kappa, kappa_direct)
        result = kappa > 1.0 - 1e-12
        self.assertTrue(gs.all(result))
Ejemplo n.º 15
0
    def test_parallel_transport(self):
        metric = self.group.left_canonical_metric
        tan_a = self.tangent_vec
        tan_b = self.group.to_tangent(
            gs.random.rand(self.n_samples, self.group.n + 1, self.group.n + 1),
            self.point)
        end_point = metric.exp(tan_b, self.point)

        def is_isometry(tan_a, trans_a, basepoint, endpoint):
            is_tangent = self.group.is_tangent(trans_a, endpoint, atol=1e-6)
            is_equinormal = gs.isclose(metric.norm(trans_a, endpoint),
                                       metric.norm(tan_a, basepoint))
            return gs.logical_and(is_tangent, is_equinormal)

        transported = metric.parallel_transport(tan_a, tan_b, self.point)
        result = is_isometry(tan_a, transported, self.point, end_point)
        expected_end_point = metric.exp(tan_b, self.point)
        self.assertTrue(gs.all(result))
        self.assertAllClose(end_point, expected_end_point)

        new_tan_b = metric.log(self.point, end_point)
        result_vec = metric.parallel_transport(transported, new_tan_b,
                                               end_point)
        self.assertAllClose(result_vec, tan_a)
Ejemplo n.º 16
0
    def belongs(self, point, atol=gs.atol):
        """Test if a point belongs to the manifold.

        Parameters
        ----------
        point : array-like, shape=[..., {dim, [n_manifolds, dim_each]}]
            Point.
        atol : float,
            Tolerance.

        Returns
        -------
        belongs : array-like, shape=[...,]
            Boolean evaluating if the point belongs to the manifold.
        """
        point_type = self.default_point_type

        if point_type == "vector":
            intrinsic = self.metric.is_intrinsic(point)
            belongs = self._iterate_over_manifolds("belongs", {
                "point": point,
                "atol": atol
            }, intrinsic)
            belongs = gs.stack(belongs, axis=-1)

        else:
            belongs = gs.stack(
                [
                    space.belongs(point[..., i, :], atol)
                    for i, space in enumerate(self.manifolds)
                ],
                axis=-1,
            )

        belongs = gs.all(belongs, axis=-1)
        return belongs
Ejemplo n.º 17
0
    def fit(self, X, y):
        """Fit Wrapped Gaussian process regression model.

        The Wrapped Gaussian process is fit through the following steps:

        - Compute the tangent dataset using the prior
        - Fit a Gaussian process regression on the tangent dataset
        - Store the resulting euclidean Gaussian process

        Parameters
        ----------
        X : array-like of shape (n_samples, n_features) or list of object
            Feature vectors or other representations of training data.
        y : array-like of shape (n_samples,) or (n_samples, n_targets)
            Target values. The target must belongs to the manifold space

        Returns
        -------
        self : object
            WrappedGaussianProcessRegressor class instance.
        """
        if not gs.all(self.space.belongs(y)):
            raise AttributeError(
                "The target values must belongs to the given space")

        # compute the tangent dataset using the prior
        tangent_y = self._get_tangent_targets(X, y)
        # fit a gpr on the tangent dataset
        self._euclidean_gpr.fit(X, tangent_y)
        # update the attributes of the wgpr using the new attributes of the gpr

        self.__dict__.update(self._euclidean_gpr.__dict__)
        self.y_train_ = y
        self.tangent_y_train_ = tangent_y  # = self._euclidean_gpr.y_train_

        return self
Ejemplo n.º 18
0
    def is_vertical(self, tangent_vec, base_point, atol=gs.atol):
        """Evaluate if the tangent vector is vertical at base_point.

        Parameters
        ----------
        tangent_vec : array-like, shape=[..., {ambient_dim, [n, n]}]
            Tangent vector.
        base_point : array-like, shape=[..., {ambient_dim, [n, n]}]
            Point on the manifold.
            Optional, default: None.
        atol : float
            Absolute tolerance.
            Optional, default: backend atol.

        Returns
        -------
        is_vertical : bool
            Boolean denoting if tangent vector is vertical.
        """
        return gs.all(gs.isclose(tangent_vec,
                                 self.vertical_projection(
                                     tangent_vec, base_point),
                                 atol=atol),
                      axis=(-2, -1))
Ejemplo n.º 19
0
    def belongs(self, point, point_type=None):
        """Check if the point belongs to the manifold.

        Parameters
        ----------
        point
        point_type : str, {'vector', 'matrix'}

        Returns
        -------
        belongs: array-like, shape=[n_samples, 1]
        """
        if point_type is None:
            point_type = self.default_point_type
        assert point_type in ['vector', 'matrix']

        if point_type == 'vector':
            point = gs.to_ndarray(point, to_ndim=2)
        else:
            point = gs.to_ndarray(point, to_ndim=3)

        n_manifolds = self.n_manifolds
        belongs = gs.empty((point.shape[0], n_manifolds))
        cum_dim = 0
        # FIXME: this only works if the points are in intrinsic representation
        for i in range(n_manifolds):
            manifold_i = self.manifolds[i]
            cum_dim_next = cum_dim + manifold_i.dimension
            point_i = point[:, cum_dim:cum_dim_next]
            belongs_i = manifold_i.belongs(point_i)
            belongs[:, i] = belongs_i
            cum_dim = cum_dim_next

        belongs = gs.all(belongs, axis=1)
        belongs = gs.to_ndarray(belongs, to_ndim=2)
        return belongs
Ejemplo n.º 20
0
    def belongs(self, mat, atol=gs.atol):
        r"""Check if the matrix belongs to the space.

        Parameters
        ----------
        mat : array-like, shape=[..., n, n]
            Matrix to be checked.
        atol : float
            Tolerance.
            Optional, default: backend atol.

        Returns
        -------
        belongs : array-like, shape=[...,]
            Boolean denoting if mat is an SPD matrix.
        """
        is_symmetric = self.sym.belongs(mat, atol)
        eigvalues = gs.linalg.eigvalsh(mat)
        is_semipositive = gs.all(eigvalues > -atol, axis=-1)
        is_rankk = gs.sum(gs.where(eigvalues < atol, 0, 1),
                          axis=-1) == self.rank
        belongs = gs.logical_and(gs.logical_and(is_symmetric, is_semipositive),
                                 is_rankk)
        return belongs
Ejemplo n.º 21
0
    def test_to_tangent_is_tangent_in_ambient_space(self, space_args, vector,
                                                    base_point,
                                                    is_tangent_atol):
        """Check that tangent vectors are in ambient space's tangent space.

        This projects a vector to the tangent space of the manifold, and
        then checks that tangent vector belongs to ambient space's tangent space.

        Parameters
        ----------
        space_args : tuple
            Arguments to pass to constructor of the manifold.
        vector : array-like
            Vector to be projected on the tangent space at base_point.
        base_point : array-like
            Point on the manifold.
        is_tangent_atol : float
            Absolute tolerance for the is_tangent function.
        """
        space = self.space(*space_args)
        tangent_vec = space.to_tangent(gs.array(vector), gs.array(base_point))
        result = gs.all(
            space.ambient_space.is_tangent(tangent_vec, is_tangent_atol))
        self.assertAllClose(result, gs.array(True))
Ejemplo n.º 22
0
    def to_vector(mat):
        """Convert a symmetric matrix into a vector.

        Parameters
        ----------
        mat : array-like, shape=[..., n, n]
            Matrix.

        Returns
        -------
        vec : array-like, shape=[..., n(n+1)/2]
            Vector.
        """
        if not gs.all(Matrices.is_symmetric(mat)):
            logging.warning('non-symmetric matrix encountered.')
        mat = Matrices.to_symmetric(mat)
        _, dim, _ = mat.shape
        indices_i, indices_j = gs.triu_indices(dim)
        vec = []
        for i, j in zip(indices_i, indices_j):
            vec.append(mat[:, i, j])
        vec = gs.stack(vec, axis=1)

        return vec
Ejemplo n.º 23
0
 def add_points(self, points):
     assert gs.all(S1.belongs(points))
     if not isinstance(points, list):
         points = points.tolist()
     self.points.extend(points)
 def test_random_and_belongs(self):
     """Test of random point sampling method."""
     mat = self.space.random_point(5)
     result = self.space.belongs(mat)
     self.assertTrue(gs.all(result))
Ejemplo n.º 25
0
 def add_points(self, points):
     assert gs.all(H2.belongs(points))
     points = self.convert_to_klein_coordinates(points)
     if not isinstance(points, list):
         points = points.tolist()
     self.points.extend(points)
Ejemplo n.º 26
0
 def test_random_von_mises_fisher_belongs(self, dim, n_samples):
     space = self.space(dim)
     result = space.belongs(space.random_von_mises_fisher(n_samples=n_samples))
     self.assertAllClose(gs.all(result), gs.array(True))
Ejemplo n.º 27
0
 def test_riemannian_submersion(self, n, mat):
     bundle = self.bundle(n)
     point = bundle.riemannian_submersion(mat)
     result = gs.all(bundle.belongs(point))
     self.assertTrue(result)
Ejemplo n.º 28
0
 def test_cholesky_factor_belongs(self, n, mat):
     result = SPDMatrices(n).cholesky_factor(gs.array(mat))
     self.assertAllClose(
         gs.all(PositiveLowerTriangularMatrices(n).belongs(result)), True
     )
Ejemplo n.º 29
0
 def test_to_center_is_centered_vectorization(self):
     point = gs.ones((self.n_samples, self.k_landmarks, self.m_ambient))
     point = self.space.center(point)
     result = gs.all(self.space.is_centered(point))
     self.assertTrue(result)
Ejemplo n.º 30
0
 def add_points(self, points):
     if not gs.all(S2.belongs(points)):
         raise ValueError('Points do not belong to the sphere.')
     if not isinstance(points, list):
         points = list(points)
     self.points.extend(points)