Example #1
0
    def log(self, x, y):
        k = self._k

        d, q = la.eigh(x)
        if k == 1:
            x_sqrt = [email protected](np.sqrt(d))@q.conj().T
            x_isqrt = [email protected](1/np.sqrt(d))@q.conj().T
        else:
            temp = np.zeros(q.shape, dtype=np.complex)
            for i in range(q.shape[0]):
                temp[i, :, :] = np.diag(np.sqrt(d[i, :]))[np.newaxis, :, :]
            x_sqrt = multiprod(multiprod(q, temp), multihconj(q))

            temp = np.zeros(q.shape, dtype=np.complex)
            for i in range(q.shape[0]):
                temp[i, :, :] = np.diag(1/np.sqrt(d[i, :]))[np.newaxis, :, :]
            x_isqrt = multiprod(multiprod(q, temp), multihconj(q))

        d, q = la.eigh(multiprod(multiprod(x_isqrt, y), x_isqrt))
        if k == 1:
            log = [email protected](np.log(d))@q.conj().T
        else:
            temp = np.zeros(q.shape, dtype=np.complex)
            for i in range(q.shape[0]):
                temp[i, :, :] = np.diag(np.log(d[i, :]))[np.newaxis, :, :]
            d = temp
            log = multiprod(multiprod(q, d), multihconj(q))

        xi = multiprod(multiprod(x_sqrt, log), x_sqrt)
        xi = multiherm(xi)
        return xi
Example #2
0
 def log(self, point_a, point_b):
     YHX = multihconj(point_b) @ point_a
     AH = multihconj(point_b) - YHX @ multihconj(point_a)
     BH = np.linalg.solve(YHX, AH)
     U, S, VH = np.linalg.svd(multihconj(BH), full_matrices=False)
     arctan_S = np.expand_dims(np.arctan(S), -2)
     return (U * arctan_S) @ VH
Example #3
0
    def exp(self, x, u):
        k = self._k

        d, q = la.eigh(x)
        if k == 1:
            x_sqrt = [email protected](np.sqrt(d))@q.conj().T
            x_isqrt = [email protected](1/np.sqrt(d))@q.conj().T
        else:
            temp = np.zeros(q.shape, dtype=np.complex)
            for i in range(q.shape[0]):
                temp[i, :, :] = np.diag(np.sqrt(d[i, :]))[np.newaxis, :, :]
            x_sqrt = multiprod(multiprod(q, temp), multihconj(q))

            temp = np.zeros(q.shape, dtype=np.complex)
            for i in range(q.shape[0]):
                temp[i, :, :] = np.diag(1/np.sqrt(d[i, :]))[np.newaxis, :, :]
            x_isqrt = multiprod(multiprod(q, temp), multihconj(q))

        d, q = la.eigh(multiprod(multiprod(x_isqrt, u), x_isqrt))
        if k == 1:
            e = [email protected](np.exp(d))@q.conj().T
        else:
            temp = np.zeros(q.shape, dtype=np.complex)
            for i in range(q.shape[0]):
                temp[i, :, :] = np.diag(np.exp(d[i, :]))[np.newaxis, :, :]
            d = temp
            e = multiprod(multiprod(q, d), multihconj(q))

        e = multiprod(multiprod(x_sqrt, e), x_sqrt)
        e = multiherm(e)
        return e
Example #4
0
 def log(self, X, Y):
     YHX = multiprod(multihconj(Y), X)
     AH = multihconj(Y) - multiprod(YHX, multihconj(X))
     BH = np.linalg.solve(YHX, AH)
     U, S, VH = np.linalg.svd(multihconj(BH), full_matrices=False)
     arctan_S = np.expand_dims(np.arctan(S), -2)
     U = multiprod(U * arctan_S, VH)
     return U
Example #5
0
 def transp(self, x1, x2, d):
     E = multihconj(la.solve(multihconj(x1), multihconj(x2)))
     if self._k == 1:
         E = sqrtm(E)
     else:
         for i in range(len(E)):
             E[i, :, :] = sqrtm(E[i, :, :])
     transp_d = multiprod(multiprod(E, d), multihconj(E))
     return transp_d
