Source code for flatsurf.geometry.categories.cone_surfaces

r"""
The category of cone surfaces.

A cone surface is a surface that can be built by gluing Euclidean polygons
along their edges such that the matrix describing `monodromy
<https://en.wikipedia.org/wiki/(G,X)-manifold#Monodromy>`_ along a closed path
is an isometry; that matrix is given by multiplying the individual matrices
that describe how to transition between pairs of glued edges, see
:meth:`~.similarity_surfaces.SimilaritySurfaces.Oriented.ParentMethods.edge_matrix`.

In sage-flatsurf, we restrict cone surfaces slightly by requiring that a cone
surface is given by polygons such that each edge matrix is an isometry.

See :mod:`flatsurf.geometry.categories` for a general description of the
category framework in sage-flatsurf.

Normally, you won't create this (or any other) category directly. The correct
category is automatically determined for immutable surfaces.

EXAMPLES:

We glue the sides of a square with a rotation of π/2. Since each gluing is just
a rotation, this is a cone surface::

    sage: from flatsurf import Polygon, MutableOrientedSimilaritySurface
    sage: P = Polygon(vertices=[(0,0), (1,0), (1,1), (0,1)])
    sage: S = MutableOrientedSimilaritySurface(QQ)
    sage: S.add_polygon(P, label=0)
    0
    sage: S.glue((0, 0), (0, 1))
    sage: S.glue((0, 2), (0, 3))
    sage: S.set_immutable()

    sage: C = S.category()

    sage: from flatsurf.geometry.categories import ConeSurfaces
    sage: C.is_subcategory(ConeSurfaces())
    True

"""
# ####################################################################
#  This file is part of sage-flatsurf.
#
#        Copyright (C) 2013-2019 Vincent Delecroix
#                      2013-2019 W. Patrick Hooper
#                           2023 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.categories.surface_category import (
    SurfaceCategory,
    SurfaceCategoryWithAxiom,
)


