def to_tangent(self, vector, base_point): """Project a vector in the tangent space. Project a vector in Minkowski space on the tangent space of the hyperbolic space at a base point. Parameters ---------- vector : array-like, shape=[..., n_disks, dim + 1] Vector. base_point : array-like, shape=[..., n_disks, dim + 1] Base point. Returns ------- tangent_vec : array-like, shape=[..., n_disks, dim + 1] Tangent vector at base point. """ n_disks = self.n_disks hyperbolic_space = Hyperboloid(2, self.coords_type) tangent_vec = gs.stack( [ hyperbolic_space.to_tangent(vector=vector[..., i_disk, :], base_point=base_point[..., i_disk, :]) for i_disk in range(n_disks) ], axis=1, ) return tangent_vec
def test_extrinsic_ball_extrinsic_composition(self, dim, point_intrinsic): x = Hyperboloid(dim, coords_type="intrinsic").to_coordinates( point_intrinsic, to_coords_type="extrinsic" ) x_b = Hyperboloid(dim).to_coordinates(x, to_coords_type="ball") x2 = PoincareBall(dim).to_coordinates(x_b, to_coords_type="extrinsic") self.assertAllClose(x, x2)
def setup_method(self): gs.random.seed(1234) self.dimension = 3 self.space = Hyperboloid(dim=self.dimension) self.metric = self.space.metric self.ball_manifold = PoincareBall(dim=2) self.n_samples = 10
def test_exp_after_log_intrinsic_ball_extrinsic( self, dim, x_intrinsic, y_intrinsic ): intrinsic_manifold = Hyperboloid(dim=dim, coords_type="intrinsic") extrinsic_manifold = Hyperbolic(dim=dim, coords_type="extrinsic") ball_manifold = PoincareBall(dim) x_extr = intrinsic_manifold.to_coordinates( x_intrinsic, to_coords_type="extrinsic" ) y_extr = intrinsic_manifold.to_coordinates( y_intrinsic, to_coords_type="extrinsic" ) x_ball = extrinsic_manifold.to_coordinates(x_extr, to_coords_type="ball") y_ball = extrinsic_manifold.to_coordinates(y_extr, to_coords_type="ball") x_ball_exp_after_log = ball_manifold.metric.exp( ball_manifold.metric.log(y_ball, x_ball), x_ball ) x_extr_a = extrinsic_manifold.metric.exp( extrinsic_manifold.metric.log(y_extr, x_extr), x_extr ) x_extr_b = extrinsic_manifold.from_coordinates( x_ball_exp_after_log, from_coords_type="ball" ) self.assertAllClose(x_extr_a, x_extr_b, atol=3e-4)
def test_predict_hyperboloid_distance(self): """Test the 'predict' class method using the hyperboloid distance.""" dim = 2 space = Hyperboloid(dim=dim) distance = space.metric.dist training_dataset_intrinsic = gs.array([[1 / 2, 1 / 4], [1 / 2, 0], [1 / 2, -1 / 4], [-1 / 2, 1 / 4], [-1 / 2, 0], [-1 / 2, -1 / 4]]) training_dataset = space.change_coordinates_system( training_dataset_intrinsic, from_coordinates_system='intrinsic', to_coordinates_system='extrinsic') labels = [0, 0, 0, 1, 1, 1] kde = KernelDensityEstimationClassifier(distance=distance, kernel='distance') kde.fit(training_dataset, labels) target_dataset_intrinsic = gs.array([[1 / 2, 1 / 5], [1 / 2, 0], [1 / 2, -1 / 5], [-1 / 2, 1 / 5], [-1 / 2, 0], [-1 / 2, -1 / 5]]) target_dataset = space.change_coordinates_system( target_dataset_intrinsic, from_coordinates_system='intrinsic', to_coordinates_system='extrinsic') result = kde.predict(target_dataset) expected = [0, 0, 0, 1, 1, 1] self.assertAllClose(expected, result)
def test_scaled_inner_product(self): base_point_intrinsic = gs.array([1., 1., 1.]) base_point = self.space.from_coordinates( base_point_intrinsic, 'intrinsic') tangent_vec_a = gs.array([1., 2., 3., 4.]) tangent_vec_b = gs.array([5., 6., 7., 8.]) tangent_vec_a = self.space.to_tangent( tangent_vec_a, base_point) tangent_vec_b = self.space.to_tangent( tangent_vec_b, base_point) scale = 2 default_space = Hyperboloid(dim=self.dimension) scaled_space = Hyperboloid(dim=self.dimension, scale=2) inner_product_default_metric = \ default_space.metric.inner_product( tangent_vec_a, tangent_vec_b, base_point) inner_product_scaled_metric = \ scaled_space.metric.inner_product( tangent_vec_a, tangent_vec_b, base_point) result = inner_product_scaled_metric expected = scale ** 2 * inner_product_default_metric self.assertAllClose(result, expected)
def projection_to_tangent_space(self, vector, base_point): """Project a vector in the tangent space. Project a vector in Minkowski space on the tangent space of the hyperbolic space at a base point. Parameters ---------- vector : array-like, shape=[n_samples, n_disks, dim + 1] base_point : array-like, shape=[n_samples, n_disks, dim + 1] Returns ------- tangent_vec : array-like, shape=[n_samples, n_disks, dim + 1] """ n_disks = base_point.shape[1] hyperbolic_space = Hyperboloid(2, self.coords_type) tangent_vec = gs.stack([ hyperbolic_space.projection_to_tangent_space( vector=vector[:, i_disk, :], base_point=base_point[:, i_disk, :]) for i_disk in range(n_disks) ], axis=1) return tangent_vec
def test_extrinsic_half_plane_extrinsic_composition(self, dim, point_intrinsic): x = Hyperboloid(dim, coords_type="intrinsic").to_coordinates( point_intrinsic, to_coords_type="extrinsic" ) x_up = Hyperboloid(dim).to_coordinates(x, to_coords_type="half-space") x2 = Hyperbolic.change_coordinates_system(x_up, "half-space", "extrinsic") self.assertAllClose(x, x2)
def test_scaled_inner_product(self): base_point_intrinsic = gs.array([1, 1, 1]) base_point = self.space.from_coordinates( base_point_intrinsic, "intrinsic") tangent_vec_a = gs.array([1, 2, 3, 4]) tangent_vec_b = gs.array([5, 6, 7, 8]) tangent_vec_a = self.space.projection_to_tangent_space( tangent_vec_a, base_point) tangent_vec_b = self.space.projection_to_tangent_space( tangent_vec_b, base_point) scale = 2 default_space = Hyperboloid(dim=self.dimension) scaled_space = Hyperboloid(dim=self.dimension, scale=2) inner_product_default_metric = \ default_space.metric.inner_product( tangent_vec_a, tangent_vec_b, base_point) inner_product_scaled_metric = \ scaled_space.metric.inner_product( tangent_vec_a, tangent_vec_b, base_point) result = inner_product_scaled_metric expected = scale ** 2 * inner_product_default_metric self.assertAllClose(result, expected)
def test_scaled_dist(self, dim, scale, point_a, point_b): default_space = Hyperboloid(dim=dim) scaled_space = Hyperboloid(dim=dim, scale=scale) distance_default_metric = default_space.metric.dist(point_a, point_b) distance_scaled_metric = scaled_space.metric.dist(point_a, point_b) result = distance_scaled_metric expected = scale * distance_default_metric self.assertAllClose(result, expected)
def test_ball_to_half_space_coordinates(self, dim, point_ball): space = self.space(dim) point_half_space = space.ball_to_half_space_coordinates(point_ball) point_ext = Hyperboloid(dim).from_coordinates(point_ball, "ball") point_half_space_expected = Hyperboloid(dim).to_coordinates( point_ext, "half-space" ) self.assertAllClose(point_half_space, point_half_space_expected)
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, point_type='matrix')
def scaled_dist_test_data(self): space = Hyperboloid(3) point_a = space.from_coordinates(gs.array([1.0, 2.0, 3.0]), "intrinsic") point_b = space.from_coordinates(gs.array([4.0, 5.0, 6.0]), "intrinsic") smoke_data = [dict(dim=3, scale=2, point_a=point_a, point_b=point_b)] return self.generate_tests(smoke_data)
def setUp(self): gs.random.seed(1234) self.space_matrix = ProductManifold( manifolds=[Hypersphere(dim=2), Hyperboloid(dim=2)], default_point_type='matrix') self.space_vector = ProductManifold( manifolds=[Hypersphere(dim=2), Hyperboloid(dim=5)], default_point_type='vector')
def test_scaled_squared_norm(self, dim, scale, tangent_vec, base_point): default_space = Hyperboloid(dim=dim) scaled_space = Hyperboloid(dim=dim, scale=scale) squared_norm_default_metric = default_space.metric.squared_norm( tangent_vec, base_point) squared_norm_scaled_metric = scaled_space.metric.squared_norm( tangent_vec, base_point) result = squared_norm_scaled_metric expected = scale**2 * squared_norm_default_metric self.assertAllClose(result, expected)
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_scaled_inner_product(self, dim, scale, tangent_vec_a, tangent_vec_b, base_point): default_space = Hyperboloid(dim=dim) scaled_space = Hyperboloid(dim=dim, scale=scale) inner_product_default_metric = default_space.metric.inner_product( tangent_vec_a, tangent_vec_b, base_point) inner_product_scaled_metric = scaled_space.metric.inner_product( tangent_vec_a, tangent_vec_b, base_point) result = inner_product_scaled_metric expected = scale**2 * inner_product_default_metric self.assertAllClose(result, expected)
def setup_method(self): gs.random.seed(1234) self.space_matrix = ProductManifold( manifolds=[Hypersphere(dim=2), Hyperboloid(dim=2)], default_point_type="matrix", ) self.space_vector = ProductManifold( manifolds=[Hypersphere(dim=2), Hyperboloid(dim=3)], default_point_type="vector", )
def test_exp_and_belongs(self): H2 = Hyperboloid(dim=2) METRIC = H2.metric base_point = gs.array([1., 0., 0.]) self.assertTrue(H2.belongs(base_point)) tangent_vec = H2.to_tangent(vector=gs.array([1., 2., 1.]), base_point=base_point) exp = METRIC.exp(tangent_vec=tangent_vec, base_point=base_point) self.assertTrue(H2.belongs(exp))
def scaled_squared_norm_test_data(self): space = Hyperboloid(3) base_point = space.from_coordinates(gs.array([1.0, 1.0, 1.0]), "intrinsic") tangent_vec = space.to_tangent(gs.array([1.0, 2.0, 3.0, 4.0]), base_point) smoke_data = [ dict(dim=3, scale=2, tangent_vec=tangent_vec, base_point=base_point) ] return self.generate_tests(smoke_data)
def test_log_and_exp_general_case_general_dim(self): """ Test that the Riemannian exponential and the Riemannian logarithm are inverse. Expect their composition to give the identity function. """ # Riemannian Log then Riemannian Exp dim = 5 n_samples = self.n_samples h5 = Hyperboloid(dim=dim) h5_metric = h5.metric base_point = h5.random_point() point = h5.random_point() point = gs.cast(point, gs.float64) base_point = gs.cast(base_point, gs.float64) one_log = h5_metric.log(point=point, base_point=base_point) result = h5_metric.exp(tangent_vec=one_log, base_point=base_point) expected = point self.assertAllClose(result, expected) # Test vectorization of log base_point = gs.stack([base_point] * n_samples, axis=0) point = gs.stack([point] * n_samples, axis=0) expected = gs.stack([one_log] * n_samples, axis=0) log = h5_metric.log(point=point, base_point=base_point) result = log self.assertAllClose(gs.shape(result), (n_samples, dim + 1)) self.assertAllClose(result, expected) result = h5_metric.exp(tangent_vec=log, base_point=base_point) expected = point self.assertAllClose(gs.shape(result), (n_samples, dim + 1)) self.assertAllClose(result, expected) # Test vectorization of exp tangent_vec = gs.stack([one_log] * n_samples, axis=0) exp = h5_metric.exp(tangent_vec=tangent_vec, base_point=base_point) result = exp expected = point self.assertAllClose(gs.shape(result), (n_samples, dim + 1)) self.assertAllClose(result, expected)
def setUp(self): gs.random.seed(1234) self.dimension = 2 self.extrinsic_manifold = Hyperboloid(dim=self.dimension) self.extrinsic_metric = self.extrinsic_manifold.metric self.ball_manifold = PoincareBall(dim=self.dimension) self.ball_metric = self.ball_manifold.metric self.intrinsic_manifold = Hyperboloid(dim=self.dimension, coords_type="intrinsic") self.intrinsic_metric = self.intrinsic_manifold.metric self.n_samples = 10
def test_coordinate(self, dim, point_a, point_b): metric = self.metric(dim) point_a_h = PoincareBall(dim).to_coordinates(gs.array(point_a), "extrinsic") point_b_h = PoincareBall(dim).to_coordinates(gs.array(point_b), "extrinsic") dist_in_ball = metric.dist(gs.array(point_a), gs.array(point_b)) dist_in_hype = Hyperboloid(dim).metric.dist(point_a_h, point_b_h) self.assertAllClose(dist_in_ball, dist_in_hype)
def test_scaled_squared_norm(self): base_point_intrinsic = gs.array([1., 1., 1.]) base_point = self.space.from_coordinates(base_point_intrinsic, 'intrinsic') tangent_vec = gs.array([1., 2., 3., 4.]) tangent_vec = self.space.to_tangent(tangent_vec, base_point) scale = 2 default_space = Hyperboloid(dim=self.dimension) scaled_space = Hyperboloid(dim=self.dimension, scale=2) squared_norm_default_metric = default_space.metric.squared_norm( tangent_vec, base_point) squared_norm_scaled_metric = scaled_space.metric.squared_norm( tangent_vec, base_point) result = squared_norm_scaled_metric expected = scale**2 * squared_norm_default_metric self.assertAllClose(result, expected)
def product_distance_extrinsic_representation_test_data(self): point_a_intrinsic = gs.array([0.01, 0.0]) point_b_intrinsic = gs.array([0.0, 0.0]) hyperbolic_space = Hyperboloid(dim=2) point_a_extrinsic = hyperbolic_space.from_coordinates( point_a_intrinsic, "intrinsic") point_b_extrinsic = hyperbolic_space.from_coordinates( point_b_intrinsic, "intrinsic") smoke_data = [ dict( n_disks=1, point_a_extrinsic=point_a_extrinsic, point_b_extrinsic=point_b_extrinsic, ) ] return self.generate_tests(smoke_data)
def scaled_inner_product_test_data(self): space = Hyperboloid(3) base_point = space.from_coordinates(gs.array([1.0, 1.0, 1.0]), "intrinsic") tangent_vec_a = space.to_tangent(gs.array([1.0, 2.0, 3.0, 4.0]), base_point) tangent_vec_b = space.to_tangent(gs.array([5.0, 6.0, 7.0, 8.0]), base_point) smoke_data = [ dict( dim=3, scale=2, tangent_vec_a=tangent_vec_a, tangent_vec_b=tangent_vec_b, base_point=base_point, ) ] return self.generate_tests(smoke_data)
def test_distance_ball_extrinsic_from_ball(self, dim, x_ball, y_ball): ball_manifold = PoincareBall(dim) space = Hyperboloid(dim) x_extr = ball_manifold.to_coordinates(x_ball, to_coords_type="extrinsic") y_extr = ball_manifold.to_coordinates(y_ball, to_coords_type="extrinsic") dst_ball = ball_manifold.metric.dist(x_ball, y_ball) dst_extr = space.metric.dist(x_extr, y_extr) self.assertAllClose(dst_ball, dst_extr)
def __init__(self, n_disks, coords_type='extrinsic'): self.n_disks = n_disks self.coords_type = coords_type self.point_type = PoincarePolydisk.default_point_type disk = Hyperboloid(2, coords_type=coords_type) list_disks = [disk, ] * n_disks super(PoincarePolydisk, self).__init__( manifolds=list_disks, default_point_type='matrix') self.metric = PoincarePolydiskMetric(n_disks=n_disks, coords_type=coords_type)
def __new__(cls, *args, default_coords_type='extrinsic', **kwargs): """Instantiate class that corresponds to the default_coords_type.""" errors.check_parameter_accepted_values( default_coords_type, 'default_coords_type', ['extrinsic', 'ball', 'half-space']) if default_coords_type == 'extrinsic': return Hyperboloid(*args, **kwargs) if default_coords_type == 'ball': return PoincareBall(*args, **kwargs) return PoincareHalfSpace(*args, **kwargs)
def inner_product_is_minkowski_inner_product_test_data(self): space = Hyperboloid(dim=3) base_point = gs.array( [1.16563816, 0.36381045, -0.47000603, 0.07381469]) tangent_vec_a = space.to_tangent(vector=gs.array( [10.0, 200.0, 1.0, 1.0]), base_point=base_point) tangent_vec_b = space.to_tangent(vector=gs.array( [11.0, 20.0, -21.0, 0.0]), base_point=base_point) smoke_data = [ dict( dim=3, tangent_vec_a=tangent_vec_a, tangent_vec_b=tangent_vec_b, base_point=base_point, ) ] return self.generate_tests(smoke_data)