Source code for surface_dynamics.flat_surfaces.twist_space

# encoding=utf-8
r"""
Homology of cylinder decomposition.
"""
#*****************************************************************************
#       Copyright (C) 2023 Christopher Zhang <christophertzhang@gmail.com>
#
#  Distributed under the terms of the GNU General Public License (GPL)
#  as published by the Free Software Foundation; either version 2 of
#  the License, or (at your option) any later version.
#                  https://www.gnu.org/licenses/
#*****************************************************************************

from collections import defaultdict

from sage.rings.rational_field import QQ
from sage.matrix.special import identity_matrix
from sage.matrix.constructor import matrix
from sage.modules.free_module_element import vector


[docs] class TwistSpace: r""" Subspace of relative homology generated by horizontal saddle connections. This subspace contains the core curves of cylinders. The subspace spanned by the latter is an isotropic subspace of absolute homology. EXAMPLES:: sage: from surface_dynamics import CylinderDiagram sage: from surface_dynamics.flat_surfaces.twist_space import TwistSpace sage: cd = CylinderDiagram("(0,1)-(0,5) (2)-(4) (3,4)-(1) (5)-(2,3)") sage: tw = TwistSpace(cd) sage: tw TwistSpace('(0,1)-(0,5) (2)-(4) (3,4)-(1) (5)-(2,3)') sage: tw.homologous_cylinders() [[2, 3]] sage: tw.cylinder_dimension() 3 In this example, we get that the last two cylinders (3,4)-(1) and (5)-(2,3) are homologous. """ def __init__(self, cd): self._cylinder_diagram = cd degree = cd.degree() ncyls = cd.ncyls() # write down the projection from the vector space generated by # saddle connections to homology (in the canonical basis # given by the row reduced echelon form) relations = matrix(QQ, ncyls, degree) for i, (bot, top) in enumerate(cd.cylinders()): for s in bot: relations[i, s] += 1 for s in top: relations[i, s] -= 1 rref = relations.rref() pivots = relations.pivots() self._projection = identity_matrix(QQ, degree, degree) if pivots: for j, eq in zip(pivots, rref): self._projection[j] -= eq self._projection = self._projection.delete_columns(pivots) self._projection.set_immutable() def __repr__(self): return f"TwistSpace('{self._cylinder_diagram}')" def __call__(self, v): r""" Return the projection of a vector expressed on saddle connections. The result is expressed in the canonical basis of homology given by the row reduced echelon form. EXAMPLES:: sage: from surface_dynamics.flat_surfaces.separatrix_diagram import CylinderDiagram sage: from surface_dynamics.flat_surfaces.twist_space import TwistSpace sage: c = CylinderDiagram('(0,3,1,2)-(5,7) (4,5)-(4,6) (6,7)-(0,3,1,2)') sage: tw = TwistSpace(c) sage: for e in (QQ^8).basis(): ....: print(tw(e)) (-1, -1, -1, 0, 1, 1) (1, 0, 0, 0, 0, 0) (0, 1, 0, 0, 0, 0) (0, 0, 1, 0, 0, 0) (0, 0, 0, 1, 0, 0) (0, 0, 0, 0, 1, 0) (0, 0, 0, 0, 1, 0) (0, 0, 0, 0, 0, 1) """ output = vector(QQ, self._cylinder_diagram.degree(), v) * self._projection output.set_immutable() return output
[docs] def cylinder_core_curves(self): r""" Iterate through the core curves of cylinders as homology elements. EXAMPLES:: sage: from surface_dynamics.flat_surfaces.separatrix_diagram import CylinderDiagram sage: from surface_dynamics.flat_surfaces.twist_space import TwistSpace sage: cd = CylinderDiagram('(0,7,1,2)-(3,6,4,5) (3,6,4,5)-(0,7,1,2)') sage: tw = TwistSpace(cd) sage: list(tw.cylinder_core_curves()) [(0, 0, 1, 1, 1, 1, 0), (0, 0, 1, 1, 1, 1, 0)] sage: cd = CylinderDiagram('(0,7,3,4)-(0,5,3,6) (1,5,2,6)-(1,7,2,4)') sage: tw = TwistSpace(cd) sage: list(tw.cylinder_core_curves()) [(1, 0, 0, 1, 1, 1, 0), (0, 1, 1, 0, 1, 1, 0)] """ cd = self._cylinder_diagram for bot, _ in cd.cylinders(): vec = vector(QQ, [0] * cd.degree()) for s in bot: vec[s] += 1 vec = self(vec) vec.set_immutable() yield vec
[docs] def homologous_cylinders(self): r""" Return the list of homologous cylinders. OUTPUT: a list of lists. Each sublist is an equivalence class of > 1 homologous cylinders. EXAMPLES:: sage: from surface_dynamics import Stratum sage: from surface_dynamics.flat_surfaces.twist_space import TwistSpace sage: for cd in Stratum([1,1,1,1], k=1).cylinder_diagrams(2): ....: hom_cyls = TwistSpace(cd).homologous_cylinders() ....: if hom_cyls: ....: print(cd) ....: print(hom_cyls) (0,7,1,2)-(3,6,4,5) (3,6,4,5)-(0,7,1,2) [[0, 1]] """ # Build the dictionary "homology vector" -> list of cylinder diagrams homologous_cylinders_partition = defaultdict(list) for i, vec in enumerate(self.cylinder_core_curves()): homologous_cylinders_partition[vec].append(i) # Filter the classes with more than one cylinder output = [] for homology_class in homologous_cylinders_partition.values(): if len(homology_class) > 1: output.append(homology_class) return output
[docs] def cylinder_dimension(self): r""" Return the dimension of the span of core curves. See also the method ``homological_dimension_of_cylinders`` for ``CylinderDiagram``. EXAMPLES:: sage: from surface_dynamics import Stratum sage: from surface_dynamics.flat_surfaces.twist_space import TwistSpace sage: for cd in Stratum([1,1,1,1], k=1).cylinder_diagrams(): ....: assert TwistSpace(cd).cylinder_dimension() == cd.homological_dimension_of_cylinders() """ return matrix(list(self.cylinder_core_curves())).rank()