[docs]class ConeSurfaces(SurfaceCategory): r""" The category of surfaces built by gluing (Euclidean) polygons with isometries on the edges. See :mod:`~flatsurf.geometry.categories.cone_surfaces` and :meth:`~ParentMethods.is_cone_surface` on how this differs slightly from the customary definition of a cone surface. EXAMPLES:: sage: from flatsurf.geometry.categories import ConeSurfaces sage: ConeSurfaces() Category of cone surfaces """
[docs] def super_categories(self): r""" Return the categories that a cone surfaces is also always a member of. EXAMPLES:: sage: from flatsurf.geometry.categories import ConeSurfaces sage: ConeSurfaces().super_categories() [Category of similarity surfaces] """ from flatsurf.geometry.categories.similarity_surfaces import SimilaritySurfaces return [SimilaritySurfaces()]
[docs] class ParentMethods: r""" Provides methods available to all cone surfaces. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def is_cone_surface(self): r""" Return whether this surface is a cone surface, i.e., whether its edges are glued by isometries. .. NOTE:: This is a stronger requirement than the usual definition of a cone surface, see :mod:`~flatsurf.geometry.categories.cone_surfaces` for details. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.infinite_staircase() sage: S.is_cone_surface() True """ return True
@staticmethod def _is_cone_surface(surface, limit=None): r""" Return whether ``surface`` is a cone surface by checking how its polygons are glued. This is a helper method for :meth:`is_cone_surface` and :meth:`_test_cone_surface`. INPUT: - ``surface`` -- an oriented similarity surface - ``limit`` -- an integer or ``None`` (default: ``None``); if set, only the first ``limit`` polygons are checked EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.infinite_staircase() sage: from flatsurf.geometry.categories import ConeSurfaces sage: ConeSurfaces.ParentMethods._is_cone_surface(S, limit=8) True :: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(edges=[(2, 0),(-1, 3),(-1, -3)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: ConeSurfaces.ParentMethods._is_cone_surface(S) True """ if "Oriented" not in surface.category().axioms(): raise NotImplementedError( "cannot check whether a non-oriented surface is a cone surface yet" ) labels = surface.labels() if limit is not None: from itertools import islice labels = islice(labels, limit) checked = set() for label in labels: for edge in range(len(surface.polygon(label).vertices())): cross = surface.opposite_edge(label, edge) if cross is None: continue if cross in checked: continue checked.add((label, edge)) # We do not call self.edge_matrix() since the surface might # have overridden this (just returning the identity matrix e.g.) # and we want to deduce the matrix from the attached polygon # edges instead. from flatsurf.geometry.categories import SimilaritySurfaces matrix = SimilaritySurfaces.Oriented.ParentMethods.edge_matrix.f( # pylint: disable=no-member surface, label, edge ) if matrix * matrix.transpose() != 1: return False return True
[docs] class FiniteType(SurfaceCategoryWithAxiom): r""" The category of cone surfaces built from finitely many polygons. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(edges=[(2, 0),(-1, 3),(-1, -3)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: from flatsurf.geometry.categories import ConeSurfaces sage: S in ConeSurfaces().FiniteType() True """
[docs] class ParentMethods: r""" Provides methods available to all cone surfaces built from finitely many polygons. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def area(self): r""" Return the area of this surface. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(edges=[(2, 0),(-1, 3),(-1, -3)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.area() 3 """ return sum(p.area() for p in self.polygons())
[docs] class Oriented(SurfaceCategoryWithAxiom): r""" The category of oriented cone surfaces, i.e., orientable cone surfaces whose orientation can be chosen to be compatible with the embedding of its polygons in the real plane. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(edges=[(2, 0),(-1, 3),(-1, -3)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: from flatsurf.geometry.categories import ConeSurfaces sage: S in ConeSurfaces().Oriented() True """
[docs] class ParentMethods: r""" Provides methods available to all oriented cone surfaces. If you want to add functionality for such surfaces you most likely want to put it here. """ def _test_cone_surface(self, **options): r""" Verify that this is a cone surface. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: S.set_immutable() sage: S._test_cone_surface() """ tester = self._tester(**options) limit = None if not self.is_finite_type(): limit = 32 tester.assertTrue( ConeSurfaces.ParentMethods._is_cone_surface(self, limit=limit) )
[docs] class WithoutBoundary(SurfaceCategoryWithAxiom): r""" The category of oriented cone surfaces without boundary. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(edges=[(2, 0),(-1, 3),(-1, -3)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: from flatsurf.geometry.categories import ConeSurfaces sage: S in ConeSurfaces().Oriented().WithoutBoundary() True """
[docs] class ParentMethods: r""" Provides methods available to all oriented cone surfaces without boundary. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def angles(self, numerical=False, return_adjacent_edges=False): r""" Return the set of angles around the vertices of the surface. EXAMPLES:: sage: from flatsurf import polygons, similarity_surfaces sage: T = polygons.triangle(3, 4, 5) sage: S = similarity_surfaces.billiard(T) sage: S.angles() [1/3, 1/4, 5/12] sage: S.angles(numerical=True) # abs tol 1e-14 [0.333333333333333, 0.250000000000000, 0.416666666666667] sage: S.angles(return_adjacent_edges=True) [(1/3, [(0, 1), (1, 2)]), (1/4, [(0, 0), (1, 0)]), (5/12, [(1, 1), (0, 2)])] """ if not numerical and any( not p.is_rational() for p in self.polygons() ): raise NotImplementedError( "cannot compute exact angles in this surface built from non-rational polygons yet" ) edges = list(self.edges()) edges = set(edges) angles = [] if return_adjacent_edges: while edges: p, e = edges.pop() adjacent_edges = [(p, e)] angle = self.polygon(p).angle(e, numerical=numerical) pp, ee = self.opposite_edge( p, (e - 1) % len(self.polygon(p).vertices()) ) while pp != p or ee != e: edges.remove((pp, ee)) adjacent_edges.append((pp, ee)) angle += self.polygon(pp).angle( ee, numerical=numerical ) pp, ee = self.opposite_edge( pp, (ee - 1) % len(self.polygon(pp).vertices()) ) angles.append((angle, adjacent_edges)) else: while edges: p, e = edges.pop() angle = self.polygon(p).angle(e, numerical=numerical) pp, ee = self.opposite_edge( p, (e - 1) % len(self.polygon(p).vertices()) ) while pp != p or ee != e: edges.remove((pp, ee)) angle += self.polygon(pp).angle( ee, numerical=numerical ) pp, ee = self.opposite_edge( pp, (ee - 1) % len(self.polygon(pp).vertices()) ) angles.append(angle) return angles
[docs] class Connected(SurfaceCategoryWithAxiom): r""" The category of oriented connected cone surfaces without boundary. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(edges=[(2, 0),(-1, 3),(-1, -3)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: from flatsurf.geometry.categories import ConeSurfaces sage: S in ConeSurfaces().Oriented().Connected() True """
[docs] class ParentMethods: r""" Provides methods available to all oriented connected cone surfaces without boundary. If you want to add functionality for such surfaces you most likely want to put it here. """ def _test_genus(self, **options): r""" Verify that the genus is compatible with the angles of the singularities. ALGORITHM: We use the angles around the vertices of the surface to compute the genus, see e.g. [Massart2021] p.17 and compare this to the genus computed directly from the polygon gluings. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: translation_surfaces.octagon_and_squares()._test_genus() .. [Massart2021] \D. Massart. A short introduction to translation surfaces, Veech surfaces, and Teichműller dynamics. https://hal.science/hal-03300179/document """ tester = self._tester(**options) for edge in self.edges(): if self.opposite_edge(*edge) == edge: # The genus formula below is wrong when # there is a non-materialized vertex on an # edge. return tester.assertAlmostEqual( self.genus(), sum(a - 1 for a in self.angles(numerical=True)) / 2.0 + 1, )