def skew_matrix_from_vector(vec):
    """
    In 3D, compute the skew-symmetric matrix,
    known as the cross-product of a vector,
    associated to the vector vec.

    In nD, fill a skew-symmetric matrix with
    the values of the vector.
    """
    vec = gs.to_ndarray(vec, to_ndim=2)
    n_vecs, vec_dim = vec.shape

    mat_dim = int((1 + gs.sqrt(1 + 8 * vec_dim)) / 2)
    skew_mat = gs.zeros((n_vecs, ) + (mat_dim, ) * 2)

    if vec_dim == 3:
        for i in range(n_vecs):
            skew_mat[i] = gs.cross(gs.eye(vec_dim), vec[i])
    else:
        upper_triangle_indices = gs.triu_indices(mat_dim, k=1)
        for i in range(n_vecs):
            skew_mat[i][upper_triangle_indices] = vec[i]
            skew_mat[i] = skew_mat[i] - skew_mat[i].transpose()

    assert skew_mat.ndim == 3
    return skew_mat
Пример #2
0
    def from_vector(vec, dtype=gs.float32):
        """Convert a vector into a symmetric matrix.

        Parameters
        ----------
        vec : array-like, shape=[..., n(n+1)/2]
            Vector.

        Returns
        -------
        mat : array-like, shape=[..., n, n]
            Symmetric matrix.
        """
        vec_dim = vec.shape[-1]
        mat_dim = (gs.sqrt(8. * vec_dim + 1) - 1) / 2
        if mat_dim != int(mat_dim):
            raise ValueError('Invalid input dimension, it must be of the form'
                             '(n_samples, n * (n + 1) / 2)')
        mat_dim = int(mat_dim)
        shape = (mat_dim, mat_dim)
        mask = 2 * gs.ones(shape) - gs.eye(mat_dim)
        indices = list(zip(*gs.triu_indices(mat_dim)))
        vec = gs.cast(vec, dtype)
        upper_triangular = gs.stack(
            [gs.array_from_sparse(indices, data, shape) for data in vec])
        mat = Matrices.to_symmetric(upper_triangular) * mask
        return mat
Пример #3
0
 def vector_from_symmetric_matrix(mat):
     """Convert the symmetric part of a symmetric matrix into a vector."""
     if not gs.all(Matrices.is_symmetric(mat)):
         logging.warning('non-symmetric matrix encountered.')
     mat = Matrices.make_symmetric(mat)
     _, dim, _ = mat.shape
     i, j = gs.triu_indices(dim)
     vec = mat[:, i, j]
     return vec