Example #6
0
 def egrad(Q):
     """
     need to be fixed
     """
     QQ = np.matmul(Q, multihconj(Q))
     tmp = np.array([QQ for i in range(N)])
     XQQX = multiprod(multiprod(multihconj(X), tmp), X)
     lam, V = np.linalg.eigh(XQQX)
     theta = np.arccos(np.sqrt(lam))
     d = -2*theta/(np.cos(theta)*np.sin(theta))
     Sig = np.array([np.diag(dd) for dd in d])
     XV = multiprod(X,V)
     eg = multiprod(XV, multiprod(Sig, multitransp(XV.conj())))
     eg = np.mean(eg, axis = 0)
     eg = np.matmul(eg, Q)
     return eg
Example #7
0
    def rand(self):
        # Generate eigenvalues between 1 and 2
        # (eigenvalues of a symmetric matrix are always real).
        d = np.ones((self._k, self._n, 1)) + rnd.rand(self._k, self._n, 1)

        # Generate an orthogonal matrix. Annoyingly qr decomp isn't
        # vectorized so need to use a for loop. Could be done using
        # svd but this is slower for bigger matrices.
        u = np.zeros((self._k, self._n, self._n), dtype=np.complex)
        for i in range(self._k):
            u[i], r = la.qr(
                rnd.randn(self._n, self._n)+1j*rnd.randn(self._n, self._n))

        if self._k == 1:
            return multiprod(u, d * multihconj(u))[0]
        return multiprod(u, d * multihconj(u))
Example #8
0
 def test_multiexpm_conjugate_symmetric(self):
     shape = (self.k, self.m, self.m)
     A = np.random.normal(size=shape) + 1j * np.random.normal(size=shape)
     A = 0.5 * (A + multihconj(A))
     # Compare fast path for conjugate symmetric matrices vs. general slow
     # one.
     np_testing.assert_allclose(multiexpm(A, symmetric=True),
                                multiexpm(A, symmetric=False))
Example #9
0
 def norm(self, x, u):
     # This implementation is as fast as np.linalg.solve_triangular and is
     # more stable, as the above solver tends to output non positive
     # definite results.
     c = la.cholesky(x)
     c_inv = la.inv(c)
     return np.real(
         la.norm(multiprod(multiprod(c_inv, u), multihconj(c_inv))))
Example #10
0
 def test_rand(self):
     # Just make sure that things generated are on the manifold and that
     # if you generate two they are not equal.
     X = self.man.rand()
     np_testing.assert_allclose(multiprod(multihconj(X), X),
                                multieye(self.k, self.n), atol=1e-10)
     Y = self.man.rand()
     assert la.norm(X - Y) > 1e-6
     assert np.iscomplex(X).all()
Example #11
0
    def exp(self, point, tangent_vector):
        U, S, VH = np.linalg.svd(tangent_vector, full_matrices=False)
        cos_S = np.expand_dims(np.cos(S), -2)
        sin_S = np.expand_dims(np.sin(S), -2)
        Y = point @ (multihconj(VH) * cos_S) @ VH + (U * sin_S) @ VH

        # From numerical experiments, it seems necessary to
        # re-orthonormalize. This is overall quite expensive.
        q, _ = multiqr(Y)
        return q
Example #12
0
 def test_multilogm_complex_positive_definite(self):
     shape = (self.k, self.m, self.m)
     A = np.random.normal(size=shape) + 1j * np.random.normal(size=shape)
     A = A @ multihconj(A)
     # Compare fast path for positive definite matrices vs. general slow
     # one.
     np_testing.assert_allclose(
         multilogm(A, positive_definite=True),
         multilogm(A, positive_definite=False),
     )
Example #13
0
 def test_randvec(self):
     # Make sure things generated are in tangent space and if you generate
     # two then they are not equal.
     X = self.man.rand()
     U = self.man.randvec(X)
     np_testing.assert_allclose(multisym(multiprod(multihconj(X), U)),
                                np.zeros((self.k, self.n, self.n)),
                                atol=1e-10)
     V = self.man.randvec(X)
     assert la.norm(U - V) > 1e-6
     assert np.iscomplex(U).all()
 def test_random_point(self):
     # Just make sure that things generated are on the manifold
     # and that if you generate two they are not equal.
     # Test also that matrices are complex.
     X = self.manifold.random_point()
     np_testing.assert_allclose(multihconj(X) @ X,
                                np.eye(self.n),
                                atol=1e-10)
     Y = self.manifold.random_point()
     assert np.linalg.norm(X - Y) > 1e-6
     assert np.iscomplex(X).all()
