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_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_single_cluster(self): gs.random.seed(10) sphere = Hypersphere(dim=2) metric = sphere.metric cluster = sphere.random_von_mises_fisher(kappa=100, n_samples=10) rms = riemannian_mean_shift( manifold=sphere, metric=metric, bandwidth=float("inf"), tol=1e-4, n_centers=1, max_iter=1, ) rms.fit(cluster) center = rms.predict(cluster) mean = FrechetMean(metric=metric, init_step_size=1.0) mean.fit(cluster) result = center[0] expected = mean.estimate_ 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_stiefel_n_samples(self): space = Stiefel(3, 2) metric = space.metric point = space.random_point(2) mean = FrechetMean(metric, lr=0.5, verbose=True, method="default") mean.fit(point) result = space.belongs(mean.estimate_) self.assertTrue(result)
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_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_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)
def test_weighted_frechet_mean(self): """Test for weighted mean.""" data = gs.array([[0.1, 0.2], [0.25, 0.35], [-0.1, -0.2], [-0.4, 0.3]]) weights = gs.repeat([0.5], data.shape[0]) mean_o = FrechetMean(metric=self.metric, point_type='vector') mean_o.fit(data, weights) mean = mean_o.estimate_ mean_verdict = [-0.03857, 0.15922] self.assertAllClose(mean, mean_verdict, TOLERANCE)
def test_riemannian_normal_frechet_mean(self, dim): space = self.space(dim) mean = space.random_uniform() precision = gs.eye(space.dim) * 10 sample = space.random_riemannian_normal(mean, precision, 30000) estimator = FrechetMean(space.metric, method="adaptive") estimator.fit(sample) estimate = estimator.estimate_ self.assertAllClose(estimate, mean, atol=1e-1)
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)
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_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)
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_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_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)
def empirical_frechet_var_bubble(n_samples, theta, dim, n_expectation=1000): """Variance of the empirical Fréchet mean for a bubble distribution. Draw n_sampless from a bubble distribution, computes its empirical Fréchet mean and the square distance to the asymptotic mean. This is repeated n_expectation times to compute an approximation of its expectation (i.e. its variance) by sampling. The bubble distribution is an isotropic distributions on a Riemannian hyper sub-sphere of radius 0 < theta < Pi around the north pole of the sphere of dimension dim. Parameters ---------- n_samples : int Number of samples to draw. theta: float Radius of the bubble distribution. dim : int Dimension of the sphere (embedded in R^{dim+1}). n_expectation: int, optional (defaults to 1000) Number of computations for approximating the expectation. Returns ------- tuple (variance, std-dev on the computed variance) """ if dim <= 1: raise ValueError( "Dim > 1 needed to draw a uniform sample on sub-sphere.") var = [] sphere = Hypersphere(dim=dim) bubble = Hypersphere(dim=dim - 1) north_pole = gs.zeros(dim + 1) north_pole[dim] = 1.0 for _ in range(n_expectation): # Sample n points from the uniform distribution on a sub-sphere # of radius theta (i.e cos(theta) in ambient space) # TODO (nina): Add this code as a method of hypersphere last_col = gs.cos(theta) * gs.ones(n_samples) last_col = last_col[:, None] if (n_samples > 1) else last_col directions = bubble.random_uniform(n_samples) rest_col = gs.sin(theta) * directions data = gs.concatenate([rest_col, last_col], axis=-1) estimator = FrechetMean(sphere.metric, max_iter=32, method="adaptive", init_point=north_pole) estimator.fit(data) current_mean = estimator.estimate_ var.append(sphere.metric.squared_dist(north_pole, current_mean)) return gs.mean(var), 2 * gs.std(var) / gs.sqrt(n_expectation)
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_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_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_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 main(): """Perform tangent PCA at the mean.""" fig = plt.figure(figsize=(15, 5)) hyperbolic_plane = Hyperbolic(dimension=2) data = hyperbolic_plane.random_uniform(n_samples=140) mean = FrechetMean(metric=hyperbolic_plane.metric) mean.fit(data) mean_estimate = mean.estimate_ tpca = TangentPCA(metric=hyperbolic_plane.metric, n_components=2) tpca = tpca.fit(data, base_point=mean_estimate) tangent_projected_data = tpca.transform(data) geodesic_0 = hyperbolic_plane.metric.geodesic( initial_point=mean_estimate, initial_tangent_vec=tpca.components_[0]) geodesic_1 = hyperbolic_plane.metric.geodesic( initial_point=mean_estimate, initial_tangent_vec=tpca.components_[1]) n_steps = 100 t = np.linspace(-1, 1, n_steps) geodesic_points_0 = geodesic_0(t) geodesic_points_1 = geodesic_1(t) logging.info( 'Coordinates of the Log of the first 5 data points at the mean, ' 'projected on the principal components:') logging.info('\n{}'.format(tangent_projected_data[:5])) ax_var = fig.add_subplot(121) xticks = np.arange(1, 2 + 1, 1) ax_var.xaxis.set_ticks(xticks) ax_var.set_title('Explained variance') ax_var.set_xlabel('Number of Principal Components') ax_var.set_ylim((0, 1)) ax_var.plot(xticks, tpca.explained_variance_ratio_) ax = fig.add_subplot(122) visualization.plot( mean_estimate, ax, space='H2_poincare_disk', color='darkgreen', s=10) visualization.plot( geodesic_points_0, ax, space='H2_poincare_disk', linewidth=2) visualization.plot( geodesic_points_1, ax, space='H2_poincare_disk', linewidth=2) visualization.plot( data, ax, space='H2_poincare_disk', color='black', alpha=0.7) plt.show()
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_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_weighted_frechet_mean(self): """Test for weighted mean.""" data = gs.array([[0.1, 0.2], [0.25, 0.35]]) weights = gs.array([3., 1.]) mean_o = FrechetMean(metric=self.metric, point_type='vector', lr=1.) mean_o.fit(data, weights=weights) result = mean_o.estimate_ expected = self.metric.exp( weights[1] / gs.sum(weights) * self.metric.log(data[1], data[0]), data[0]) self.assertAllClose(result, expected)
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_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_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_coincides_with_frechet_so(self): gs.random.seed(0) point = self.so.random_uniform(self.n_samples) estimator = ExponentialBarycenter(self.so, max_iter=40, epsilon=1e-10) estimator.fit(point) result = estimator.estimate_ frechet_estimator = FrechetMean(self.so.bi_invariant_metric, max_iter=40, epsilon=1e-10) frechet_estimator.fit(point) expected = frechet_estimator.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)