def randvec(self, x): k = self._k n = self._n if k == 1: u = multiherm(rnd.randn(n, n)+1j*rnd.randn(n, n)) else: u = multiherm(rnd.randn(k, n, n)+1j*rnd.randn(k, n, n)) return u / self.norm(x, u)
def test_proj(self): man = self.man x = man.rand() a = rnd.randn(self.k, self.n, self.n) +1j * rnd.randn(self.k, self.n, self.n) np.testing.assert_allclose(man.proj(x, a), multiherm(a)) np.testing.assert_allclose(man.proj(x, a), man.proj(x, man.proj(x, a)))
def test_rand(self): # Just test that rand returns a point on the manifold and two # different matrices generated by rand aren't too close together k = self.k n = self.n man = self.man x = man.rand() y = man.rand() assert np.shape(x) == (k, n, n) assert x.dtype == np.complex # Check symmetry np_testing.assert_allclose(x, multiherm(x)) # Check positivity of eigenvalues w = la.eigvalsh(x) assert (w > [[0]]).all() # Check unit determinant d = np.real(la.det(x)) np_testing.assert_allclose(d, 1) # Check randomness assert la.norm(x - y) > 1e-3
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
def test_egrad2rgrad(self): man = self.man x = man.rand() u = rnd.randn(self.k, self.n, self.n) +1j * rnd.randn(self.k, self.n, self.n) np.testing.assert_allclose(man.egrad2rgrad(x, u), multiprod(multiprod(x, multiherm(u)), x))
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
def test_randvec(self): # Just test that randvec returns an element of the tangent space # with norm 1 and that two randvecs are different. man = self.man x = man.rand() u = man.randvec(x) v = man.randvec(x) np_testing.assert_allclose(multiherm(u), u) np_testing.assert_almost_equal(1, man.norm(x, u)) assert la.norm(u - v) > 1e-3
def test_proj(self): man = self.man x = man.rand() a = rnd.randn(self.n, self.n) +1j * rnd.randn(self.n, self.n) p = man.proj(x, a) assert np.shape(p) == (self.n, self.n) np.testing.assert_allclose(p, multiherm(p)) t = np.real(np.trace(la.solve(x, p))) np_testing.assert_almost_equal(t, 0) np.testing.assert_allclose(p, man.proj(x, p))
def proj(self, x, u): n = self._n k = self._k # Project matrix on tangent space of HPD. u = multiherm(u) # Project on tangent space of SHPD at x. t = np.trace(la.solve(x, u), axis1=-2, axis2=-1) if k == 1: u = u - (1/n) * np.real(t) * x else: u = u - (1/n) * np.real(t.reshape(-1, 1, 1)) * x return u
def test_proj(self): man = self.man x = man.rand() a = rnd.randn(self.k, self.n, self.n) +1j * rnd.randn(self.k, self.n, self.n) p = man.proj(x, a) np.testing.assert_allclose(p, multiherm(p)) t = np.ones(man._k, dtype=np.complex) temp = la.solve(x, p) for i in range(man._k): t[i] = np.real(np.trace(temp[i, :, :])) np_testing.assert_allclose(t, 0, atol=1e-7) np.testing.assert_allclose(p, man.proj(x, p))
def test_exp(self): # exp(x, u) = x + u. man = self.man x = man.rand() u = man.randvec(x) e = man.exp(x, u) # Check symmetry np_testing.assert_allclose(e, multiherm(e)) # Check positivity of eigenvalues w = la.eigvalsh(e) assert (w > [0]).all() u = u * 1e-6 np_testing.assert_allclose(man.exp(x, u), x + u)
def test_rand(self): # Just test that rand returns a point on the manifold and two # different matrices generated by rand aren't too close together n = self.n man = self.man x = man.rand() assert np.shape(x) == (n, n) assert x.dtype == np.complex # Check symmetry np_testing.assert_allclose(x, multiherm(x)) # Check positivity of eigenvalues w = la.eigvalsh(x) assert (w > [0]).all()
def test_exp(self): # Test against manopt implementation, test that for small vectors # exp(x, u) = x + u. man = self.man x = man.rand() u = man.randvec(x) e = man.exp(x, u) # Check symmetry np_testing.assert_allclose(e, multiherm(e)) # Check positivity of eigenvalues w = la.eigvalsh(e) assert (w > [[0]]).all() u = u * 1e-6 np_testing.assert_allclose(man.exp(x, u), x + u)
def test_retr(self): # Check that result is on manifold and for small vectors # retr(x, u) = x + u. man = self.man x = man.rand() u = man.randvec(x) y = man.retr(x, u) assert np.shape(y) == (self.k, self.n, self.n) # Check symmetry np_testing.assert_allclose(y, multiherm(y)) # Check positivity of eigenvalues w = la.eigvalsh(y) assert (w > [[0]]).all() u = u * 1e-6 np_testing.assert_allclose(man.retr(x, u), x + u)
def test_randvec(self): # Just test that randvec returns an element of the tangent space # with norm 1 and that two randvecs are different. man = self.man x = man.rand() u = man.randvec(x) v = man.randvec(x) np_testing.assert_allclose(multiherm(u), u) t = np.empty(man._k, dtype=np.complex) temp = la.solve(x, u) for i in range(man._k): t[i] = np.real(np.trace(temp[i, :, :])) np_testing.assert_allclose(t, 0, atol=1e-7) np_testing.assert_almost_equal(1, man.norm(x, u)) assert la.norm(u - v) > 1e-3
def test_randvec(self): # Just test that randvec returns an element of the tangent space # with norm 1 and that two randvecs are different. man = self.man n = self.n man = self.man x = man.rand() u = man.randvec(x) v = man.randvec(x) assert np.shape(x) == (n, n) assert x.dtype == np.complex np_testing.assert_allclose(multiherm(u), u) t = np.real(np.trace(la.solve(x, u))) np_testing.assert_almost_equal(t, 0) np_testing.assert_almost_equal(1, man.norm(x, u)) assert la.norm(u - v) > 1e-3
def ehess2rhess(self, x, egrad, ehess, u): egrad = multiherm(egrad) hess = multiprod(multiprod(x, multiherm(ehess)), x) hess += multiherm(multiprod(multiprod(u, egrad), x)) return hess
def egrad2rgrad(self, x, u): return multiprod(multiprod(x, multiherm(u)), x)
def proj(self, X, G): return multiherm(G)