def randvec(self, x): k = self._k n = self._n if k == 1: u = multisym(rnd.randn(n, n)) else: u = multisym(rnd.randn(k, n, n)) return u / self.norm(x, u)
def random_tangent_vector(self, point): k = self._k n = self._n if k == 1: tangent_vector = multisym(np.random.normal(size=(n, n))) else: tangent_vector = multisym(np.random.normal(size=(k, n, n))) return tangent_vector / self.norm(point, tangent_vector)
def test_ehess2rhess(self): # Use manopt's slow method man = self.man n = self.n k = self.k x = man.rand() egrad, ehess = rnd.randn(2, k, n, n) u = man.randvec(x) Hess = (multiprod(multiprod(x, multisym(ehess)), x) + 2*multisym(multiprod(multiprod(u, multisym(egrad)), x))) # Correction factor for the non-constant metric Hess = Hess - multisym(multiprod(multiprod(u, multisym(egrad)), x)) np_testing.assert_almost_equal(Hess, man.ehess2rhess(x, egrad, ehess, u))
def test_random_point(self): e = self.manifold x = e.random_point() y = e.random_point() assert np.shape(x) == (self.k, self.n, self.n) np_testing.assert_allclose(x, multisym(x)) assert np.linalg.norm(x - y) > 1e-6
def test_ehess2rhess(self): e = self.man x = e.rand() u = e.randvec(x) egrad, ehess = rnd.randn(2, self.k, self.n, self.n) np_testing.assert_allclose(e.ehess2rhess(x, egrad, ehess, u), multisym(ehess))
def euclidean_to_riemannian_hessian(self, point, euclidean_gradient, euclidean_hessian, tangent_vector): Xt = multitransp(point) Xtegrad = Xt @ euclidean_gradient symXtegrad = multisym(Xtegrad) Xtehess = Xt @ euclidean_hessian return multiskew(Xtehess - tangent_vector @ symXtegrad)
def test_euclidean_to_riemannian_hessian(self): # Use manopt's slow method manifold = self.manifold n = self.n k = self.k x = manifold.random_point() egrad, ehess = np.random.normal(size=(2, k, n, n)) u = manifold.random_tangent_vector(x) Hess = x @ multisym(ehess) @ x + 2 * multisym(u @ multisym(egrad) @ x) # Correction factor for the non-constant metric Hess = Hess - multisym(u @ multisym(egrad) @ x) np_testing.assert_almost_equal( Hess, manifold.euclidean_to_riemannian_hessian(x, egrad, ehess, u) )
def test_rand(self): e = self.man x = e.rand() y = e.rand() assert np.shape(x) == (self.k, self.n, self.n) np_testing.assert_allclose(x, multisym(x)) assert la.norm(x - y) > 1e-6
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(X.T.dot(U)), np.zeros((self.n, self.n)), atol=1e-10) V = self.man.randvec(X) assert la.norm(U - V) > 1e-6
def test_multisym(self): A = rnd.randn(self.k, self.m, self.m) C = np.zeros((self.k, self.m, self.m)) for i in range(self.k): C[i] = .5 * (A[i] + A[i].T) np.testing.assert_allclose(C, multisym(A))
def test_euclidean_to_riemannian_gradient(self): manifold = self.manifold x = manifold.random_point() u = np.random.normal(size=(self.k, self.n, self.n)) np_testing.assert_allclose( manifold.euclidean_to_riemannian_gradient(x, u), x @ multisym(u) @ x, )
def test_multisym(self): A = rnd.randn(self.k, self.m, self.m) C = np.zeros((self.k, self.m, self.m)) for i in range(self.k): C[i] = 0.5 * (A[i] + A[i].T) np.testing.assert_allclose(C, multisym(A))
def test_multisym(self): A = np.random.normal(size=(self.k, self.m, self.m)) C = np.zeros((self.k, self.m, self.m)) for i in range(self.k): C[i] = 0.5 * (A[i] + A[i].T) np.testing.assert_allclose(C, multisym(A))
def log(self, *argv): """Computes the Lie-theoretic and Riemannian logarithmic map (depending on signature, i.e. whether footpoint is given as well) """ X = log_mat(argv[-1]) if len(argv) == 2: # Riemannian log X -= log_mat(argv[0]) return multisym(X)
def test_randvec(self): e = self.man x = e.rand() u = e.randvec(x) v = e.randvec(x) assert np.shape(u) == (self.k, self.n, self.n) np_testing.assert_allclose(u, multisym(u)) np_testing.assert_almost_equal(la.norm(u), 1) assert la.norm(u - v) > 1e-6
def test_euclidean_to_riemannian_hessian(self): e = self.manifold x = e.random_point() u = e.random_tangent_vector(x) egrad, ehess = np.random.normal(size=(2, self.k, self.n, self.n)) np_testing.assert_allclose( e.euclidean_to_riemannian_hessian(x, egrad, ehess, u), multisym(ehess), )
def test_random_tangent_vector(self): e = self.manifold x = e.random_point() u = e.random_tangent_vector(x) v = e.random_tangent_vector(x) assert np.shape(u) == (self.k, self.n, self.n) np_testing.assert_allclose(u, multisym(u)) np_testing.assert_almost_equal(np.linalg.norm(u), 1) assert np.linalg.norm(u - v) > 1e-6
def test_random_tangent_vector(self): # Just test that random_tangent_vector returns an element of the tangent space # with norm 1 and that two random_tangent_vectors are different. manifold = self.manifold x = manifold.random_point() u = manifold.random_tangent_vector(x) v = manifold.random_tangent_vector(x) np_testing.assert_allclose(multisym(u), u) np_testing.assert_almost_equal(1, manifold.norm(x, u)) assert np.linalg.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 x = man.rand() u = man.randvec(x) v = man.randvec(x) np_testing.assert_allclose(multisym(u), u) np_testing.assert_almost_equal(1, man.norm(x, u)) assert la.norm(u - v) > 1e-3
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(X.T @ U), np.zeros((self.n, self.n)), atol=1e-10) V = self.manifold.random_tangent_vector(X) assert np.linalg.norm(U - V) > 1e-6
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_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) # Check symmetry np_testing.assert_allclose(x, multisym(x)) # Check positivity of eigenvalues w = la.eigvalsh(x) assert (w > [0]).all()
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) # Check symmetry np_testing.assert_allclose(x, multisym(x)) # Check positivity of eigenvalues l = la.eigvalsh(x) assert (l > [0]).all()
def test_retraction(self): # Check that result is on manifold and for small vectors # retr(x, u) = x + u. manifold = self.manifold x = manifold.random_point() u = manifold.random_tangent_vector(x) y = manifold.retraction(x, u) assert np.shape(y) == (self.k, self.n, self.n) # Check symmetry np_testing.assert_allclose(y, multisym(y)) # Check positivity of eigenvalues w = np.linalg.eigvalsh(y) assert (w > [[0]]).all() u = u * 1e-6 np_testing.assert_allclose(manifold.retraction(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, multisym(y)) # Check positivity of eigenvalues l = la.eigvalsh(y) assert (l > [[0]]).all() u = u * 1e-6 np_testing.assert_allclose(man.retr(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, multisym(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_proj(self): man = self.man x = man.rand() a = rnd.randn(self.k, self.n, self.n) np.testing.assert_allclose(man.proj(x, a), multisym(a))
def egrad2rgrad(self, x, u): # TODO: Check that this is correct return multiprod(multiprod(x, multisym(u)), x)
def ehess2rhess(self, x, egrad, ehess, u): # TODO: Check that this is correct return (multiprod(multiprod(x, multisym(ehess)), x) + multisym(multiprod(multiprod(u, multisym(egrad)), x)))
def randvec(self, x): if self._k == 1: u = multisym(np.random.randn(self._n, self._n)) else: u = multisym(np.random.randn(self._k, self._n, self._n)) return u / self.norm(x, u)
def proj(self, X, G): return multisym(G)
def egrad2rgrad(self, X, U): return multisym(U)
def rand(self): return multisym(rnd.randn(*self._shape))
def randvec(self, X): Y = self.rand() return multisym(Y / self.norm(X, Y))
def test_multiexp(self): A = multisym(rnd.randn(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(multiexp(A, sym=True), e)
def proj(self, X, U): return multisym(U)
def ehess2rhess(self, X, egrad, ehess, H): # Convert Euclidean into Riemannian Hessian. XtG = multiprod(multitransp(X), egrad) symXtG = multisym(XtG) HsymXtG = multiprod(H, symXtG) return self.proj(X, ehess - HsymXtG)
def proj(self, X, U): return U - multiprod(X, multisym(multiprod(multitransp(X), U)))
def test_egrad2rgrad(self): man = self.man x = man.rand() u = rnd.randn(self.k, self.n, self.n) np.testing.assert_allclose(man.egrad2rgrad(x, u), multiprod(multiprod(x, multisym(u)), x))
def ehess2rhess(self, X, egrad, ehess, H): return multisym(ehess)
def ehess2rhess(self, X, egrad, ehess, H): Xt = multitransp(X) Xtegrad = multiprod(Xt, egrad) symXtegrad = multisym(Xtegrad) Xtehess = multiprod(Xt, ehess) return multiskew(Xtehess - multiprod(H, symXtegrad))
def test_proj(self): e = self.man x = e.rand() u = np.random.randn(self.k, self.n, self.n) np_testing.assert_allclose(e.proj(x, u), multisym(u))