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))
def exp(self, point, tangent_vector): pt_tv = multitransp(point) @ tangent_vector if self._k == 1: identity = np.eye(self._p) else: identity = multieye(self._k, self._p) a = np.block([point, tangent_vector]) b = multiexpm( np.block([ [ pt_tv, -multitransp(tangent_vector) @ tangent_vector, ], [identity, pt_tv], ]))[..., :self._p] c = multiexpm(-pt_tv) return a @ (b @ c)
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)
def test_multiexpm(self): A = multisym(np.random.normal(size=(self.k, self.m, self.m))) e = np.zeros((self.k, self.m, self.m)) for i in range(self.k): e[i] = expm(A[i]) np_testing.assert_allclose(multiexpm(A, symmetric=True), e)
def test_multiexpm_singlemat(self): # A is a positive definite matrix A = np.random.normal(size=(self.m, self.m)) A = A + A.T np_testing.assert_allclose(multiexpm(A, symmetric=True), expm(A))
def exp(self, point, tangent_vector): p_inv_tv = np.linalg.solve(point, tangent_vector) return point @ multiexpm(p_inv_tv, symmetric=False)
def exp(self, point, tangent_vector): return point @ multiexpm(tangent_vector)