Source code for flatsurf.geometry.categories.topological_surfaces

r"""
The category of topological surfaces.

This module provides a base category for all surfaces in sage-flatsurf.

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::

    sage: from flatsurf import MutableOrientedSimilaritySurface
    sage: S = MutableOrientedSimilaritySurface(QQ)

    sage: from flatsurf.geometry.categories import TopologicalSurfaces
    sage: S in TopologicalSurfaces()
    True

"""
# ****************************************************************************
#  This file is part of sage-flatsurf.
#
#        Copyright (C) 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 sage.categories.category_with_axiom import all_axioms
from sage.categories.topological_spaces import TopologicalSpaces
from sage.misc.abstract_method import abstract_method
from flatsurf.geometry.categories.surface_category import (
    SurfaceCategory,
    SurfaceCategoryWithAxiom,
)


[docs] class TopologicalSurfaces(SurfaceCategory): r""" The category of topological surfaces, i.e., surfaces that are locally homeomorphic to the real plane or the closed upper half plane. This category does not provide much functionality but just a common base for all the other categories defined in sage-flatsurf. In particular, this does not require a topology since there is no general concept of open subsets of a surface in sage-flatsurf. EXAMPLES:: sage: from flatsurf.geometry.categories import TopologicalSurfaces sage: TopologicalSurfaces() Category of topological surfaces """
[docs] def super_categories(self): r""" Return the categories a topological surface is also a member of. EXAMPLES:: sage: from flatsurf.geometry.categories import TopologicalSurfaces sage: TopologicalSurfaces().super_categories() [Category of topological spaces] """ return [TopologicalSpaces()]
[docs] class ParentMethods: r""" Provides methods available to all surfaces in sage-flatsurf. If you want to add functionality for all surfaces you most likely want to put it here. """
[docs] def refined_category(self): r""" Return the smallest subcategory that this surface is in. The result of this method can be fed to ``_refine_category_`` to change the category of the surface (and enable functionality specific to the smaller classes of surfaces.) Note that this method does have much effect for a general topological surface. Subcategories and implementations of surfaces should override this method to derive more features. EXAMPLES:: sage: from flatsurf import MutableOrientedSimilaritySurface sage: S = MutableOrientedSimilaritySurface(QQ) sage: from flatsurf import polygons sage: S.add_polygon(polygons.square(), label=0) 0 sage: S.refined_category() Category of connected with boundary finite type translation surfaces sage: S.glue((0, 0), (0, 2)) sage: S.glue((0, 1), (0, 3)) sage: S.refined_category() Category of connected without boundary finite type translation surfaces """ category = self.category() if self.is_orientable(): category &= category.Orientable() if self.is_with_boundary(): category &= category.WithBoundary() else: category &= category.WithoutBoundary() if self.is_compact(): category &= category.Compact() if self.is_connected(): category &= category.Connected() return category
def _test_refined_category(self, **options): r""" Verify that all (immutable) surfaces are contained in their refined category automatically. To pass this test, surfaces should either set their ``category`` explicitly or ensure to run `_refine_category_(refined_category())` at some point. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S._test_refined_category() """ tester = self._tester(**options) tester.assertTrue(self.category().is_subcategory(self.refined_category())) def _Hom_(self, Y, category=None): r""" Return the space of morphisms from this surface to ``Y``. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: S = translation_surfaces.square_torus() sage: End(S) Surface Endomorphisms of Translation Surface in H_1(0) built from a square """ if Y in TopologicalSurfaces(): from flatsurf.geometry.morphism import SurfaceMorphismSpace return SurfaceMorphismSpace(self, Y, category=category) return super()._Hom_(Y, category=category)
[docs] @abstract_method def is_mutable(self): r""" Return whether this surface allows modifications. All surfaces in sage-flatsurf must implement this method. .. NOTE:: We do not specify the interface of such mutations. Any mutable surface should come up with a good interface for its use case. The point of this method is to signal that is likely unsafe to use this surface in caches (since it might change later) and that the category of the surface might still change. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S._test_refined_category() """
[docs] @abstract_method def is_orientable(self): r""" Return whether this surface is orientable. All surfaces in sage-flatsurf must implement this method. .. NOTE:: This method is used by :meth:`refined_category` to determine whether this surface satisfies the axiom :class:`.TopologicalSurfaces.Orientable`. Surfaces must override this method to perform specialized logic, see the note in :mod:`flatsurf.geometry.categories` for performance considerations. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_orientable() True """
[docs] @abstract_method def is_with_boundary(self): r""" Return whether this a topological surface with boundary. All surfaces in sage-flatsurf must implement this method. .. NOTE:: This method is used by :meth:`refined_category` to determine whether this surface satisfies the axiom :class:`.WithBoundary` or :class:`.TopologicalSurfaces.WithoutBoundary`. Surfaces must override this method to perform specialized logic, see the note in :mod:`flatsurf.geometry.categories` for performance considerations. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_with_boundary() False """
[docs] @abstract_method def is_compact(self): r""" Return whether this surface is compact. All surfaces in sage-flatsurf must implement this method. .. NOTE:: This method is used by :meth:`refined_category` to determine whether this surface satisfies the axiom of compactness. Surfaces can override this method to perform specialized logic, see the note in :mod:`flatsurf.geometry.categories` for performance considerations. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_compact() True """
[docs] @abstract_method def is_connected(self): r""" Return whether this surface is connected. All surfaces in sage-flatsurf must implement this method. .. NOTE:: This method is used by :meth:`refined_category` to determine whether this surface satisfies the axiom of connectedness. Surfaces can override this method to perform specialized logic, see the note in :mod:`flatsurf.geometry.categories` for performance considerations. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_connected() True """
[docs] @abstract_method(optional=True) def genus(self): r""" Return the genus of this surface. EXAMPLES:: sage: from flatsurf import translation_surfaces sage: translation_surfaces.octagon_and_squares().genus() 3 """
def _an_element_(self): r""" Return a point on this surface. EXAMPLES:: sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators sage: s = SimilaritySurfaceGenerators.example() sage: s.an_element() Point (4/3, -2/3) of polygon 0 :: sage: from flatsurf import Polygon, MutableOrientedSimilaritySurface sage: S = MutableOrientedSimilaritySurface(QQ) sage: S.add_polygon(Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])) 0 sage: S.glue((0, 0), (0, 2)) sage: S.glue((0, 1), (0, 3)) sage: S.an_element() Point (1/2, 1/2) of polygon 0 TESTS: Verify that this method works over non-fields (if 2 is invertible):: sage: from flatsurf import similarity_surfaces sage: from flatsurf import EuclideanPolygonsWithAngles sage: E = EuclideanPolygonsWithAngles((3, 3, 5)) sage: from pyexactreal import ExactReals # optional: pyexactreal # random output due to pkg_resources deprecation warnings in some contexts sage: R = ExactReals(E.base_ring()) # optional: pyexactreal sage: angles = (3, 3, 5) sage: slopes = EuclideanPolygonsWithAngles(*angles).slopes() sage: P = Polygon(angles=angles, edges=[R.random_element() * slopes[0]]) # optional: pyexactreal sage: S = similarity_surfaces.billiard(P) # optional: pyexactreal sage: S.an_element() # optional: pyexactreal Point ((1/2 ~ 0.50000000)*ℝ(0.303644…), 0) of polygon 0 """ return next(iter(self.some_elements()))
[docs] class Orientable(SurfaceCategoryWithAxiom): r""" The axiom satisfied by surfaces that can be oriented. As of 2023, all surfaces in sage-flatsurf satisfy this axiom. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: 'Orientable' in S.category().axioms() True """
[docs] class ParentMethods: r""" Provides methods available to all orientable surfaces in sage-flatsurf. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def is_orientable(self): r""" Return whether this surface is orientable, i.e., return ``True``. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_orientable() True """ return True
[docs] class WithBoundary(SurfaceCategoryWithAxiom): r""" The axiom satisfied by surfaces that have a boundary, i.e., at some points this surface is homeomorphic to the closed upper half plane. EXAMPLES:: sage: from flatsurf import MutableOrientedSimilaritySurface sage: S = MutableOrientedSimilaritySurface(QQ) sage: from flatsurf import polygons sage: S.add_polygon(polygons.square(), label=0) 0 sage: S.set_immutable() sage: 'WithBoundary' in S.category().axioms() True """
[docs] class ParentMethods: r""" Provides methods available to all surfaces with boundary in sage-flatsurf. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def is_with_boundary(self): r""" Return whether this is a surface with boundary, i.e., return ``True``. EXAMPLES:: sage: from flatsurf import MutableOrientedSimilaritySurface sage: S = MutableOrientedSimilaritySurface(QQ) sage: from flatsurf import polygons sage: S.add_polygon(polygons.square(), label=0) 0 sage: S.set_immutable() sage: S.is_with_boundary() True """ return True
[docs] class WithoutBoundary(SurfaceCategoryWithAxiom): r""" An impossible category, the surfaces with and without boundary. EXAMPLES:: sage: from flatsurf.geometry.categories import TopologicalSurfaces sage: C = TopologicalSurfaces() sage: C.WithBoundary().WithoutBoundary() Traceback (most recent call last): ... TypeError: a surface cannot be both with and without boundary sage: C.WithoutBoundary().WithBoundary() Traceback (most recent call last): ... TypeError: a surface cannot be both with and without boundary """ def __init__(self, *args, **kwargs): raise TypeError("a surface cannot be both with and without boundary")
[docs] class WithoutBoundary(SurfaceCategoryWithAxiom): r""" The axiom satisfied by surfaces that have no boundary, i.e., the surface is everywhere homeomorphic to the real plane. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: 'WithoutBoundary' in S.category().axioms() True """
[docs] class ParentMethods: r""" Provides methods available to all surfaces without boundary in sage-flatsurf. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def is_with_boundary(self): r""" Return whether this is a surface with boundary, i.e., return ``False``. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_with_boundary() False """ return False
[docs] class Connected(SurfaceCategoryWithAxiom): r""" The axiom satisfied by surfaces that are topologically connected. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: 'Connected' in S.category().axioms() True """
[docs] class ParentMethods: r""" Provides methods available to all connected surfaces in sage-flatsurf. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def is_connected(self): r""" Return whether this surface is connected, i.e., return ``True``. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_connected() True """ return True
[docs] class Compact(SurfaceCategoryWithAxiom): r""" The axiom satisfied by surfaces that are compact as topological spaces. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: 'Compact' in S.category().axioms() True """
[docs] class ParentMethods: r""" Provides methods available to all compact surfaces in sage-flatsurf. If you want to add functionality for such surfaces you most likely want to put it here. """
[docs] def is_compact(self): r""" Return whether this surface is compact, i.e., return ``True``. EXAMPLES:: sage: from flatsurf import Polygon, similarity_surfaces sage: P = Polygon(vertices=[(0,0), (2,0), (1,4), (0,5)]) sage: S = similarity_surfaces.self_glued_polygon(P) sage: S.is_compact() True """ return True
[docs] class SubcategoryMethods:
[docs] def Orientable(self): r""" Return the subcategory of surfaces that can be oriented. EXAMPLES:: sage: from flatsurf.geometry.categories import TopologicalSurfaces sage: TopologicalSurfaces().Orientable() Category of orientable topological surfaces """ return self._with_axiom("Orientable")
[docs] def WithBoundary(self): r""" Return the subcategory of surfaces that have a boundary, i.e., points at which they are homeomorphic to the closed upper half plane. EXAMPLES:: sage: from flatsurf.geometry.categories import TopologicalSurfaces sage: TopologicalSurfaces().WithBoundary() Category of with boundary topological surfaces """ return self._with_axiom("WithBoundary")
[docs] def WithoutBoundary(self): r""" Return the subcategory of surfaces that have no boundary, i.e., they are everywhere isomorphic to the real plane. EXAMPLES:: sage: from flatsurf.geometry.categories import TopologicalSurfaces sage: TopologicalSurfaces().WithoutBoundary() Category of without boundary topological surfaces """ return self._with_axiom("WithoutBoundary")
# Currently, there is no "Orientable", "WithBoundary", and "WithoutBoundary" # axiom in SageMath so we make it known to the category framework. all_axioms += ("Orientable", "WithBoundary", "WithoutBoundary")