Source code for surface_dynamics.flat_surfaces.strata

r"""
Strata of differential on Riemann surfaces

This file gather common code used in
:mod:`~surface_dynamics.flat_surfaces.abelian_strata` and
:mod:`~surface_dynamics.flat_surfaces.quadratic_strata`.
"""
#*****************************************************************************
#       Copyright (C) 2009-2019 Vincent Delecroix <20100.delecroix@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/
#*****************************************************************************

import numbers

from functools import total_ordering

from sage.misc.cachefunc import cached_method
from sage.structure.unique_representation import UniqueRepresentation
from sage.structure.sage_object import SageObject
from sage.structure.parent import Parent

[docs] def list_to_exp_list(l): r""" Convert list into exponential notation. EXAMPLES:: sage: from surface_dynamics import * sage: from surface_dynamics.flat_surfaces.strata import list_to_exp_list sage: l = [0,0,2,2,3,2,0,0,0] sage: list_to_exp_list(l) [(0, 2), (2, 2), (3, 1), (2, 1), (0, 3)] """ d = [] i = 0 while i < len(l): j = i while j < len(l) and l[j] == l[i]: j += 1 d.append((l[i],j-i)) i = j return d
# # Stratum, stratum component #
[docs] class Stratum(UniqueRepresentation, SageObject): r""" Stratum of holomorphic or meromorphic k-differentials on smooth connected Riemann surfaces. INPUT: - ``signature`` -- a list of ``n`` integers (determine the angles of conical singularities) - ``k`` -- optional integer (default ``1``) the order of the differential EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum((2,), k=1) H_2(2) TESTS:: sage: S = Stratum((2,), k=1) sage: loads(dumps(S)) == S True sage: S = Stratum((2, 2, 2), k=3) sage: loads(dumps(S)) == S True """ @staticmethod def __classcall_private__(self, signature, k=1): if not isinstance(k, numbers.Integral) or k <= 0: raise ValueError('k must be a positive integer') k = int(k) if isinstance(signature, dict): signature = sum(([i] * mult for i, mult in signature.items()), []) signature = tuple(signature) if not signature: raise ValueError('the signature must be non-empty') for m in signature: if not isinstance(m, numbers.Integral): raise ValueError('mu must be a list of integers') signature = tuple(sorted(map(int, signature), reverse=True)) return super().__classcall__(Stratum, signature, k) def __new__(cls, signature, k): if k == 1: from .abelian_strata import AbelianStratum as cls elif k == 2: from .quadratic_strata import QuadraticStratum as cls else: cls = Stratum return object.__new__(cls) def __init__(self, signature, k=1): s = sum(signature) if s % (2 * k): raise ValueError('the sum of orders must be congruent to 2 k = {} got {} (mu={})'.format(2 * k, s, signature)) if s < - 2 * k: raise ValueError('the sum of orders must be at least {} (got {})'.format(- 2 * k, s)) self._k = k self._signature = signature def __reduce__(self): return Stratum, (self._signature, self._k)
[docs] def surface_differential_order(self): r""" Return the order of differentials in this stratum. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([1]*6, 3).surface_differential_order() 3 """ return self._k
# NOTE: called g in diffstrata GeneralisedStratum # the name here might be misleading as this is not the genus of the space but of the object in the moduli
[docs] def surface_genus(self): r""" Return the genus of the surfaces in this stratum. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum((0,), k=1).surface_genus() 1 sage: Stratum((1,1), k=1).surface_genus() 2 sage: Stratum((3,2,1), k=1).surface_genus() 4 sage: Stratum((-1,-1,-1,-1), k=2).surface_genus() 0 """ return sum(self._signature) // (2 * self._k) + 1
[docs] def genus(self): import warnings warnings.warn('genus() has been deprecated and will be removed in a future version of surface-dynamics; use surface_genus()') return self.surface_genus()
[docs] def surface_has_finite_area(self): r""" Return whether the k-differentials in this moduli space have finite or infinite area. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum((3, 2, 1), k=1).surface_has_finite_area() True sage: Stratum((1, 0, -1), k=1).surface_has_finite_area() False sage: Stratum([-1]*6, k=3).surface_has_finite_area() True sage: Stratum([-2]*3, k=3).surface_has_finite_area() True sage: Stratum([-3]*2, k=3).surface_has_finite_area() False """ return self._signature[-1] > -self._k
[docs] def dimension(self): r""" Return the complex dimension of this stratum. The dimension is `2g-2+s+1` where `g` is the genus of surfaces in the stratum, `s` the number of singularities. The complex dimension of a stratum is also the number of intervals of any interval exchange transformations associated to the strata. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum((0,), k=1).dimension() 2 sage: Stratum((0,0), k=1).dimension() 3 sage: Stratum((2,), k=1).dimension() 4 sage: Stratum((1,1), k=1).dimension() 5 sage: Stratum({-1:4}, k=2).dimension() 2 :: sage: a = Stratum((4,3,2,1,0), k=1) sage: p = a.permutation_representative() sage: len(p) == a.dimension() True """ if self._k == 1 and all(x >= 0 for x in self._signature): return 2 * self.surface_genus() + len(self._signature) - 1 elif self._k == 2 and all(x >= -1 for x in self._signature): return 2 * self.surface_genus() + len(self._signature) - 2 raise NotImplementedError('higher order differential')
[docs] def rank(self): r""" Return the rank of this GL(2,R)-invariant manifold (half dimension of the absolute part of the tangent space). EXAMPLES:: sage: from surface_dynamics import Stratum, QuadraticStrata sage: Stratum((0,0), k=1).rank() 1 sage: Stratum((2,), k=1).rank() 2 sage: Stratum((2,0,0), k=1).rank() 2 sage: Stratum({-1: 4}, k=2).rank() 1 sage: Stratum({-1:4, 0:5}, k=2).rank() 1 Complete list of rank 2 quadratic strata listed by dimension:: sage: for dim in range(4, 9): ....: quad = [Q for Q in QuadraticStrata(dimension=dim) if Q.rank() == 2] ....: print("%d: %s" % (dim, ", ".join(map(str, quad)))) 4: Q_2(5, -1), Q_1(1^2, -1^2), Q_1(3, -1^3), Q_0(1, -1^5) 5: Q_3(8), Q_2(2, 1^2), Q_2(4, 1, -1), Q_2(3, 2, -1), Q_2(6, -1^2), Q_1(2, 1, -1^3), Q_1(4, -1^4), Q_0(2, -1^6) 6: Q_3(6, 2), Q_3(4^2), Q_2(2^2, 1, -1), Q_2(4, 2, -1^2), Q_1(2^2, -1^4) 7: Q_3(4, 2^2), Q_2(2^3, -1^2) 8: Q_3(2^4) """ if self._k == 1: if all(x >= 0 for x in self._signature): return self.surface_genus() else: # is there a meaning for rank? raise NotImplementedError elif self._k == 2: if all(x >= -1 for x in self._signature): return self.surface_genus() + sum(z % 2 for z in self._signature) // 2 - 1 else: # is there a meaning for rank? raise NotImplementedError elif self._k >= 3: raise ValueError('not a GL(2,R)-invariant subvariety')
[docs] def signature(self): r""" Return the order of zeros with multiplicities. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([1, 2, 3], k=1).signature() (3, 2, 1) sage: Stratum({2: 4}, k=1).signature() (2, 2, 2, 2) sage: Stratum([-1, 1], k=1).signature() (1, -1) sage: Stratum({-1: 4}, k=2).signature() (-1, -1, -1, -1) sage: Stratum({1: 8}, k=2).signature() (1, 1, 1, 1, 1, 1, 1, 1) sage: Stratum({-2: 2, 0: 1}, k=2).signature() (0, -2, -2) """ return self._signature
[docs] def zeros(self, fake_zeros=True, poles=True): import warnings warnings.warn('zeros() has been deprecated and will be removed in a future version of surface-dynamics; use signature()') s = self.signature() if not fake_zeros: s = tuple(m for m in s if m) if not poles: s = tuple(m for m in s if m >= 0) return s
[docs] def nb_zeros(self, fake_zeros=True, poles=True): r""" Returns the number of zeros of self. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([0], k=1).nb_zeros() doctest:warning ... UserWarning: nb_zero() has been deprecated and will be removed in a future version of surface-dynamics; use signature() 1 sage: Stratum({2:4,3:2}, k=1).nb_zeros() 6 sage: Stratum({-1:4}, k=2).nb_zeros() 4 sage: Stratum({-1:4,1:4}, k=2).nb_zeros() 8 """ import warnings warnings.warn('nb_zero() has been deprecated and will be removed in a future version of surface-dynamics; use signature()') return sum(int((fake_zeros or m) and (poles or m >= 0)) for m in self.signature())
[docs] def nb_fake_zeros(self): r""" Return the number of fake zeros. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([0], k=1).nb_fake_zeros() doctest:warning ... UserWarning: nb_fake_zeros() has been deprecated and will be removed in a future version of surface-dynamics; use signature() 1 sage: Stratum([1,1,0,0], k=1).nb_fake_zeros() 2 sage: Stratum([0,4,2,2], k=2).nb_fake_zeros() 1 """ import warnings warnings.warn('nb_fake_zeros() has been deprecated and will be removed in a future version of surface-dynamics; use signature()') return self._signature.count(0)
[docs] def nb_poles(self): r""" Return the number of poles of this quadratic stratum. """ import warnings warnings.warn('nb_poles() has been deprecated and will be removed in a future version of surface-dynamics; use signature()') return sum(int(m < 0) for m in self.signature())
[docs] @cached_method def connected_components(self): r""" Return the connected components of this stratum of differentials. - Abelian holomorphic differentials [KonZor03]_ - Quadratic differentials with at most simple poles [Lan08]_ """ zeros = tuple(m for m in self._signature if m) if not self.surface_has_finite_area(): raise NotImplementedError('meromorphic differentials with higher order poles') if self._k == 1: # Abelian differentials: Kontsevich-Zorich classification from .abelian_strata import ASC, HypASC, NonHypASC, OddASC, EvenASC s = sum(zeros) genus = s // 2 + 1 if genus == 1: return (HypASC(self),) elif genus == 2: return (HypASC(self),) elif genus == 3: if zeros == (2, 2) or zeros == (4,): return (HypASC(self), OddASC(self)) else: return (ASC(self),) elif len(zeros) == 1: # just one zeros [2g-2] return (HypASC(self), OddASC(self), EvenASC(self)) elif zeros == (genus-1, genus-1): # two identical zeros [g-1, g-1] if genus % 2 == 0: return (HypASC(self), NonHypASC(self)) else: return (HypASC(self), OddASC(self), EvenASC(self)) elif all(x%2 == 0 for x in zeros): # even zeroes [2 l_1, 2 l_2, ..., 2 l_n] return (OddASC(self), EvenASC(self)) else: return (ASC(self),) elif self._k == 2: # quadratic differentials: Lanneau classification from .quadratic_strata import CQSC, HQSC, GTNQSC, GTHQSC, GOQSC, REQSC, IEQSC, GZQSC, NQSC nb_poles = zeros.count(-1) s = sum(zeros) genus = s // 4 + 1 #TODO: check genus 2 components #TODO: in genus 2, decide between GTHQSC/GTNQSC and HQSC/NQSC if genus == 0: return (GZQSC(self),) #TODO: all genus 1 strata are connected, but two are hyperelliptic; give the component a different name then? elif genus == 1: if zeros == () or zeros == (1, -1): # empty! return () else: return (GOQSC(self),) elif genus == 2: if zeros == (4,) or zeros == (3, 1): # empty! return () elif zeros == (6, -1, -1): return (HQSC(self), GTNQSC(self)) elif zeros == (3, 3, -1, -1): return (HQSC(self), GTNQSC(self)) elif zeros == (2, 2) or zeros == (2, 1, 1) or zeros == (1, 1, 1, 1): return (GTHQSC(self),) else: return (GTNQSC(self),) elif genus == 3 and nb_poles == 1 and all((z == -1 or z % 3 == 0) for z in zeros): return (REQSC(self), IEQSC(self)) elif genus == 4 and nb_poles == 0 and all(z % 3 == 0 for z in zeros): if zeros == (12,) or zeros == (9, 3): return (REQSC(self), IEQSC(self)) elif zeros == (6, 6) or zeros == (6, 3, 3) or zeros == (3, 3, 3, 3): return (HQSC(self), REQSC(self), IEQSC(self)) else: if len(zeros) == 2 and zeros[0] % 4 == 2 and zeros[1] % 4 == 2: return (HQSC(self), NQSC(self)) elif len(zeros) == 4 and zeros[0] == zeros[1] and zeros[2] == zeros[3] and zeros[0] % 2 and zeros[2] % 2: return (HQSC(self), NQSC(self)) elif len(zeros) == 3 and zeros[0] == zeros[1] and zeros[0] % 2 and zeros[2] % 4 == 2: return (HQSC(self), NQSC(self)) elif len(zeros) == 3 and zeros[1] == zeros[2] and zeros[1] % 2 and zeros[0] % 4 == 2: return (HQSC(self), NQSC(self)) else: return (CQSC(self),) raise NotImplementedError('higher order differential')
# # String representation # def _flat_zero_str(self): r""" String representation of the zeros. EXAMPLES:: sage: from surface_dynamics import Stratum sage: a = Stratum({2:3}, k=1) sage: a._flat_zero_str() '2, 2, 2' """ return ', '.join(map(str, self.signature())) def _exp_zero_str(self): r""" String representation with exponential notation EXAMPLES:: sage: from surface_dynamics import Stratum sage: a = Stratum({2: 3}, k=1) sage: a._exp_zero_str() '2^3' """ return ', '.join('%d^%d' %(i,e) if e != 1 else '%d' %i for (i,e) in list_to_exp_list(self.signature())) # this attribute can be switched between _flat_zero_str and _exp_zero_str _zero_str = _exp_zero_str def _repr_(self): """ TESTS:: sage: from surface_dynamics import Stratum sage: repr(Stratum([1,1], k=1)) # indirect doctest 'H_2(1^2)' sage: repr(Stratum([1,1,1,1], k=2)) # indirect doctest 'Q_2(1^4)' """ try: name = self._name except AttributeError: if self._k == 1: name = 'H' elif self._k == 2: name = 'Q' else: name = 'H^{{({})}}'.format(self._k) return name + "_" + str(self.surface_genus()) + "(" + self._zero_str() + ")" def _latex_(self): r""" Latex string representation EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([0], k=1)._latex_() '\\mathcal{H}_1(0)' sage: Stratum({-1:4}, k=2)._latex_() '\\mathcal{Q}_0(-1^4)' """ return self._latex_name + '_' + str(self.surface_genus()) + "(" + self._zero_str() + ")" # # Equality and comparisons # def __lt__(self, other): r""" Comparison ALGORITHM: First compare the class, then the dimension and then the list of zeros. TESTS:: sage: from surface_dynamics import Stratum sage: Stratum([0], k=1) == Stratum([0], k=1) True sage: Stratum([5,-1], k=2) == Stratum([5,-1], k=2) True sage: Stratum([5,-1], k=2) != Stratum([5,-1], k=2) False sage: Stratum([12], k=1) == Stratum([12], k=2) False sage: Stratum([12,0,0], k=2) == Stratum([12,0], k=2) False sage: Stratum([2,0], k=1) == Stratum([2], k=1) False sage: Stratum([2,0], k=1) != Stratum([2], k=1) True sage: Stratum([1,1], k=1) < Stratum([1,1,0], k=1) True sage: Stratum([1,1,0], k=1) < Stratum([1,1], k=1) False sage: Stratum([1,1,0], k=1) < Stratum([1,1,0,0], k=1) True sage: Stratum([2], k=1) < Stratum([1,1], k=1) True sage: Stratum([4,0], k=1) > Stratum([1,1,1,1], k=1) False sage: Stratum([4,0,0,0], k=1) > Stratum([1,1,1,1], k=1) True :: sage: Stratum([2,2], k=2) < Stratum([2,2,0], k=2) True sage: Stratum([2,2,0], k=2) < Stratum([2,2], k=2) False sage: Stratum([2,2,0], k=2) < Stratum([2,2,0,0], k=2) True sage: Stratum([4], k=2) < Stratum([2,2], k=2) True sage: Stratum([4,0], k=2) > Stratum([1,1,1,1], k=2) False sage: Q1 = Stratum([4,0,0,0], k=2) sage: Q2 = Stratum([1,1,1,1], k=2) sage: Q1 > Q2 True sage: Q1 >= Q2 True sage: Q1 < Q2 False sage: Q1 <= Q2 False """ if not isinstance(self, Stratum) or not isinstance(other, Stratum): raise TypeError if self._k == other._k: # compare the dimension if self.dimension() < other.dimension(): return True elif self.dimension() > other.dimension(): return False # compare the list of zeros if self.signature() < other.signature(): return True elif self.signature() > other.signature(): return False # equality return False else: return self._k < other._k def __ne__(self, other): return not self == other def __le__(self, other): return self == other or self < other def __ge__(self, other): return not self < other def __gt__(self, other): return not self <= other # # Connected components #
[docs] def is_connected(self): r""" Test if the strata is connected. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([2], k=1).is_connected() True sage: Stratum([2,2], k=1).is_connected() False sage: Stratum([-1,-1,-1,-1], k=2).is_connected() True sage: Stratum([12], k=2).is_connected() False """ return len(self.connected_components()) <= 1
[docs] def permutation_representative(self, *args, **kwds): r""" Return a permutation of interval exchanges associated to this stratum. This method only makes sense for Abelian and quadratic differentials. EXAMPLES:: sage: from surface_dynamics import Stratum Examples from Abelian differentials:: sage: a = Stratum([3,2,1,0,0], k=1) sage: p = a.permutation_representative() sage: p.stratum() H_4(3, 2, 1, 0^2) sage: a = Stratum([2, 2, 2], k=1) sage: p = a.permutation_representative() sage: p.stratum() H_4(2^3) Examples from quadratic differentials:: sage: a = Stratum([6,-1,-1], k=2) sage: p = a.permutation_representative() sage: p.stratum() Q_2(6, -1^2) sage: a = Stratum([-1,-1,-1,-1,0,0], k=2) sage: p = a.permutation_representative() sage: p.stratum() Q_0(0^2, -1^4) """ if self._k > 2: raise ValueError('stratum of higher order differentials') return self.one_component().permutation_representative(*args,**kwds)
[docs] def is_empty(self): r""" Return True if the stratum is empty EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([2], k=1).is_empty() False sage: Stratum([1,-1], k=2).is_empty() True """ return len(self.connected_components()) == 0
[docs] def number_of_components(self): r""" Returns the number of connected components of self EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([2], k=1).number_of_components() 1 sage: Stratum([4], k=1).number_of_components() 2 sage: Stratum([3,3], k=1).number_of_components() 2 """ return len(self.connected_components())
[docs] def one_component(self): r""" Returns a connected component of this stratum. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([2], k=1).one_component() H_2(2)^hyp """ if self.components(): return self.components()[-1] from sage.categories.sets_cat import EmptySetError raise EmptySetError("The stratum is empty")
[docs] def unique_component(self): r""" Returns the unique component of self or raise a ValueError. EXAMPLES:: sage: from surface_dynamics import Stratum sage: a = Stratum([1,1], k=1) sage: a H_2(1^2) sage: a.unique_component() H_2(1^2)^hyp sage: a = Stratum([3,2,1], k=1) sage: a H_4(3, 2, 1) sage: a.unique_component() H_4(3, 2, 1)^c sage: Stratum({1:1, -1:5}, k=2).unique_component() Q_0(1, -1^5)^c sage: Stratum([3,2,-1], k=2).unique_component() Q_2(3, 2, -1)^nonhyp sage: Stratum([12], k=2).unique_component() Traceback (most recent call last): ... ValueError: several components for this stratum """ ccs = self.connected_components() if len(ccs) != 1: raise ValueError("several components for this stratum") return ccs[0]
[docs] def random_component(self): r""" Returns a random connected component of this stratum. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Q = Stratum([6,6], k=2) sage: Q.random_component() # random Q_4(6^2)^hyp sage: Q.random_component() # random Q_4(6^2)^reg """ if self.components(): from sage.misc.prandom import choice return choice(self.components()) from sage.categories.sets_cat import EmptySetError raise EmptySetError("The stratum is empty")
[docs] def components(self): """ Lists the connected components of the Stratum. OUTPUT: list -- a list of connected components of stratum EXAMPLES:: sage: from surface_dynamics import Stratum Some abelian strata:: sage: Stratum([0], k=1).components() (H_1(0)^hyp,) sage: Stratum([2], k=1).components() (H_2(2)^hyp,) sage: Stratum([4], k=1).components() (H_3(4)^hyp, H_3(4)^odd) sage: Stratum([2,2], k=1).components() (H_3(2^2)^hyp, H_3(2^2)^odd) sage: Stratum([1,1,1,1], k=1).components() (H_3(1^4)^c,) Some quadratic strata:: sage: Stratum([12], k=2).components() (Q_4(12)^reg, Q_4(12)^irr) sage: Stratum([6,-1,-1], k=2).components() (Q_2(6, -1^2)^hyp, Q_2(6, -1^2)^nonhyp) """ # TODO: deprecate return self.connected_components()
[docs] def masur_veech_volume(self, rational=False, method=None): r""" Return the Masur-Veech volume of this stratum. INPUT: - ``rational`` (optional, boolean) - if ``False`` (default) return the Masur-Veech volume and if ``True`` return the Masur-Veech volume divided by `\zeta(2g)`. - ``method`` (optional string) - the method to use to compute the volume either, see :func:`~surface_dynamics.flat_surfaces.masur_veech_volumes.masur_veech_volume` EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([2], k=1).masur_veech_volume() 1/120*pi^4 sage: Stratum([1,1,1,1], k=1).masur_veech_volume() 1/4860*pi^6 sage: Stratum([20], k=1).masur_veech_volume() 1604064377302075061983/792184445986404135075840000000000*pi^22 """ from .masur_veech_volumes import masur_veech_volume return masur_veech_volume(self, rational, method)
[docs] class StratumComponent(SageObject): r""" Generic class for connected component of a stratum of flat surfaces. Assumes there are implemented - a method .permutation_representative() There may be - an attribute ._name - an attribute ._latex_name """ _name = '' _latex_name = '' def __init__(self, stratum): r""" TESTS:: sage: from surface_dynamics import Stratum sage: a = Stratum([4,4], k=1).one_component() sage: a == loads(dumps(a)) True sage: q = Stratum([5,5,-1,-1], k=2).one_component() sage: q == loads(dumps(q)) True """ self._stratum = stratum def __reduce__(self): r""" Reduce method for pickling TESTS:: sage: from surface_dynamics import Stratum Tests for Abelian strata:: sage: a = Stratum([2,2], k=1) sage: all(loads(dumps(cc)) == cc for cc in a.components()) True sage: a = Stratum([3,3], k=1) sage: all(loads(dumps(cc)) == cc for cc in a.components()) True sage: a = Stratum([6], k=1) sage: all(loads(dumps(cc)) == cc for cc in a.components()) True sage: a = Stratum([1,1,1,1], k=1) sage: all(loads(dumps(cc)) == cc for cc in a.components()) True Tests for quadratic strata:: sage: q = Stratum([-1,-1,-1,-1], k=2) sage: all(loads(dumps(cc)) == cc for cc in q.components()) True sage: q = Stratum([12], k=2) sage: all(loads(dumps(cc)) == cc for cc in q.components()) True """ return self.__class__, (self._stratum,) def _repr_(self): r""" String representation EXAMPLES:: sage: from surface_dynamics import Stratum sage: a_hyp = Stratum([4], k=1).hyperelliptic_component() sage: a_hyp._repr_() 'H_3(4)^hyp' sage: a_odd = Stratum([4], k=1).odd_component() sage: a_odd._repr_() 'H_3(4)^odd' """ return str(self._stratum) + "^" + self._name def __hash__(self): r""" TESTS:: sage: from surface_dynamics import Stratum sage: A4hyp = Stratum([4], k=1).hyperelliptic_component() sage: A4odd = Stratum([4], k=1).odd_component() sage: hash(A4hyp) != hash(A4odd) True sage: A22hyp = Stratum([2,2], k=1).hyperelliptic_component() sage: hash(A22hyp) != hash(A4hyp) True """ return hash(self._stratum) ^ hash(self._name)
[docs] def stratum(self): r""" Return the stratum associated to self EXAMPLES:: sage: from surface_dynamics import Stratum sage: a = Stratum([4,4], k=1) sage: all([c.stratum() == a for c in a.components()]) True """ return self._stratum
[docs] def surface_genus(self): r""" Return genus of the corresponding stratum EXAMPLES:: sage: from surface_dynamics import Stratum sage: a = Stratum([4,4], k=1) sage: a.one_component().surface_genus() 5 """ return self._stratum.surface_genus()
[docs] def surface_has_finite_area(self): return self._stratum.surface_has_finite_area()
[docs] def surface_differential_order(self): return self._stratum.surface_differential_order()
[docs] def genus(self): import warnings warnings.warn('genus() has been deprecated and will be removed in a future version of surface-dynamics; use surface_genus()') return self.surface_genus()
[docs] def dimension(self): r""" Return the (complex) dimension of this GL(2,R)-invariant orbifold. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([4], k=1).odd_component().dimension() 6 sage: Stratum([12], k=2).regular_component().dimension() 7 """ return self._stratum.dimension()
[docs] def rank(self): r""" Return the rank of this GL(2,R)-invariant orbifold. EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([4], k=1).odd_component().rank() 3 sage: Stratum([12], k=2).regular_component().rank() 3 """ return self._stratum.rank()
def __eq__(self,other): r""" Equality test EXAMPLES:: sage: from surface_dynamics import Stratum sage: c_hyp = Stratum([6], k=1).hyperelliptic_component() sage: c_odd = Stratum([6], k=1).odd_component() sage: c_hyp == c_hyp True sage: c_hyp == c_odd False """ if not isinstance(self, StratumComponent) or not isinstance(other, StratumComponent): return NotImplemented return type(self) == type(other) and self._stratum == other._stratum def __lt__(self, other): r""" Comparison TESTS:: sage: from surface_dynamics import Stratum sage: a1 = Stratum([1,1,1,1], k=1) sage: c1 = a1.components()[0] sage: a2 = Stratum([3,1], k=1) sage: c2 = a2.components()[0] sage: c1 == c1 True sage: c1 == c2 False sage: a1 = Stratum([1,1,1,1], k=1) sage: c1 = a1.components()[0] sage: a2 = Stratum([2, 2], k=1) sage: c2_hyp, c2_odd = a2.components() sage: c1 != c1 False sage: c1 != c2_hyp True sage: c2_hyp != c2_odd True """ if not isinstance(self, StratumComponent) or not isinstance(other, StratumComponent): return NotImplemented if self._stratum < other._stratum: return True elif self._stratum > other._stratum: return False if type(self) < type(other): return True elif type(self) > type(other): return False
[docs] def masur_veech_volume(self, rational=False, method=None): r""" Return the Masur-Veech volume of this stratum component. INPUT: - ``rational`` (optional, boolean) - if ``False`` (default) return the Masur-Veech volume and if ``True`` return the Masur-Veech volume divided by `\zeta(2g)`. - ``method`` (optional string) - the method to use to compute the volume either, see :func:`~surface_dynamics.flat_surfaces.masur_veech_volumes.masur_veech_volume` EXAMPLES:: sage: from surface_dynamics import Stratum sage: Stratum([4], k=1).hyperelliptic_component().masur_veech_volume() 1/6720*pi^6 sage: Stratum([6], k=1).even_component().masur_veech_volume() 32/1913625*pi^8 """ from .masur_veech_volumes import masur_veech_volume return masur_veech_volume(self, rational, method)
# # Strata (family of strata) #
[docs] class Strata(Parent): r""" Strata of Abelian or Quadratic differentials. """ pass