def test_logm(self): """Test of logm method.""" expected = gs.array([[0.0, 1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]]) c = math.cosh(1) s = math.sinh(1) e = math.exp(1) v = gs.array([[c, s, 0.0], [s, c, 0.0], [0.0, 0.0, e]]) result = self.space.logm(v) four_dim_expected = gs.broadcast_to(expected, (2, 2) + expected.shape) four_dim_v = gs.broadcast_to(v, (2, 2) + v.shape) four_dim_result = self.space.logm(four_dim_v) self.assertAllClose(result, expected) self.assertAllClose(four_dim_result, four_dim_expected)
def test_expm(self): """Test of expm method.""" sym_n = SymmetricMatrices(self.n) v = gs.array([[0.0, 1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]]) result = sym_n.expm(v) c = math.cosh(1) s = math.sinh(1) e = math.exp(1) expected = gs.array([[c, s, 0.0], [s, c, 0.0], [0.0, 0.0, e]]) four_dim_v = gs.broadcast_to(v, (2, 2) + v.shape) four_dim_expected = gs.broadcast_to(expected, (2, 2) + expected.shape) four_dim_result = sym_n.expm(four_dim_v) self.assertAllClose(result, expected) self.assertAllClose(four_dim_result, four_dim_expected)
def tangent_natural_to_standard(self, vec, base_point): """Convert tangent vector from natural coordinates to standard coordinates. The change of variable is symmetric. Parameters ---------- base_point : array-like, shape=[..., 2] Point of the Gamma manifold, given in natural coordinates. vec : array-like, shape=[..., 2] Tangent vector at base_point, given in natural coordinates. Returns ------- vec : array-like, shape=[..., 2] Tangent vector at base_point, given in standard coordinates. """ vec = gs.to_ndarray(vec, to_ndim=2) base_point = gs.broadcast_to(base_point, vec.shape) n_points = base_point.shape[0] kappa, scale = ( base_point[..., 0], base_point[..., 1], ) jac = gs.array([[gs.ones(n_points), gs.zeros(n_points)], [1 / scale, -kappa / scale**2]]) jac = gs.transpose(jac, [2, 0, 1]) vec = gs.einsum("...jk,...k->...j", jac, vec) return gs.squeeze(vec)
def exp(self, tangent_vec, base_point, n_steps=N_STEPS, step="euler", point_type=None, **kwargs): """Exponential map associated to the affine connection. Exponential map at base_point of tangent_vec computed by integration of the geodesic equation (initial value problem), using the christoffel symbols. Parameters ---------- tangent_vec : array-like, shape=[..., dim] Tangent vector at the base point. base_point : array-like, shape=[..., dim] Point on the manifold. n_steps : int Number of discrete time steps to take in the integration. Optional, default: N_STEPS. step : str, {'euler', 'rk4'} The numerical scheme to use for integration. Optional, default: 'euler'. point_type : str, {'vector', 'matrix'} Type of representation used for points. Optional, default: None. Returns ------- exp : array-like, shape=[..., dim] Point on the manifold. """ base_point = gs.broadcast_to(base_point, tangent_vec.shape) initial_state = gs.stack([base_point, tangent_vec]) flow = integrate(self.geodesic_equation, initial_state, n_steps=n_steps, step=step) exp = flow[-1][0] return exp
def test_permute_vectorization(self, space, graph, id_permutation): permuted_graph = space.permute(graph, id_permutation) if graph.ndim == 2 and id_permutation.ndim == 1: n_out = 1 expected = graph else: n_out = max( 1 if graph.ndim == 2 else graph.shape[0], 1 if id_permutation.ndim == 1 else id_permutation.shape[0], ) expected = gs.broadcast_to(graph, (n_out, *graph.shape[-2:])) if n_out == 1: self.assertTrue(permuted_graph.shape == graph.shape) else: self.assertTrue(permuted_graph.shape[0] == n_out) self.assertAllClose(permuted_graph, expected)
def tangent_diffeomorphism(self, tangent_vec, base_point): r"""Tangent diffeomorphism at base point. Let :math:`f` be the diffeomorphism :math:`f: M \rightarrow N` of the manifold :math:`M` into the manifold `N`. df_p is a linear map from T_pM to T_f(p)N called the tangent immesion Parameters ---------- tangent_vec : array-like, shape=[..., *shape] Tangent vector at base point. base_point : array-like, shape=[..., *shape] Base point. Returns ------- image_tangent_vec : array-like, shape=[..., *i_shape] Image tangent vector at image of the base point. """ base_point = gs.broadcast_to(base_point, tangent_vec.shape) rad = base_point.shape[:-len(self.shape)] J_flat = gs.reshape( self.jacobian_diffeomorphism(base_point), (-1, self.embedding_space_shape_dim, self.shape_dim), ) tv_flat = gs.reshape(tangent_vec, (-1, self.shape_dim)) image_tv = gs.reshape( gs.einsum("...ij,...j->...i", J_flat, tv_flat), rad + self.embedding_metric.shape, ) return image_tv
def inner_product(self, tangent_vec_a, tangent_vec_b, base_point=None): """Compute the inner-product of two tangent vectors at a base point. Parameters ---------- tangent_vec_a : array-like, shape=[..., n_samples] First tangent vector at base point. tangent_vec_b : array-like, shape=[..., n_samples] Second tangent vector at base point. base_point : array-like, shape=[..., n_samples], optional Point on the hypersphere. Returns ------- inner_prod : array-like, shape=[...,] Inner-product of the two tangent vectors. """ tangent_vec_a, tangent_vec_b = gs.broadcast_arrays(tangent_vec_a, tangent_vec_b) x = gs.broadcast_to(self.x, tangent_vec_a.shape) l2_norm = gs.trapz(tangent_vec_a * tangent_vec_b, x=x, axis=-1) return l2_norm