Source code for flatsurf.geometry.pyflatsurf.morphism

r"""
Morphisms involving pylatsurf backed surfaces.

This module extends :mod:`flatsurf.geometry.morphism` with morphisms that rely
on the C++/Python library ``pyflatsurf``.

EXAMPLES::

    sage: from flatsurf import translation_surfaces
    sage: S = translation_surfaces.veech_double_n_gon(5)
    sage: to_pyflatsurf = S.pyflatsurf()  # optional: pyflatsurf  # random output due to cppyy deprecation warnings
    sage: to_pyflatsurf  # optional: pyflatsurf
    Composite morphism:
      From: Translation Surface in H_2(2) built from 2 regular pentagons
      To:   Surface backed by FlatTriangulationCombinatorial(...) with vectors ...
      Defn: Triangulation morphism:
              ...
            then pyflatsurf conversion morphism:
              ...

    sage: to_pyflatsurf.codomain().flat_triangulation()  # optional: pyflatsurf
    FlatTriangulationCombinatorial(...) with vectors ...

.. SEEALSO:

    :mod:`flatsurf.geometry.pyflatsurf.conversion` for much of the underlying
    machinery.

"""

# ********************************************************************
#  This file is part of sage-flatsurf.
#
#        Copyright (C) 2024 Julian Rüth
#
#  sage-flatsurf is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 2 of the License, or
#  (at your option) any later version.
#
#  sage-flatsurf is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with sage-flatsurf. If not, see <https://www.gnu.org/licenses/>.
# ********************************************************************
from flatsurf.geometry.morphism import SurfaceMorphism