Example #15
0
    def test_proj(self):
        # Test proj(proj(X)) == proj(X)
        # and proj(X) belongs to the horizontal space of Stiefel
        X = self.man.rand()
        U = rnd.randn(self.m, self.n) + 1j*rnd.randn(self.m, self.n)
        proj_U = self.man.proj(X, U)
        proj_proj_U = self.man.proj(X, proj_U)

        np_testing.assert_allclose(proj_U, proj_proj_U)

        np_testing.assert_allclose(multiprod(multihconj(X), proj_U),
                                   np.zeros((self.n, self.n)), atol=1e-10)
Example #16
0
 def test_randvec(self):
     # Just make sure that things generated are on the horizontal space of
     # complex Stiefel manifold
     # and that if you generate two they are not equal.
     # Test also that matrices are complex.
     X = self.man.rand()
     G = self.man.randvec(X)
     np_testing.assert_allclose(multiprod(multihconj(X), G),
                                np.zeros((self.n, self.n)), atol=1e-10)
     H = self.man.randvec(X)
     assert la.norm(G - H) > 1e-6
     assert np.iscomplex(G).all()
 def test_random_tangent_vector(self):
     # Make sure things generated are in tangent space and if you generate
     # two then they are not equal.
     X = self.manifold.random_point()
     U = self.manifold.random_tangent_vector(X)
     np_testing.assert_allclose(
         multisym(multihconj(X) @ U),
         np.zeros((self.k, self.n, self.n)),
         atol=1e-10,
     )
     V = self.manifold.random_tangent_vector(X)
     assert np.linalg.norm(U - V) > 1e-6
     assert np.iscomplex(U).all()
    def test_retraction(self):
        # Test that the result is on the manifold and that for small
        # tangent vectors it has little effect.
        x = self.manifold.random_point()
        u = self.manifold.random_tangent_vector(x)

        xretru = self.manifold.retraction(x, u)

        np_testing.assert_allclose(multihconj(xretru) @ xretru,
                                   np.eye(self.n),
                                   atol=1e-10)

        u = u * 1e-6
        xretru = self.manifold.retraction(x, u)
        np_testing.assert_allclose(xretru, x + u)
Example #19
0
    def test_retr(self):
        # Test that the result is on the manifold and that for small
        # tangent vectors it has little effect.
        x = self.man.rand()
        u = self.man.randvec(x)

        xretru = self.man.retr(x, u)

        np_testing.assert_allclose(multiprod(multihconj(xretru), xretru),
                                   np.eye(self.n),
                                   atol=1e-10)

        u = u * 1e-6
        xretru = self.man.retr(x, u)
        np_testing.assert_allclose(xretru, x + u)
    def test_projection(self):
        # Test proj(proj(X)) == proj(X)
        # and proj(X) belongs to the horizontal space of Stiefel
        X = self.manifold.random_point()
        U = np.random.normal(size=(
            self.m, self.n)) + 1j * np.random.normal(size=(self.m, self.n))
        proj_U = self.manifold.projection(X, U)
        proj_proj_U = self.manifold.projection(X, proj_U)

        np_testing.assert_allclose(proj_U, proj_proj_U)

        np_testing.assert_allclose(
            multihconj(X) @ proj_U,
            np.zeros((self.n, self.n)),
            atol=1e-10,
        )
Example #21
0
    def exp(self, X, U):
        U, S, VH = np.linalg.svd(U, full_matrices=False)
        cos_S = np.expand_dims(np.cos(S), -2)
        sin_S = np.expand_dims(np.sin(S), -2)
        Y = (multiprod(multiprod(X,
                                 multihconj(VH) * cos_S), VH) +
             multiprod(U * sin_S, VH))

        # From numerical experiments, it seems necessary to
        # re-orthonormalize. This is overall quite expensive.
        if self._k == 1:
            Y, _ = np.linalg.qr(Y)
            return Y
        else:
            for i in range(self._k):
                Y[i], _ = np.linalg.qr(Y[i])
            return Y
Example #22
0
 def proj(self, X, U):
     return U - multiprod(X, multiprod(multihconj(X), U))
