示例#1
0
    def random_gaussian_rotation_orbit_noisy(self, mean_spd=None,
                                             eigensummary=None,
                                             var_rotations=1.,
                                             var_eigenvalues=None,
                                             n_samples=1):
        r"""
        Define a Gaussian-like random sample of SPD matrices.

        Formally speaking, sample an orbit for given rotations in the SPD
        manifold. For all means and purposes, it looks rather Gaussian.

        Parameters
        ----------
        mean_spd : array-like, shape = [n, n]
            Mean SPD matrix.
        var_rotations : float
            Variance in rotation.
        var_eigenvalues : array-like, shape = [n,]
            Additional variance in eigenvalues.
        eigensummary : EigenSummary
            Represents the mean SPD matrix decomposed in eigenspace and
            eigenvalues.

        Notes
        -----
        :math:'mean_spd' is the mean SPD matrix; :math:'var_rotations' is the
        scalar variance by which the mean is rotated:
        :math:'\Sigma_{mid} \sim \mathcal{N}(\Sigma_{in}, \sigma_{eig}';
        :math:'X_{out} = R \Sigma_{in} R^T'.
        mean_spd and eigensummary are mutually exclusive; an error is thrown
        if both are not None, or if both are None.
        """
        n = self.n
        if var_eigenvalues is None:
            var_eigenvalues = gs.ones(n)

        if mean_spd is not None and eigensummary is not None:
            raise NotImplementedError
        if mean_spd is None and eigensummary is None:
            raise NotImplementedError
        if eigensummary is None:
            eigenvalues, eigenspace = gs.linalg.eigh(mean_spd)
            eigenvalues = gs.diag(eigenvalues)
        if mean_spd is None:
            eigenvalues, eigenspace\
                = eigensummary.eigenvalues, eigensummary.eigenspace
        rotations = SpecialOrthogonal(n).random_gaussian(
            eigenspace, var_rotations, n_samples=n_samples)

        eigenvalues =\
            gs.abs(gs.diag(gs.random.multivariate_normal(
                gs.diag(eigenvalues), gs.diag(var_eigenvalues))))
        spd_mat = Matrices.mul(rotations, eigenvalues, Matrices.transpose(
            rotations))

        return spd_mat
示例#2
0
    def retraction(self, tangent_vec, base_point):
        """
        Retraction map, based on QR-decomposion:
        P_x(V) = qf(X + V)
        """
        tangent_vec = gs.to_ndarray(tangent_vec, to_ndim=3)
        n_tangent_vecs, _, _ = tangent_vec.shape

        base_point = gs.to_ndarray(base_point, to_ndim=3)
        n_base_points, n, p = base_point.shape

        assert (n_tangent_vecs == n_base_points
                or n_tangent_vecs == 1
                or n_base_points == 1)

        if n_base_points == 1:
            base_point = gs.tile(base_point, (n_tangent_vecs, 1, 1))
        if n_tangent_vecs == 1:
            tangent_vec = gs.tile(tangent_vec, (n_base_points, 1, 1))

        matrix_q, matrix_r = gs.linalg.qr(base_point+tangent_vec)

        diagonal = gs.diagonal(matrix_r, axis1=1, axis2=2)
        sign = gs.sign(gs.sign(diagonal) + 0.5)
        diag = gs.diag(sign)
        result = gs.einsum('nij,njk->nik', matrix_q, diag)

        return result
def closest_rotation_matrix(mat):
    """
    Compute the closest rotation matrix of a given matrix mat,
    in terms of the Frobenius norm.
    """
    mat = gs.to_ndarray(mat, to_ndim=3)

    n_mats, mat_dim_1, mat_dim_2 = mat.shape
    assert mat_dim_1 == mat_dim_2

    if mat_dim_1 == 3:
        mat_unitary_u, diag_s, mat_unitary_v = gs.linalg.svd(mat)
        rot_mat = gs.matmul(mat_unitary_u, mat_unitary_v)

        mask = gs.where(gs.linalg.det(rot_mat) < 0)
        new_mat_diag_s = gs.tile(gs.diag([1, 1, -1]), len(mask))

        rot_mat[mask] = gs.matmul(
            gs.matmul(mat_unitary_u[mask], new_mat_diag_s),
            mat_unitary_v[mask])
    else:
        aux_mat = gs.matmul(gs.transpose(mat, axes=(0, 2, 1)), mat)

        inv_sqrt_mat = gs.zeros_like(mat)
        for i in range(n_mats):
            sym_mat = aux_mat[i]

            assert spd_matrices_space.is_symmetric(sym_mat)
            inv_sqrt_mat[i] = gs.linalg.inv(spd_matrices_space.sqrtm(sym_mat))
        rot_mat = gs.matmul(mat, inv_sqrt_mat)

    assert rot_mat.ndim == 3
    return rot_mat