[docs] class Morphism_to_pyflatsurf(SurfaceMorphism): r""" A trivial isomorphism from a sage-flatsurf translation surface to a pyflatsurf backed translation surface. You should not create such morphisms directly but rely on the caching provided by :meth:`~flatsurf.geometry.categories.translation_surfaces.TranslationSurfaces.FiniteType.ParentMethods.pyflatsurf`. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: to_pyflatsurf = S.pyflatsurf() # optional: pyflatsurf TESTS:: sage: from flatsurf.geometry.pyflatsurf.morphism import Morphism_to_pyflatsurf sage: isinstance(to_pyflatsurf, Morphism_to_pyflatsurf) # optional: pyflatsurf True sage: TestSuite(to_pyflatsurf).run() # optional: pyflatsurf """
[docs] def __init__(self, parent, pyflatsurf_conversion): super().__init__(parent) self._pyflatsurf_conversion = pyflatsurf_conversion
def _image_edge(self, label, edge): r""" Helper method for :meth:`_image_homology_edge` and others. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: to_pyflatsurf = S.pyflatsurf() # optional: pyflatsurf sage: to_pyflatsurf._image_edge((0, 0), 0) # optional: pyflatsurf ((1, 2, 3), 0) """ half_edge = self._pyflatsurf_conversion((label, edge)) face = tuple(self.codomain().flat_triangulation().face(half_edge)) label = type(self.codomain())._normalize_label(face) edge = label.index(half_edge) return (label, edge) def _image_homology_edge(self, label, edge, codomain): r""" Implements :meth:`SurfaceMorphism._image_homology_edge`. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: to_pyflatsurf = S.pyflatsurf() # optional: pyflatsurf sage: to_pyflatsurf._image_homology_edge((0, 0), 0, codomain=to_pyflatsurf.codomain().homology()) # optional: pyflatsurf B[((1, 2, 3), 0)] """ return codomain(self._image_edge(label, edge))
[docs] def section(self): r""" Return the inverse of this morphism. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: to_pyflatsurf = S.pyflatsurf() # optional: pyflatsurf sage: to_pyflatsurf.section() # optional: pyflatsurf pyflatsurf reconversion morphism: From: Surface backed by FlatTriangulationCombinatorial(...) with vectors ... To: Triangulation of Translation Surface in H_2(2) built from 2 regular pentagons """ return Morphism_from_pyflatsurf._create_morphism( self.codomain(), self.domain(), self._pyflatsurf_conversion )
def _repr_type(self): r""" Helper method for printing this morphism. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: S.pyflatsurf() # optional: pyflatsurf pyflatsurf conversion morphism: From: Triangulation of Translation Surface in H_2(2) built from 2 regular pentagons To: Surface backed by FlatTriangulationCombinatorial(...) with vectors ... """ return "pyflatsurf conversion" def _test_section_point(self, **options): r""" Do not verify that :meth:`_section_point` has been implemented correctly. Surfaces backed by pyflatsurf cannot represent points yet. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: to_pyflatsurf = S.pyflatsurf() # optional: pyflatsurf sage: to_pyflatsurf._test_section_point() # optional: pyflatsurf """ try: super()._test_section_point(**options) except NotImplementedError: # This test is known to fail until #211 adds mapping of points through pyflatsurf morphisms return raise Exception("this test is expected to fail until #211 is merged")
[docs] def __eq__(self, other): r""" Return whether this morphism is indistinguishable from ``other``. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: S.pyflatsurf() == S.pyflatsurf() # optional: pyflatsurf True """ if not isinstance(other, Morphism_to_pyflatsurf): return False return ( self.parent() == other.parent() and self._pyflatsurf_conversion == other._pyflatsurf_conversion )
[docs] def __hash__(self): r""" Return a hash value for this morphism that is compatible with :meth:`__eq__`. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: hash(S.pyflatsurf()) == hash(S.pyflatsurf()) # optional: pyflatsurf True """ return hash(self.parent())
[docs] class Morphism_from_pyflatsurf(SurfaceMorphism): r""" A trivial isomorphism from a pyflatsurf backed translation surface to a sage-flatsurf translation surface. You should not create such morphisms directly but only create them as the :meth:`Morphism_to_pyflatsurf.section` of another morphism. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: from_pyflatsurf = S.pyflatsurf().section() # optional: pyflatsurf TESTS:: sage: from flatsurf.geometry.pyflatsurf.morphism import Morphism_from_pyflatsurf sage: isinstance(from_pyflatsurf, Morphism_from_pyflatsurf) # optional: pyflatsurf True sage: TestSuite(from_pyflatsurf).run() # optional: pyflatsurf """
[docs] def __init__(self, parent, pyflatsurf_conversion): super().__init__(parent) self._pyflatsurf_conversion = pyflatsurf_conversion
def _image_half_edge(self, half_edge): r""" Helper method for :meth:`_image_homology_edge` and others. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: from_pyflatsurf = S.pyflatsurf().section() # optional: pyflatsurf sage: from_pyflatsurf._image_half_edge(1R) # optional: pyflatsurf ((1, 2, 3), 0) """ face = tuple(self.domain().flat_triangulation().face(half_edge)) label = type(self.domain())._normalize_label(face) edge = label.index(half_edge) return (label, edge) def _image_homology_edge(self, label, edge, codomain): r""" Implements :meth:`SurfaceMorphism._image_homology_edge`. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: from_pyflatsurf = S.pyflatsurf().section() # optional: pyflatsurf sage: from_pyflatsurf._image_homology_edge((1, 2, 3), 0, codomain=from_pyflatsurf.codomain().homology()) # optional: pyflatsurf B[((0, 0), 0)] """ half_edge = label[edge] import pyflatsurf half_edge = pyflatsurf.flatsurf.HalfEdge(int(half_edge)) return codomain(self._pyflatsurf_conversion._preimage_half_edge(half_edge)) def _repr_type(self): r""" Helper method for printing this morphism. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: S.pyflatsurf().section() # optional: pyflatsurf pyflatsurf reconversion morphism: From: Surface backed by FlatTriangulationCombinatorial(...) with vectors ... To: Triangulation of Translation Surface in H_2(2) built from 2 regular pentagons """ return "pyflatsurf reconversion" def _test_section_point(self, **options): r""" Do not verify that :meth:`_section_point` has been implemented correctly. Surfaces backed by pyflatsurf cannot represent points yet. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: from_pyflatsurf = S.pyflatsurf().section() # optional: pyflatsurf sage: from_pyflatsurf._test_section_point() # optional: pyflatsurf """ try: super()._test_section_point(**options) except NotImplementedError: # This test is known to fail until #211 adds mapping of points through pyflatsurf morphisms return raise Exception("this test is expected to fail until #211 is merged")
[docs] def __eq__(self, other): r""" Return whether this morphism is indistinguishable from ``other``. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: S.pyflatsurf().section() == S.pyflatsurf().section() # optional: pyflatsurf True """ if not isinstance(other, Morphism_from_pyflatsurf): return False return ( self.parent() == other.parent() and self._pyflatsurf_conversion == other._pyflatsurf_conversion )
[docs] def __hash__(self): r""" Return a hash value for this morphism that is compatible with :meth:`__eq__`. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.veech_double_n_gon(5).triangulate().codomain() sage: hash(S.pyflatsurf().section()) == hash(S.pyflatsurf().section()) # optional: pyflatsurf True """ return hash(self.parent())
[docs] class Morphism_Deformation(SurfaceMorphism): r""" A morphism of :class:`~flatsurf.geometry.pyflatsurf.surface.Surface_pyflatsurf` surfaces that is backed by a libflatsurf ``Deformation``. These morphisms are usually hidden deep inside the machinery of some complex morphism constructions. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: T = S.relabel({0: 1}) sage: isomorphism = S.delaunay_decompose(codomain=T) # optional: pyflatsurf sage: deformation = isomorphism._factorization()._factorization()._morphisms[2] # optional: pyflatsurf sage: deformation # optional: pyflatsurf pyflatsurf deformation morphism: From: Surface backed by FlatTriangulationCombinatorial(vertices = (1, -3, 2, -1, 3, -2), faces = (1, 2, 3)(-1, -2, -3)) with vectors {1: (1, 0), 2: (0, 1), 3: (-1, -1)} To: Surface backed by FlatTriangulationCombinatorial(vertices = (1, -3, 2, -1, 3, -2), faces = (1, 2, 3)(-1, -2, -3)) with vectors {1: (1, 0), 2: (0, 1), 3: (-1, -1)} Defn: FlatTriangulationCombinatorial(vertices = (1, -3, 2, -1, 3, -2), faces = (1, 2, 3)(-1, -2, -3)) with vectors {1: (1, 0), 2: (0, 1), 3: (-1, -1)} → ... TESTS:: sage: from flatsurf.geometry.pyflatsurf.morphism import Morphism_Deformation sage: isinstance(deformation, Morphism_Deformation) # optional: pyflatsurf True sage: TestSuite(deformation).run() # optional: pyflatsurf """
[docs] def __init__(self, parent, deformation): super().__init__(parent) self._deformation = deformation
def _repr_type(self): r""" Helper method for the printing of this morphism. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: isomorphism = S.delaunay_decompose(codomain=S) # optional: pyflatsurf sage: deformation = isomorphism._factorization()._factorization()._morphisms[2] # optional: pyflatsurf sage: deformation # optional: pyflatsurf pyflatsurf deformation morphism: From: ... To: ... Defn: ... """ return "pyflatsurf deformation" def _repr_defn(self): r""" Helper method for the printing of this morphism. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: isomorphism = S.delaunay_decompose(codomain=S) # optional: pyflatsurf sage: deformation = isomorphism._factorization()._factorization()._morphisms[2] # optional: pyflatsurf sage: deformation # optional: pyflatsurf pyflatsurf deformation morphism: From: ... To: ... Defn: FlatTriangulationCombinatorial(vertices = (1, -3, 2, -1, 3, -2), faces = (1, 2, 3)(-1, -2, -3)) with vectors {1: (1, 0), 2: (0, 1), 3: (-1, -1)} → ... """ return repr(self._deformation) def _image_homology_edge(self, label, edge, codomain): r""" Implements :meth:`SurfaceMorphism._image_homology_edge`. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: isomorphism = S.delaunay_decompose(codomain=S) # optional: pyflatsurf sage: deformation = isomorphism._factorization()._factorization()._morphisms[2] # optional: pyflatsurf sage: H = deformation.domain().homology() # optional: pyflatsurf sage: H.hom(deformation).matrix() # optional: pyflatsurf [1 0] [0 1] """ half_edge = label[edge] from pyflatsurf import flatsurf saddle_connection = flatsurf.SaddleConnection[ type(self.domain().flat_triangulation()) ](self.domain().flat_triangulation(), flatsurf.HalfEdge(half_edge)) path = flatsurf.Path[type(self.domain().flat_triangulation())]( saddle_connection ) path = self._deformation(path) if not path: raise NotImplementedError( "cannot map edge through this deformation in pyflatsurf yet" ) path = path.value() image = codomain.zero() for step in path: chain = step.chain() for edge, coefficient in chain: from flatsurf.geometry.pyflatsurf.conversion import RingConversion coefficient = RingConversion.from_pyflatsurf_from_elements( [coefficient] ).section(coefficient) half_edge = edge.positive() face = tuple(self.codomain().flat_triangulation().face(half_edge)) label = type(self.codomain())._normalize_label(face) edge = label.index(half_edge) image += coefficient * codomain((label, edge)) return image def _test_section_point(self, **options): r""" Do not verify that :meth:`_section_point` has been implemented correctly. Surfaces backed by pyflatsurf cannot represent points yet. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: T = S.relabel({0: 1}) sage: isomorphism = S.delaunay_decompose(codomain=T) # optional: pyflatsurf sage: deformation = isomorphism._factorization()._factorization()._morphisms[2] # optional: pyflatsurf sage: deformation._test_section_point() # optional: pyflatsurf """ try: super()._test_section_point(**options) except NotImplementedError: # This test is known to fail until #211 adds mapping of points through pyflatsurf morphisms return raise Exception("this test is expected to fail until #211 is merged") def _test_pickling(self, **options): r""" Do not test that this morphism can be serialized and deserialized. This cannot work because libflatsurf deformations do not implement cereal serialization yet. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: T = S.relabel({0: 1}) sage: isomorphism = S.delaunay_decompose(codomain=T) # optional: pyflatsurf sage: deformation = isomorphism._factorization()._factorization()._morphisms[2] # optional: pyflatsurf sage: deformation._test_pickling() # optional: pyflatsurf """ try: super()._test_pickling(**options) except Exception: return raise Exception("libflatsurf is not expected to implement serialization yet")
[docs] def __eq__(self, other): r""" Return whether this morphism is indistinguishable from ``other``. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: T = S.relabel({0: 1}) sage: S.delaunay_decompose(codomain=T)._factorization()._factorization()._morphisms[2] == S.delaunay_decompose(codomain=T)._factorization()._factorization()._morphisms[2] # optional: pyflatsurf Traceback (most recent call last): ... NotImplementedError: deformations do not implement the == operator yet """ if not isinstance(other, Morphism_Deformation): return False if self.parent() != other.parent(): return False if self is other: return True # This is not implemented in Deformation in libflatsurf raise NotImplementedError("deformations do not implement the == operator yet")
[docs] def __hash__(self): r""" Return a hash value for this morphism that is compatible with :meth:`__eq__`. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: T = S.relabel({0: 1}) sage: hash(S.delaunay_decompose(codomain=T)._factorization()._factorization()._morphisms[2]) == hash(S.delaunay_decompose(codomain=T)._factorization()._factorization()._morphisms[2]) # optional: pyflatsurf True """ # In libflatsurf there is no implementation for hashing of Deformation yet return hash((self.parent(), repr(self)))