Example #23
0
 def dist(self, x, y):
     c = la.cholesky(x)
     c_inv = la.inv(c)
     logm = multilog(multiprod(multiprod(c_inv, y), multihconj(c_inv)),
                     pos_def=True)
     return np.real(la.norm(logm))
Example #24
0
 def dist(self, X, Y):
     _, s, _ = np.linalg.svd(multiprod(multihconj(X), Y))
     s[s > 1] = 1
     s = np.arccos(s)
     return np.linalg.norm(np.real(s))
Example #25
0
 def ehess2rhess(self, X, egrad, ehess, H):
     PXehess = self.proj(X, ehess)
     XHG = multiprod(multihconj(X), egrad)
     HXHG = multiprod(H, XHG)
     return PXehess - HXHG
Example #26
0
def DR_geod_complex(X, m, verbosity=0):
    """ 
    X: array of N points on Gr(n, p); N x n x p array
    aim to represent X by X_hat (N points on Gr(m, p), m < n) 
    where X_hat_i = R^T X_i, W \in St(n, m)
    minimizing the projection error (using geodesic distance)
    """
    N, n, p = X.shape
    Cgr = ComplexGrassmann(n, p, N)
    Cgr_low = Grassmann(m, p)
    Cgr_map = ComplexGrassmann(n, m) # n x m
    XXT = multiprod(X, multihconj(X))
    
    @pymanopt.function.Callable
    def cost(Q):
        tmp = np.array([np.matmul(Q, Q.T) for i in range(N)]) # N x n x n
        new_X = multiprod(tmp, X) # N x n x p
        q = np.array([qr(new_X[i])[0] for i in range(N)])
        d2 = Cgr.dist(X, q)**2
        return d2/N
    
    @pymanopt.function.Callable
    def egrad(Q):
        """
        need to be fixed
        """
        QQ = np.matmul(Q, multihconj(Q))
        tmp = np.array([QQ for i in range(N)])
        XQQX = multiprod(multiprod(multihconj(X), tmp), X)
        lam, V = np.linalg.eigh(XQQX)
        theta = np.arccos(np.sqrt(lam))
        d = -2*theta/(np.cos(theta)*np.sin(theta))
        Sig = np.array([np.diag(dd) for dd in d])
        XV = multiprod(X,V)
        eg = multiprod(XV, multiprod(Sig, multitransp(XV.conj())))
        eg = np.mean(eg, axis = 0)
        eg = np.matmul(eg, Q)
        return eg

    def egrad_num(R, eps = 1e-8+1e-8j):
        """
        compute egrad numerically
        """
        g = np.zeros(R.shape, dtype=np.complex128)
        for i in range(n):
            for j in range(m):
                R1 = R.copy()
                R2 = R.copy()
                R1[i,j] += eps
                R2[i,j] -= eps
                g[i,j] = (cost(R1) - cost(R2))/(2*eps)
        return g

    # solver = ConjugateGradient()
    solver = SteepestDescent()
    problem = Problem(manifold=Cst, cost=cost, egrad=egrad, verbosity=verbosity)
    Q_proj = solver.solve(problem)

    tmp = np.array([multihconj(Q_proj) for i in range(N)])
    X_low = multiprod(tmp, X)
    X_low = X_low/np.expand_dims(np.linalg.norm(X_low, axis=1), axis = 2)

    M_hat = compute_centroid(Cgr_low, X_low)
    v_hat = var(Cgr_low, X_low, M_hat)/N
    var_ratio = v_hat/v
    return var_ratio, X_low, Q_proj
Example #27
0
 def euclidean_to_riemannian_hessian(self, point, euclidean_gradient,
                                     euclidean_hessian, tangent_vector):
     PXehess = self.projection(point, euclidean_hessian)
     XHG = multihconj(point) @ euclidean_gradient
     HXHG = tangent_vector @ XHG
     return PXehess - HXHG
Example #28
0
 def projection(self, point, vector):
     return vector - point @ multihconj(point) @ vector
Example #29
0
 def dist(self, point_a, point_b):
     s = np.linalg.svd(multihconj(point_a) @ point_b, compute_uv=False)
     s[s > 1] = 1
     s = np.arccos(s)
     return np.linalg.norm(np.real(s))