def test_parallel_transport(self, n): space = SPDMatrices(*n) metric = self.metric(*n) shape = (2, *n, *n) point = space.random_point(2) end_point = space.random_point(2) tan_b = gs.random.rand(*shape) tan_b = space.to_tangent(tan_b, point) # use a vector orthonormal to tan_b tan_a = gs.random.rand(*shape) tan_a = space.to_tangent(tan_a, point) # orthonormalize and move to base_point tan_a -= gs.einsum( "...,...ij->...ij", metric.inner_product(tan_a, tan_b, point) / metric.squared_norm(tan_b, point), tan_b, ) tan_b = gs.einsum("...ij,...->...ij", tan_b, 1.0 / metric.norm(tan_b, point)) tan_a = gs.einsum("...ij,...->...ij", tan_a, 1.0 / metric.norm(tan_a, point)) transported = metric.parallel_transport(tan_a, point, end_point=end_point, n_steps=15, step="rk4") result = metric.norm(transported, end_point) expected = metric.norm(tan_a, point) self.assertAllClose(result, expected) is_tangent = space.is_tangent(transported, end_point) self.assertTrue(gs.all(is_tangent)) transported = metric.parallel_transport(tan_a, point, tan_b, n_steps=15, step="rk4") end_point = metric.exp(tan_b, point) result = metric.norm(transported, end_point) expected = metric.norm(tan_a, point) self.assertAllClose(result, expected) is_tangent = space.is_tangent(transported, end_point) self.assertTrue(gs.all(is_tangent))
def test_estimate_spd_two_samples(self): space = SPDMatrices(3) metric = SPDMetricAffine(3) point = space.random_point(2) mean = FrechetMean(metric) mean.fit(point) result = mean.estimate_ expected = metric.exp(metric.log(point[0], point[1]) / 2, point[1]) self.assertAllClose(expected, result)
def test_batched(self): space = SPDMatrices(3) metric = SPDMetricAffine(3) point = space.random_point(4) mean_batch = FrechetMean(metric, method="batch", verbose=True) data = gs.stack([point[:2], point[2:]], axis=1) mean_batch.fit(data) result = mean_batch.estimate_ mean = FrechetMean(metric) mean.fit(data[:, 0]) expected_1 = mean.estimate_ mean.fit(data[:, 1]) expected_2 = mean.estimate_ expected = gs.stack([expected_1, expected_2]) self.assertAllClose(expected, result)
class TestSPDMatrices(geomstats.tests.TestCase): """Test of SPDMatrices methods.""" def setUp(self): """Set up the test.""" warnings.simplefilter('ignore', category=ImportWarning) gs.random.seed(1234) self.n = 3 self.space = SPDMatrices(n=self.n) self.metric_affine = SPDMetricAffine(n=self.n) self.metric_bureswasserstein = SPDMetricBuresWasserstein(n=self.n) self.metric_euclidean = SPDMetricEuclidean(n=self.n) self.metric_logeuclidean = SPDMetricLogEuclidean(n=self.n) self.n_samples = 4 def test_belongs(self): """Test of belongs method.""" mats = gs.array([[3., -1.], [-1., 3.]]) result = SPDMatrices(2).belongs(mats) expected = True self.assertAllClose(result, expected) mats = gs.array([[-1., -1.], [-1., 3.]]) result = SPDMatrices(2).belongs(mats) expected = False self.assertAllClose(result, expected) mats = gs.eye(3) result = SPDMatrices(2).belongs(mats) expected = False self.assertAllClose(result, expected) def test_belongs_vectorization(self): """Test of belongs method.""" mats = gs.array([[[1., 0], [0, 1.]], [[1., 2.], [2., 1.]], [[1., 0.], [1., 1.]]]) result = SPDMatrices(2).belongs(mats) expected = gs.array([True, False, False]) self.assertAllClose(result, expected) def test_random_point_and_belongs(self): """Test of random_point and belongs methods.""" point = self.space.random_point() result = self.space.belongs(point) expected = True self.assertAllClose(result, expected) def test_random_point_and_belongs_vectorization(self): """Test of random_point and belongs methods.""" points = self.space.random_point(4) result = self.space.belongs(points) expected = gs.array([True] * 4) self.assertAllClose(result, expected) def test_vector_from_symmetric_matrix_and_symmetric_matrix_from_vector( self): """Test for matrix to vector and vector to matrix conversions.""" sym_mat_1 = gs.array([[1., 0.6, -3.], [0.6, 7., 0.], [-3., 0., 8.]]) vector_1 = self.space.to_vector(sym_mat_1) result_1 = self.space.from_vector(vector_1) expected_1 = sym_mat_1 self.assertTrue(gs.allclose(result_1, expected_1)) vector_2 = gs.array([1., 2., 3., 4., 5., 6.]) sym_mat_2 = self.space.from_vector(vector_2) result_2 = self.space.to_vector(sym_mat_2) expected_2 = vector_2 self.assertTrue(gs.allclose(result_2, expected_2)) def test_vector_and_symmetric_matrix_vectorization(self): """Test of vectorization.""" n_samples = self.n_samples vector = gs.random.rand(n_samples, 6) sym_mat = self.space.from_vector(vector) result = self.space.to_vector(sym_mat) expected = vector self.assertTrue(gs.allclose(result, expected)) sym_mat = self.space.random_point(n_samples) vector = self.space.to_vector(sym_mat) result = self.space.from_vector(vector) expected = sym_mat self.assertTrue(gs.allclose(result, expected)) def test_logm(self): """Test of logm method.""" expected = gs.array([[[0., 1., 0.], [1., 0., 0.], [0., 0., 1.]]]) c = math.cosh(1) s = math.sinh(1) e = math.exp(1) v = gs.array([[[c, s, 0.], [s, c, 0.], [0., 0., e]]]) result = self.space.logm(v) self.assertAllClose(result, expected) def test_differential_power(self): """Test of differential_power method.""" base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]]) tangent_vec = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]]) power = .5 result = self.space.differential_power(power=power, tangent_vec=tangent_vec, base_point=base_point) expected = gs.array([[1., 1 / 3, 1 / 3], [1 / 3, .125, .125], [1 / 3, .125, .125]]) self.assertAllClose(result, expected) def test_inverse_differential_power(self): """Test of inverse_differential_power method.""" base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]]) tangent_vec = gs.array([[1., 1 / 3, 1 / 3], [1 / 3, .125, .125], [1 / 3, .125, .125]]) power = .5 result = self.space.inverse_differential_power(power=power, tangent_vec=tangent_vec, base_point=base_point) expected = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]]) self.assertAllClose(result, expected) def test_differential_log(self): """Test of differential_log method.""" base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 4.]]) tangent_vec = gs.array([[1., 1., 3.], [1., 1., 3.], [3., 3., 4.]]) result = self.space.differential_log(tangent_vec, base_point) x = 2 * gs.log(2.) expected = gs.array([[1., 1., x], [1., 1., x], [x, x, 1]]) self.assertAllClose(result, expected) def test_inverse_differential_log(self): """Test of inverse_differential_log method.""" base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 4.]]) x = 2 * gs.log(2.) tangent_vec = gs.array([[1., 1., x], [1., 1., x], [x, x, 1]]) result = self.space.inverse_differential_log(tangent_vec, base_point) expected = gs.array([[1., 1., 3.], [1., 1., 3.], [3., 3., 4.]]) self.assertAllClose(result, expected) def test_differential_exp(self): """Test of differential_exp method.""" base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., -1.]]) tangent_vec = gs.array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) result = self.space.differential_exp(tangent_vec, base_point) x = gs.exp(1.) y = gs.sinh(1.) expected = gs.array([[x, x, y], [x, x, y], [y, y, 1 / x]]) self.assertAllClose(result, expected) def test_inverse_differential_exp(self): """Test of inverse_differential_exp method.""" base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., -1.]]) x = gs.exp(1.) y = gs.sinh(1.) tangent_vec = gs.array([[x, x, y], [x, x, y], [y, y, 1. / x]]) result = self.space.inverse_differential_exp(tangent_vec, base_point) expected = gs.array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) self.assertAllClose(result, expected) def test_bureswasserstein_inner_product(self): """Test of SPDMetricBuresWasserstein.inner_product method.""" base_point = gs.array([[1., 0., 0.], [0., 1.5, .5], [0., .5, 1.5]]) tangent_vec_a = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]]) tangent_vec_b = gs.array([[1., 2., 4.], [2., 3., 8.], [4., 8., 5.]]) metric = SPDMetricBuresWasserstein(3) result = metric.inner_product(tangent_vec_a, tangent_vec_b, base_point) expected = gs.array(4.) self.assertAllClose(result, expected) def test_power_affine_inner_product(self): """Test of SPDMetricAffine.inner_product method.""" base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]]) tangent_vec = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]]) metric = SPDMetricAffine(3, power_affine=.5) result = metric.inner_product(tangent_vec, tangent_vec, base_point) expected = 713 / 144 self.assertAllClose(result, expected) def test_power_euclidean_inner_product(self): """Test of SPDMetricEuclidean.inner_product method.""" base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]]) tangent_vec = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]]) metric = SPDMetricEuclidean(3, power_euclidean=.5) result = metric.inner_product(tangent_vec, tangent_vec, base_point) expected = 3472 / 576 self.assertAllClose(result, expected) result = self.metric_euclidean.inner_product(tangent_vec, tangent_vec, base_point) expected = MatricesMetric(3, 3).inner_product(tangent_vec, tangent_vec) self.assertAllClose(result, expected) @geomstats.tests.np_and_tf_only def test_euclidean_exp_domain(self): """Test of SPDMetricEuclidean.exp_domain method.""" base_point = gs.array([[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) tangent_vec = gs.array([[-1., 0., 0.], [0., -.5, 0.], [0., 0., 1.]]) metric = self.metric_euclidean result = metric.exp_domain(tangent_vec, base_point) expected = gs.array([-3, 1]) self.assertAllClose(result, expected) def test_log_euclidean_inner_product(self): """Test of SPDMetricLogEuclidean.inner_product method.""" base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 4.]]) tangent_vec = gs.array([[1., 1., 3.], [1., 1., 3.], [3., 3., 4.]]) metric = self.metric_logeuclidean result = metric.inner_product(tangent_vec, tangent_vec, base_point) x = 2 * gs.log(2.) expected = 5. + 4. * x**2 self.assertAllClose(result, expected) def test_log_and_exp_affine_invariant(self): """Test of SPDMetricAffine.log and exp methods with power=1.""" base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]]) point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]]) metric = self.metric_affine log = metric.log(point=point, base_point=base_point) result = metric.exp(tangent_vec=log, base_point=base_point) expected = point self.assertAllClose(result, expected) def test_log_and_exp_power_affine(self): """Test of SPDMetricAffine.log and exp methods with power!=1.""" base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]]) point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]]) metric = SPDMetricAffine(3, power_affine=.5) log = metric.log(point, base_point) result = metric.exp(log, base_point) expected = point self.assertAllClose(result, expected) def test_log_and_exp_bureswasserstein(self): """Test of SPDMetricBuresWasserstein.log and exp methods.""" base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]]) point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]]) metric = self.metric_bureswasserstein log = metric.log(point=point, base_point=base_point) result = metric.exp(tangent_vec=log, base_point=base_point) expected = point self.assertAllClose(result, expected) def test_log_and_exp_logeuclidean(self): """Test of SPDMetricLogEuclidean.log and exp methods.""" base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]]) point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]]) metric = self.metric_logeuclidean log = metric.log(point=point, base_point=base_point) result = metric.exp(tangent_vec=log, base_point=base_point) expected = point self.assertAllClose(result, expected) def test_exp_and_belongs(self): """Test of SPDMetricAffine.exp with power=1 and belongs methods.""" n_samples = self.n_samples base_point = self.space.random_point(n_samples=1) tangent_vec = self.space.random_tangent_vec(n_samples=n_samples, base_point=base_point) metric = self.metric_affine exps = metric.exp(tangent_vec, base_point) result = self.space.belongs(exps) expected = gs.array([True] * n_samples) self.assertAllClose(result, expected) def test_exp_vectorization(self): """Test of SPDMetricAffine.exp with power=1 and vectorization.""" n_samples = self.n_samples one_base_point = self.space.random_point(n_samples=1) n_base_point = self.space.random_point(n_samples=n_samples) n_tangent_vec_same_base = self.space.random_tangent_vec( n_samples=n_samples, base_point=one_base_point) n_tangent_vec = self.space.random_tangent_vec(n_samples=n_samples, base_point=n_base_point) metric = self.metric_affine # Test with the 1 base_point, and several different tangent_vecs result = metric.exp(n_tangent_vec_same_base, one_base_point) self.assertAllClose(gs.shape(result), (n_samples, self.space.n, self.space.n)) # Test with the same number of base_points and tangent_vecs result = metric.exp(n_tangent_vec, n_base_point) self.assertAllClose(gs.shape(result), (n_samples, self.space.n, self.space.n)) def test_log_vectorization(self): """Test of SPDMetricAffine.log with power 1 and vectorization.""" n_samples = self.n_samples one_base_point = self.space.random_point(n_samples=1) n_base_point = self.space.random_point(n_samples=n_samples) one_point = self.space.random_point(n_samples=1) n_point = self.space.random_point(n_samples=n_samples) metric = self.metric_affine # Test with different points, one base point result = metric.log(n_point, one_base_point) self.assertAllClose(gs.shape(result), (n_samples, self.space.n, self.space.n)) # Test with the same number of points and base points result = metric.log(n_point, n_base_point) self.assertAllClose(gs.shape(result), (n_samples, self.space.n, self.space.n)) # Test with the one point and n base points result = metric.log(one_point, n_base_point) self.assertAllClose(gs.shape(result), (n_samples, self.space.n, self.space.n)) def test_geodesic_and_belongs(self): """Test of SPDMetricAffine.geodesic with power 1 and belongs.""" initial_point = self.space.random_point() initial_tangent_vec = self.space.random_tangent_vec( n_samples=1, base_point=initial_point) metric = self.metric_affine geodesic = metric.geodesic(initial_point=initial_point, initial_tangent_vec=initial_tangent_vec) n_points = 10 t = gs.linspace(start=0., stop=1., num=n_points) points = geodesic(t) result = self.space.belongs(points) self.assertTrue(gs.all(result)) def test_squared_dist_is_symmetric(self): """Test of SPDMetricAffine.squared_dist (power=1) and is_symmetric.""" n_samples = self.n_samples point_1 = self.space.random_point(n_samples=1) point_2 = self.space.random_point(n_samples=1) point_1 = gs.cast(point_1, gs.float64) point_2 = gs.cast(point_2, gs.float64) metric = self.metric_affine sq_dist_1_2 = metric.squared_dist(point_1, point_2) sq_dist_2_1 = metric.squared_dist(point_2, point_1) self.assertAllClose(sq_dist_1_2, sq_dist_2_1) point_2 = self.space.random_point(n_samples=n_samples) point_2 = gs.cast(point_2, gs.float64) sq_dist_1_2 = metric.squared_dist(point_1, point_2) sq_dist_2_1 = metric.squared_dist(point_2, point_1) self.assertAllClose(sq_dist_1_2, sq_dist_2_1) point_1 = self.space.random_point(n_samples=n_samples) point_2 = self.space.random_point(n_samples=1) point_1 = gs.cast(point_1, gs.float64) point_2 = gs.cast(point_2, gs.float64) sq_dist_1_2 = metric.squared_dist(point_1, point_2) sq_dist_2_1 = metric.squared_dist(point_2, point_1) self.assertAllClose(sq_dist_1_2, sq_dist_2_1) sq_dist_1_2 = metric.squared_dist(point_1, point_2) sq_dist_2_1 = metric.squared_dist(point_2, point_1) self.assertAllClose(sq_dist_1_2, sq_dist_2_1) def test_squared_dist_vectorization(self): """Test of SPDMetricAffine.squared_dist (power=1) and vectorization.""" n_samples = self.n_samples point_1 = self.space.random_point(n_samples=n_samples) point_2 = self.space.random_point(n_samples=n_samples) metric = self.metric_affine result = metric.squared_dist(point_1, point_2) self.assertAllClose(gs.shape(result), (n_samples, )) point_1 = self.space.random_point(n_samples=1) point_2 = self.space.random_point(n_samples=n_samples) result = metric.squared_dist(point_1, point_2) self.assertAllClose(gs.shape(result), (n_samples, )) point_1 = self.space.random_point(n_samples=n_samples) point_2 = self.space.random_point(n_samples=1) result = metric.squared_dist(point_1, point_2) self.assertAllClose(gs.shape(result), (n_samples, )) point_1 = self.space.random_point(n_samples=1) point_2 = self.space.random_point(n_samples=1) result = metric.squared_dist(point_1, point_2) self.assertAllClose(gs.shape(result), ()) def test_parallel_transport_affine_invariant(self): """Test of SPDMetricAffine.parallel_transport method with power=1.""" n_samples = self.n_samples gs.random.seed(1) point = self.space.random_point(n_samples) tan_a = self.space.random_tangent_vec(n_samples, point) tan_b = self.space.random_tangent_vec(n_samples, point) point = gs.cast(point, gs.float64) tan_a = gs.cast(tan_a, gs.float64) tan_b = gs.cast(tan_b, gs.float64) metric = self.metric_affine expected = metric.norm(tan_a, point) end_point = metric.exp(tan_b, point) transported = metric.parallel_transport(tan_a, tan_b, point) result = metric.norm(transported, end_point) self.assertAllClose(expected, result) def test_squared_dist_bureswasserstein(self): """Test of SPDMetricBuresWasserstein.squared_dist method.""" point_a = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]]) point_b = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]]) metric = self.metric_bureswasserstein result = metric.squared_dist(point_a, point_b) log = metric.log(point=point_b, base_point=point_a) expected = metric.squared_norm(vector=log, base_point=point_a) self.assertAllClose(result, expected) def test_squared_dist_bureswasserstein_vectorization(self): """Test of SPDMetricBuresWasserstein.squared_dist method.""" point_a = self.space.random_point(2) point_b = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]]) point_a = gs.cast(point_a, gs.float64) point_b = gs.cast(point_b, gs.float64) metric = self.metric_bureswasserstein result = metric.squared_dist(point_a, point_b) log = metric.log(point=point_b, base_point=point_a) expected = metric.squared_norm(vector=log, base_point=point_a) self.assertAllClose(result, expected) def test_to_tangent_and_is_tangent(self): mat = gs.random.rand(3, 3) projection = self.space.to_tangent(mat) result = self.space.is_tangent(projection) self.assertTrue(result)
def test_check_belongs_with_tol(): spd = SPDMatrices(5) point = spd.random_point() geomstats.errors.check_belongs(point, spd)
class TestTangentPCA(geomstats.tests.TestCase): _multiprocess_can_split_ = True def setup_method(self): self.so3 = SpecialOrthogonal(n=3, point_type="vector") self.spd = SPDMatrices(3) self.spd_metric = SPDMetricAffine(3) self.n_samples = 10 self.X = self.so3.random_uniform(n_samples=self.n_samples) self.metric = self.so3.bi_invariant_metric self.n_components = 2 def test_tangent_pca_error(self): X = self.X tpca = TangentPCA(self.metric, n_components=self.n_components) tpca.fit(X) X_diff_size = gs.ones((self.n_samples, gs.shape(X)[1] + 1)) with pytest.raises(ValueError): tpca.transform(X_diff_size) def test_tangent_pca(self): X = self.X tpca = TangentPCA(self.metric, n_components=gs.shape(X)[1]) tpca.fit(X) self.assertEqual(tpca.n_features_, gs.shape(X)[1]) def test_fit_mle(self): X = self.X tpca = TangentPCA(self.metric, n_components="mle") tpca.fit(X) self.assertEqual(tpca.n_features_, gs.shape(X)[1]) def test_fit_to_target_explained_variance(self): X = self.spd.random_point(n_samples=5) target = 0.90 tpca = TangentPCA(self.spd_metric, n_components=target) tpca.fit(X) result = gs.cumsum(tpca.explained_variance_ratio_)[-1] > target expected = True self.assertAllClose(result, expected) def test_fit_matrix(self): expected = 2 X = self.spd.random_point(n_samples=5) tpca = TangentPCA(metric=self.spd_metric, n_components=expected) tpca.fit(X) result = tpca.n_components_ self.assertAllClose(result, expected) def test_fit_transform_matrix(self): expected = 2 X = self.spd.random_point(n_samples=5) tpca = TangentPCA(metric=self.spd_metric, n_components=expected) tangent_projected_data = tpca.fit_transform(X) result = tangent_projected_data.shape[-1] self.assertAllClose(result, expected) def test_fit_inverse_transform_matrix(self): X = self.spd.random_point(n_samples=5) tpca = TangentPCA(metric=self.spd_metric) tangent_projected_data = tpca.fit_transform(X) result = tpca.inverse_transform(tangent_projected_data) expected = X self.assertAllClose(result, expected, atol=1e-6) def test_fit_transform_vector(self): expected = 2 tpca = TangentPCA(metric=self.metric, n_components=expected) tangent_projected_data = tpca.fit_transform(self.X) result = tangent_projected_data.shape[-1] self.assertAllClose(result, expected) def test_fit_inverse_transform_vector(self): tpca = TangentPCA(metric=self.metric) tangent_projected_data = tpca.fit_transform(self.X) result = tpca.inverse_transform(tangent_projected_data) expected = self.X self.assertAllClose(result, expected) def test_fit_fit_transform_matrix(self): X = self.spd.random_point(n_samples=5) tpca = TangentPCA(metric=self.spd_metric) expected = tpca.fit_transform(X) result = tpca.fit(X).transform(X) self.assertAllClose(result, expected) def test_fit_matrix_se(self): se_mat = SpecialEuclidean(n=3) X = se_mat.random_point(self.n_samples) estimator = ExponentialBarycenter(se_mat) estimator.fit(X) mean = estimator.estimate_ tpca = TangentPCA(metric=se_mat) tangent_projected_data = tpca.fit_transform(X, base_point=mean) result = tpca.inverse_transform(tangent_projected_data) expected = X self.assertAllClose(result, expected)
class TestQuotientMetric(geomstats.tests.TestCase): def setUp(self): gs.random.seed(0) n = 3 self.base = SPDMatrices(n) self.base_metric = SPDMetricBuresWasserstein(n) self.group = SpecialOrthogonal(n) self.bundle = FiberBundle(GeneralLinear(n), base=self.base, group=self.group, ambient_metric=MatricesMetric(n, n)) self.quotient_metric = QuotientMetric(self.bundle) def submersion(point): return GeneralLinear.mul(point, GeneralLinear.transpose(point)) def tangent_submersion(tangent_vec, base_point): product = GeneralLinear.mul(base_point, GeneralLinear.transpose(tangent_vec)) return 2 * GeneralLinear.to_symmetric(product) def horizontal_lift(tangent_vec, point, base_point=None): if base_point is None: base_point = submersion(point) sylvester = gs.linalg.solve_sylvester(base_point, base_point, tangent_vec) return GeneralLinear.mul(sylvester, point) self.bundle.submersion = submersion self.bundle.tangent_submersion = tangent_submersion self.bundle.horizontal_lift = horizontal_lift self.bundle.lift = gs.linalg.cholesky def test_belongs(self): point = self.base.random_point() result = self.bundle.belongs(point) self.assertTrue(result) def test_submersion(self): mat = self.bundle.total_space.random_point() point = self.bundle.submersion(mat) result = self.bundle.belongs(point) self.assertTrue(result) def test_lift_and_submersion(self): point = self.base.random_point() mat = self.bundle.lift(point) result = self.bundle.submersion(mat) self.assertAllClose(result, point) def test_tangent_submersion(self): mat = self.bundle.total_space.random_point() point = self.bundle.submersion(mat) vec = self.bundle.total_space.random_point() tangent_vec = self.bundle.tangent_submersion(vec, point) result = self.base.is_tangent(tangent_vec, point) self.assertTrue(result) def test_horizontal_projection(self): mat = self.bundle.total_space.random_point() vec = self.bundle.total_space.random_point() horizontal_vec = self.bundle.horizontal_projection(vec, mat) product = GeneralLinear.mul(horizontal_vec, GeneralLinear.inverse(mat)) is_horizontal = GeneralLinear.is_symmetric(product) self.assertTrue(is_horizontal) def test_vertical_projection(self): mat = self.bundle.total_space.random_point() vec = self.bundle.total_space.random_point() vertical_vec = self.bundle.vertical_projection(vec, mat) result = self.bundle.tangent_submersion(vertical_vec, mat) expected = gs.zeros_like(result) self.assertAllClose(result, expected, atol=1e-5) def test_horizontal_lift_and_tangent_submersion(self): mat = self.bundle.total_space.random_point() tangent_vec = GeneralLinear.to_symmetric( self.bundle.total_space.random_point()) horizontal = self.bundle.horizontal_lift(tangent_vec, mat) result = self.bundle.tangent_submersion(horizontal, mat) self.assertAllClose(result, tangent_vec) def test_is_horizontal(self): mat = self.bundle.total_space.random_point() tangent_vec = GeneralLinear.to_symmetric( self.bundle.total_space.random_point()) horizontal = self.bundle.horizontal_lift(tangent_vec, mat) result = self.bundle.is_horizontal(horizontal, mat) self.assertTrue(result) def test_is_vertical(self): mat = self.bundle.total_space.random_point() tangent_vec = self.bundle.total_space.random_point() vertical = self.bundle.vertical_projection(tangent_vec, mat) result = self.bundle.is_vertical(vertical, mat) self.assertTrue(result) def test_align(self): point = self.bundle.total_space.random_point(2) aligned = self.bundle.align(point[0], point[1], tol=1e-10) result = self.bundle.is_horizontal(point[1] - aligned, point[1], atol=1e-5) self.assertTrue(result) def test_inner_product(self): mat = self.bundle.total_space.random_point() point = self.bundle.submersion(mat) tangent_vecs = GeneralLinear.to_symmetric( self.bundle.total_space.random_point(2)) / 10 result = self.quotient_metric.inner_product(tangent_vecs[0], tangent_vecs[1], point=mat) expected = self.base_metric.inner_product(tangent_vecs[0], tangent_vecs[1], point) self.assertAllClose(result, expected) def test_exp(self): mat = self.bundle.total_space.random_point() point = self.bundle.submersion(mat) tangent_vec = GeneralLinear.to_symmetric( self.bundle.total_space.random_point()) / 5 result = self.quotient_metric.exp(tangent_vec, point) expected = self.base_metric.exp(tangent_vec, point) self.assertAllClose(result, expected) def test_log(self): mats = self.bundle.total_space.random_point(2) points = self.bundle.submersion(mats) result = self.quotient_metric.log(points[1], points[0], tol=1e-10) expected = self.base_metric.log(points[1], points[0]) self.assertAllClose(result, expected, atol=3e-4) def test_squared_dist(self): mats = self.bundle.total_space.random_point(2) points = self.bundle.submersion(mats) result = self.quotient_metric.squared_dist(points[1], points[0], tol=1e-10) expected = self.base_metric.squared_dist(points[1], points[0]) self.assertAllClose(result, expected, atol=1e-5) def test_integrability_tensor(self): mat = self.bundle.total_space.random_point() point = self.bundle.submersion(mat) tangent_vec = GeneralLinear.to_symmetric( self.bundle.total_space.random_point()) / 5 self.assertRaises( NotImplementedError, lambda: self.bundle.integrability_tensor( tangent_vec, tangent_vec, point))
class TestVisualization(geomstats.tests.TestCase): def setup_method(self): self.n_samples = 10 self.SO3_GROUP = SpecialOrthogonal(n=3, point_type="vector") self.SE3_GROUP = SpecialEuclidean(n=3, point_type="vector") self.S1 = Hypersphere(dim=1) self.S2 = Hypersphere(dim=2) self.H2 = Hyperbolic(dim=2) self.H2_half_plane = PoincareHalfSpace(dim=2) self.M32 = Matrices(m=3, n=2) self.S32 = PreShapeSpace(k_landmarks=3, m_ambient=2) self.KS = visualization.KendallSphere() self.M33 = Matrices(m=3, n=3) self.S33 = PreShapeSpace(k_landmarks=3, m_ambient=3) self.KD = visualization.KendallDisk() self.spd = SPDMatrices(n=2) plt.figure() @staticmethod def test_tutorial_matplotlib(): visualization.tutorial_matplotlib() def test_plot_points_so3(self): points = self.SO3_GROUP.random_uniform(self.n_samples) visualization.plot(points, space="SO3_GROUP") def test_plot_points_se3(self): points = self.SE3_GROUP.random_point(self.n_samples) visualization.plot(points, space="SE3_GROUP") def test_draw_pre_shape_2d(self): self.KS.draw() def test_draw_points_pre_shape_2d(self): points = self.S32.random_point(self.n_samples) visualization.plot(points, space="S32") points = self.M32.random_point(self.n_samples) visualization.plot(points, space="M32") self.KS.clear_points() def test_draw_curve_pre_shape_2d(self): self.KS.draw() base_point = self.S32.random_point() vec = self.S32.random_point() tangent_vec = self.S32.to_tangent(vec, base_point) times = gs.linspace(0.0, 1.0, 1000) speeds = gs.array([-t * tangent_vec for t in times]) points = self.S32.ambient_metric.exp(speeds, base_point) self.KS.add_points(points) self.KS.draw_curve() self.KS.clear_points() def test_draw_vector_pre_shape_2d(self): self.KS.draw() base_point = self.S32.random_point() vec = self.S32.random_point() tangent_vec = self.S32.to_tangent(vec, base_point) self.KS.draw_vector(tangent_vec, base_point) def test_convert_to_spherical_coordinates_pre_shape_2d(self): points = self.S32.random_point(self.n_samples) coords = self.KS.convert_to_spherical_coordinates(points) x = coords[:, 0] y = coords[:, 1] z = coords[:, 2] result = x**2 + y**2 + z**2 expected = 0.25 * gs.ones(self.n_samples) self.assertAllClose(result, expected) def test_rotation_pre_shape_2d(self): theta = gs.random.rand(1)[0] phi = gs.random.rand(1)[0] rot = self.KS.rotation(theta, phi) result = _SpecialOrthogonalMatrices(3).belongs(rot) expected = True self.assertAllClose(result, expected) def test_draw_pre_shape_3d(self): self.KD.draw() def test_draw_points_pre_shape_3d(self): points = self.S33.random_point(self.n_samples) visualization.plot(points, space="S33") points = self.M33.random_point(self.n_samples) visualization.plot(points, space="M33") self.KD.clear_points() def test_draw_curve_pre_shape_3d(self): self.KD.draw() base_point = self.S33.random_point() vec = self.S33.random_point() tangent_vec = self.S33.to_tangent(vec, base_point) tangent_vec = 0.5 * tangent_vec / self.S33.ambient_metric.norm( tangent_vec) times = gs.linspace(0.0, 1.0, 1000) speeds = gs.array([-t * tangent_vec for t in times]) points = self.S33.ambient_metric.exp(speeds, base_point) self.KD.add_points(points) self.KD.draw_curve() self.KD.clear_points() def test_draw_vector_pre_shape_3d(self): self.KS.draw() base_point = self.S32.random_point() vec = self.S32.random_point() tangent_vec = self.S32.to_tangent(vec, base_point) self.KS.draw_vector(tangent_vec, base_point) def test_convert_to_planar_coordinates_pre_shape_3d(self): points = self.S33.random_point(self.n_samples) coords = self.KD.convert_to_planar_coordinates(points) x = coords[:, 0] y = coords[:, 1] radius = x**2 + y**2 result = [r <= 1.0 for r in radius] self.assertTrue(gs.all(result)) @geomstats.tests.np_autograd_and_torch_only def test_plot_points_s1(self): points = self.S1.random_uniform(self.n_samples) visualization.plot(points, space="S1") def test_plot_points_s2(self): points = self.S2.random_uniform(self.n_samples) visualization.plot(points, space="S2") def test_plot_points_h2_poincare_disk(self): points = self.H2.random_point(self.n_samples) visualization.plot(points, space="H2_poincare_disk") def test_plot_points_h2_poincare_half_plane_ext(self): points = self.H2.random_point(self.n_samples) visualization.plot(points, space="H2_poincare_half_plane", point_type="extrinsic") def test_plot_points_h2_poincare_half_plane_none(self): points = self.H2_half_plane.random_point(self.n_samples) visualization.plot(points, space="H2_poincare_half_plane") def test_plot_points_h2_poincare_half_plane_hs(self): points = self.H2_half_plane.random_point(self.n_samples) visualization.plot(points, space="H2_poincare_half_plane", point_type="half_space") def test_plot_points_h2_klein_disk(self): points = self.H2.random_point(self.n_samples) visualization.plot(points, space="H2_klein_disk") @staticmethod def test_plot_points_se2(): points = SpecialEuclidean(n=2, point_type="vector").random_point(4) visu = visualization.SpecialEuclidean2(points, point_type="vector") ax = visu.set_ax() visu.draw_points(ax) def test_plot_points_spd2(self): one_point = self.spd.random_point() visualization.plot(one_point, space="SPD2") points = self.spd.random_point(4) visualization.plot(points, space="SPD2") def test_compute_coordinates_spd2(self): point = gs.eye(2) ellipsis = visualization.Ellipses(n_sampling_points=4) x, y = ellipsis.compute_coordinates(point) self.assertAllClose(x, gs.array([1, 0, -1, 0, 1])) self.assertAllClose(y, gs.array([0, 1, 0, -1, 0])) @staticmethod def teardown_method(): plt.close()