def test_spherical_to_extrinsic_and_inverse(self): dim = 2 n_samples = 5 sphere = Hypersphere(dim) points = gs.random.rand(n_samples, 2) * gs.pi * gs.array([1., 2. ])[None, :] extrinsic = sphere.spherical_to_extrinsic(points) result = sphere.extrinsic_to_spherical(extrinsic) self.assertAllClose(result, points) points_extrinsic = sphere.random_uniform(n_samples) spherical = sphere.extrinsic_to_spherical(points_extrinsic) result = sphere.spherical_to_extrinsic(spherical) self.assertAllClose(result, points_extrinsic)
def test_exp_connection_metric(self, dim, tangent_vec, base_point): sphere = Hypersphere(dim) connection = Connection(dim) point_ext = sphere.spherical_to_extrinsic(base_point) vector_ext = sphere.tangent_spherical_to_extrinsic( tangent_vec, base_point) connection.christoffels = sphere.metric.christoffels expected = sphere.metric.exp(vector_ext, point_ext) result_spherical = connection.exp(tangent_vec, base_point, n_steps=50, step="rk4") result = sphere.spherical_to_extrinsic(result_spherical) self.assertAllClose(result, expected)
def test_log_connection_metric(self, dim, point, base_point, atol): sphere = Hypersphere(dim) connection = Connection(dim) connection.christoffels = sphere.metric.christoffels vector = connection.log(point=point, base_point=base_point, n_steps=75, step="rk4", tol=1e-10) result = sphere.tangent_spherical_to_extrinsic(vector, base_point) p_ext = sphere.spherical_to_extrinsic(base_point) q_ext = sphere.spherical_to_extrinsic(point) expected = sphere.metric.log(base_point=p_ext, point=q_ext) self.assertAllClose(result, expected, atol)
def load_cities(): """Load data from data/cities/cities.json. Returns ------- data : array-like, shape=[50, 2] Array with each row representing one sample, i. e. latitude and longitude of a city. Angles are in radians. name : list List of city names. """ with open(CITIES_PATH, encoding='utf-8') as json_file: data_file = json.load(json_file) names = [row['city'] for row in data_file] data = list( map( lambda row: [row[col_name] / 180 * gs.pi for col_name in ['lat', 'lng']], data_file, )) data = gs.array(data) colat = gs.pi / 2 - data[:, 0] colat = gs.expand_dims(colat, axis=1) lng = gs.expand_dims(data[:, 1] + gs.pi, axis=1) data = gs.concatenate([colat, lng], axis=1) sphere = Hypersphere(dim=2) data = sphere.spherical_to_extrinsic(data) return data, names
def test_spherical_to_extrinsic_vectorization(self): dim = 2 sphere = Hypersphere(dim) points_spherical = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]]) result = sphere.spherical_to_extrinsic(points_spherical) expected = gs.array([[1., 0., 0.], [gs.sqrt(2) / 4, gs.sqrt(2) / 4, gs.sqrt(3) / 2]]) self.assertAllClose(result, expected)
def test_spherical_to_extrinsic(self): """ Check vectorization of conversion from spherical to extrinsic coordinates on the 2-sphere. """ dim = 2 sphere = Hypersphere(dim) points_spherical = gs.array([gs.pi / 2, 0]) result = sphere.spherical_to_extrinsic(points_spherical) expected = gs.array([1.0, 0.0, 0.0]) self.assertAllClose(result, expected)
class TestConnection(geomstats.tests.TestCase): def setup_method(self): warnings.simplefilter("ignore", category=UserWarning) gs.random.seed(0) self.dim = 4 self.euc_metric = EuclideanMetric(dim=self.dim) self.connection = Connection(dim=2) self.hypersphere = Hypersphere(dim=2) def test_metric_matrix(self): base_point = gs.array([0.0, 1.0, 0.0, 0.0]) result = self.euc_metric.metric_matrix(base_point) expected = gs.eye(self.dim) self.assertAllClose(result, expected) def test_parallel_transport(self): n_samples = 2 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) expected = self.hypersphere.metric.parallel_transport( tan_vec_a, base_point, tan_vec_b) expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point) base_point = gs.cast(base_point, gs.float64) base_point, tan_vec_a, tan_vec_b = gs.convert_to_wider_dtype( [base_point, tan_vec_a, tan_vec_b]) for step, alpha in zip(["pole", "schild"], [1, 2]): min_n = 1 if step == "pole" else 50 tol = 1e-5 if step == "pole" else 1e-2 for n_rungs in [min_n, 11]: ladder = self.hypersphere.metric.ladder_parallel_transport( tan_vec_a, base_point, tan_vec_b, n_rungs=n_rungs, scheme=step, alpha=alpha, ) result = ladder["transported_tangent_vec"] result_point = ladder["end_point"] self.assertAllClose(result, expected, rtol=tol, atol=tol) self.assertAllClose(result_point, expected_point) def test_parallel_transport_trajectory(self): n_samples = 2 for step in ["pole", "schild"]: n_steps = 1 if step == "pole" else 50 tol = 1e-6 if step == "pole" else 1e-2 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.to_tangent( gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.to_tangent( gs.random.rand(n_samples, 3), base_point) expected = self.hypersphere.metric.parallel_transport( tan_vec_a, base_point, tan_vec_b) expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point) ladder = self.hypersphere.metric.ladder_parallel_transport( tan_vec_a, base_point, tan_vec_b, n_rungs=n_steps, scheme=step, return_geodesics=True, ) result = ladder["transported_tangent_vec"] result_point = ladder["end_point"] self.assertAllClose(result, expected, rtol=tol, atol=tol) self.assertAllClose(result_point, expected_point) def test_ladder_alpha(self): n_samples = 2 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) with pytest.raises(ValueError): self.hypersphere.metric.ladder_parallel_transport( tan_vec_a, base_point, tan_vec_b, n_rungs=1, scheme="pole", alpha=0.5, return_geodesics=False, ) def test_exp_connection_metric(self): point = gs.array([gs.pi / 2, 0]) vector = gs.array([0.25, 0.5]) point_ext = self.hypersphere.spherical_to_extrinsic(point) vector_ext = self.hypersphere.tangent_spherical_to_extrinsic( vector, point) self.connection.christoffels = self.hypersphere.metric.christoffels expected = self.hypersphere.metric.exp(vector_ext, point_ext) result_spherical = self.connection.exp(vector, point, n_steps=50, step="rk4") result = self.hypersphere.spherical_to_extrinsic(result_spherical) self.assertAllClose(result, expected) def test_exp_connection_metric_vectorization(self): point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]]) vector = gs.array([[0.25, 0.5], [0.30, 0.2]]) point_ext = self.hypersphere.spherical_to_extrinsic(point) vector_ext = self.hypersphere.tangent_spherical_to_extrinsic( vector, point) self.connection.christoffels = self.hypersphere.metric.christoffels expected = self.hypersphere.metric.exp(vector_ext, point_ext) result_spherical = self.connection.exp(vector, point, n_steps=50, step="rk4") result = self.hypersphere.spherical_to_extrinsic(result_spherical) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_log_connection_metric(self): base_point = gs.array([gs.pi / 3, gs.pi / 4]) point = gs.array([1.0, gs.pi / 2]) self.connection.christoffels = self.hypersphere.metric.christoffels vector = self.connection.log(point=point, base_point=base_point, n_steps=75, step="rk4", tol=1e-10) result = self.hypersphere.tangent_spherical_to_extrinsic( vector, base_point) p_ext = self.hypersphere.spherical_to_extrinsic(base_point) q_ext = self.hypersphere.spherical_to_extrinsic(point) expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_log_connection_metric_vectorization(self): base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]]) point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]]) self.connection.christoffels = self.hypersphere.metric.christoffels vector = self.connection.log(point=point, base_point=base_point, n_steps=75, step="rk4", tol=1e-10) result = self.hypersphere.tangent_spherical_to_extrinsic( vector, base_point) p_ext = self.hypersphere.spherical_to_extrinsic(base_point) q_ext = self.hypersphere.spherical_to_extrinsic(point) expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext) self.assertAllClose(result, expected, atol=1e-6) def test_geodesic_and_coincides_exp_hypersphere(self): n_geodesic_points = 10 initial_point = self.hypersphere.random_uniform(2) vector = gs.array([[2.0, 0.0, -1.0]] * 2) initial_tangent_vec = self.hypersphere.to_tangent( vector=vector, base_point=initial_point) geodesic = self.hypersphere.metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) t = gs.linspace(start=0.0, stop=1.0, num=n_geodesic_points) points = geodesic(t) result = points[:, -1] expected = self.hypersphere.metric.exp(vector, initial_point) self.assertAllClose(expected, result) initial_point = initial_point[0] initial_tangent_vec = initial_tangent_vec[0] geodesic = self.hypersphere.metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) points = geodesic(t) result = points[-1] expected = self.hypersphere.metric.exp(initial_tangent_vec, initial_point) self.assertAllClose(expected, result) def test_geodesic_and_coincides_exp_son(self): n_geodesic_points = 10 space = SpecialOrthogonal(n=4) initial_point = space.random_uniform(2) vector = gs.random.rand(2, 4, 4) initial_tangent_vec = space.to_tangent(vector=vector, base_point=initial_point) geodesic = space.bi_invariant_metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) t = gs.linspace(start=0.0, stop=1.0, num=n_geodesic_points) points = geodesic(t) result = points[:, -1] expected = space.bi_invariant_metric.exp(initial_tangent_vec, initial_point) self.assertAllClose(result, expected) initial_point = initial_point[0] initial_tangent_vec = initial_tangent_vec[0] geodesic = space.bi_invariant_metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) points = geodesic(t) result = points[-1] expected = space.bi_invariant_metric.exp(initial_tangent_vec, initial_point) self.assertAllClose(expected, result) def test_geodesic_invalid_initial_conditions(self): space = SpecialOrthogonal(n=4) initial_point = space.random_uniform(2) vector = gs.random.rand(2, 4, 4) initial_tangent_vec = space.to_tangent(vector=vector, base_point=initial_point) end_point = space.random_uniform(2) with pytest.raises(RuntimeError): space.bi_invariant_metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec, end_point=end_point, ) def test_geodesic_vectorization(self): space = Hypersphere(2) metric = space.metric initial_point = space.random_uniform(2) vector = gs.random.rand(2, 3) initial_tangent_vec = space.to_tangent(vector=vector, base_point=initial_point) end_point = space.random_uniform(2) time = gs.linspace(0, 1, 10) geo = metric.geodesic(initial_point, initial_tangent_vec) path = geo(time) result = path.shape expected = (2, 10, 3) self.assertAllClose(result, expected) geo = metric.geodesic(initial_point, end_point=end_point) path = geo(time) result = path.shape expected = (2, 10, 3) self.assertAllClose(result, expected) geo = metric.geodesic(initial_point, end_point=end_point[0]) path = geo(time) result = path.shape expected = (2, 10, 3) self.assertAllClose(result, expected) initial_tangent_vec = space.to_tangent(vector=vector, base_point=initial_point[0]) geo = metric.geodesic(initial_point[0], initial_tangent_vec) path = geo(time) result = path.shape expected = (2, 10, 3) self.assertAllClose(result, expected)
class TestConnection(geomstats.tests.TestCase): def setUp(self): warnings.simplefilter('ignore', category=UserWarning) self.dim = 4 self.euc_metric = EuclideanMetric(dim=self.dim) self.connection = Connection(dim=2) self.hypersphere = Hypersphere(dim=2) def test_metric_matrix(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.metric_matrix(base_point) expected = gs.eye(self.dim) self.assertAllClose(result, expected) def test_cometric_matrix(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_inverse_matrix(base_point) expected = gs.eye(self.dim) self.assertAllClose(result, expected) @geomstats.tests.np_only def test_metric_derivative(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_derivative_matrix(base_point) expected = gs.zeros((self.dim, ) * 3) self.assertAllClose(result, expected) @geomstats.tests.np_only def test_christoffels(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.christoffels(base_point) expected = gs.zeros((self.dim, ) * 3) self.assertAllClose(result, expected) def test_parallel_transport(self): n_samples = 2 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) expected = self.hypersphere.metric.parallel_transport( tan_vec_a, tan_vec_b, base_point) expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point) base_point = gs.cast(base_point, gs.float64) base_point, tan_vec_a, tan_vec_b = gs.convert_to_wider_dtype( [base_point, tan_vec_a, tan_vec_b]) for step, alpha in zip(['pole', 'schild'], [1, 2]): min_n = 1 if step == 'pole' else 50 tol = 1e-5 if step == 'pole' else 1e-2 for n_rungs in [min_n, 11]: ladder = self.hypersphere.metric.ladder_parallel_transport( tan_vec_a, tan_vec_b, base_point, scheme=step, n_rungs=n_rungs, alpha=alpha) result = ladder['transported_tangent_vec'] result_point = ladder['end_point'] self.assertAllClose(result, expected, rtol=tol, atol=tol) self.assertAllClose(result_point, expected_point) def test_parallel_transport_trajectory(self): n_samples = 2 for step in ['pole', 'schild']: n_steps = 1 if step == 'pole' else 50 tol = 1e-6 if step == 'pole' else 1e-2 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.to_tangent( gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.to_tangent( gs.random.rand(n_samples, 3), base_point) expected = self.hypersphere.metric.parallel_transport( tan_vec_a, tan_vec_b, base_point) expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point) ladder = self.hypersphere.metric.ladder_parallel_transport( tan_vec_a, tan_vec_b, base_point, return_geodesics=True, scheme=step, n_rungs=n_steps) result = ladder['transported_tangent_vec'] result_point = ladder['end_point'] self.assertAllClose(result, expected, rtol=tol, atol=tol) self.assertAllClose(result_point, expected_point) def test_ladder_alpha(self): n_samples = 2 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3), base_point) self.assertRaises( ValueError, lambda: self.hypersphere.metric. ladder_parallel_transport(tan_vec_a, tan_vec_b, base_point, return_geodesics=False, scheme='pole', n_rungs=1, alpha=0.5)) def test_exp_connection_metric(self): point = gs.array([gs.pi / 2, 0]) vector = gs.array([0.25, 0.5]) point_ext = self.hypersphere.spherical_to_extrinsic(point) vector_ext = self.hypersphere.tangent_spherical_to_extrinsic( vector, point) self.connection.christoffels = self.hypersphere.metric.christoffels expected = self.hypersphere.metric.exp(vector_ext, point_ext) result_spherical = self.connection.exp(vector, point, n_steps=50, step='rk4') result = self.hypersphere.spherical_to_extrinsic(result_spherical) self.assertAllClose(result, expected, rtol=1e-6) def test_exp_connection_metric_vectorization(self): point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]]) vector = gs.array([[0.25, 0.5], [0.30, 0.2]]) point_ext = self.hypersphere.spherical_to_extrinsic(point) vector_ext = self.hypersphere.tangent_spherical_to_extrinsic( vector, point) self.connection.christoffels = self.hypersphere.metric.christoffels expected = self.hypersphere.metric.exp(vector_ext, point_ext) result_spherical = self.connection.exp(vector, point, n_steps=50, step='rk4') result = self.hypersphere.spherical_to_extrinsic(result_spherical) self.assertAllClose(result, expected, rtol=1e-6) def test_log_connection_metric(self): base_point = gs.array([gs.pi / 3, gs.pi / 4]) point = gs.array([1.0, gs.pi / 2]) self.connection.christoffels = self.hypersphere.metric.christoffels vector = self.connection.log(point=point, base_point=base_point, n_steps=75, step='rk', tol=1e-10) result = self.hypersphere.tangent_spherical_to_extrinsic( vector, base_point) p_ext = self.hypersphere.spherical_to_extrinsic(base_point) q_ext = self.hypersphere.spherical_to_extrinsic(point) expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext) self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5) def test_log_connection_metric_vectorization(self): base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]]) point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]]) self.connection.christoffels = self.hypersphere.metric.christoffels vector = self.connection.log(point=point, base_point=base_point, n_steps=75, step='rk', tol=1e-10) result = self.hypersphere.tangent_spherical_to_extrinsic( vector, base_point) p_ext = self.hypersphere.spherical_to_extrinsic(base_point) q_ext = self.hypersphere.spherical_to_extrinsic(point) expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext) self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5) def test_geodesic_and_coincides_exp_hypersphere(self): n_geodesic_points = 10 initial_point = self.hypersphere.random_uniform(2) vector = gs.array([[2., 0., -1.]] * 2) initial_tangent_vec = self.hypersphere.to_tangent( vector=vector, base_point=initial_point) geodesic = self.hypersphere.metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) t = gs.linspace(start=0., stop=1., num=n_geodesic_points) points = geodesic(t) result = points[-1] expected = self.hypersphere.metric.exp(vector, initial_point) self.assertAllClose(expected, result) initial_point = initial_point[0] initial_tangent_vec = initial_tangent_vec[0] geodesic = self.hypersphere.metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) points = geodesic(t) result = points[-1] expected = self.hypersphere.metric.exp(initial_tangent_vec, initial_point) self.assertAllClose(expected, result) def test_geodesic_and_coincides_exp_son(self): n_geodesic_points = 10 space = SpecialOrthogonal(n=4) initial_point = space.random_uniform(2) vector = gs.random.rand(2, 4, 4) initial_tangent_vec = space.to_tangent(vector=vector, base_point=initial_point) geodesic = space.bi_invariant_metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) t = gs.linspace(start=0., stop=1., num=n_geodesic_points) points = geodesic(t) result = points[-1] expected = space.bi_invariant_metric.exp(initial_tangent_vec, initial_point) self.assertAllClose(result, expected) initial_point = initial_point[0] initial_tangent_vec = initial_tangent_vec[0] geodesic = space.bi_invariant_metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) points = geodesic(t) result = points[-1] expected = space.bi_invariant_metric.exp(initial_tangent_vec, initial_point) self.assertAllClose(expected, result) def test_geodesic_invalid_initial_conditions(self): space = SpecialOrthogonal(n=4) initial_point = space.random_uniform(2) vector = gs.random.rand(2, 4, 4) initial_tangent_vec = space.to_tangent(vector=vector, base_point=initial_point) end_point = space.random_uniform(2) self.assertRaises( RuntimeError, lambda: space.bi_invariant_metric.geodesic( initial_point=initial_point, initial_tangent_vec=initial_tangent_vec, end_point=end_point))
class TestPullbackMetric(geomstats.tests.TestCase): def setUp(self): warnings.simplefilter("ignore", category=UserWarning) gs.random.seed(0) self.dim = 2 self.sphere = Hypersphere(dim=self.dim) self.sphere_metric = self.sphere.metric def _sphere_immersion(spherical_coords): theta = spherical_coords[..., 0] phi = spherical_coords[..., 1] return gs.array([ gs.cos(phi) * gs.sin(theta), gs.sin(phi) * gs.sin(theta), gs.cos(theta), ]) self.immersion = _sphere_immersion self.pullback_metric = PullbackMetric(dim=self.dim, embedding_dim=self.dim + 1, immersion=self.immersion) @geomstats.tests.autograd_tf_and_torch_only def test_immersion(self): expected = gs.array([0.0, 0.0, 1.0]) result = self.immersion(gs.array([0.0, 0.0])) self.assertAllClose(result, expected) expected = gs.array([0.0, 0.0, -1.0]) result = self.immersion(gs.array([gs.pi, 0.0])) self.assertAllClose(result, expected) expected = gs.array([-1.0, 0.0, 0.0]) result = self.immersion(gs.array([gs.pi / 2.0, gs.pi])) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_immersion_and_spherical_to_extrinsic(self): point = gs.array([0.0, 0.0]) expected = self.immersion(point) result = self.sphere.spherical_to_extrinsic(point) self.assertAllClose(result, expected) point = gs.array([0.2, 0.1]) expected = self.immersion(point) result = self.sphere.spherical_to_extrinsic(point) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_jacobian_immersion(self): def _expected_jacobian_immersion(point): theta = point[..., 0] phi = point[..., 1] jacobian = gs.array([ [gs.cos(phi) * gs.cos(theta), -gs.sin(phi) * gs.sin(theta)], [gs.sin(phi) * gs.cos(theta), gs.cos(phi) * gs.sin(theta)], [-gs.sin(theta), 0.0], ]) return jacobian pole = gs.array([0.0, 0.0]) result = self.pullback_metric.jacobian_immersion(pole) expected = _expected_jacobian_immersion(pole) self.assertAllClose(result, expected) base_point = gs.array([0.22, 0.1]) result = self.pullback_metric.jacobian_immersion(base_point) expected = _expected_jacobian_immersion(base_point) self.assertAllClose(result, expected) base_point = gs.array([0.1, 0.88]) result = self.pullback_metric.jacobian_immersion(base_point) expected = _expected_jacobian_immersion(base_point) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_tangent_immersion(self): point = gs.array([gs.pi / 2.0, gs.pi / 2.0]) tangent_vec = gs.array([1.0, 0.0]) result = self.pullback_metric.tangent_immersion(tangent_vec, point) expected = gs.array([0.0, 0.0, -1.0]) self.assertAllClose(result, expected) tangent_vec = gs.array([0.0, 1.0]) result = self.pullback_metric.tangent_immersion(tangent_vec, point) expected = gs.array([-1.0, 0.0, 0.0]) self.assertAllClose(result, expected) point = gs.array([gs.pi / 2.0, 0.0]) tangent_vec = gs.array([1.0, 0.0]) result = self.pullback_metric.tangent_immersion(tangent_vec, point) expected = gs.array([0.0, 0.0, -1.0]) self.assertAllClose(result, expected) tangent_vec = gs.array([0.0, 1.0]) result = self.pullback_metric.tangent_immersion(tangent_vec, point) expected = gs.array([0.0, 1.0, 0.0]) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_metric_matrix(self): def _expected_metric_matrix(point): theta = point[..., 0] mat = gs.array([[1.0, 0.0], [0.0, gs.sin(theta)**2]]) return mat base_point = gs.array([0.0, 0.0]) result = self.pullback_metric.metric_matrix(base_point) expected = _expected_metric_matrix(base_point) self.assertAllClose(result, expected) base_point = gs.array([1.0, 1.0]) result = self.pullback_metric.metric_matrix(base_point) expected = _expected_metric_matrix(base_point) self.assertAllClose(result, expected) base_point = gs.array([0.3, 0.8]) result = self.pullback_metric.metric_matrix(base_point) expected = _expected_metric_matrix(base_point) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_inverse_metric_matrix(self): def _expected_inverse_metric_matrix(point): theta = point[..., 0] mat = gs.array([[1.0, 0.0], [0.0, gs.sin(theta)**(-2)]]) return mat base_point = gs.array([0.6, -1.0]) result = self.pullback_metric.metric_inverse_matrix(base_point) expected = _expected_inverse_metric_matrix(base_point) self.assertAllClose(result, expected) base_point = gs.array([0.8, -0.8]) result = self.pullback_metric.metric_inverse_matrix(base_point) expected = _expected_inverse_metric_matrix(base_point) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_inner_product_and_sphere_inner_product(self): """Test consistency between sphere's inner-products. The inner-product of the class Hypersphere is defined in terms of extrinsic coordinates. The inner-product of pullback_metric is defined in terms of the spherical coordinates. """ tangent_vec_a = gs.array([0.0, 1.0]) tangent_vec_b = gs.array([0.0, 1.0]) base_point = gs.array([gs.pi / 2.0, 0.0]) immersed_base_point = self.immersion(base_point) jac_immersion = self.pullback_metric.jacobian_immersion(base_point) immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a) immersed_tangent_vec_b = gs.matmul(jac_immersion, tangent_vec_b) result = self.pullback_metric.inner_product(tangent_vec_a, tangent_vec_b, base_point=base_point) expected = self.sphere_metric.inner_product( immersed_tangent_vec_a, immersed_tangent_vec_b, base_point=immersed_base_point, ) self.assertAllClose(result, expected) tangent_vec_a = gs.array([0.4, 1.0]) tangent_vec_b = gs.array([0.2, 0.6]) base_point = gs.array([gs.pi / 2.0, 0.1]) immersed_base_point = self.immersion(base_point) jac_immersion = self.pullback_metric.jacobian_immersion(base_point) immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a) immersed_tangent_vec_b = gs.matmul(jac_immersion, tangent_vec_b) result = self.pullback_metric.inner_product(tangent_vec_a, tangent_vec_b, base_point=base_point) expected = self.sphere_metric.inner_product( immersed_tangent_vec_a, immersed_tangent_vec_b, base_point=immersed_base_point, ) self.assertAllClose(result, expected) @geomstats.tests.autograd_and_tf_only def test_christoffels_and_sphere_christoffels(self): """Test consistency between sphere's christoffels. The christoffels of the class Hypersphere are defined in terms of spherical coordinates. The christoffels of pullback_metric are also defined in terms of the spherical coordinates. """ base_point = gs.array([0.1, 0.2]) result = self.pullback_metric.christoffels(base_point=base_point) expected = self.sphere_metric.christoffels(point=base_point) self.assertAllClose(result, expected) base_point = gs.array([0.7, 0.233]) result = self.pullback_metric.christoffels(base_point=base_point) expected = self.sphere_metric.christoffels(point=base_point) self.assertAllClose(result, expected) @geomstats.tests.autograd_tf_and_torch_only def test_exp_and_sphere_exp(self): """Test consistency between sphere's Riemannian exp. The exp map of the class Hypersphere is defined in terms of extrinsic coordinates. The exp map of pullback_metric is defined in terms of the spherical coordinates. """ base_point = gs.array([gs.pi / 2.0, 0.0]) tangent_vec_a = gs.array([0.0, 1.0]) immersed_base_point = self.immersion(base_point) jac_immersion = self.pullback_metric.jacobian_immersion(base_point) immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a) result = self.pullback_metric.exp(tangent_vec_a, base_point=base_point) result = self.sphere.spherical_to_extrinsic(result) expected = self.sphere.metric.exp(immersed_tangent_vec_a, base_point=immersed_base_point) self.assertAllClose(result, expected) base_point = gs.array([gs.pi / 2.0, 0.1]) tangent_vec_a = gs.array([0.4, 1.0]) immersed_base_point = self.immersion(base_point) jac_immersion = self.pullback_metric.jacobian_immersion(base_point) immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a) result = self.pullback_metric.exp(tangent_vec_a, base_point=base_point) result = self.sphere.spherical_to_extrinsic(result) expected = self.sphere.metric.exp(immersed_tangent_vec_a, base_point=immersed_base_point) self.assertAllClose(result, expected, atol=1e-1) @geomstats.tests.autograd_and_torch_only def test_parallel_transport_and_sphere_parallel_transport(self): """Test consistency between sphere's parallel transports. The parallel transport of the class Hypersphere is defined in terms of extrinsic coordinates. The parallel transport of pullback_metric is defined in terms of the spherical coordinates. """ tangent_vec_a = gs.array([0.0, 1.0]) tangent_vec_b = gs.array([0.0, 1.0]) base_point = gs.array([gs.pi / 2.0, 0.0]) immersed_base_point = self.immersion(base_point) jac_immersion = self.pullback_metric.jacobian_immersion(base_point) immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a) immersed_tangent_vec_b = gs.matmul(jac_immersion, tangent_vec_b) result_dict = self.pullback_metric.ladder_parallel_transport( tangent_vec_a, tangent_vec_b, base_point=base_point) result = result_dict["transported_tangent_vec"] end_point = result_dict["end_point"] result = self.pullback_metric.tangent_immersion(v=result, x=end_point) expected = self.sphere_metric.parallel_transport( immersed_tangent_vec_a, immersed_tangent_vec_b, base_point=immersed_base_point, ) self.assertAllClose(result, expected, atol=1e-5)
class TestConnectionMethods(geomstats.tests.TestCase): def setUp(self): warnings.simplefilter('ignore', category=UserWarning) self.dimension = 4 self.euc_metric = EuclideanMetric(dimension=self.dimension) self.connection = Connection(dimension=2) self.hypersphere = Hypersphere(dimension=2) def test_metric_matrix(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_matrix(base_point) expected = gs.array([gs.eye(self.dimension)]) with self.session(): self.assertAllClose(result, expected) def test_cometric_matrix(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_inverse_matrix(base_point) expected = gs.array([gs.eye(self.dimension)]) with self.session(): self.assertAllClose(result, expected) @geomstats.tests.np_only def test_metric_derivative(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_derivative_matrix(base_point) expected = gs.zeros((1, ) + (self.dimension, ) * 3) self.assertAllClose(result, expected) @geomstats.tests.np_only def test_christoffels(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.christoffels(base_point) expected = gs.zeros((1, ) + (self.dimension, ) * 3) self.assertAllClose(result, expected) @geomstats.tests.np_only def test_parallel_transport(self): n_samples = 10 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.projection_to_tangent_space( gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.projection_to_tangent_space( gs.random.rand(n_samples, 3), base_point) expected = self.hypersphere.metric.parallel_transport( tan_vec_a, tan_vec_b, base_point) result = self.hypersphere.metric.pole_ladder_parallel_transport( tan_vec_a, tan_vec_b, base_point) self.assertAllClose(result, expected, rtol=1e-7, atol=1e-5) @geomstats.tests.np_only def test_exp(self): point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]]) vector = gs.array([[0.25, 0.5], [0.30, 0.2]]) point_ext = self.hypersphere.spherical_to_extrinsic(point) vector_ext = self.hypersphere.tangent_spherical_to_extrinsic( vector, point) self.connection.christoffels = self.hypersphere.metric.christoffels expected = self.hypersphere.metric.exp(vector_ext, point_ext) result_spherical = self.connection.exp(vector, point, n_steps=50, step='rk4') result = self.hypersphere.spherical_to_extrinsic(result_spherical) self.assertAllClose(result, expected, rtol=1e-6) @geomstats.tests.np_only def test_log(self): base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]]) point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]]) self.connection.christoffels = self.hypersphere.metric.christoffels vector = self.connection.log(point=point, base_point=base_point, n_steps=75, step='rk') result = self.hypersphere.tangent_spherical_to_extrinsic( vector, base_point) p_ext = self.hypersphere.spherical_to_extrinsic(base_point) q_ext = self.hypersphere.spherical_to_extrinsic(point) expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext) self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5)
class TestConnectionMethods(geomstats.tests.TestCase): def setUp(self): warnings.simplefilter('ignore', category=UserWarning) self.dim = 4 self.euc_metric = EuclideanMetric(dim=self.dim) self.connection = Connection(dim=2) self.hypersphere = Hypersphere(dim=2) def test_metric_matrix(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_matrix(base_point) expected = gs.eye(self.dim) self.assertAllClose(result, expected) def test_cometric_matrix(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_inverse_matrix(base_point) expected = gs.eye(self.dim) self.assertAllClose(result, expected) @geomstats.tests.np_only def test_metric_derivative(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.inner_product_derivative_matrix(base_point) expected = gs.zeros((self.dim, ) * 3) self.assertAllClose(result, expected) @geomstats.tests.np_only def test_christoffels(self): base_point = gs.array([0., 1., 0., 0.]) result = self.euc_metric.christoffels(base_point) expected = gs.zeros((self.dim, ) * 3) self.assertAllClose(result, expected) @geomstats.tests.np_and_pytorch_only def test_parallel_transport(self): n_samples = 2 for step in ['pole', 'schild']: n_steps = 1 if step == 'pole' else 100 tol = 1e-6 if step == 'pole' else 1e-1 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.projection_to_tangent_space( gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.projection_to_tangent_space( gs.random.rand(n_samples, 3), base_point) expected = self.hypersphere.metric.parallel_transport( tan_vec_a, tan_vec_b, base_point) ladder = self.hypersphere.metric.ladder_parallel_transport( tan_vec_a, tan_vec_b, base_point, step=step, n_steps=n_steps) result = ladder['transported_tangent_vec'] self.assertAllClose(result, expected, rtol=tol, atol=tol) @geomstats.tests.np_and_pytorch_only def test_parallel_transport_trajectory(self): n_samples = 2 for step in ['pole', 'schild']: n_steps = 1 if step == 'pole' else 100 rtol = 1e-6 if step == 'pole' else 1e-1 base_point = self.hypersphere.random_uniform(n_samples) tan_vec_a = self.hypersphere.projection_to_tangent_space( gs.random.rand(n_samples, 3), base_point) tan_vec_b = self.hypersphere.projection_to_tangent_space( gs.random.rand(n_samples, 3), base_point) expected = self.hypersphere.metric.parallel_transport( tan_vec_a, tan_vec_b, base_point) ladder = self.hypersphere.metric.ladder_parallel_transport( tan_vec_a, tan_vec_b, base_point, return_geodesics=True, step=step, n_steps=n_steps) result = ladder['transported_tangent_vec'] self.assertAllClose(result, expected, rtol=rtol) @geomstats.tests.np_only def test_exp(self): point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]]) vector = gs.array([[0.25, 0.5], [0.30, 0.2]]) point_ext = self.hypersphere.spherical_to_extrinsic(point) vector_ext = self.hypersphere.tangent_spherical_to_extrinsic( vector, point) self.connection.christoffels = self.hypersphere.metric.christoffels expected = self.hypersphere.metric.exp(vector_ext, point_ext) result_spherical = self.connection.exp(vector, point, n_steps=50, step='rk4') result = self.hypersphere.spherical_to_extrinsic(result_spherical) self.assertAllClose(result, expected, rtol=1e-6) @geomstats.tests.np_only def test_log(self): base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]]) point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]]) self.connection.christoffels = self.hypersphere.metric.christoffels vector = self.connection.log(point=point, base_point=base_point, n_steps=75, step='rk') result = self.hypersphere.tangent_spherical_to_extrinsic( vector, base_point) p_ext = self.hypersphere.spherical_to_extrinsic(base_point) q_ext = self.hypersphere.spherical_to_extrinsic(point) expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext) self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5)