Пример #4
0
    def to_vector(mat):
        """Convert the symmetric part of a symmetric matrix into a 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
Пример #5
0
 def symmetric_matrix_from_vector(vec, dtype=gs.float32):
     """Convert a vector into a symmetric matrix."""
     vec_dim = vec.shape[-1]
     mat_dim = (gs.sqrt(8. * vec_dim + 1) - 1) / 2
     if mat_dim != int(mat_dim):
         raise ValueError('Invalid input dimension, it must be of the form'
                          '(n_samples, n * (n - 1) / 2)')
     mat_dim = int(mat_dim)
     mask = 2 * gs.ones((mat_dim, mat_dim)) - gs.eye(mat_dim)
     indices = list(zip(*gs.triu_indices(3)))
     shape = (mat_dim, mat_dim)
     vec = gs.cast(vec, dtype)
     upper_triangular = gs.stack(
         [gs.array_from_sparse(indices, data, shape) for data in vec])
     mat = Matrices.make_symmetric(upper_triangular) * mask
     return mat
    def basis_representation(self, matrix_representation):
        """Calculate the coefficients of given matrix in the basis.

        Parameters
        ----------
        matrix_representation: array-like, shape=[n_sample, n, n]

        Returns
        ------
        basis_representation: array-like, shape=[n_sample, dimension]
        """
        old_shape = gs.shape(matrix_representation)
        as_vector = gs.reshape(matrix_representation, (old_shape[0], -1))
        upper_tri_indices = gs.reshape(gs.arange(
            0, self.n**2), (self.n, self.n))[gs.triu_indices(self.n, k=1)]

        return as_vector[:, upper_tri_indices]
Пример #7
0
    def basis_representation(self, matrix_representation):
        """Calculate the coefficients of given matrix in the basis.

        Compute a 1d-array that corresponds to the input matrix in the basis
        representation.

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

        Returns
        -------
        basis_representation : array-like, shape=[..., dim]
        """
        old_shape = gs.shape(matrix_representation)
        as_vector = gs.reshape(matrix_representation, (old_shape[0], -1))
        upper_tri_indices = gs.reshape(gs.arange(
            0, self.n**2), (self.n, self.n))[gs.triu_indices(self.n, k=1)]

        return as_vector[:, upper_tri_indices]
Пример #8
0
    def dist_pairwise(self, points, n_jobs=1, **joblib_kwargs):
        """Compute the pairwise distance between points.

        Parameters
        ----------
        points : array-like, shape=[n_samples, dim]
            Set of points in the manifold.
        n_jobs : int
            Number of jobs to run in parallel, using joblib. Note that a
            higher number of jobs may not be beneficial when one computation
            of a geodesic distance is cheap.
            Optional. Default: 1.
        **joblib_kwargs : dict
            Keyword arguments to joblib.Parallel

        Returns
        -------
        dist : array-like, shape=[n_samples, n_samples]
            Pairwise distance matrix between all the points.

        See Also
        --------
        https://joblib.readthedocs.io/en/latest/
        """
        n_samples = points.shape[0]
        rows, cols = gs.triu_indices(n_samples)

        @joblib.delayed
        @joblib.wrap_non_picklable_objects
        def pickable_dist(x, y):
            """Wrap distance function to make it pickable."""
            return self.dist(x, y)

        pool = joblib.Parallel(n_jobs=n_jobs, **joblib_kwargs)
        out = pool(
            pickable_dist(points[i], points[j]) for i, j in zip(rows, cols))

        pairwise_dist = (
            geometry.symmetric_matrices.SymmetricMatrices.from_vector(
                gs.array(out)))
        return pairwise_dist
Пример #9
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
Пример #10
0
    def skew_matrix_from_vector(self, vec):
        """Get the skew-symmetric matrix derived from the vector.

        In 3D, compute the skew-symmetric matrix,known as the cross-product of
        a vector, associated to the vector `vec`.

        In nD, fill a skew-symmetric matrix with the values of the vector.

        Parameters
        ----------
        vec : array-like, shape=[..., dim]

        Returns
        -------
        skew_mat : array-like, shape=[..., n, n]
        """
        n_vecs, vec_dim = gs.shape(vec)

        if self.n == 2:
            vec = gs.tile(vec, [1, 2])
            vec = gs.reshape(vec, (n_vecs, 2))

            id_skew = gs.array(gs.tile([[[0., 1.], [-1., 0.]]],
                                       (n_vecs, 1, 1)))
            skew_mat = gs.einsum('...ij,...i->...ij',
                                 gs.cast(id_skew, gs.float32), vec)

        elif self.n == 3:
            levi_civita_symbol = gs.tile(
                [[[[0., 0., 0.], [0., 0., 1.], [0., -1., 0.]],
                  [[0., 0., -1.], [0., 0., 0.], [1., 0., 0.]],
                  [[0., 1., 0.], [-1., 0., 0.], [0., 0., 0.]]]],
                (n_vecs, 1, 1, 1))

            levi_civita_symbol = gs.array(levi_civita_symbol)
            levi_civita_symbol += self.epsilon

            # This avoids dividing by 0.
            basis_vec_1 = gs.array(gs.tile([[1., 0., 0.]],
                                           (n_vecs, 1))) + self.epsilon
            basis_vec_2 = gs.array(gs.tile([[0., 1., 0.]],
                                           (n_vecs, 1))) + self.epsilon
            basis_vec_3 = gs.array(gs.tile([[0., 0., 1.]],
                                           (n_vecs, 1))) + self.epsilon

            cross_prod_1 = gs.einsum('nijk,ni,nj->nk', levi_civita_symbol,
                                     basis_vec_1, vec)
            cross_prod_2 = gs.einsum('nijk,ni,nj->nk', levi_civita_symbol,
                                     basis_vec_2, vec)
            cross_prod_3 = gs.einsum('nijk,ni,nj->nk', levi_civita_symbol,
                                     basis_vec_3, vec)

            cross_prod_1 = gs.to_ndarray(cross_prod_1, to_ndim=3, axis=1)
            cross_prod_2 = gs.to_ndarray(cross_prod_2, to_ndim=3, axis=1)
            cross_prod_3 = gs.to_ndarray(cross_prod_3, to_ndim=3, axis=1)
            skew_mat = gs.concatenate(
                [cross_prod_1, cross_prod_2, cross_prod_3], axis=1)

        else:  # SO(n)
            mat_dim = gs.cast(((1. + gs.sqrt(1. + 8. * vec_dim)) / 2.),
                              gs.int32)
            skew_mat = gs.zeros((n_vecs, ) + (self.n, ) * 2)
            upper_triangle_indices = gs.triu_indices(mat_dim, k=1)
            for i in range(n_vecs):
                skew_mat[i][upper_triangle_indices] = vec[i]
                skew_mat[i] = skew_mat[i] - gs.transpose(skew_mat[i])
        return skew_mat