Source code for geomstats.geometry.open_hemisphere

"""Open hemisphere.

For more details, check section 7.4.1 of [T2022]_.

Lead author: Olivier Bisson.

References
----------
.. [T2022] Yann Thanwerdas. Riemannian and stratified
    geometries on covariance and correlation matrices. Differential
    Geometry [math.DG]. Université Côte d'Azur, 2022.
"""

import geomstats.backend as gs
from geomstats.geometry.base import OpenSet
from geomstats.geometry.diffeo import InvolutionDiffeomorphism
from geomstats.geometry.hyperboloid import Hyperboloid
from geomstats.geometry.hypersphere import Hypersphere
from geomstats.geometry.product_manifold import ProductManifold, ProductRiemannianMetric
from geomstats.geometry.pullback_metric import PullbackDiffeoMetric


[docs] class OpenHemisphereToHyperboloidDiffeo(InvolutionDiffeomorphism): """A diffeomorphism between the open hemisphere and the hyperboloid.""" def __call__(self, base_point): """Diffeomorphism at base point.""" return_point = gs.copy(base_point) return_point[..., 0] = 1.0 first_term = base_point[..., 0] return gs.einsum("...,...i->...i", 1 / first_term, return_point)
[docs] def tangent(self, tangent_vec, base_point=None, image_point=None): """Tangent diffeomorphism at base point.""" if base_point is None: base_point = self.inverse(image_point) coeffs = tangent_vec[..., 0] / base_point[..., 0] image_tangent_vec_0 = gs.array(-tangent_vec[..., 0] / base_point[..., 0]) image_tangent_vec_other = tangent_vec[..., 1:] - gs.einsum( "...,...i->...i", coeffs, base_point[..., 1:] ) image_tangent_vec = gs.concatenate( [gs.expand_dims(image_tangent_vec_0, axis=-1), image_tangent_vec_other], axis=-1, ) return gs.einsum("...,...i->...i", 1 / base_point[..., 0], image_tangent_vec)
[docs] class OpenHemisphere(OpenSet): r"""Open hemisphere. An open set of the hypersphere where the first coordinate is always positive. .. math:: \mathrm{HS}^{k-1}=\left\{x \in \mathbb{R}^k: \|x\|=1 \text { and } x_0>0\right\} """ def __init__(self, dim, equip=True): self.dim = dim super().__init__( dim=dim, intrinsic=False, embedding_space=Hypersphere(dim, equip=equip), equip=equip, )
[docs] @staticmethod def default_metric(): """Metric to equip the space with if equip is True.""" return OpenHemispherePullbackMetric
[docs] def belongs(self, point, atol=gs.atol): """Check if a point belongs to the open hemisphere.""" is_on_sphere = self.embedding_space.belongs(point) is_on_upper_part = gs.greater(point[..., 0], 0.0) return gs.logical_and(is_on_sphere, is_on_upper_part)
[docs] def projection(self, point): """Project a point on the open hemisphere. Parameters ---------- point : array-like, shape=[..., dim] Point in embedding hypersphere space. Returns ------- projected_point : array-like, shape=[..., dim] Point projected on the open hemisphere. """ proj_point = self.embedding_space.projection(point) proj_point[..., 0] = gs.abs(proj_point[..., 0]) return proj_point
[docs] class OpenHemispherePullbackMetric(PullbackDiffeoMetric): """Pullback diffeo metric for Open Hemisphere. Pulls back metric from hyperboloid. """ def __init__(self, space): image_space = Hyperboloid(dim=space.dim) diffeo = OpenHemisphereToHyperboloidDiffeo() super().__init__(space=space, diffeo=diffeo, image_space=image_space)
[docs] class OpenHemispheresProduct(ProductManifold): r"""A consecutively factor-dim increasing product manifold of open hemispheres. .. math:: HS^1\times \dots \times HS(n) """ def __init__(self, n, equip=True): factors = [OpenHemisphere(dim=dim, equip=True) for dim in range(1, n)] super().__init__( factors=factors, point_ndim=1, equip=equip, )
[docs] @staticmethod def default_metric(): """Metric to equip the space with if equip is True.""" return OpenHemispheresProductMetric
[docs] class OpenHemispheresProductMetric(ProductRiemannianMetric): """Define the product metric on these manifolds."""