示例#4
0
    def setup_data(self):
        """Generate the un-shuffled dataset.

        Returns
        -------
        X : array-like,
           shape = [n_samples * n_classes, n_features, n_features]
            Data.
        y : array-like, shape = [n_samples * n_classes, n_classes]
            Labels.
        """
        mean_covariance_eigenvalues = gs.random.uniform(
            0.1, 5., (self.n_classes, self.n_features))
        var = 1.
        base_rotations = SpecialOrthogonal(n=self.n_features).random_gaussian(
            gs.eye(self.n_features), var, n_samples=self.n_classes)
        var_rotations = gs.random.uniform(.5, .75, (self.n_classes))

        y = gs.zeros((self.n_classes * self.n_samples, self.n_classes))
        X = []
        for i in range(self.n_classes):
            value_x = self.make_data(base_rotations[i],
                                     gs.diag(mean_covariance_eigenvalues[i]),
                                     var_rotations[i])
            value_y = 1
            idx_y = [
                (j, i)
                for j in range(i * self.n_samples, (i + 1) * self.n_samples)
            ]
            y = gs.assignment(y, value_y, idx_y)
            X.append(value_x)
        return gs.concatenate(X, axis=0), y
示例#5
0
    def projection(self, mat):
        """
        Project a matrix on SO(n), using the Frobenius norm.
        """
        # TODO(nina): projection when the point_type is not 'matrix'?
        mat = gs.to_ndarray(mat, to_ndim=3)

        n_mats, mat_dim_1, mat_dim_2 = mat.shape
        assert mat_dim_1 == mat_dim_2 == self.n

        if self.n == 3:
            mat_unitary_u, diag_s, mat_unitary_v = gs.linalg.svd(mat)
            rot_mat = gs.matmul(mat_unitary_u, mat_unitary_v)
            mask = gs.nonzero(gs.linalg.det(rot_mat) < 0)
            diag = gs.array([1, 1, -1])
            new_mat_diag_s = gs.tile(gs.diag(diag), len(mask))

            rot_mat[mask] = gs.matmul(
                gs.matmul(mat_unitary_u[mask], new_mat_diag_s),
                mat_unitary_v[mask])
        else:
            aux_mat = gs.matmul(gs.transpose(mat, axes=(0, 2, 1)), mat)

            inv_sqrt_mat = gs.zeros_like(mat)
            for i in range(n_mats):
                sym_mat = aux_mat[i]

                assert spd_matrices_space.is_symmetric(sym_mat)
                inv_sqrt_mat[i] = gs.linalg.inv(
                    spd_matrices_space.sqrtm(sym_mat))
            rot_mat = gs.matmul(mat, inv_sqrt_mat)

        assert gs.ndim(rot_mat) == 3
        return rot_mat
示例#6
0
    def retraction(self, tangent_vec, base_point):
        """Compute the retraction of a tangent vector.

        This computation is based on the QR-decomposition.

        e.g. :math:`P_x(V) = qf(X + V)`.

        Parameters
        ----------
        tangent_vec : array-like, shape=[n_samples, n, p]
            Tangent vector at a base point.
        base_point : array-like, shape=[n_samples, n, p]
            Point in the Stiefel manifold.

        Returns
        -------
        exp : array-like, shape=[n_samples, n, p]
            Point in the Stiefel manifold equal to the retraction
            of tangent_vec at the base point.
        """
        tangent_vec = gs.to_ndarray(tangent_vec, to_ndim=3)
        n_tangent_vecs, _, _ = tangent_vec.shape

        base_point = gs.to_ndarray(base_point, to_ndim=3)
        n_base_points, n, p = base_point.shape

        assert (n_tangent_vecs == n_base_points or n_tangent_vecs == 1
                or n_base_points == 1)

        if n_base_points == 1:
            base_point = gs.tile(base_point, (n_tangent_vecs, 1, 1))
        if n_tangent_vecs == 1:
            tangent_vec = gs.tile(tangent_vec, (n_base_points, 1, 1))

        matrix_q, matrix_r = gs.linalg.qr(base_point + tangent_vec)

        diagonal = gs.diagonal(matrix_r, axis1=1, axis2=2)
        sign = gs.sign(gs.sign(diagonal) + 0.5)
        diag = gs.diag(sign)
        result = gs.einsum('nij,njk->nik', matrix_q, diag)

        return result
示例#7
0
 def origin(self):
     return gs.diag(gs.repeat([1, 0], [self.k, self.n - self.k]))[0]
示例#8
0
 def closest(rot):
     d_coefs = gs.diagonal(rot)
     d_sign = gs.where(d_coefs >= 0, 1., -1.)
     return mul(rot, gs.diag(d_sign)[0])