Example #1
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 #2
0
    def test_dist(self):
        # n = self.n
        manifold = self.manifold
        x = manifold.random_point()
        y = manifold.random_point()
        z = manifold.random_point()

        # Test separability
        np_testing.assert_almost_equal(manifold.dist(x, x), 0.0)

        # Test symmetry
        np_testing.assert_almost_equal(
            manifold.dist(x, y), manifold.dist(y, x)
        )

        # Test triangle inequality
        assert manifold.dist(x, y) <= manifold.dist(x, z) + manifold.dist(z, y)

        # Test exponential metric increasing property
        # (see equation (6.8) in [Bha2007]).
        logx, logy = multilogm(x), multilogm(y)
        assert manifold.dist(x, y) >= np.linalg.norm(logx - logy)

        # check that dist is consistent with log
        np_testing.assert_almost_equal(
            manifold.dist(x, y), manifold.norm(x, manifold.log(x, y))
        )

        # Test invariance under inversion
        np_testing.assert_almost_equal(
            manifold.dist(x, y),
            manifold.dist(np.linalg.inv(y), np.linalg.inv(x)),
        )

        # Test congruence-invariance
        a = np.random.normal(size=(self.n, self.n))  # must be invertible
        axa = a @ x @ multitransp(a)
        aya = a @ y @ multitransp(a)
        np_testing.assert_almost_equal(
            manifold.dist(x, y), manifold.dist(axa, aya)
        )

        # Test proportionality (see equation (6.12) in [Bha2007]).
        alpha = np.random.uniform()
        np_testing.assert_almost_equal(
            manifold.dist(x, geodesic(x, y, alpha)),
            alpha * manifold.dist(x, y),
        )
Example #3
0
 def test_multilogm_singlemat(self):
     a = np.diag(np.random.uniform(size=self.m))
     q, _ = np.linalg.qr(np.random.normal(size=(self.m, self.m)))
     # A is a positive definite matrix
     A = q @ a @ q.T
     np_testing.assert_allclose(multilogm(A, positive_definite=True),
                                logm(A))
Example #4
0
 def dist(self, point_a, point_b):
     c = np.linalg.cholesky(point_a)
     c_inv = np.linalg.inv(c)
     logm = multilogm(
         c_inv @ point_b @ multitransp(c_inv),
         positive_definite=True,
     )
     return np.linalg.norm(logm)
Example #5
0
 def test_multilogm(self):
     A = np.zeros((self.k, self.m, self.m))
     L = np.zeros((self.k, self.m, self.m))
     for i in range(self.k):
         a = np.diag(np.random.uniform(size=self.m))
         q, _ = np.linalg.qr(np.random.normal(size=(self.m, self.m)))
         A[i] = q @ a @ q.T
         L[i] = logm(A[i])
     np_testing.assert_allclose(multilogm(A, positive_definite=True), L)
Example #6
0
def geodesic(point_a, point_b, alpha):
    if alpha < 0 or 1 < alpha:
        raise ValueError("Exponent must be in [0,1]")
    c = np.linalg.cholesky(point_a)
    c_inv = np.linalg.inv(c)
    log_cbc = multilogm(
        c_inv @ point_b @ multitransp(c_inv),
        positive_definite=True,
    )
    powm = multiexpm(alpha * log_cbc, symmetric=False)
    return c @ powm @ multitransp(c)
Example #7
0
 def log(self, point_a, point_b):
     return multiskew(multilogm(multitransp(point_a) @ point_b))