class TestMinkowskiMethods(geomstats.tests.TestCase): def setUp(self): gs.random.seed(1234) self.time_like_dim = 0 self.dimension = 2 self.space = Minkowski(self.dimension) self.metric = self.space.metric self.n_samples = 10 def test_belongs(self): point = gs.array([-1., 3.]) result = self.space.belongs(point) expected = gs.array([[True]]) self.assertAllClose(result, expected) def test_random_uniform(self): point = self.space.random_uniform() self.assertAllClose(gs.shape(point), (1, self.dimension)) def test_random_uniform_and_belongs(self): point = self.space.random_uniform() result = self.space.belongs(point) expected = gs.array([[True]]) self.assertAllClose(result, expected) def test_inner_product_matrix(self): result = self.metric.inner_product_matrix() expected = gs.array([[-1., 0.], [0., 1.]]) self.assertAllClose(result, expected) def test_inner_product(self): point_a = gs.array([0., 1.]) point_b = gs.array([2., 10.]) result = self.metric.inner_product(point_a, point_b) expected = helper.to_scalar(gs.dot(point_a, point_b)) expected -= (2 * point_a[self.time_like_dim] * point_b[self.time_like_dim]) self.assertAllClose(result, expected) def test_inner_product_vectorization(self): n_samples = 3 one_point_a = gs.array([[-1., 0.]]) one_point_b = gs.array([[1.0, 0.]]) n_points_a = gs.array([ [-1., 0.], [1., 0.], [2., math.sqrt(3)]]) n_points_b = gs.array([ [2., -math.sqrt(3)], [4.0, math.sqrt(15)], [-4.0, math.sqrt(15)]]) result = self.metric.inner_product(one_point_a, one_point_b) expected = gs.dot(one_point_a, gs.transpose(one_point_b)) expected -= (2 * one_point_a[:, self.time_like_dim] * one_point_b[:, self.time_like_dim]) expected = helper.to_scalar(expected) result_no = self.metric.inner_product(n_points_a, one_point_b) result_on = self.metric.inner_product(one_point_a, n_points_b) result_nn = self.metric.inner_product(n_points_a, n_points_b) self.assertAllClose(result, expected) self.assertAllClose(gs.shape(result_no), (n_samples, 1)) self.assertAllClose(gs.shape(result_on), (n_samples, 1)) self.assertAllClose(gs.shape(result_nn), (n_samples, 1)) with self.session(): expected = np.zeros(n_samples) for i in range(n_samples): expected[i] = gs.eval(gs.dot(n_points_a[i], n_points_b[i])) expected[i] -= (2 * gs.eval(n_points_a[i, self.time_like_dim]) * gs.eval(n_points_b[i, self.time_like_dim])) expected = helper.to_scalar(gs.array(expected)) self.assertAllClose(result_nn, expected) def test_squared_norm(self): point = gs.array([-2., 4.]) result = self.metric.squared_norm(point) expected = gs.array([[12.]]) self.assertAllClose(result, expected) def test_squared_norm_vectorization(self): n_samples = 3 n_points = gs.array([ [-1., 0.], [1., 0.], [2., math.sqrt(3)]]) result = self.metric.squared_norm(n_points) self.assertAllClose(gs.shape(result), (n_samples, 1)) def test_exp(self): base_point = gs.array([1.0, 0.]) vector = gs.array([2., math.sqrt(3)]) result = self.metric.exp(tangent_vec=vector, base_point=base_point) expected = base_point + vector expected = helper.to_vector(expected) self.assertAllClose(result, expected) def test_exp_vectorization(self): dim = self.dimension n_samples = 3 one_tangent_vec = gs.array([[-1., 0.]]) one_base_point = gs.array([[1.0, 0.]]) n_tangent_vecs = gs.array([ [-1., 0.], [1., 0.], [2., math.sqrt(3)]]) n_base_points = gs.array([ [2., -math.sqrt(3)], [4.0, math.sqrt(15)], [-4.0, math.sqrt(15)]]) result = self.metric.exp(one_tangent_vec, one_base_point) expected = one_tangent_vec + one_base_point expected = helper.to_vector(expected) self.assertAllClose(result, expected) result = self.metric.exp(n_tangent_vecs, one_base_point) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.exp(one_tangent_vec, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.exp(n_tangent_vecs, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) def test_log(self): base_point = gs.array([-1., 0.]) point = gs.array([2., math.sqrt(3)]) result = self.metric.log(point=point, base_point=base_point) expected = point - base_point expected = helper.to_vector(expected) self.assertAllClose(result, expected) def test_log_vectorization(self): dim = self.dimension n_samples = 3 one_point = gs.array([[-1., 0.]]) one_base_point = gs.array([[1.0, 0.]]) n_points = gs.array([ [-1., 0.], [1., 0.], [2., math.sqrt(3)]]) n_base_points = gs.array([ [2., -math.sqrt(3)], [4.0, math.sqrt(15)], [-4.0, math.sqrt(15)]]) result = self.metric.log(one_point, one_base_point) expected = one_point - one_base_point expected = helper.to_vector(expected) self.assertAllClose(result, expected) result = self.metric.log(n_points, one_base_point) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.log(one_point, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.log(n_points, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) def test_squared_dist(self): point_a = gs.array([2., -math.sqrt(3)]) point_b = gs.array([4.0, math.sqrt(15)]) result = self.metric.squared_dist(point_a, point_b) vec = point_b - point_a expected = gs.dot(vec, vec) expected -= 2 * vec[self.time_like_dim] * vec[self.time_like_dim] expected = helper.to_scalar(expected) self.assertAllClose(result, expected) def test_geodesic_and_belongs(self): n_geodesic_points = 100 initial_point = gs.array([2., -math.sqrt(3)]) initial_tangent_vec = gs.array([2., 0.]) geodesic = self.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 = self.space.belongs(points) expected = gs.array(n_geodesic_points * [[True]]) self.assertAllClose(result, expected) def test_mean(self): point = gs.array([[2., -math.sqrt(3)]]) result = self.metric.mean(points=[point, point, point]) expected = point expected = helper.to_vector(expected) self.assertAllClose(result, expected) points = gs.array([ [1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) result = self.metric.mean(points, weights) result = self.space.belongs(result) expected = gs.array([[True]]) self.assertAllClose(result, expected) def test_variance(self): points = gs.array([ [1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) base_point = gs.array([-1., 0.]) variance = self.metric.variance(points, weights, base_point) result = helper.to_scalar(variance != 0) # we expect the average of the points' Minkowski sq norms. expected = helper.to_scalar(gs.array([True])) self.assertAllClose(result, expected)
class TestFrechetMean(geomstats.tests.TestCase): _multiprocess_can_split_ = True def setUp(self): gs.random.seed(123) self.sphere = Hypersphere(dim=4) self.hyperbolic = Hyperboloid(dim=3) self.euclidean = Euclidean(dim=2) self.minkowski = Minkowski(dim=2) self.so3 = SpecialOrthogonal(n=3, point_type='vector') self.so_matrix = SpecialOrthogonal(n=3) def test_logs_at_mean_default_gradient_descent_sphere(self): n_tests = 10 estimator = FrechetMean( metric=self.sphere.metric, method='default', lr=1.) result = [] for _ in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.sphere.random_uniform(n_samples=2) estimator.fit(points) mean = estimator.estimate_ logs = self.sphere.metric.log(point=points, base_point=mean) result.append(gs.linalg.norm(logs[1, :] + logs[0, :])) result = gs.stack(result) expected = gs.zeros(n_tests) self.assertAllClose(expected, result) def test_logs_at_mean_adaptive_gradient_descent_sphere(self): n_tests = 10 estimator = FrechetMean(metric=self.sphere.metric, method='adaptive') result = [] for _ in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.sphere.random_uniform(n_samples=2) estimator.fit(points) mean = estimator.estimate_ logs = self.sphere.metric.log(point=points, base_point=mean) result.append(gs.linalg.norm(logs[1, :] + logs[0, :])) result = gs.stack(result) expected = gs.zeros(n_tests) self.assertAllClose(expected, result) def test_estimate_shape_default_gradient_descent_sphere(self): dim = 5 point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean( metric=self.sphere.metric, method='default', verbose=True) mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim,)) def test_estimate_shape_adaptive_gradient_descent_sphere(self): dim = 5 point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method='adaptive') mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim,)) def test_estimate_and_belongs_default_gradient_descent_sphere(self): point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method='default') mean.fit(points) result = self.sphere.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_estimate_default_gradient_descent_so3(self): points = self.so3.random_uniform(2) mean_vec = FrechetMean( metric=self.so3.bi_invariant_metric, method='default', lr=1.) mean_vec.fit(points) logs = self.so3.bi_invariant_metric.log(points, mean_vec.estimate_) result = gs.sum(logs, axis=0) expected = gs.zeros_like(points[0]) self.assertAllClose(result, expected) def test_estimate_and_belongs_default_gradient_descent_so3(self): point = self.so3.random_uniform(10) mean_vec = FrechetMean( metric=self.so3.bi_invariant_metric, method='default') mean_vec.fit(point) result = self.so3.belongs(mean_vec.estimate_) expected = True self.assertAllClose(result, expected) @geomstats.tests.np_and_tf_only def test_estimate_default_gradient_descent_so_matrix(self): points = self.so_matrix.random_uniform(2) mean_vec = FrechetMean( metric=self.so_matrix.bi_invariant_metric, method='default', lr=1.) mean_vec.fit(points) logs = self.so_matrix.bi_invariant_metric.log( points, mean_vec.estimate_) result = gs.sum(logs, axis=0) expected = gs.zeros_like(points[0]) self.assertAllClose(result, expected, atol=1e-5) @geomstats.tests.np_and_tf_only def test_estimate_and_belongs_default_gradient_descent_so_matrix(self): point = self.so_matrix.random_uniform(10) mean = FrechetMean( metric=self.so_matrix.bi_invariant_metric, method='default') mean.fit(point) result = self.so_matrix.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) @geomstats.tests.np_and_tf_only def test_estimate_and_belongs_adaptive_gradient_descent_so_matrix(self): point = self.so_matrix.random_uniform(10) mean = FrechetMean( metric=self.so_matrix.bi_invariant_metric, method='adaptive', verbose=True, lr=.5) mean.fit(point) result = self.so_matrix.belongs(mean.estimate_) self.assertTrue(result) @geomstats.tests.np_and_tf_only def test_estimate_and_coincide_default_so_vec_and_mat(self): point = self.so_matrix.random_uniform(3) mean = FrechetMean( metric=self.so_matrix.bi_invariant_metric, method='default') mean.fit(point) expected = mean.estimate_ mean_vec = FrechetMean( metric=self.so3.bi_invariant_metric, method='default') point_vec = self.so3.rotation_vector_from_matrix(point) mean_vec.fit(point_vec) result_vec = mean_vec.estimate_ result = self.so3.matrix_from_rotation_vector(result_vec) self.assertAllClose(result, expected) def test_estimate_and_belongs_adaptive_gradient_descent_sphere(self): point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method='adaptive') mean.fit(points) result = self.sphere.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_variance_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.array([point, point]) result = variance( points, base_point=point, metric=self.sphere.metric) expected = gs.array(0.) self.assertAllClose(expected, result) def test_estimate_default_gradient_descent_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.sphere.metric, method='default') mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) def test_estimate_adaptive_gradient_descent_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.sphere.metric, method='adaptive') mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) def test_estimate_spd(self): point = SPDMatrices(3).random_point() points = gs.array([point, point]) mean = FrechetMean(metric=SPDMetricAffine(3), point_type='matrix') mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) def test_variance_hyperbolic(self): point = gs.array([2., 1., 1., 1.]) points = gs.array([point, point]) result = variance( points, base_point=point, metric=self.hyperbolic.metric) expected = gs.array(0.) self.assertAllClose(result, expected) def test_estimate_hyperbolic(self): point = gs.array([2., 1., 1., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) expected = point result = mean.estimate_ self.assertAllClose(result, expected) def test_estimate_and_belongs_hyperbolic(self): point_a = self.hyperbolic.random_point() point_b = self.hyperbolic.random_point() point_c = self.hyperbolic.random_point() points = gs.stack([point_a, point_b, point_c], axis=0) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) result = self.hyperbolic.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_mean_euclidean_shape(self): dim = 2 point = gs.array([1., 4.]) mean = FrechetMean(metric=self.euclidean.metric) points = [point, point, point] mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim,)) def test_mean_euclidean(self): point = gs.array([1., 4.]) mean = FrechetMean(metric=self.euclidean.metric) points = [point, point, point] mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) points = gs.array([ [1., 2.], [2., 3.], [3., 4.], [4., 5.]]) weights = [1., 2., 1., 2.] mean = FrechetMean(metric=self.euclidean.metric) mean.fit(points, weights=weights) result = mean.estimate_ expected = gs.array([16. / 6., 22. / 6.]) self.assertAllClose(result, expected) def test_variance_euclidean(self): points = gs.array([ [1., 2.], [2., 3.], [3., 4.], [4., 5.]]) weights = gs.array([1., 2., 1., 2.]) base_point = gs.zeros(2) result = variance( points, weights=weights, base_point=base_point, metric=self.euclidean.metric) # we expect the average of the points' sq norms. expected = gs.array((1 * 5. + 2 * 13. + 1 * 25. + 2 * 41.) / 6.) self.assertAllClose(result, expected) def test_mean_matrices_shape(self): m, n = (2, 2) point = gs.array([ [1., 4.], [2., 3.]]) metric = MatricesMetric(m, n) mean = FrechetMean(metric=metric, point_type='matrix') points = [point, point, point] mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (m, n)) def test_mean_matrices(self): m, n = (2, 2) point = gs.array([ [1., 4.], [2., 3.]]) metric = MatricesMetric(m, n) mean = FrechetMean(metric=metric, point_type='matrix') points = [point, point, point] mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) def test_mean_minkowski_shape(self): dim = 2 point = gs.array([2., -math.sqrt(3)]) points = [point, point, point] mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim,)) def test_mean_minkowski(self): point = gs.array([2., -math.sqrt(3)]) points = [point, point, point] mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) points = gs.array([ [1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points, weights=weights) result = mean.estimate_ result = self.minkowski.belongs(result) expected = gs.array(True) self.assertAllClose(result, expected) def test_variance_minkowski(self): points = gs.array([ [1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) base_point = gs.array([-1., 0.]) var = variance( points, weights=weights, base_point=base_point, metric=self.minkowski.metric) result = var != 0 # we expect the average of the points' Minkowski sq norms. expected = True self.assertAllClose(result, expected) def test_one_point(self): point = gs.array([0., 0., 0., 0., 1.]) mean = FrechetMean(metric=self.sphere.metric, method='default') mean.fit(X=point) result = mean.estimate_ expected = point self.assertAllClose(expected, result) mean = FrechetMean( metric=self.sphere.metric, method='frechet-poincare-ball') mean.fit(X=point) result = mean.estimate_ expected = point self.assertAllClose(expected, result)
class TestFrechetMean(geomstats.tests.TestCase): _multiprocess_can_split_ = True def setUp(self): self.sphere = Hypersphere(dimension=4) self.hyperbolic = Hyperbolic(dimension=3) self.euclidean = Euclidean(dimension=2) self.minkowski = Minkowski(dimension=2) @geomstats.tests.np_only def test_adaptive_gradient_descent_sphere(self): n_tests = 100 result = gs.zeros(n_tests) expected = gs.zeros(n_tests) for i in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.sphere.random_uniform(n_samples=2) mean = _adaptive_gradient_descent(points=points, metric=self.sphere.metric) logs = self.sphere.metric.log(point=points, base_point=mean) result[i] = gs.linalg.norm(logs[1, :] + logs[0, :]) self.assertAllClose(expected, result, rtol=1e-10, atol=1e-10) @geomstats.tests.np_and_pytorch_only def test_estimate_and_belongs_sphere(self): point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.zeros((2, point_a.shape[0])) points[0, :] = point_a points[1, :] = point_b mean = FrechetMean(metric=self.sphere.metric) mean.fit(points) result = self.sphere.belongs(mean.estimate_) expected = gs.array([[True]]) self.assertAllClose(result, expected) @geomstats.tests.np_and_pytorch_only def test_variance_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.zeros((2, point.shape[0])) points[0, :] = point points[1, :] = point result = variance(points, base_point=point, metric=self.sphere.metric) expected = helper.to_scalar(0.) self.assertAllClose(expected, result) @geomstats.tests.np_and_pytorch_only def test_estimate_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.zeros((2, point.shape[0])) points[0, :] = point points[1, :] = point mean = FrechetMean(metric=self.sphere.metric) mean.fit(X=points) result = mean.estimate_ expected = helper.to_vector(point) self.assertAllClose(expected, result) @geomstats.tests.np_and_tf_only def test_variance_hyperbolic(self): point = gs.array([2., 1., 1., 1.]) points = gs.array([point, point]) result = variance(points, base_point=point, metric=self.hyperbolic.metric) expected = helper.to_scalar(0.) self.assertAllClose(result, expected) @geomstats.tests.np_and_tf_only def test_estimate_hyperbolic(self): point = gs.array([2., 1., 1., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) result = mean.estimate_ expected = helper.to_vector(point) self.assertAllClose(result, expected) @geomstats.tests.np_and_tf_only def test_estimate_and_belongs_hyperbolic(self): point_a = self.hyperbolic.random_uniform() point_b = self.hyperbolic.random_uniform() point_c = self.hyperbolic.random_uniform() points = gs.concatenate([point_a, point_b, point_c], axis=0) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) result = self.hyperbolic.belongs(mean.estimate_) expected = gs.array([[True]]) self.assertAllClose(result, expected) def test_mean_euclidean(self): point = gs.array([[1., 4.]]) mean = FrechetMean(metric=self.euclidean.metric) points = [point, point, point] mean.fit(points) result = mean.estimate_ expected = point expected = helper.to_vector(expected) self.assertAllClose(result, expected) points = gs.array([[1., 2.], [2., 3.], [3., 4.], [4., 5.]]) weights = gs.array([1., 2., 1., 2.]) mean = FrechetMean(metric=self.euclidean.metric) mean.fit(points, weights=weights) result = mean.estimate_ expected = gs.array([16. / 6., 22. / 6.]) expected = helper.to_vector(expected) self.assertAllClose(result, expected) def test_variance_euclidean(self): points = gs.array([[1., 2.], [2., 3.], [3., 4.], [4., 5.]]) weights = gs.array([1., 2., 1., 2.]) base_point = gs.zeros(2) result = variance(points, weights=weights, base_point=base_point, metric=self.euclidean.metric) # we expect the average of the points' sq norms. expected = (1 * 5. + 2 * 13. + 1 * 25. + 2 * 41.) / 6. expected = helper.to_scalar(expected) self.assertAllClose(result, expected) def test_mean_minkowski(self): point = gs.array([[2., -math.sqrt(3)]]) points = [point, point, point] mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points) result = mean.estimate_ expected = point expected = helper.to_vector(expected) self.assertAllClose(result, expected) points = gs.array([[1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points, weights=weights) result = mean.estimate_ result = self.minkowski.belongs(result) expected = gs.array([[True]]) self.assertAllClose(result, expected) def test_variance_minkowski(self): points = gs.array([[1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) base_point = gs.array([-1., 0.]) var = variance(points, weights=weights, base_point=base_point, metric=self.minkowski.metric) result = helper.to_scalar(var != 0) # we expect the average of the points' Minkowski sq norms. expected = helper.to_scalar(gs.array([True])) self.assertAllClose(result, expected)
class TestFrechetMean(geomstats.tests.TestCase): _multiprocess_can_split_ = True def setup_method(self): gs.random.seed(123) self.sphere = Hypersphere(dim=4) self.hyperbolic = Hyperboloid(dim=3) self.euclidean = Euclidean(dim=2) self.minkowski = Minkowski(dim=2) self.so3 = SpecialOrthogonal(n=3, point_type="vector") self.so_matrix = SpecialOrthogonal(n=3) self.curves_2d = DiscreteCurves(R2) self.elastic_metric = ElasticMetric(a=1, b=1, ambient_manifold=R2) def test_logs_at_mean_curves_2d(self): n_tests = 10 metric = self.curves_2d.srv_metric estimator = FrechetMean(metric=metric, init_step_size=1.0) result = [] for _ in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.curves_2d.random_point(n_samples=2) estimator.fit(points) mean = estimator.estimate_ # Expand and tile are added because of GitHub issue 1575 mean = gs.expand_dims(mean, axis=0) mean = gs.tile(mean, (2, 1, 1)) logs = metric.log(point=points, base_point=mean) logs_srv = metric.aux_differential_srv_transform(logs, curve=mean) # Note that the logs are NOT inverse, only the logs_srv are. result.append(gs.linalg.norm(logs_srv[1, :] + logs_srv[0, :])) result = gs.stack(result) expected = gs.zeros(n_tests) self.assertAllClose(expected, result, atol=1e-5) def test_logs_at_mean_default_gradient_descent_sphere(self): n_tests = 10 estimator = FrechetMean(metric=self.sphere.metric, method="default", init_step_size=1.0) result = [] for _ in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.sphere.random_uniform(n_samples=2) estimator.fit(points) mean = estimator.estimate_ logs = self.sphere.metric.log(point=points, base_point=mean) result.append(gs.linalg.norm(logs[1, :] + logs[0, :])) result = gs.stack(result) expected = gs.zeros(n_tests) self.assertAllClose(expected, result) def test_logs_at_mean_adaptive_gradient_descent_sphere(self): n_tests = 10 estimator = FrechetMean(metric=self.sphere.metric, method="adaptive") result = [] for _ in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.sphere.random_uniform(n_samples=2) estimator.fit(points) mean = estimator.estimate_ logs = self.sphere.metric.log(point=points, base_point=mean) result.append(gs.linalg.norm(logs[1, :] + logs[0, :])) result = gs.stack(result) expected = gs.zeros(n_tests) self.assertAllClose(expected, result) def test_estimate_shape_default_gradient_descent_sphere(self): dim = 5 point_a = gs.array([1.0, 0.0, 0.0, 0.0, 0.0]) point_b = gs.array([0.0, 1.0, 0.0, 0.0, 0.0]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method="default", verbose=True) mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) def test_estimate_shape_adaptive_gradient_descent_sphere(self): dim = 5 point_a = gs.array([1.0, 0.0, 0.0, 0.0, 0.0]) point_b = gs.array([0.0, 1.0, 0.0, 0.0, 0.0]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method="adaptive") mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) def test_estimate_shape_elastic_metric(self): points = self.curves_2d.random_point(n_samples=2) mean = FrechetMean(metric=self.elastic_metric) mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (points.shape[1:])) def test_estimate_shape_metric(self): points = self.curves_2d.random_point(n_samples=2) mean = FrechetMean(metric=self.curves_2d.srv_metric) mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (points.shape[1:])) def test_estimate_and_belongs_default_gradient_descent_sphere(self): point_a = gs.array([1.0, 0.0, 0.0, 0.0, 0.0]) point_b = gs.array([0.0, 1.0, 0.0, 0.0, 0.0]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method="default") mean.fit(points) result = self.sphere.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_estimate_and_belongs_curves_2d(self): points = self.curves_2d.random_point(n_samples=2) mean = FrechetMean(metric=self.curves_2d.srv_metric) mean.fit(points) result = self.curves_2d.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_estimate_default_gradient_descent_so3(self): points = self.so3.random_uniform(2) mean_vec = FrechetMean(metric=self.so3.bi_invariant_metric, method="default", init_step_size=1.0) mean_vec.fit(points) logs = self.so3.bi_invariant_metric.log(points, mean_vec.estimate_) result = gs.sum(logs, axis=0) expected = gs.zeros_like(points[0]) self.assertAllClose(result, expected) def test_estimate_and_belongs_default_gradient_descent_so3(self): point = self.so3.random_uniform(10) mean_vec = FrechetMean(metric=self.so3.bi_invariant_metric, method="default") mean_vec.fit(point) result = self.so3.belongs(mean_vec.estimate_) expected = True self.assertAllClose(result, expected) @geomstats.tests.np_autograd_and_tf_only def test_estimate_default_gradient_descent_so_matrix(self): points = self.so_matrix.random_uniform(2) mean_vec = FrechetMean( metric=self.so_matrix.bi_invariant_metric, method="default", init_step_size=1.0, ) mean_vec.fit(points) logs = self.so_matrix.bi_invariant_metric.log(points, mean_vec.estimate_) result = gs.sum(logs, axis=0) expected = gs.zeros_like(points[0]) self.assertAllClose(result, expected, atol=1e-5) @geomstats.tests.np_autograd_and_tf_only def test_estimate_and_belongs_default_gradient_descent_so_matrix(self): point = self.so_matrix.random_uniform(10) mean = FrechetMean(metric=self.so_matrix.bi_invariant_metric, method="default") mean.fit(point) result = self.so_matrix.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) @geomstats.tests.np_autograd_and_tf_only def test_estimate_and_belongs_adaptive_gradient_descent_so_matrix(self): point = self.so_matrix.random_uniform(10) mean = FrechetMean( metric=self.so_matrix.bi_invariant_metric, method="adaptive", init_step_size=0.5, verbose=True, ) mean.fit(point) result = self.so_matrix.belongs(mean.estimate_) self.assertTrue(result) @geomstats.tests.np_autograd_and_tf_only def test_estimate_and_coincide_default_so_vec_and_mat(self): point = self.so_matrix.random_uniform(3) mean = FrechetMean(metric=self.so_matrix.bi_invariant_metric, method="default") mean.fit(point) expected = mean.estimate_ mean_vec = FrechetMean(metric=self.so3.bi_invariant_metric, method="default") point_vec = self.so3.rotation_vector_from_matrix(point) mean_vec.fit(point_vec) result_vec = mean_vec.estimate_ result = self.so3.matrix_from_rotation_vector(result_vec) self.assertAllClose(result, expected) def test_estimate_and_belongs_adaptive_gradient_descent_sphere(self): point_a = gs.array([1.0, 0.0, 0.0, 0.0, 0.0]) point_b = gs.array([0.0, 1.0, 0.0, 0.0, 0.0]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method="adaptive") mean.fit(points) result = self.sphere.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_variance_sphere(self): point = gs.array([0.0, 0.0, 0.0, 0.0, 1.0]) points = gs.array([point, point]) result = variance(points, base_point=point, metric=self.sphere.metric) expected = gs.array(0.0) self.assertAllClose(expected, result) def test_estimate_default_gradient_descent_sphere(self): point = gs.array([0.0, 0.0, 0.0, 0.0, 1.0]) points = gs.array([point, point]) mean = FrechetMean(metric=self.sphere.metric, method="default") mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) def test_estimate_elastic_metric(self): point = self.curves_2d.random_point(n_samples=1) points = gs.array([point, point]) mean = FrechetMean(metric=self.elastic_metric) mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) def test_estimate_curves_2d(self): point = self.curves_2d.random_point(n_samples=1) points = gs.array([point, point]) mean = FrechetMean(metric=self.curves_2d.srv_metric) mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) def test_estimate_adaptive_gradient_descent_sphere(self): point = gs.array([0.0, 0.0, 0.0, 0.0, 1.0]) points = gs.array([point, point]) mean = FrechetMean(metric=self.sphere.metric, method="adaptive") mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) def test_estimate_spd(self): point = SPDMatrices(3).random_point() points = gs.array([point, point]) mean = FrechetMean(metric=SPDMetricAffine(3), point_type="matrix") mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) 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_variance_hyperbolic(self): point = gs.array([2.0, 1.0, 1.0, 1.0]) points = gs.array([point, point]) result = variance(points, base_point=point, metric=self.hyperbolic.metric) expected = gs.array(0.0) self.assertAllClose(result, expected) def test_estimate_hyperbolic(self): point = gs.array([2.0, 1.0, 1.0, 1.0]) points = gs.array([point, point]) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) expected = point result = mean.estimate_ self.assertAllClose(result, expected) def test_estimate_and_belongs_hyperbolic(self): point_a = self.hyperbolic.random_point() point_b = self.hyperbolic.random_point() point_c = self.hyperbolic.random_point() points = gs.stack([point_a, point_b, point_c], axis=0) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) result = self.hyperbolic.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_mean_euclidean_shape(self): dim = 2 point = gs.array([1.0, 4.0]) mean = FrechetMean(metric=self.euclidean.metric) points = [point, point, point] mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) def test_mean_euclidean(self): point = gs.array([1.0, 4.0]) mean = FrechetMean(metric=self.euclidean.metric) points = [point, point, point] mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) points = gs.array([[1.0, 2.0], [2.0, 3.0], [3.0, 4.0], [4.0, 5.0]]) weights = [1.0, 2.0, 1.0, 2.0] mean = FrechetMean(metric=self.euclidean.metric) mean.fit(points, weights=weights) result = mean.estimate_ expected = gs.array([16.0 / 6.0, 22.0 / 6.0]) self.assertAllClose(result, expected) def test_variance_euclidean(self): points = gs.array([[1.0, 2.0], [2.0, 3.0], [3.0, 4.0], [4.0, 5.0]]) weights = gs.array([1.0, 2.0, 1.0, 2.0]) base_point = gs.zeros(2) result = variance(points, weights=weights, base_point=base_point, metric=self.euclidean.metric) # we expect the average of the points' sq norms. expected = gs.array((1 * 5.0 + 2 * 13.0 + 1 * 25.0 + 2 * 41.0) / 6.0) self.assertAllClose(result, expected) def test_mean_matrices_shape(self): m, n = (2, 2) point = gs.array([[1.0, 4.0], [2.0, 3.0]]) metric = MatricesMetric(m, n) mean = FrechetMean(metric=metric, point_type="matrix") points = [point, point, point] mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (m, n)) def test_mean_matrices(self): m, n = (2, 2) point = gs.array([[1.0, 4.0], [2.0, 3.0]]) metric = MatricesMetric(m, n) mean = FrechetMean(metric=metric, point_type="matrix") points = [point, point, point] mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) def test_mean_minkowski_shape(self): dim = 2 point = gs.array([2.0, -math.sqrt(3)]) points = [point, point, point] mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) def test_mean_minkowski(self): point = gs.array([2.0, -math.sqrt(3)]) points = [point, point, point] mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) points = gs.array([[1.0, 0.0], [2.0, math.sqrt(3)], [3.0, math.sqrt(8)], [4.0, math.sqrt(24)]]) weights = gs.array([1.0, 2.0, 1.0, 2.0]) mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points, weights=weights) result = self.minkowski.belongs(mean.estimate_) self.assertTrue(result) def test_variance_minkowski(self): points = gs.array([[1.0, 0.0], [2.0, math.sqrt(3)], [3.0, math.sqrt(8)], [4.0, math.sqrt(24)]]) weights = gs.array([1.0, 2.0, 1.0, 2.0]) base_point = gs.array([-1.0, 0.0]) var = variance(points, weights=weights, base_point=base_point, metric=self.minkowski.metric) result = var != 0 # we expect the average of the points' Minkowski sq norms. expected = True self.assertAllClose(result, expected) def test_one_point(self): point = gs.array([0.0, 0.0, 0.0, 0.0, 1.0]) mean = FrechetMean(metric=self.sphere.metric, method="default") mean.fit(X=point) result = mean.estimate_ expected = point self.assertAllClose(expected, result) mean = FrechetMean(metric=self.sphere.metric, method="default") mean.fit(X=point) result = mean.estimate_ expected = point 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) @geomstats.tests.np_and_autograd_only def test_stiefel_two_samples(self): space = Stiefel(3, 2) metric = space.metric 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) @geomstats.tests.np_and_autograd_only def test_stiefel_n_samples(self): space = Stiefel(3, 2) metric = space.metric point = space.random_point(2) mean = FrechetMean(metric, method="default", init_step_size=0.5, verbose=True) mean.fit(point) result = space.belongs(mean.estimate_) self.assertTrue(result) def test_circle_mean(self): space = Hypersphere(1) points = space.random_uniform(10) mean_circle = FrechetMean(space.metric) mean_circle.fit(points) estimate_circle = mean_circle.estimate_ # set a wrong dimension so that the extrinsic coordinates are used metric = space.metric metric.dim = 2 mean_extrinsic = FrechetMean(metric) mean_extrinsic.fit(points) estimate_extrinsic = mean_extrinsic.estimate_ self.assertAllClose(estimate_circle, estimate_extrinsic)
class TestMinkowski(geomstats.tests.TestCase): def setUp(self): gs.random.seed(1234) self.time_like_dim = 0 self.dimension = 2 self.space = Minkowski(self.dimension) self.metric = self.space.metric self.n_samples = 10 def test_belongs(self): point = gs.array([-1., 3.]) result = self.space.belongs(point) expected = True self.assertAllClose(result, expected) def test_random_uniform(self): point = self.space.random_uniform() self.assertAllClose(gs.shape(point), (self.dimension, )) def test_random_uniform_and_belongs(self): point = self.space.random_uniform() result = self.space.belongs(point) expected = True self.assertAllClose(result, expected) def test_inner_product_matrix(self): result = self.metric.inner_product_matrix() expected = gs.array([[-1., 0.], [0., 1.]]) self.assertAllClose(result, expected) def test_inner_product(self): point_a = gs.array([0., 1.]) point_b = gs.array([2., 10.]) result = self.metric.inner_product(point_a, point_b) expected = gs.dot(point_a, point_b) expected -= (2 * point_a[self.time_like_dim] * point_b[self.time_like_dim]) self.assertAllClose(result, expected) def test_inner_product_vectorization(self): n_samples = 3 one_point_a = gs.array([-1., 0.]) one_point_b = gs.array([1.0, 0.]) n_points_a = gs.array([[-1., 0.], [1., 0.], [2., math.sqrt(3)]]) n_points_b = gs.array([[2., -math.sqrt(3)], [4.0, math.sqrt(15)], [-4.0, math.sqrt(15)]]) result = self.metric.inner_product(one_point_a, one_point_b) expected = gs.dot(one_point_a, gs.transpose(one_point_b)) expected -= (2 * one_point_a[self.time_like_dim] * one_point_b[self.time_like_dim]) result_no = self.metric.inner_product(n_points_a, one_point_b) result_on = self.metric.inner_product(one_point_a, n_points_b) result_nn = self.metric.inner_product(n_points_a, n_points_b) self.assertAllClose(result, expected) self.assertAllClose(gs.shape(result_no), (n_samples, )) self.assertAllClose(gs.shape(result_on), (n_samples, )) self.assertAllClose(gs.shape(result_nn), (n_samples, )) expected = np.zeros(n_samples) for i in range(n_samples): expected[i] = gs.dot(n_points_a[i], n_points_b[i]) expected[i] -= (2 * n_points_a[i, self.time_like_dim] * n_points_b[i, self.time_like_dim]) self.assertAllClose(result_nn, expected) def test_squared_norm(self): point = gs.array([-2., 4.]) result = self.metric.squared_norm(point) expected = 12. self.assertAllClose(result, expected) def test_squared_norm_vectorization(self): n_samples = 3 n_points = gs.array([[-1., 0.], [1., 0.], [2., math.sqrt(3)]]) result = self.metric.squared_norm(n_points) self.assertAllClose(gs.shape(result), (n_samples, )) def test_exp(self): base_point = gs.array([1.0, 0.]) vector = gs.array([2., math.sqrt(3)]) result = self.metric.exp(tangent_vec=vector, base_point=base_point) expected = base_point + vector self.assertAllClose(result, expected) def test_exp_vectorization(self): dim = self.dimension n_samples = 3 one_tangent_vec = gs.array([-1., 0.]) one_base_point = gs.array([1.0, 0.]) n_tangent_vecs = gs.array([[-1., 0.], [1., 0.], [2., math.sqrt(3)]]) n_base_points = gs.array([[2., -math.sqrt(3)], [4.0, math.sqrt(15)], [-4.0, math.sqrt(15)]]) result = self.metric.exp(one_tangent_vec, one_base_point) expected = one_tangent_vec + one_base_point self.assertAllClose(result, expected) result = self.metric.exp(n_tangent_vecs, one_base_point) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.exp(one_tangent_vec, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.exp(n_tangent_vecs, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) def test_log(self): base_point = gs.array([-1., 0.]) point = gs.array([2., math.sqrt(3)]) result = self.metric.log(point=point, base_point=base_point) expected = point - base_point self.assertAllClose(result, expected) def test_log_vectorization(self): dim = self.dimension n_samples = 3 one_point = gs.array([-1., 0.]) one_base_point = gs.array([1.0, 0.]) n_points = gs.array([[-1., 0.], [1., 0.], [2., math.sqrt(3)]]) n_base_points = gs.array([[2., -math.sqrt(3)], [4.0, math.sqrt(15)], [-4.0, math.sqrt(15)]]) result = self.metric.log(one_point, one_base_point) expected = one_point - one_base_point self.assertAllClose(result, expected) result = self.metric.log(n_points, one_base_point) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.log(one_point, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) result = self.metric.log(n_points, n_base_points) self.assertAllClose(gs.shape(result), (n_samples, dim)) def test_squared_dist(self): point_a = gs.array([2., -math.sqrt(3)]) point_b = gs.array([4.0, math.sqrt(15)]) result = self.metric.squared_dist(point_a, point_b) vec = point_b - point_a expected = gs.dot(vec, vec) expected -= 2 * vec[self.time_like_dim] * vec[self.time_like_dim] self.assertAllClose(result, expected) def test_geodesic_and_belongs(self): n_geodesic_points = 100 initial_point = gs.array([2., -math.sqrt(3)]) initial_tangent_vec = gs.array([2., 0.]) geodesic = self.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 = self.space.belongs(points) expected = gs.array(n_geodesic_points * [True]) self.assertAllClose(result, expected)
class TestFrechetMean(geomstats.tests.TestCase): _multiprocess_can_split_ = True def setUp(self): gs.random.seed(123) self.sphere = Hypersphere(dim=4) self.hyperbolic = Hyperboloid(dim=3) self.euclidean = Euclidean(dim=2) self.minkowski = Minkowski(dim=2) @geomstats.tests.np_only def test_logs_at_mean_default_gradient_descent_sphere(self): n_tests = 100 estimator = FrechetMean(metric=self.sphere.metric, method='default') result = gs.zeros(n_tests) for i in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.sphere.random_uniform(n_samples=2) estimator.fit(points) mean = estimator.estimate_ logs = self.sphere.metric.log(point=points, base_point=mean) result[i] = gs.linalg.norm(logs[1, :] + logs[0, :]) expected = gs.zeros(n_tests) self.assertAllClose(expected, result, rtol=1e-10, atol=1e-10) @geomstats.tests.np_only def test_logs_at_mean_adaptive_gradient_descent_sphere(self): n_tests = 100 estimator = FrechetMean(metric=self.sphere.metric, method='adaptive') result = gs.zeros(n_tests) for i in range(n_tests): # take 2 random points, compute their mean, and verify that # log of each at the mean is opposite points = self.sphere.random_uniform(n_samples=2) estimator.fit(points) mean = estimator.estimate_ logs = self.sphere.metric.log(point=points, base_point=mean) result[i] = gs.linalg.norm(logs[1, :] + logs[0, :]) expected = gs.zeros(n_tests) self.assertAllClose(expected, result, rtol=1e-10, atol=1e-10) @geomstats.tests.np_and_pytorch_only def test_estimate_shape_default_gradient_descent_sphere(self): dim = 5 point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method='default') mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) @geomstats.tests.np_and_pytorch_only def test_estimate_shape_adaptive_gradient_descent_sphere(self): dim = 5 point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method='adaptive') mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) @geomstats.tests.np_and_pytorch_only def test_estimate_and_belongs_default_gradient_descent_sphere(self): point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method='default') mean.fit(points) result = self.sphere.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) @geomstats.tests.np_and_pytorch_only def test_estimate_and_belongs_adaptive_gradient_descent_sphere(self): point_a = gs.array([1., 0., 0., 0., 0.]) point_b = gs.array([0., 1., 0., 0., 0.]) points = gs.array([point_a, point_b]) mean = FrechetMean(metric=self.sphere.metric, method='adaptive') mean.fit(points) result = self.sphere.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) @geomstats.tests.np_and_pytorch_only def test_variance_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.array([point, point]) result = variance(points, base_point=point, metric=self.sphere.metric) expected = gs.array(0.) self.assertAllClose(expected, result) @geomstats.tests.np_and_pytorch_only def test_estimate_default_gradient_descent_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.sphere.metric, method='default') mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) @geomstats.tests.np_and_pytorch_only def test_estimate_adaptive_gradient_descent_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.sphere.metric, method='adaptive') mean.fit(X=points) result = mean.estimate_ expected = point self.assertAllClose(expected, result) @geomstats.tests.np_and_pytorch_only def test_estimate_transform_sphere(self): point = gs.array([0., 0., 0., 0., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.sphere.metric) mean.fit(X=points) result = mean.transform(points) expected = gs.zeros_like(points) self.assertAllClose(expected, result) @geomstats.tests.np_and_pytorch_only def test_estimate_transform_spd(self): point = SPDMatrices(3).random_uniform() points = gs.array([point, point]) mean = FrechetMean(metric=SPDMetricAffine(3), point_type='matrix') mean.fit(X=points) result = mean.transform(points) expected = gs.zeros((2, 6)) self.assertAllClose(expected, result) def test_fit_transform_hyperbolic(self): point = gs.array([2., 1., 1., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.hyperbolic.metric) result = mean.fit_transform(X=points) expected = gs.zeros_like(points) self.assertAllClose(expected, result) def test_inverse_transform_hyperbolic(self): points = self.hyperbolic.random_uniform(10) mean = FrechetMean(metric=self.hyperbolic.metric) X = mean.fit_transform(X=points) result = mean.inverse_transform(X) expected = points self.assertAllClose(expected, result) @geomstats.tests.np_and_pytorch_only def test_inverse_transform_spd(self): point = SPDMatrices(3).random_uniform(10) mean = FrechetMean(metric=SPDMetricAffine(3), point_type='matrix') X = mean.fit_transform(X=point) result = mean.inverse_transform(X) expected = point self.assertAllClose(expected, result) @geomstats.tests.np_and_tf_only def test_variance_hyperbolic(self): point = gs.array([2., 1., 1., 1.]) points = gs.array([point, point]) result = variance(points, base_point=point, metric=self.hyperbolic.metric) expected = gs.array(0.) self.assertAllClose(result, expected) @geomstats.tests.np_and_tf_only def test_estimate_hyperbolic(self): point = gs.array([2., 1., 1., 1.]) points = gs.array([point, point]) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) expected = point result = mean.estimate_ self.assertAllClose(result, expected) @geomstats.tests.np_and_tf_only def test_estimate_and_belongs_hyperbolic(self): point_a = self.hyperbolic.random_uniform() point_b = self.hyperbolic.random_uniform() point_c = self.hyperbolic.random_uniform() points = gs.stack([point_a, point_b, point_c], axis=0) mean = FrechetMean(metric=self.hyperbolic.metric) mean.fit(X=points) result = self.hyperbolic.belongs(mean.estimate_) expected = True self.assertAllClose(result, expected) def test_mean_euclidean_shape(self): dim = 2 point = gs.array([1., 4.]) mean = FrechetMean(metric=self.euclidean.metric) points = [point, point, point] mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) def test_mean_euclidean(self): point = gs.array([1., 4.]) mean = FrechetMean(metric=self.euclidean.metric) points = [point, point, point] mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) points = gs.array([[1., 2.], [2., 3.], [3., 4.], [4., 5.]]) weights = gs.array([1., 2., 1., 2.]) mean = FrechetMean(metric=self.euclidean.metric) mean.fit(points, weights=weights) result = mean.estimate_ expected = gs.array([16. / 6., 22. / 6.]) self.assertAllClose(result, expected) def test_variance_euclidean(self): points = gs.array([[1., 2.], [2., 3.], [3., 4.], [4., 5.]]) weights = gs.array([1., 2., 1., 2.]) base_point = gs.zeros(2) result = variance(points, weights=weights, base_point=base_point, metric=self.euclidean.metric) # we expect the average of the points' sq norms. expected = gs.array((1 * 5. + 2 * 13. + 1 * 25. + 2 * 41.) / 6.) self.assertAllClose(result, expected) def test_mean_matrices_shape(self): m, n = (2, 2) point = gs.array([[1., 4.], [2., 3.]]) metric = MatricesMetric(m, n) mean = FrechetMean(metric=metric, point_type='matrix') points = [point, point, point] mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (m, n)) def test_mean_matrices(self): m, n = (2, 2) point = gs.array([[1., 4.], [2., 3.]]) metric = MatricesMetric(m, n) mean = FrechetMean(metric=metric, point_type='matrix') points = [point, point, point] mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) def test_mean_minkowski_shape(self): dim = 2 point = gs.array([2., -math.sqrt(3)]) points = [point, point, point] mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points) result = mean.estimate_ self.assertAllClose(gs.shape(result), (dim, )) def test_mean_minkowski(self): point = gs.array([2., -math.sqrt(3)]) points = [point, point, point] mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points) result = mean.estimate_ expected = point self.assertAllClose(result, expected) points = gs.array([[1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) mean = FrechetMean(metric=self.minkowski.metric) mean.fit(points, weights=weights) result = mean.estimate_ result = self.minkowski.belongs(result) expected = gs.array(True) self.assertAllClose(result, expected) def test_variance_minkowski(self): points = gs.array([[1., 0.], [2., math.sqrt(3)], [3., math.sqrt(8)], [4., math.sqrt(24)]]) weights = gs.array([1., 2., 1., 2.]) base_point = gs.array([-1., 0.]) var = variance(points, weights=weights, base_point=base_point, metric=self.minkowski.metric) result = var != 0 # we expect the average of the points' Minkowski sq norms. expected = True self.assertAllClose(result, expected)