Strata of Abelian and quadratic differentials#

Template file#

Strata of differential on Riemann surfaces

This file gather common code used in abelian_strata and quadratic_strata.

class surface_dynamics.flat_surfaces.strata.Strata[source]#

Bases: Parent

Strata of Abelian or Quadratic differentials.

class surface_dynamics.flat_surfaces.strata.Stratum[source]#

Bases: UniqueRepresentation, SageObject

Generic class for stratum of flat surfaces.

Assumes there are

  • a method .zeros() which returns the list of all zeros

  • a method .nb_zeros() which returns the number of zeros with an option fake_zeros which could be true or false

  • a method .nb_fake_zeros() which returns the number of fake zeros (or marked points)

  • a method .dimension() which returns the dimension of the stratum

  • an attribute ._cc which is a list of classes associated to the connected components of self

There may be

  • an attribute ._name which corresponds to the beginning of the string representation (default is the empty string)

  • an attribute ._latex_name which corresponds to the beginning of the latex string representation (uses _name by default)

TESTS:

sage: from surface_dynamics import *

sage: A = AbelianStratum(2,2)
sage: B = AbelianStratum(1,1)
sage: hash(A) == hash(B)
False
components()[source]#

Lists the connected components of the Stratum.

OUTPUT:

list – a list of connected components of stratum

EXAMPLES:

sage: from surface_dynamics import *

Some abelian strata:

sage: AbelianStratum(0).components()
[H_1(0)^hyp]
sage: AbelianStratum(2).components()
[H_2(2)^hyp]
sage: AbelianStratum(4).components()
[H_3(4)^hyp, H_3(4)^odd]
sage: AbelianStratum(2,2).components()
[H_3(2^2)^hyp, H_3(2^2)^odd]
sage: AbelianStratum(1,1,1,1).components()
[H_3(1^4)^c]

Some quadratic strata:

sage: QuadraticStratum(12).components()
[Q_4(12)^reg, Q_4(12)^irr]
sage: QuadraticStratum(6,-1,-1).components()
[Q_2(6, -1^2)^hyp, Q_2(6, -1^2)^nonhyp]
is_connected()[source]#

Test if the strata is connected.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum([2]).is_connected()
True
sage: AbelianStratum([2,2]).is_connected()
False
sage: QuadraticStratum([-1,-1,-1,-1]).is_connected()
True
sage: QuadraticStratum([12]).is_connected()
False
is_empty()[source]#

Return True if the stratum is empty

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(2).is_empty()
False
sage: QuadraticStratum(1,-1).is_empty()
True
masur_veech_volume(rational=False, method=None)[source]#

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 masur_veech_volume()

EXAMPLES:

sage: from surface_dynamics import AbelianStratum

sage: AbelianStratum(2).masur_veech_volume()
1/120*pi^4
sage: AbelianStratum(1,1,1,1).masur_veech_volume()
1/4860*pi^6
sage: AbelianStratum(20).masur_veech_volume()
1604064377302075061983/792184445986404135075840000000000*pi^22
number_of_components()[source]#

Returns the number of connected components of self

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(2).number_of_components()
1
sage: AbelianStratum(4).number_of_components()
2
sage: AbelianStratum(3,3).number_of_components()
2
one_component()[source]#

Returns a connected component of this stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(2).one_component()
H_2(2)^hyp
permutation_representative(*args, **kwds)[source]#

Return a permutation of interval exchanges associated to this stratum.

EXAMPLES:

sage: from surface_dynamics import *

Examples from Abelian differentials:

sage: a = AbelianStratum([3,2,1,0,0])
sage: p = a.permutation_representative()
sage: p.stratum()
H_4(3, 2, 1, 0^2)
sage: a = AbelianStratum([2, 2, 2])
sage: p = a.permutation_representative()
sage: p.stratum()
H_4(2^3)

Examples from quadratic differentials:

sage: a = QuadraticStratum([6,-1,-1])
sage: p = a.permutation_representative()
sage: p.stratum()
Q_2(6, -1^2)
sage: a = QuadraticStratum([-1,-1,-1,-1,0,0])
sage: p = a.permutation_representative()
sage: p.stratum()
Q_0(0^2, -1^4)
random_component()[source]#

Returns a random connected component of this stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStratum(6,6)
sage: Q.random_component() # random
Q_4(6^2)^hyp
sage: Q.random_component() # random
Q_4(6^2)^reg
unique_component()[source]#

Returns the unique component of self or raise a ValueError.

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(1,1); a
H_2(1^2)
sage: a.unique_component()
H_2(1^2)^hyp

sage: a = AbelianStratum(3,2,1); a
H_4(3, 2, 1)
sage: a.unique_component()
H_4(3, 2, 1)^c

sage: QuadraticStratum({1:1, -1:5}).unique_component()
Q_0(1, -1^5)^c
sage: QuadraticStratum(3,2,-1).unique_component()
Q_2(3, 2, -1)^nonhyp

sage: QuadraticStratum(12).unique_component()
Traceback (most recent call last):
...
ValueError: several components for this stratum
class surface_dynamics.flat_surfaces.strata.StratumComponent(stratum)[source]#

Bases: SageObject

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

dimension()[source]#

Return the (complex) dimension of this GL(2,R)-invariant orbifold.

EXAMPLES:

sage: from surface_dynamics import AbelianStratum, QuadraticStratum

sage: AbelianStratum(4).odd_component().dimension()
6
sage: QuadraticStratum(12).regular_component().dimension()
7
genus()[source]#

Return genus of the corresponding stratum

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(4,4)
sage: a.one_component().genus()
5
masur_veech_volume(rational=False, method=None)[source]#

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 masur_veech_volume()

EXAMPLES:

sage: from surface_dynamics import AbelianStratum

sage: AbelianStratum(4).hyperelliptic_component().masur_veech_volume()
1/6720*pi^6
sage: AbelianStratum(6).even_component().masur_veech_volume()
32/1913625*pi^8
rank()[source]#

Return the rank of this GL(2,R)-invariant orbifold.

EXAMPLES:

sage: from surface_dynamics import AbelianStratum, QuadraticStratum

sage: AbelianStratum(4).odd_component().rank()
3
sage: QuadraticStratum(12).regular_component().rank()
3
stratum()[source]#

Return the stratum associated to self

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(4,4)
sage: all([c.stratum() == a for c in a.components()])
True
surface_dynamics.flat_surfaces.strata.list_to_exp_list(l)[source]#

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)]

Abelian strata#

Strata of differentials on Riemann surfaces

The space of Abelian differentials on Riemann surfaces of a given genus is stratified by degrees of zeros. Each stratum has one, two or three connected components each of which is associated to an extended Rauzy class. The components() method lists connected components of a stratum.

The work for Abelian differentials was done by Maxim Kontsevich and Anton Zorich in [KonZor03] and for quadratic differentials by Erwan Lanneau in [Lan08]. Zorich gave an algorithm to pass from a connected component of a stratum to the associated Rauzy class (for both interval exchange transformations and linear involutions) in [Zor08] and is implemented for Abelian stratum at different level (approximately one for each component):

The inverse operation (pass from an interval exchange transformation to the connected component) is partially written in [KonZor03] and simply named here ?

Some of the code here was first available on Mathematica [ZS].

A refinement of Zorich representatives was worked out by L. Jefreys in [Jef19]. Namely, for each connected component of Abelian differential his construction provides a square-tiled surface with both in horizontal and vertical direction a decomposition with single cylinder of height one. The implementation is available as

AUTHORS:

  • Vincent Delecroix (2009-09-29): initial version

EXAMPLES:

sage: from surface_dynamics import *

Construction of a stratum from a list of singularity degrees:

sage: a = AbelianStratum(1,1)
sage: a
H_2(1^2)
sage: a.genus()
2
sage: a.dimension()
5
sage: a = AbelianStratum(4,3,2,1)
sage: a
H_6(4, 3, 2, 1)
sage: a.genus()
6
sage: a.dimension()
15

By convention, the degrees are always written in decreasing order:

sage: a1 = AbelianStratum(4,3,2,1)
sage: a1
H_6(4, 3, 2, 1)
sage: a2 = AbelianStratum(2,3,1,4)
sage: a2
H_6(4, 3, 2, 1)
sage: a1 == a2
True

It is possible to lis strata and their connected components:

sage: AbelianStratum(10).components()
[H_6(10)^hyp, H_6(10)^odd, H_6(10)^even]

Get a list of strata with constraints on genus or on the number of intervals of a representative:

sage: AbelianStrata(genus=3).list()
[H_3(4), H_3(3, 1), H_3(2^2), H_3(2, 1^2), H_3(1^4)]

Obtains the connected components of a stratum:

sage: a = AbelianStratum(0)
sage: a.components()
[H_1(0)^hyp]
sage: @cached_function
....: def nb_irred_perm(n):
....:     if n == 0 or n == 1: return 1
....:     return factorial(n) - sum(nb_irred_perm(k) * factorial(n - k) for k in range(1,n))
sage: [nb_irred_perm(i) for i in range(10)]
[1, 1, 1, 3, 13, 71, 461, 3447, 29093, 273343]
sage: A = AbelianStrata(dimension=5, fake_zeros=True)
sage: N = 0
sage: for a in A:
....:    for cc in a.components():
....:       for z in set(a.zeros()):
....:           p = cc.permutation_representative(left_degree=z)
....:           n = p.rauzy_diagram().cardinality()
....:           print("%13s, %d  :  %d"%(cc, z, n))
....:           print(p)
....:           N += n
H_2(2, 0)^hyp, 0  :  11
0 1 2 3 4
4 2 1 3 0
H_2(2, 0)^hyp, 2  :  35
0 1 2 3 4
4 1 3 2 0
 H_2(1^2)^hyp, 1  :  15
0 1 2 3 4
4 3 2 1 0
 H_1(0^4)^hyp, 0  :  10
0 1 2 3 4
4 0 1 2 3
sage: N
71
sage: nb_irred_perm(5)
71
surface_dynamics.flat_surfaces.abelian_strata.ASC#

alias of AbelianStratumComponent

class surface_dynamics.flat_surfaces.abelian_strata.AbelianStrata(genus=None, dimension=None, fake_zeros=None)[source]#

Bases: Strata

Abelian strata.

INPUT:

  • genus - a non negative integer or None

  • dimension - a non negative integer or None

  • fake_zeros - boolean

EXAMPLES:

sage: from surface_dynamics import *

Abelian strata with a given genus:

sage: for s in AbelianStrata(genus=1): print(s)
H_1(0)
sage: for s in AbelianStrata(genus=2): print(s)
H_2(2)
H_2(1^2)
sage: for s in AbelianStrata(genus=3): print(s)
H_3(4)
H_3(3, 1)
H_3(2^2)
H_3(2, 1^2)
H_3(1^4)
sage: for s in AbelianStrata(genus=4): print(s)
H_4(6)
H_4(5, 1)
H_4(4, 2)
H_4(4, 1^2)
H_4(3^2)
H_4(3, 2, 1)
H_4(3, 1^3)
H_4(2^3)
H_4(2^2, 1^2)
H_4(2, 1^4)
H_4(1^6)

Get outside of the tests. Abelian strata with a given number of intervals

sage for s in AbelianStrata(dimension=2): print(s) H^out([0])

sage for s in AbelianStrata(dimension=3): print(s) H^out([0], 0)

sage for s in AbelianStrata(dimension=4): print(s) H^out([2]) H^out([0], 0, 0)

Get outside of tests sage for s in AbelianStrata(dimension=5): print(s) H^out(2, [0]) H^out([2], 0) H^out([1], 1) H^out([0], 0, 0, 0)

class surface_dynamics.flat_surfaces.abelian_strata.AbelianStrata_all(genus=None, dimension=None, fake_zeros=None)[source]#

Bases: AbelianStrata

Abelian strata.

INPUT:

  • fake_zeros - boolean (default: False)

EXAMPLES:

sage: from surface_dynamics import *

sage: A = AbelianStrata()
sage: it = iter(A)
sage: for _ in range(10):
....:     print(next(it))
H_1(0)
H_2(2)
H_2(1^2)
H_3(4)
H_3(3, 1)
H_3(2^2)
H_4(6)
H_3(2, 1^2)
H_4(5, 1)
H_4(4, 2)

sage: A = AbelianStrata(fake_zeros=True)
sage: it = iter(A)
sage: for _ in range(10):
....:     print(next(it))
H_1(0)
H_1(0^2)
H_2(2)
H_1(0^3)
H_2(2, 0)
H_2(1^2)
H_1(0^4)
H_3(4)
H_2(2, 0^2)
H_2(1^2, 0)
class surface_dynamics.flat_surfaces.abelian_strata.AbelianStrata_d(genus=None, dimension=None, fake_zeros=None)[source]#

Bases: AbelianStrata

Strata with prescribed dimension.

INPUT:

  • dimension - an integer greater than 1

  • fake_zeros - boolean (default: False) - allows or not fake zeros

EXAMPLES:

sage: from surface_dynamics import *

sage: for a in AbelianStrata(dimension=5,fake_zeros=True):
....:     print(a)
....:     print(a.permutation_representative())
H_2(2, 0)
0 1 2 3 4
4 1 3 2 0
H_2(1^2)
0 1 2 3 4
4 3 2 1 0
H_1(0^4)
0 1 2 3 4
4 0 1 2 3
an_element()#

Returns the first stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(dimension=2).first()
H_1(0)
sage: AbelianStrata(dimension=3).first()
H_1(0^2)
sage: AbelianStrata(dimension=4).first()
H_2(2)
cardinality()[source]#

Return the number of Abelian strata with given dimension.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(dimension=5,fake_zeros=True).cardinality()
3
sage: AbelianStrata(dimension=5,fake_zeros=False).cardinality()
1

sage: AbelianStrata(dimension=6,fake_zeros=True).cardinality()
4
sage: AbelianStrata(dimension=6,fake_zeros=False).cardinality()
1

sage: AbelianStrata(dimension=7,fake_zeros=True).cardinality()
6
sage: AbelianStrata(dimension=7,fake_zeros=False).cardinality()
2

sage: AbelianStrata(dimension=12,fake_zeros=True).cardinality()
29
sage: AbelianStrata(dimension=12,fake_zeros=False).cardinality()
7

TESTS:

sage: for d in range(1,15):
....:   A = AbelianStrata(dimension=d,fake_zeros=True)
....:   assert len(A.list()) == A.cardinality()
....:   A = AbelianStrata(dimension=d,fake_zeros=False)
....:   assert len(A.list()) == A.cardinality()
first()[source]#

Returns the first stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(dimension=2).first()
H_1(0)
sage: AbelianStrata(dimension=3).first()
H_1(0^2)
sage: AbelianStrata(dimension=4).first()
H_2(2)
last()[source]#

Return the last stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(dimension=9,fake_zeros=True).last()
H_1(0^8)
sage: AbelianStrata(dimension=9,fake_zeros=False).last()
H_3(1^4)

sage: AbelianStrata(dimension=10,fake_zeros=True).last()
H_1(0^9)
sage: AbelianStrata(dimension=10,fake_zeros=False).last()
H_4(2^3)
class surface_dynamics.flat_surfaces.abelian_strata.AbelianStrata_g(genus=None, dimension=None, fake_zeros=None)[source]#

Bases: AbelianStrata

Stratas of genus g surfaces without fake zeros.

INPUT:

  • genus - a non negative integer

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(genus=2).list()
[H_2(2), H_2(1^2)]
sage: AbelianStrata(genus=3).list()
[H_3(4), H_3(3, 1), H_3(2^2), H_3(2, 1^2), H_3(1^4)]
sage: AbelianStrata(genus=4).random_element() #random
H_4(4, 2)
an_element_()#

Return the first element of this list of strata.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(genus=3).first()
H_3(4)
sage: AbelianStrata(genus=4).first()
H_4(6)
cardinality()[source]#

Return the number of abelian strata with a given genus.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(genus=1).cardinality()
1
sage: AbelianStrata(genus=2).cardinality()
2
sage: AbelianStrata(genus=3).cardinality()
5
sage: AbelianStrata(genus=4).cardinality()
11
first()[source]#

Return the first element of this list of strata.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(genus=3).first()
H_3(4)
sage: AbelianStrata(genus=4).first()
H_4(6)
last()[source]#

Return the last element of this list of strata.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStrata(genus=4).last()
H_4(1^6)
sage: AbelianStrata(genus=5).last()
H_5(1^8)
random_element()[source]#

Return a random stratum.

class surface_dynamics.flat_surfaces.abelian_strata.AbelianStrata_gd(genus=None, dimension=None, fake_zeros=None)[source]#

Bases: AbelianStrata

Abelian strata of prescribed genus and number of intervals.

INPUT:

  • genus - integer: the genus of the surfaces

  • dimension - integer: the number of intervals

  • fake_zeros - boolean: whether or not consider fake zeros

class surface_dynamics.flat_surfaces.abelian_strata.AbelianStratum(zeros, nb_fake_zeros)[source]#

Bases: Stratum

Stratum of Abelian differentials.

A stratum with a marked outgoing separatrix corresponds to Rauzy diagram with left induction, a stratum with marked incoming separatrix correspond to Rauzy diagram with right induction. If there is no marked separatrix, the associated Rauzy diagram is the extended Rauzy diagram (consideration of the surface_dynamics.interval_exchanges.template.Permutation.symmetric() operation of Boissy-Lanneau).

When you want to specify a marked separatrix, the degree on which it is is the first term of your degrees list.

INPUT:

  • marked_separatrix - None (default) or ‘in’ (for incoming separatrix) or ‘out’ (for outgoing separatrix).

EXAMPLES:

sage: from surface_dynamics import *

Creation of an Abelian stratum and get its connected components:

sage: a = AbelianStratum(2, 2)
sage: a
H_3(2^2)
sage: a.components()
[H_3(2^2)^hyp, H_3(2^2)^odd]

Get a permutation representative of a connected component:

sage: a = AbelianStratum(2,2)
sage: a_hyp, a_odd = a.components()
sage: a_hyp.permutation_representative()
0 1 2 3 4 5 6
6 5 4 3 2 1 0
sage: a_odd.permutation_representative()
0 1 2 3 4 5 6
3 2 4 6 5 1 0

You can specify the alphabet:

sage: a_odd.permutation_representative(alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ")
A B C D E F G
D C E G F B A
cylinder_diagram_iterator(ncyls=None, up_to_symmetry=True, force_computation=False)[source]#

Iterator over all cylinder diagram of this stratum.

The generation is up to isomorphism and horizontal/vertical symmetry (and they are in standard form).

INPUT:

  • ncyls – an optional number of cylinders

  • up_to_symmetry - (boolean, default True) to return only cylinder diagrams up to horizontal and vertical symmetry.

  • force_computation – if True do no use the database of cylinder diagrams (default is False)

EXAMPLES:

sage: from surface_dynamics import *

sage: A = AbelianStratum(4)
sage: C1 = [CylinderDiagram('(0,2,1)-(0,3,4) (3)-(2) (4)-(1)'),
....:       CylinderDiagram('(0,2,1)-(0,3,4) (3)-(1) (4)-(2)'),
....:       CylinderDiagram('(0,1)-(0,3,4) (2,3)-(1) (4)-(2)'),
....:       CylinderDiagram('(0,2)-(4) (1,4)-(2,3) (3)-(0,1)'),
....:       CylinderDiagram('(0,2)-(0,3) (1,3)-(1,4) (4)-(2)'),
....:       CylinderDiagram('(0,1)-(0,3) (2,3)-(1,4) (4)-(2)')]
sage: C2 = list(A.cylinder_diagram_iterator(3, force_computation=True))
sage: assert len(C1) == len(C2)
sage: for (c1, c2) in zip(C1, C2):
....:     assert c1.is_isomorphic(c2) or \
....:            c1.is_isomorphic(c2.horizontal_symmetry()) or \
....:            c1.is_isomorphic(c2.vertical_symmetry()) or \
....:            c1.is_isomorphic(c2.inverse())

sage: sum(1 for _ in A.cylinder_diagram_iterator(3, True, True))
6
sage: sum(1 for _ in A.cylinder_diagram_iterator(3, True, False))
6
sage: sum(1 for _ in A.cylinder_diagram_iterator(3, False, True))
9
sage: sum(1 for _ in A.cylinder_diagram_iterator(3, False, False))
9
cylinder_diagrams(ncyls=None, up_to_symmetry=True, force_computation=False)[source]#

Return a list of cylinder diagram of this stratum.

INPUT:

- ``ncyls`` -- an optional number of cylinders
  • up_to_symmetry - (boolean, default True) to return only cylinder diagrams up to horizontal and vertical symmetry.

  • force_computation – If True then do not use the database of cylinder diagrams (default is False).

EXAMPLES:

sage: from surface_dynamics import *

sage: A = AbelianStratum(2,2)
sage: C1 = [CylinderDiagram('(0,1)-(0,5) (2)-(4) (3,4)-(1) (5)-(2,3)'),
....:       CylinderDiagram('(0,2,1)-(3,4,5) (3)-(1) (4)-(2) (5)-(0)'),
....:       CylinderDiagram('(0,2,1)-(3,5,4) (3)-(1) (4)-(2) (5)-(0)'),
....:       CylinderDiagram('(0,3)-(5) (1)-(0) (2,5)-(3,4) (4)-(1,2)'),
....:       CylinderDiagram('(0,3)-(0,5) (1,2)-(1,4) (4)-(3) (5)-(2)'),
....:       CylinderDiagram('(0,5)-(3,4) (1,4)-(2,5) (2)-(0) (3)-(1)'),
....:       CylinderDiagram('(0,5)-(3,4) (1,4)-(2,5) (2)-(1) (3)-(0)')]
sage: C2 = A.cylinder_diagrams(4)
sage: assert len(C1) == len(C2)
sage: isoms = []
sage: for c in A.cylinder_diagrams(4):
....:     isom = []
....:     for i,cc in enumerate(C1):
....:         if c.is_isomorphic(cc) or \
....:            c.is_isomorphic(cc.horizontal_symmetry()) or \
....:            c.is_isomorphic(cc.vertical_symmetry()) or \
....:            c.is_isomorphic(cc.inverse()):
....:              isom.append(i)
....:     assert len(isom) == 1, isom
....:     isoms.extend(isom)
sage: assert sorted(isoms) == [0, 1, 2, 3, 4, 5, 6]

sage: len(A.cylinder_diagrams(4, up_to_symmetry=False))
7
sage: sum(4 / (1 + sum(cd.symmetries())) for cd in A.cylinder_diagrams(4, up_to_symmetry=True))
7

Recovering the multiplicity of the symmetric versions:

sage: total = 0
sage: for c in AbelianStratum(2,1,1).cylinder_diagrams(2):
....:     total += 4 // (1 + sum(c.symmetries()))
sage: total
61
sage: len(AbelianStratum(2, 1, 1).cylinder_diagrams(2, up_to_symmetry=False))
61

You obtain the same number directly:

sage: AbelianStratum(2, 1, 1).cylinder_diagrams_number(2, up_to_symmetry=False)
61
cylinder_diagrams_by_component(ncyls=None, up_to_symmetry=True, force_computation=False)[source]#

Return a dictionary component -> list of cylinder diagrams.

INPUT:

  • ncyls - None or integer (default: None) - the number of cylinders

  • up_to_symmetry - (boolean, default True) to return only cylinder diagrams up to horizontal and vertical symmetry.

  • force_computation - boolean (default: False) - if False, then try to use the database.

EXAMPLES:

sage: from surface_dynamics import *

sage: A = AbelianStratum(4)
sage: cyls = A.cylinder_diagrams_by_component(ncyls=2, force_computation=True)
sage: A_hyp = A.hyperelliptic_component()
sage: A_odd = A.odd_component()
sage: len(cyls[A_odd])
4
sage: len(cyls[A_hyp])
2

sage: all(c.ncyls() == 2 for c in cyls[A_hyp])
True
sage: all(c.stratum_component() == A_hyp for c in cyls[A_hyp])
True

sage: all(c.ncyls() == 2 for c in cyls[A_odd])
True
sage: all(c.stratum_component() == A_odd for c in cyls[A_odd])
True

sage: for ncyls in range(1, 4):
....:     for up_to_symmetry in [True, False]:
....:         cd1 = A.cylinder_diagrams_by_component(ncyls, up_to_symmetry, True)
....:         cd2 = A.cylinder_diagrams_by_component(ncyls, up_to_symmetry, False)
....:         assert len(cd1[A_hyp]) == len(cd2[A_hyp])
....:         assert len(cd1[A_odd]) == len(cd2[A_odd])
cylinder_diagrams_number(ncyls=None, up_to_symmetry=True, force_computation=False)[source]#

Return the number of cylinder diagram that belongs to this stratum.

INPUT:

  • ncyls – an optional number of cylinders

  • up_to_symmetry - (boolean, default True) to return only cylinder diagrams up to horizontal and vertical symmetry.

  • force_computation – if True do no use the database of cylinder diagrams (default is False)

EXAMPLES:

sage: from surface_dynamics import *

sage: H22 = AbelianStratum(2,2)
sage: H22.cylinder_diagrams_number(3)
18
sage: H22.cylinder_diagrams_number(4)
7

If force_computation is set to True then the database is not used. It might be slower for large strata:

sage: H22.cylinder_diagrams_number(3, force_computation=True)
18
sage: H22.cylinder_diagrams_number(4, force_computation=True)
7

sage: H31 = AbelianStratum(3,1)
sage: for d in range(1,5):
....:     print("%d %d" %(H31.cylinder_diagrams_number(d, True, False),
....:                     H31.cylinder_diagrams_number(d, True, True)))
2 2
12 12
16 16
4 4

sage: H211 = AbelianStratum(2,1,1)
sage: for d in range(1,6):
....:     print("%d %d" % (H211.cylinder_diagrams_number(d, True, False),
....:               H211.cylinder_diagrams_number(d, True, True)))
5 5
29 29
53 53
27 27
8 8
dimension()[source]#

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 *

sage: AbelianStratum(0).dimension()
2
sage: AbelianStratum(0,0).dimension()
3
sage: AbelianStratum(2).dimension()
4
sage: AbelianStratum(1,1).dimension()
5
sage: a = AbelianStratum(4,3,2,1,0)
sage: p = a.permutation_representative()
sage: len(p) == a.dimension()
True
even_component()[source]#

Return the even component of self (if any)

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum({2:4}); a
H_5(2^4)
sage: a.even_component()
H_5(2^4)^even
genus()[source]#

Return the genus of the stratum.

OUTPUT:

integer – the genus

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(0).genus()
1
sage: AbelianStratum(1,1).genus()
2
sage: AbelianStratum(3,2,1).genus()
4
has_even_component()[source]#

Test whether this stratum has an even spin component.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(2,2).has_even_component()
False
sage: AbelianStratum(6).has_even_component()
True
sage: AbelianStratum(6).even_component()
H_4(6)^even
has_hyperelliptic_component()[source]#

Test whether this stratum has an hyperelliptic component.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(2,1,1).has_hyperelliptic_component()
False
sage: AbelianStratum(2,2).has_hyperelliptic_component()
True
sage: AbelianStratum(2,2).hyperelliptic_component()
H_3(2^2)^hyp
has_non_hyperelliptic_component()[source]#

Test whether this stratum has a non-hyperelliptic component.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(1,1).has_non_hyperelliptic_component()
False
sage: AbelianStratum(3,3).has_non_hyperelliptic_component()
True
sage: AbelianStratum(3,3).non_hyperelliptic_component()
H_4(3^2)^nonhyp
has_odd_component()[source]#

Test whether this stratum has an odd spin component.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(2).has_odd_component()
False
sage: AbelianStratum(4).has_odd_component()
True
sage: AbelianStratum(4).odd_component()
H_3(4)^odd
hyperelliptic_component()[source]#

Return the hyperelliptic component of self (if any)

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(10); a
H_6(10)
sage: a.hyperelliptic_component()
H_6(10)^hyp
nb_fake_zeros()[source]#

Return the number of fake zeros.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(0).nb_fake_zeros()
1
sage: AbelianStratum(1,1,0,0).nb_fake_zeros()
2

sage: QuadraticStratum(0,4,2,2).nb_fake_zeros()
1
nb_zeros(fake_zeros=True)[source]#

Returns the number of zeros of self.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(0).nb_zeros()
1
sage: AbelianStratum({2:4,3:2}).nb_zeros()
6
non_hyperelliptic_component()[source]#

Return the non hyperelliptic component of self (if any)

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(3,3); a
H_4(3^2)
sage: a.non_hyperelliptic_component()
H_4(3^2)^nonhyp
odd_component()[source]#

Return the odd component of self (if any).

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum([2,2]); a
H_3(2^2)
sage: a.odd_component()
H_3(2^2)^odd
one_cylinder_diagram()[source]#

Return a diagram with one cylinder in this connected component.

The diagram returned is the one deduced from the method representative.

INPUT:

  • ncyls - the number of cylinders

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(3,2,1); a
H_4(3, 2, 1)
sage: c = a.one_cylinder_diagram();c
(0,8,3,2,1,6,5,4,7)-(0,8,7,6,5,4,3,2,1)
sage: c.stratum()
H_4(3, 2, 1)
orientation_quotients(fake_zeros=False)[source]#

Return the list of quadratic strata such that their orientation cover are contained in this stratum.

If fake_zeros (default: False) is True we do care about poles which becomes a marked zero.

EXAMPLES:

sage: from surface_dynamics import *

The stratum H(2g-2) has one conic singularities of angle 2(2g-1)pi. The only way a surface in H(2g-2) covers a quadratic differential is that the quadratic differential has as unique zeros a conical singularity of angle (2g-1) pi. The number of poles may vary and give a collection of possibilities:

sage: AbelianStratum(2).orientation_quotients()
[Q_0(1, -1^5)]
sage: AbelianStratum(4).orientation_quotients()
[Q_1(3, -1^3), Q_0(3, -1^7)]
sage: AbelianStratum(6).orientation_quotients()
[Q_2(5, -1), Q_1(5, -1^5), Q_0(5, -1^9)]

A stratum with two zeros may or may not have orientation quotients:

sage: AbelianStratum(1,1).orientation_quotients()
[Q_1(2, -1^2), Q_0(2, -1^6)]
sage: AbelianStratum(2,2).orientation_quotients()
[Q_1(1^2, -1^2), Q_0(1^2, -1^6), Q_1(4, -1^4), Q_0(4, -1^8)]
sage: AbelianStratum(3,1).orientation_quotients()
[]

To impose that covering of poles are fake zeros, switch option fake_zeros to True:

sage: AbelianStratum(2,2,0,0).orientation_quotients(fake_zeros=True)
[Q_1(1^2, -1^2)]
rank()[source]#

Return the rank of this manifold (half dimension of the absolute part of the tangent space).

EXAMPLES:

sage: from surface_dynamics import AbelianStratum

sage: AbelianStratum(0,0).rank()
1
sage: AbelianStratum(2).rank()
2
sage: AbelianStratum(2,0,0).rank()
2
separatrix_diagram_iterator(ncyls=None)[source]#

Return an iterator over the separatrix diagrams of this stratum.

For strata of small dimension, it could be faster to use the method separatrix_diagrams.

INPUT:

  • ncyls – an optional number of cylinders

separatrix_diagrams(ncyls=None)[source]#

Returns the list of separatrix diagrams that appears in this stratum.

INPUT:

  • database - boolean (default: True) - if True, use the FlatSurfacesDatabase

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(2); a
H_2(2)
sage: for s in a.separatrix_diagrams(): print(s)
(0,1,2)-(0,1,2)
(0)(1,2)-(0,1)(2)

TESTS:

sage: from surface_dynamics import *

sage: for (zeros, ncyl) in [((4,), 3), ((2,2), 4)]:
....:     S = AbelianStratum(4).separatrix_diagrams(3)
....:     for i in range(len(S)):
....:         for j in range(i):
....:              assert not S[i].is_isomorphic(S[j])
separatrix_diagrams_number(ncyls=None)[source]#

Return the number of separatrix diagram that belongs to this stratum.

single_cylinder_origami()[source]#

Returns an origami associated to a single cylinder permutation representative.

Returns an origami in this connected component having a single vertical cylinder and a single horizontal cylinder.

Examples:

sage: from surface_dynamics import *

sage: C = AbelianStratum(4)
sage: O = C.single_cylinder_origami()
sage: O
(1,2,3,4,5)
(1,4,3,5,2)
sage: O.stratum() == AbelianStratum(4)
True
sage: C = AbelianStratum(2,0)
sage: O = C.single_cylinder_origami()
sage: O
(1,2,3,4)
(1,3,2,4)
sage: O.stratum() == AbelianStratum(2)
True
single_cylinder_representative(alphabet=None, reduced=True)[source]#

Returns a single cylinder permutation representative.

Returns a permutation representative of a square-tiled surface in this component having a single vertical cylinder and a single horizontal cylinder.

Such representatives were constructed for every stratum of Abelian differentials by Jeffreys [Jef19].

INPUT:

  • alphabet – an optional alphabet for the permutation representative

  • reduced (boolean, default True) – whether to return a reduced permutation (ie without labels)

EXAMPLES:

sage: from surface_dynamics import *

sage: C = AbelianStratum(2,0)
sage: p = C.single_cylinder_representative()
sage: p
0 1 2 3 4
4 3 1 2 0
sage: p.stratum() == C
True

sage: C = AbelianStratum(3,1)
sage: p = C.single_cylinder_representative(alphabet=Alphabet(name='lower'))
sage: p
a b c d e f g
c f b g e d a
sage: p.stratum() == C
True

sage: C = AbelianStratum(2)
sage: C.single_cylinder_representative()
Traceback (most recent call last):
...
ValueError: no 1,1-square-tiled surfaces in this stratum try again with H_2(2, 0)
sage: C = AbelianStratum(1,1)
sage: C.single_cylinder_representative()
Traceback (most recent call last):
...
ValueError: no 1,1-square-tiled surfaces in this stratum try again with H_2(1^2, 0^2)
zeros(fake_zeros=True)[source]#

Return the multiplicities of the zeros.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum([1,2,3]).zeros()
(3, 2, 1)
sage: AbelianStratum({2:4}).zeros()
(2, 2, 2, 2)
class surface_dynamics.flat_surfaces.abelian_strata.AbelianStratumComponent(stratum)[source]#

Bases: StratumComponent

Connected component of Abelian stratum.

Warning

Internal class! Do not use directly!

arithmetic_teichmueller_curves(n, primitive=False)[source]#

Return the arithmetic Teichmueller curves in that component of stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: A = AbelianStratum(2).hyperelliptic_component(); A
H_2(2)^hyp
sage: for i in range(3,10):
....:     print("%d %d" % (i,len(A.arithmetic_teichmueller_curves(i))))
3 1
4 1
5 2
6 1
7 2
8 1
9 2

sage: A = AbelianStratum(1,1).hyperelliptic_component(); A
H_2(1^2)^hyp
sage: for i in range(4,10):
....:    T = A.arithmetic_teichmueller_curves(i)
....:    T_prim = list(filter(lambda t:t.origami().is_primitive(), T))
....:    print("%d %d %d" % (i,len(T),len(T_prim)))
4 2 1
5 1 1
6 5 2
7 2 2
8 4 2
9 4 2

sage: A = AbelianStratum(4).hyperelliptic_component(); A
H_3(4)^hyp
sage: for i in range(5,10):
....:    print("%d %d" % (i,len(A.arithmetic_teichmueller_curves(i))))
5 2
6 4
7 3
8 3
9 4
cylinder_diagram_iterator(ncyls=None, up_to_symmetry=True, force_computation=False)[source]#

An iterator over the cylinder diagrams.

INPUT:

- ``ncyls`` -- (optional) a fixed number of cylinders
  • up_to_symmetry - (boolean, default True) to return only cylinder diagrams up to horizontal and vertical symmetry.

  • force_computation – (default False) whether the database should be used or not

EXAMPLES:

sage: from surface_dynamics import *

sage: A = AbelianStratum(1,1,1,1)
sage: cc = A.unique_component()
sage: it = cc.cylinder_diagram_iterator(3)
sage: cyl = next(it); cyl
(0,7)-(0,5) (1,6)-(1,4) (2,4,3,5)-(2,7,3,6)
sage: cyl.stratum_component()
H_3(1^4)^c
sage: cyl.ncyls()
3

Note that if you set force_computation to True the order of the iteration might be different and you might obtain cylinder diagram with some symmetries applied:

sage: C1 = list(cc.cylinder_diagram_iterator(3, force_computation=False))  # long time
sage: C2 = list(cc.cylinder_diagram_iterator(3, force_computation=True))   # long time
sage: assert len(C1) == len(C2)                                            # long time
sage: isoms = []                                                           # long time
sage: for c in C1:                                                         # long time
....:     isom = []
....:     for i,cc in enumerate(C2):
....:         if c.is_isomorphic(cc) or \
....:            c.is_isomorphic(cc.horizontal_symmetry()) or \
....:            c.is_isomorphic(cc.vertical_symmetry()) or \
....:            c.is_isomorphic(cc.inverse()):
....:              isom.append(i)
....:     assert len(isom) == 1, isom
....:     isoms.extend(isom)
sage: assert sorted(isoms) == list(range(len(C1)))                         # long time
cylinder_diagrams(ncyls=None, up_to_symmetry=True, force_computation=False)[source]#

Return the list of cylinder diagrams associated to this component.

INPUT:

  • ncyls - integer or list of integers (default: None) - consider only the cylinder diagrams with a given number of cylinders.

  • up_to_symmetry - (boolean, default True) to return only cylinder diagrams up to horizontal and vertical symmetry.

  • force_computation – boolean (default False). If True, the database of cylinder diagrams is not used.

EXAMPLES:

sage: from surface_dynamics import *

sage: C = AbelianStratum(1,1,1,1).unique_component(); C
H_3(1^4)^c
sage: for c in C.cylinder_diagrams(6): print(c)
(0,1)-(7) (2)-(0) (3)-(4) (4,7)-(5,6) (5)-(1) (6)-(2,3)
(0,1)-(7) (2)-(1) (3)-(0) (4,7)-(5,6) (5)-(4) (6)-(2,3)
(0,3)-(6,7) (1,2)-(4,5) (4)-(1) (5)-(3) (6)-(2) (7)-(0)
(0,3)-(6,7) (1,2)-(4,5) (4)-(3) (5)-(0) (6)-(2) (7)-(1)
cylinder_diagrams_number(ncyls=None, up_to_symmetry=True, force_computation=False)[source]#

Return the number of cylinder diagrams.

INPUT:

  • ncyls - integer or list of integers (default: None) - restrict the counting to a given number of cylinders.

  • up_to_symmetry - (boolean, default True) to count only cylinder diagrams up to horizontal and vertical symmetry.

  • force_computation - (default: False) whether we use the database or compute explicitly using the generation algorithm.

EXAMPLES:

sage: from surface_dynamics import *

sage: C = AbelianStratum(3,1).unique_component()
sage: C.cylinder_diagrams_number(1)
2
sage: C.cylinder_diagrams_number(2)
12
sage: C.cylinder_diagrams_number(3)
16
sage: C.cylinder_diagrams_number(4)
4

Note that when setting force_computation to True we got the same numbers:

sage: for i in range(1,5):
....:     print(C.cylinder_diagrams_number(i, force_computation=True))
2
12
16
4

sage: C = AbelianStratum(6)
sage: C_hyp = C.hyperelliptic_component()
sage: C_odd = C.odd_component()
sage: C_even = C.even_component()
sage: for i in range(1,5): print(C.cylinder_diagrams_number(i))
16
76
130
67
sage: for i in range(1,5): print(C_hyp.cylinder_diagrams_number(i))
1
3
8
4
sage: for i in range(1,5): print(C_odd.cylinder_diagrams_number(i))
11
49
80
42

sage: for i in range(1,5):
....:     print(C_even.cylinder_diagrams_number(i, True, False))
4
24
42
21
sage: for i in range(1,5):                                      # long time
....:     print(C_even.cylinder_diagrams_number(i, True, True)) # long time
4
24
42
21
lyapunov_exponents(**kargs)[source]#
lyapunov_exponents_approx(**kargs)[source]#

Return the approximate Lyapunov exponents of the KZ-cocycle.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(2).unique_component().lyapunov_exponents_approx(nb_iterations=2**21)  # abs tol .05
[1.000, 0.333]

sage: H4hyp, H4odd = AbelianStratum(4).components()
sage: H4hyp.lyapunov_exponents_approx(nb_iterations=2**21) # abs tol .05
[1.000, 0.616, 0.184]
sage: H4odd.lyapunov_exponents_approx(nb_iterations=2**21) # abs tol .05
[1.000, 0.418, 0.182]
one_cylinder_diagram()[source]#

Return a diagram with one cylinder in this connected component.

The diagram returned is the one deduced from the method permutation_representative.

EXAMPLES:

sage: from surface_dynamics import *

sage: A = AbelianStratum(2,2).odd_component()
sage: c = A.one_cylinder_diagram(); c
(0,5,1,3,2,4)-(0,5,4,3,2,1)
sage: c.stratum_component()
H_3(2^2)^odd

sage: A = AbelianStratum(3,3).non_hyperelliptic_component()
sage: c = A.one_cylinder_diagram(); c
(0,7,3,2,1,5,4,6)-(0,7,6,5,4,3,2,1)
sage: c.stratum_component()
H_4(3^2)^nonhyp
one_origami()[source]#

Returns an origami in this component

The origami returned has the minimal number of squares and one cylinder. It is obtained from the permutation representative of the stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(2,2).one_component()
sage: a.one_origami().stratum()
H_3(2^2)

sage: AbelianStratum(3,2,1).unique_component().one_origami().stratum()
H_4(3, 2, 1)
origami_iterator(n, reduced=True, primitive=False)[source]#

Iterator through the set of origamis with n squares in this stratum.

The output origamis are in normal form. But be careful as there may be repetition in the output!

INPUT:

  • n - integer - the number of squares

  • reduced - boolean (default: True)

  • primitive - boolean (default: False)

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = AbelianStratum(6).even_component()
sage: it = cc.origami_iterator(13)
sage: o = next(it)
sage: o
(1,2,3,4,5,6,7,8,9,10,11,12,13)
(1,8,2)(3,12,6,11,5,13,7,9)(4,10)
sage: o.stratum_component()
H_4(6)^even
origamis(n, reduced=True, primitive=False)[source]#

Return the set of origamis with n squares in this stratum.

INPUT:

  • n - integer - the number of squares

  • reduced - boolean (default: True)

  • primitive - boolean (default: False)

EXAMPLES:

sage: from surface_dynamics import *

sage: H11_hyp = AbelianStratum(1,1).hyperelliptic_component()
sage: len(H11_hyp.origamis(6))
88

sage: T6 = H11_hyp.arithmetic_teichmueller_curves(6)
sage: len(T6)
5
sage: sum(t.veech_group().index() for t in T6)
88

sage: H4_odd = AbelianStratum(4).odd_component()
sage: len(H4_odd.origamis(6))
155
sage: T6 = H4_odd.arithmetic_teichmueller_curves(6)
sage: sum(t.veech_group().index() for t in T6)
155
permutation_representative(left_degree=None, reduced=True, alphabet=None, relabel=True)[source]#

Returns the Zorich representative of this connected component.

Zorich constructs explicitly interval exchange transformations for each stratum in [Zor08].

INPUT:

  • reduced - boolean (default: True): whether you obtain a reduced or labelled permutation

  • alphabet - an alphabet or None: whether you want to specify an alphabet for your permutation

  • left_degree - the degree of the singularity on the left of the interval.

OUTPUT:

permutation – a permutation which lives in this component

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum(1,1,1,1).unique_component()
sage: p = c.permutation_representative(alphabet="abcdefghi")
sage: p
a b c d e f g h i
e d c f i h g b a
sage: p.stratum_component()
H_3(1^4)^c

sage: cc = AbelianStratum(3,2,1,0).unique_component()
sage: p = cc.permutation_representative(left_degree=3); p
0 1 2 3 4 5 6 7 8 9 10
4 3 7 6 5 10 9 8 2 0 1
sage: p.stratum_component()
H_4(3, 2, 1, 0)^c
sage: p.marking().left()
4
sage: p.rauzy_diagram()  # not tested
Rauzy diagram with 1060774 permutations

sage: p = cc.permutation_representative(left_degree=2); p
0 1 2 3 4 5 6 7 8 9 10
4 3 5 7 6 10 9 8 2 0 1
sage: p.stratum_component()
H_4(3, 2, 1, 0)^c
sage: p.marking().left()
3
sage: p.rauzy_diagram()  # not tested
Rauzy diagram with 792066 permutations

sage: p = cc.permutation_representative(left_degree=1); p
0 1 2 3 4 5 6 7 8 9 10
5 4 3 7 6 8 10 9 2 0 1
sage: p.stratum_component()
H_4(3, 2, 1, 0)^c
sage: p.marking().left()
2
sage: p.rauzy_diagram()  # not tested
Rauzy diagram with 538494 permutations

sage: p = cc.permutation_representative(left_degree=0); p
0 1 2 3 4 5 6 7 8 9 10
4 2 7 6 5 10 9 8 1 3 0
sage: p.stratum_component()
H_4(3, 2, 1, 0)^c
sage: p.marking().left()
1
sage: p.rauzy_diagram()  # not tested
Rauzy diagram with 246914 permutations
random_standard_permutation(nsteps=64)[source]#

Perform a random walk on rauzy diagram stopped on a standard permutation.

INPUT:

  • nsteps - integer or None - perform nsteps and then stops as soon as a Strebel differential is found.

At each step, with probability 1/3 we perform one of the following moves:

  • exchange top,bottom and left,right (proba 1/10)

  • top rauzy move (proba 9/20)

  • bot rauzy move (proba 9/20)

EXAMPLES:

sage: from surface_dynamics import *

sage: C = AbelianStratum(10).hyperelliptic_component() sage: p = C.random_standard_permutation(); p # random 0 1 2 3 4 5 6 7 8 9 10 11 11 10 9 8 7 6 5 4 3 2 1 0 sage: p.stratum_component() H_6(10)^hyp

sage: C = AbelianStratum(6,4,2).odd_component(); C H_7(6, 4, 2)^odd sage: p = C.random_standard_permutation(); p # random 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 15 2 14 12 3 11 6 10 8 5 9 13 7 4 1 0 sage: p.stratum_component() H_7(6, 4, 2)^odd

sage: C = AbelianStratum(2,2,2,2).even_component(); C H_5(2^4)^even sage: p = C.random_standard_permutation(); p # random 0 1 2 3 4 5 6 7 8 9 10 11 12 12 4 9 11 8 3 7 6 1 10 2 5 0 sage: p.stratum_component() H_5(2^4)^even

sage: C = AbelianStratum(32).odd_component(); C H_17(32)^odd sage: p = C.random_standard_permutation(); p # random 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 33 30 10 3 32 19 11 28 4 14 24 15 21 20 9 12 25 6 2 29 26 23 27 13 8 1 18 17 16 31 7 22 5 0 sage: p.stratum_component() H_17(32)^odd

rauzy_class_cardinality(left_degree=None, reduced=True)[source]#

Rauzy diagram cardinality for connected components.

Returns the cardinality of the extended Rauzy diagram associated to this connected component.

If left_degree is provided then it returns the cardinality of the Rauzy diagram with a singularity of that degree attached on the left. Otherwise it returns the cardinality of the extended Rauzy diagram.

INPUT:

  • left_degree - the degree to be attached to the singularity on the left

  • reduced - boolean (default: True) - consider the cardinality of reduced or extended Rauzy diagram

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum({1:4}).unique_component(); a
H_3(1^4)^c
sage: a.rauzy_diagram()
Rauzy diagram with 1255 permutations
sage: a.rauzy_class_cardinality()
1255

sage: cc = AbelianStratum(3,2,1).unique_component()
sage: cc.rauzy_diagram(left_degree=3)   # long time
Rauzy diagram with 96434 permutations
sage: cc.rauzy_class_cardinality(left_degree=3)
96434

sage: cc.rauzy_diagram(left_degree=2)   # long time
Rauzy diagram with 72006 permutations
sage: cc.rauzy_class_cardinality(left_degree=2)
72006

sage: cc.rauzy_diagram(left_degree=1)   # long time
Rauzy diagram with 48954 permutations
sage: cc.rauzy_class_cardinality(left_degree=1)
48954

sage: a = AbelianStratum({1:8}).unique_component(); a
H_5(1^8)^c
sage: a.rauzy_class_cardinality()
55184875

Cardinalities for labeled Rauzy classes instead of reduced:

sage: cc=AbelianStratum(2,1,1).unique_component()
sage: cc.rauzy_diagram(left_degree=2,reduced=False)
Rauzy diagram with 3676 permutations
sage: cc.rauzy_class_cardinality(left_degree=2,reduced=False)
3676

sage: cc.rauzy_diagram(left_degree=1,reduced=False)
Rauzy diagram with 3774 permutations
sage: cc.rauzy_class_cardinality(left_degree=1,reduced=False)
3774

sage: cc=AbelianStratum(2,1,1,0).unique_component()
sage: cc.rauzy_diagram(left_degree=2,reduced=False) # long time
Rauzy diagram with 33084 permutations
sage: cc.rauzy_diagram(left_degree=1,reduced=False) # long time
Rauzy diagram with 33966 permutations
sage: cc.rauzy_diagram(left_degree=0,reduced=False) # long time
Rauzy diagram with 30828 permutations

sage: cc.rauzy_class_cardinality(left_degree=2,reduced=False)
33084
sage: cc.rauzy_class_cardinality(left_degree=1,reduced=False)
33966
sage: cc.rauzy_class_cardinality(left_degree=0,reduced=False)
30828
rauzy_diagram(*args, **kwds)[source]#

Returns the extended Rauzy diagram associated to this connected component.

OUTPUT:

rauzy diagram – the Rauzy diagram associated to this stratum

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum(0).components()[0]
sage: r = c.rauzy_diagram()
single_cylinder_origami()[source]#

Returns an origami associated to a single cylinder permutation representative.

Returns an origami in this connected (or non-hyperelliptic) component having a single vertical cylinder and a single horizontal cylinder.

Such representatives were constructed for every stratum of Abelian differentials by Jeffreys [Jef19].

Examples:

sage: from surface_dynamics import *

sage: cc = AbelianStratum(4).odd_component()
sage: O = cc.single_cylinder_origami()
sage: O
(1,2,3,4,5)
(1,4,3,5,2)
sage: O.stratum_component() == cc
True
sage: cc = AbelianStratum(5,3).unique_component()
sage: O = cc.single_cylinder_origami()
sage: O
(1,2,3,4,5,6,7,8,9,10)
(1,9,8,10,6,7,4,3,5,2)
sage: O.stratum_component() == cc
True
sage: cc = AbelianStratum(4,2).even_component()
sage: O = cc.single_cylinder_origami()
sage: O
(1,2,3,4,5,6,7,8)
(1,3,7,5,6,8,4,2)
sage: O.stratum_component() == cc
True
single_cylinder_representative(alphabet=None, reduced=True)[source]#

Returns a single cylinder permutation representative.

Returns a cylindric permutation representative of this connected stratum (or non-hyperelliptic component) such that the associated square-tiled surface is made of a single cylinder of height one in both horizontal and vertical direction.

Such representatives were constructed for every stratum of Abelian differentials by Jeffreys [Jef19].

INPUT:

  • alphabet – an optional alphabet for the permutation representative

  • reduced (boolean, default True) – whether to return a reduced permutation (ie without labels)

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = AbelianStratum(1,1,1,1).unique_component()
sage: p = cc.single_cylinder_representative()
sage: p
0 1 2 3 4 5 6 7 8
2 6 5 3 1 8 4 7 0
sage: p.stratum_component() == cc
True

sage: cc = AbelianStratum(2,1,1).unique_component()
sage: p = cc.single_cylinder_representative()
sage: p
0 1 2 3 4 5 6 7
2 6 4 1 7 5 3 0
sage: p.stratum_component() == cc
True

sage: cc = AbelianStratum(3,3).non_hyperelliptic_component()
sage: p = cc.single_cylinder_representative(alphabet=Alphabet(name='lower'))
sage: p
a b c d e f g h i
c i g f h e b d a
sage: p.stratum_component() == cc
True
spin()[source]#

Return None since surfaces in this component have no spin.

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum([1,1,1,1]).unique_component(); c
H_3(1^4)^c
sage: c.spin() is None
True
standard_permutations()[source]#

Return the set of standard permutations.

EXAMPLES:

sage: from surface_dynamics import *

sage: C = AbelianStratum(4).odd_component()
sage: C
H_3(4)^odd
sage: for p in C.standard_permutations(): print("%s\n***********" % p)
0 1 2 3 4 5
5 2 1 4 3 0
***********
0 1 2 3 4 5
5 3 1 4 2 0
***********
0 1 2 3 4 5
5 4 1 3 2 0
***********
0 1 2 3 4 5
5 2 4 1 3 0
***********
0 1 2 3 4 5
5 4 2 1 3 0
***********
0 1 2 3 4 5
5 2 4 3 1 0
***********
0 1 2 3 4 5
5 3 2 4 1 0
***********
standard_permutations_number(left_degree=None)[source]#

Return the number of standard permutations in the Rauzy class associated to this connected component.

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = AbelianStratum(3,1).unique_component()
sage: sum(1 for p in cc.rauzy_diagram() if p.is_standard())
24
sage: cc.standard_permutations_number()
24

sage: sum(1 for p in cc.rauzy_diagram(left_degree=3) if p.is_standard())
16
sage: cc.standard_permutations_number(left_degree=3)
16

sage: sum(1 for p in cc.rauzy_diagram(left_degree=1) if p.is_standard())
8
sage: cc.standard_permutations_number(left_degree=1)
8

sage: cc = AbelianStratum({1:10}).unique_component(); cc
H_6(1^10)^c
sage: cc.standard_permutations_number()
59520825
surface_dynamics.flat_surfaces.abelian_strata.EvenASC#

alias of EvenAbelianStratumComponent

class surface_dynamics.flat_surfaces.abelian_strata.EvenAbelianStratumComponent(stratum)[source]#

Bases: AbelianStratumComponent

Connected component of Abelian stratum with even spin structure.

Warning

Internal class! Do not use directly!

permutation_representative(left_degree=None, reduced=True, alphabet=None, relabel=True)[source]#

Returns the Zorich representative of this connected component.

Zorich constructs explicitly interval exchange transformations for each stratum in [Zor08].

INPUT:

  • reduced - boolean (default: True): whether you obtain a reduced or labelled permutation

  • left_degree - integer (optional) - a specified degree of zero at the left of the interval.

  • alphabet - alphabet or None (default: None): whether you want to specify an alphabet for your representative

  • relabel - boolean (default: True) - if False uses Zorich’s natural numbering otherwise uses 0,1,…

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum(6).even_component()
sage: c
H_4(6)^even
sage: p = c.permutation_representative(alphabet=range(8))
sage: p
0 1 2 3 4 5 6 7
5 4 3 2 7 6 1 0
sage: p.stratum_component()
H_4(6)^even
sage: c = AbelianStratum(4,4).even_component()
sage: c
H_5(4^2)^even
sage: p = c.permutation_representative(alphabet=range(11))
sage: p
0 1 2 3 4 5 6 7 8 9 10
5 4 3 2 6 8 7 10 9 1 0
sage: p.stratum_component()
H_5(4^2)^even

Different markings lead to different Rauzy diagrams:

sage: c = AbelianStratum(4,2,0).even_component()
sage: p = c.permutation_representative(left_degree=4); p
0 1 2 3 4 5 6 7 8 9
6 5 4 3 7 9 8 2 0 1
sage: p.stratum_component()
H_4(4, 2, 0)^even
sage: p.marking().left()
5
sage: p.rauzy_diagram()   # long time
Rauzy diagram with 66140 permutations

sage: p = c.permutation_representative(left_degree=2); p
0 1 2 3 4 5 6 7 8 9
7 6 5 4 3 9 8 2 0 1
sage: p.stratum_component()
H_4(4, 2, 0)^even
sage: p.marking().left()
3
sage: p.rauzy_diagram()   # long time
Rauzy diagram with 39540 permutations

sage: p = c.permutation_representative(left_degree=0); p
0 1 2 3 4 5 6 7 8 9
6 4 3 2 7 9 8 1 5 0
sage: p.stratum_component()
H_4(4, 2, 0)^even
sage: p.marking().left()
1
sage: p.rauzy_diagram()   # long time
Rauzy diagram with 11792 permutations
rauzy_class_cardinality(left_degree=None, reduced=True)[source]#

Cardinality of rauzy diagram for even component of a stratum

INPUT:

  • left_degree - integer

  • reduced - boolean

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum(6).even_component()
sage: c.rauzy_diagram()
Rauzy diagram with 2327 permutations
sage: c.rauzy_class_cardinality()
2327

sage: c = AbelianStratum(4,2,0).even_component()
sage: c.rauzy_class_cardinality()
117472

sage: c.rauzy_diagram(left_degree=4)  # long time
Rauzy diagram with 66140 permutations
sage: c.rauzy_class_cardinality(left_degree=4)
66140
sage: c.rauzy_diagram(left_degree=4, reduced=False)  # long time
Rauzy diagram with 198420 permutations
sage: c.rauzy_class_cardinality(left_degree=4,reduced=False)
198420

sage: c.rauzy_class_cardinality(2)
39540
sage: c.rauzy_diagram(left_degree=2)  # long time
Rauzy diagram with 39540 permutations
sage: c.rauzy_diagram(left_degree=2, reduced=False)  # long time
Rauzy diagram with 197700 permutations
sage: c.rauzy_class_cardinality(left_degree=2, reduced=False)
197700

sage: c.rauzy_class_cardinality(0)
11792
sage: c.rauzy_diagram(left_degree=0)
Rauzy diagram with 11792 permutations
sage: c.rauzy_diagram(left_degree=0, reduced=False)  # long time
Rauzy diagram with 176880 permutations
sage: c.rauzy_class_cardinality(left_degree=0, reduced=False)
176880
single_cylinder_representative(alphabet=None, reduced=False)[source]#

Returns a single cylinder permutation representative.

Returns a permutation representative of a square-tiled surface in this component having a single vertical cylinder and a single horizontal cylinder.

Such representatives were constructed for every stratum of Abelian differentials by Jeffreys [Jef19].

INPUT:

  • alphabet – an optional alphabet for the permutation representative

  • reduced (boolean, default True) – whether to return a reduced permutation (ie without labels)

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = AbelianStratum(6).even_component()
sage: p = cc.single_cylinder_representative(alphabet=Alphabet(name='lower'))
sage: p
a b c d e f g h
c h g f d b e a
sage: p.stratum_component() == cc
True

sage: cc = AbelianStratum(4,4).even_component()
sage: p = cc.single_cylinder_representative()
sage: p
0 1 2 3 4 5 6 7 8 9 10
2 10 7 5 8 1 9 6 4 3 0
sage: p.stratum_component() == cc
True
spin()[source]#

Return 0.

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum(4,2).even_component(); c
H_4(4, 2)^even
sage: c.spin()
0
standard_permutations_number()[source]#

Return the number of standard permutation of this even component.

EXAMPLES:

sage: from surface_dynamics import *

For strata in genus 3, the number of standard permutations is reasonably small and the whole set can be computed:

sage: C = AbelianStratum(6).even_component()
sage: len(C.standard_permutations())  # long time
44
sage: C.standard_permutations_number()
44

sage: C = AbelianStratum(4,2).even_component()
sage: len(C.standard_permutations())   # long time
136
sage: C.standard_permutations_number()
136

sage: C = AbelianStratum(2,2,2).even_component()
sage: len(C.standard_permutations())   # long time
92
sage: C.standard_permutations_number()
92

For higher genera, this number can be very big:

sage: C = AbelianStratum(20).even_component()
sage: C.standard_permutations_number()
109398514483439999
surface_dynamics.flat_surfaces.abelian_strata.HypASC#

alias of HypAbelianStratumComponent

class surface_dynamics.flat_surfaces.abelian_strata.HypAbelianStratumComponent(stratum)[source]#

Bases: AbelianStratumComponent

Hyperelliptic component of Abelian stratum.

permutation_representative(left_degree=None, reduced=True, alphabet=None, relabel=True)[source]#

Returns the Zorich representative of this connected component.

Zorich constructs explicitly interval exchange transformations for each stratum in [Zor08].

INPUT:

  • reduced - boolean (default: True): whether you obtain a reduced or labelled permutation

  • alphabet - alphabet or None (default: None): whether you want to specify an alphabet for your representative

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum(0).hyperelliptic_component()
sage: p = c.permutation_representative()
sage: p
0 1
1 0
sage: p.stratum_component()
H_1(0)^hyp

sage: c = AbelianStratum(0,0).hyperelliptic_component()
sage: p = c.permutation_representative(alphabet="abc")
sage: p
a b c
c b a
sage: p.stratum_component()
H_1(0^2)^hyp

sage: c = AbelianStratum(2,2).hyperelliptic_component()
sage: p = c.permutation_representative(alphabet="ABCDEFGHIJKL")
sage: p
A B C D E F G
G F E D C B A
sage: c = AbelianStratum(1,1,0).hyperelliptic_component()
sage: p = c.permutation_representative(left_degree=1); p
0 1 2 3 4 5
5 1 4 3 2 0
sage: p.marking().left()
2
sage: p.rauzy_diagram()
Rauzy diagram with 90 permutations

sage: p = c.permutation_representative(left_degree=0); p
0 1 2 3 4 5
5 3 2 1 4 0
sage: p.marking().left()
1
sage: p.rauzy_diagram()
Rauzy diagram with 20 permutations
random_standard_permutation(nsteps=None)[source]#

In hyperelliptic component there is only one standard permutation.

rauzy_class_cardinality(left_degree=None, reduced=True)[source]#

Return the cardinality of the extended Rauzy diagram associated to the hyperelliptic component

The cardinality of the Rauzy diagram or extended Rauzy diagram associated to H_{hyp}(2g-2,0^k) or H_{hyp}(g-1,g-1,0^k) depends only on the dimension d of the initial stratum mathcal{H}_{hyp}(2g-2) for which d=2g or mathcal{H}_{hyp}(g-1,g-1) for which d=2g+1 and the number of fake zeros k. The formula is

\[\binom{d+k+1}{k} (2^{d-1}-1) + d \binom{d+k}{k-1}\]

INPUT:

  • left_degree - integer - the degree of the singularity attached at the left of the interval.

  • reduced - boolean (default: True) - if False, consider labeled Rauzy diagrams instead of reduced.

EXAMPLES:

sage: from surface_dynamics import *

The case of the torus is a little bit different:

sage: c = AbelianStratum(0).hyperelliptic_component()
sage: c.rauzy_diagram()
Rauzy diagram with 1 permutation
sage: c.rauzy_class_cardinality()
1
sage: c = AbelianStratum(0,0).hyperelliptic_component()
sage: c.rauzy_diagram()
Rauzy diagram with 3 permutations
sage: c.rauzy_class_cardinality()
3

Examples in genus 2:

sage: c = AbelianStratum(2,0).hyperelliptic_component()
sage: c.rauzy_diagram()
Rauzy diagram with 46 permutations
sage: c.rauzy_class_cardinality()
46

sage: c.rauzy_diagram(left_degree=2)
Rauzy diagram with 35 permutations
sage: c.rauzy_class_cardinality(left_degree=2)
35

sage: c.rauzy_diagram(left_degree=0)
Rauzy diagram with 11 permutations
sage: c.rauzy_class_cardinality(left_degree=0)
11
sage: c.rauzy_diagram(left_degree=0, reduced=False)
Rauzy diagram with 33 permutations
sage: c.rauzy_class_cardinality(left_degree=0, reduced=False)
33

sage: c = AbelianStratum(1,1,0,0).hyperelliptic_component()
sage: c.rauzy_diagram()
Rauzy diagram with 455 permutations
sage: c.rauzy_class_cardinality()
455

sage: c.rauzy_diagram(left_degree=1)
Rauzy diagram with 315 permutations
sage: c.rauzy_class_cardinality(left_degree=1)
315
sage: c.rauzy_diagram(left_degree=1, reduced=False)
Rauzy diagram with 630 permutations
sage: c.rauzy_class_cardinality(left_degree=1, reduced=False)
630

sage: c.rauzy_diagram(left_degree=0)
Rauzy diagram with 140 permutations
sage: c.rauzy_class_cardinality(left_degree=0)
140
sage: c.rauzy_diagram(left_degree=0, reduced=False)
Rauzy diagram with 560 permutations
sage: c.rauzy_class_cardinality(left_degree=0, reduced=False)
560

Other examples in higher genus:

sage: c = AbelianStratum(12,0,0).hyperelliptic_component()
sage: c.rauzy_class_cardinality()
1114200
sage: c.rauzy_class_cardinality(left_degree=12, reduced=False)
1965840

sage: c = AbelianStratum(14).hyperelliptic_component()
sage: c.rauzy_class_cardinality()
32767
single_cylinder_representative(alphabet=None, reduced=True)[source]#

Returns a single cylinder permutation representative.

Returns a permutation representative of a square-tiled surface in this component having a single vertical cylinder and a single horizontal cylinder.

Such representatives were constructed for every stratum of Abelian differentials by Jeffreys [Jef19].

INPUT:

  • alphabet – an optional alphabet for the permutation representative

  • reduced (boolean, default True) – whether to return a reduced permutation (ie without labels)

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = AbelianStratum(2,0).hyperelliptic_component()
sage: p = cc.single_cylinder_representative(alphabet=Alphabet(name='upper'))
sage: p
A B C D E
E D B C A
sage: p.stratum_component() == cc
True

sage: cc = AbelianStratum({3:2,0:6}).hyperelliptic_component()
sage: p = cc.single_cylinder_representative()
sage: p
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
14 12 13 10 11 8 9 7 5 6 3 4 1 2 0
sage: p.stratum_component() == cc
True

sage: cc = AbelianStratum(2).hyperelliptic_component()
sage: cc.single_cylinder_representative()
Traceback (most recent call last):
...
ValueError: no 1,1-square-tiled surfaces in this connected component try again with H_2(2, 0)^hyp
sage: cc = AbelianStratum({3:2,0:5}).hyperelliptic_component()
sage: cc.single_cylinder_representative()
Traceback (most recent call last):
...
ValueError: no 1,1-square-tiled surfaces in this connected component try again with H_4(3^2, 0^6)^hyp
spin()[source]#

Return the spin parity of hyperelliptic stratum.

EXAMPLES:

sage: from surface_dynamics import *

For the strata H(2g-2):

sage: c = AbelianStratum(0).hyperelliptic_component()
sage: c.spin()
1
sage: p = c.permutation_representative()
sage: p.arf_invariant()
1

sage: c = AbelianStratum(2).hyperelliptic_component()
sage: c.spin()
1
sage: p = c.permutation_representative()
sage: p.arf_invariant()
1

sage: c = AbelianStratum(4).hyperelliptic_component()
sage: c.spin()
0
sage: p = c.permutation_representative()
sage: p.arf_invariant()
0

For the strata H(g-1,g-1):

sage: c = AbelianStratum(2,2).hyperelliptic_component()
sage: c.spin()
0
sage: p = c.permutation_representative()
sage: p.arf_invariant()
0

sage: c = AbelianStratum(4,4).hyperelliptic_component()
sage: c.spin()
1
sage: p = c.permutation_representative()
sage: p.arf_invariant()
1
standard_permutations(reduced=True)[source]#

Return the standard permutations in this hyperelliptic component.

EXAMPLES:

sage: from surface_dynamics import *

sage: AbelianStratum(6).hyperelliptic_component().standard_permutations()
[0 1 2 3 4 5 6 7
 7 6 5 4 3 2 1 0]
standard_permutations_number()[source]#

Return the number of standard permutations in this hyperelliptic component.

surface_dynamics.flat_surfaces.abelian_strata.NonHypASC#

alias of NonHypAbelianStratumComponent

class surface_dynamics.flat_surfaces.abelian_strata.NonHypAbelianStratumComponent(stratum)[source]#

Bases: AbelianStratumComponent

Non hyperelliptic component of Abelian stratum.

rauzy_class_cardinality(left_degree=None, reduced=True)[source]#

Return the cardinality of Rauzy diagram associated to this non hyperelliptic component.

INPUT:

  • left_degree - integer

  • reduced - boolean (default: True)

EXAMPLES:

sage: from surface_dynamics import *

Examples in genus 3:

sage: c = AbelianStratum(3,3).non_hyperelliptic_component()
sage: c.rauzy_class_cardinality()
15568

sage: c = AbelianStratum(3,3,0).non_hyperelliptic_component()
sage: c.rauzy_class_cardinality()
173723

sage: c.rauzy_diagram(left_degree=3)  # long time
Rauzy diagram with 155680 permutations
sage: c.rauzy_class_cardinality(left_degree=3)
155680
sage: c.rauzy_diagram(left_degree=3, reduced=False)  # not tested
Rauzy diagram with 311360 permutations
sage: c.rauzy_class_cardinality(left_degree=3, reduced=False)
311360

sage: c.rauzy_diagram(left_degree=0)  # long time
Rauzy diagram with 18043 permutations
sage: c.rauzy_class_cardinality(left_degree=0)
18043
sage: cc.rauzy_diagram(left_degree=0, reduced=False) # not tested
Rauzy diagram with 288688 permutations
sage: c.rauzy_class_cardinality(left_degree=0,reduced=False)
288688

When genus growths, the size of the Rauzy diagram becomes very big:

sage: c = AbelianStratum(5,5).non_hyperelliptic_component()
sage: c.rauzy_class_cardinality()
136116680

sage: c = AbelianStratum(7,7,0).non_hyperelliptic_component()
sage: c.rauzy_class_cardinality()
88484743236111
sage: c.rauzy_class_cardinality(left_degree=7, reduced=False)
334071852804864
standard_permutations_number()[source]#

EXAMPLES:

sage: from surface_dynamics import *

sage: C = AbelianStratum(3,3).non_hyperelliptic_component()
sage: len(C.standard_permutations())  # long time
275
sage: C.standard_permutations_number()
275

sage: C = AbelianStratum(5,5).non_hyperelliptic_component()
sage: C.standard_permutations_number()
1022399

sage: C = AbelianStratum(7,7).non_hyperelliptic_component()
sage: C.standard_permutations_number()
19229011199
surface_dynamics.flat_surfaces.abelian_strata.OddASC#

alias of OddAbelianStratumComponent

class surface_dynamics.flat_surfaces.abelian_strata.OddAbelianStratumComponent(stratum)[source]#

Bases: AbelianStratumComponent

Connected component of an Abelian stratum with odd spin parity.

permutation_representative(left_degree=None, reduced=True, alphabet=None, relabel=True)[source]#

Returns the Zorich representative of this connected component.

A. Zorich constructs explicitly interval exchange transformations for each stratum in [Zor08].

EXAMPLES:

sage: from surface_dynamics import *

sage: a = AbelianStratum(6).odd_component()
sage: p = a.permutation_representative()
sage: p
0 1 2 3 4 5 6 7
3 2 5 4 7 6 1 0
sage: p.stratum_component()
H_4(6)^odd
sage: a = AbelianStratum(4,4).odd_component()
sage: p = a.permutation_representative()
sage: p
0 1 2 3 4 5 6 7 8 9 10
3 2 5 4 6 8 7 10 9 1 0
sage: p.stratum_component()
H_5(4^2)^odd

Different markings lead to different Rauzy diagrams:

sage: c = AbelianStratum(4,2,0).odd_component()
sage: p = c.permutation_representative(left_degree=4); p
0 1 2 3 4 5 6 7 8 9
4 3 6 5 7 9 8 2 0 1
sage: p.stratum_component()
H_4(4, 2, 0)^odd
sage: p.marking().left()
5
sage: p.rauzy_diagram()   # not tested
Rauzy diagram with 147090 permutations

sage: p = c.permutation_representative(left_degree=2); p
0 1 2 3 4 5 6 7 8 9
4 3 5 7 6 9 8 2 0 1
sage: p.stratum_component()
H_4(4, 2, 0)^odd
sage: p.marking().left()
3
sage: p.rauzy_diagram()   # long time
Rauzy diagram with 87970 permutations

sage: p = c.permutation_representative(left_degree=0); p
0 1 2 3 4 5 6 7 8 9
4 2 6 5 7 9 8 1 3 0
sage: p.stratum_component()
H_4(4, 2, 0)^odd
sage: p.marking().left()
1
sage: p.rauzy_diagram()   # long time
Rauzy diagram with 27754 permutations
rauzy_class_cardinality(left_degree=None, reduced=True)[source]#

Cardinality of rauzy diagram for odd component

INPUT:

  • left_degree - integer (optional)

  • reduced - boolean (default: True)

EXAMPLES:

sage: from surface_dynamics import *

The genus must be at least 3 to have an odd component:

sage: c = AbelianStratum(4).odd_component()
sage: c.rauzy_diagram()
Rauzy diagram with 134 permutations
sage: c.rauzy_class_cardinality()
134
sage: c = AbelianStratum(4,0).odd_component()
sage: c.rauzy_diagram()
Rauzy diagram with 1114 permutations
sage: c.rauzy_class_cardinality()
1114

sage: c = AbelianStratum(2,2).odd_component()
sage: c.rauzy_diagram()
Rauzy diagram with 294 permutations
sage: c.rauzy_class_cardinality()
294

sage: c = AbelianStratum(2,2,0).odd_component()
sage: c.rauzy_class_cardinality()
2723

sage: c.rauzy_diagram(left_degree=2)
Rauzy diagram with 2352 permutations
sage: c.rauzy_class_cardinality(left_degree=2)
2352
sage: c.rauzy_diagram(left_degree=2, reduced=False)
Rauzy diagram with 7056 permutations
sage: c.rauzy_class_cardinality(left_degree=2, reduced=False)
7056

sage: c.rauzy_diagram(left_degree=0)
Rauzy diagram with 371 permutations
sage: c.rauzy_class_cardinality(left_degree=0)
371
sage: c.rauzy_diagram(left_degree=0, reduced=False)
Rauzy diagram with 6678 permutations
sage: c.rauzy_class_cardinality(left_degree=0, reduced=False)
6678

Example in higher genus for which an explicit computation of the Rauzy diagram would be very long:

sage: c = AbelianStratum(4,2,0).odd_component()
sage: c.rauzy_class_cardinality()
262814
sage: c = AbelianStratum(4,4,4).odd_component()
sage: c.rauzy_class_cardinality()
24691288838
sage: c.rauzy_class_cardinality(left_degree=4, reduced=False)
1234564441900
single_cylinder_representative(alphabet=None, reduced=True)[source]#

Returns a single cylinder permutation representative.

Returns a permutation representative of a square-tiled surface in this component having a single vertical cylinder and a single horizontal cylinder.

Such representatives were constructed for every stratum of Abelian differentials by Jeffreys [Jef19].

INPUT:

  • alphabet – an optional alphabet for the permutation representative

  • reduced (boolean, default True) – whether to return a reduced permutation (ie without labels)

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = AbelianStratum(4).odd_component()
sage: p = cc.single_cylinder_representative(alphabet=Alphabet(name='upper'))
sage: p
A B C D E F
C F E B D A
sage: p.stratum_component() == cc
True

sage: cc = AbelianStratum(6,2).odd_component()
sage: p = cc.single_cylinder_representative()
sage: p
0 1 2 3 4 5 6 7 8 9 10
2 5 4 6 3 8 10 7 1 9 0
sage: p.stratum_component() == cc
True
spin()[source]#

Returns 1 which is, by definition, the spin parity of this stratum component.

EXAMPLES:

sage: from surface_dynamics import *

sage: c = AbelianStratum(4).odd_component(); c
H_3(4)^odd
sage: c.spin()
1
standard_permutations_number()[source]#

Return the number of standard permutation of this even component.

EXAMPLES:

sage: from surface_dynamics import *

In genus 2, there are two strata which contains an odd component:

sage: C = AbelianStratum(4).odd_component()
sage: len(C.standard_permutations())
7
sage: C.standard_permutations_number()
7

sage: C = AbelianStratum(2,2).odd_component()
sage: len(C.standard_permutations())
11
sage: C.standard_permutations_number()
11

In genus 3, the number of standard permutations is reasonably small and the whole set can be computed:

sage: C = AbelianStratum(6).odd_component()
sage: len(C.standard_permutations())   # long time
135
sage: C.standard_permutations_number()
135

sage: C = AbelianStratum(4,2).odd_component()
sage: len(C.standard_permutations())   # long time
472
sage: C.standard_permutations_number()
472

sage: C = AbelianStratum(2,2,2).odd_component()
sage: len(C.standard_permutations())   # long time
372
sage: C.standard_permutations_number()
372

For higher genera, this number can be very big:

sage: C = AbelianStratum(8,6,4,2).odd_component()
sage: C.standard_permutations_number()
26596699869748377600

Quadratic strata#

Strata of quadratic differentials on Riemann surfaces

More precisely, we are interested in meromorphic quadratic differentials with at most simple poles on closed compact connected Riemann surfaces, which are not globally the square of an abelian differential.

The moduli space of such quadratic differentials on Riemann surfaces of a given genus is a complex orbifold, stratified by the degrees of zeros (zeros of degree -1, or simple poles, being allowed). The strata themselves are complex orbifolds. Most strata are connected but some (infinitely many) are not.

A stratum corresponds to the Sage object QuadraticStratum.

The classification of connected components of strata of quadratic differentials was established by Erwan Lanneau in [Lan08], after a similar classification was established by Kontsevich and Zorich in [KonZor03] in the Abelian case.

Each stratum has one or two connected components and each component is associated to an extended Rauzy class. The components() method gives the decomposition of a stratum into its connected components.

A representative for each connected component of stratum is given by Zorich in [Zor08].

This is implemented here following [Zor08]:

The inverse operation, i.e., starting from a permutation, determine the connected component it lives in, is partially written in [KonZor03]. See: stratum_component().

The code here implements the descriptions in [Zor08]. Zorich already implemented all this for Mathematica in [ZS].

See also abelian_strata for Abelian strata.

AUTHORS:

  • Vincent Delecroix (2009-09-29): initial version

  • Samuel Lelievre (2010-10-08): quadratic strata

EXAMPLES:

sage: from surface_dynamics import *

Construction of a stratum from a list of singularity degrees:

sage: a = QuadraticStratum(2,2)
sage: a
Q_2(2^2)
sage: a.genus()
2
sage: a = QuadraticStratum(4,3,2,2,1)
sage: a
Q_4(4, 3, 2^2, 1)
sage: a.genus()
4

By convention, the degrees are always written in decreasing order:

sage: a1 = QuadraticStratum(7,5,3,1)
sage: a1
Q_5(7, 5, 3, 1)
sage: a2 = QuadraticStratum(3,1,7,5)
sage: a2
Q_5(7, 5, 3, 1)
sage: a1 == a2
True

List the connected components of a stratum:

sage: a = QuadraticStratum(6,2)
sage: a.components()
[Q_3(6, 2)^hyp, Q_3(6, 2)^nonhyp]
sage: a = QuadraticStratum(12)
sage: cc = a.components()
sage: cc
[Q_4(12)^reg, Q_4(12)^irr]
sage: for c in cc:
....:     print(c)
....:     print(c.permutation_representative())
Q_4(12)^reg
0 1 2 1 2 3 4 3 4 5
5 6 7 6 7 0
Q_4(12)^irr
0 1 2 3 4 5 6 5
7 6 4 7 3 2 1 0
sage: a = QuadraticStratum(1, 1, 1, 1)
sage: a.components()
[Q_2(1^4)^hyp]
sage: c = a.components()[0]
sage: p = c.permutation_representative(); p
0 1 2 3 1 4 5
2 6 5 4 6 3 0
surface_dynamics.flat_surfaces.quadratic_strata.CQSC#

alias of ConnectedQuadraticStratumComponent

class surface_dynamics.flat_surfaces.quadratic_strata.ConnectedQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

Connected component of stratum of quadratic differentials.

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

NOTES:

The representative is made by constructing two lists l0 and l1 which correspond to a generalized permutation representative for the stratum with simple zeros, and then erasing some elements from l0 and l1 (this corresponds to collapsing saddle connections to merge zeros). It may be possible to find a faster way to obtain the desired l0 and l1 than by constructing the long versions and erasing symbols; the current implementation has a loop with “del l0[l0.index(i)]” and “del l1[l1.index(i)]”.

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = QuadraticStratum(6,-1,-1).non_hyperelliptic_component()
sage: p = cc.permutation_representative(); p
0 1 2 1 3
3 4 4 5 5 2 0
sage: p.stratum_component()
Q_2(6, -1^2)^nonhyp

sage: cc = QuadraticStratum([3,3],genus=2).non_hyperelliptic_component()
sage: p = cc.permutation_representative(); p
0 1 2 1 3
4 3 5 5 4 6 6 2 0
sage: p.stratum_component()
Q_2(3^2, -1^2)^nonhyp

sage: cc = QuadraticStratum(8).unique_component()
sage: p = cc.permutation_representative(); p
0 1 2 1 2 3
4 5 4 5 3 0
sage: p.stratum_component()
Q_3(8)^c

sage: Q = QuadraticStratum(4,4).unique_component()
sage: p = Q.permutation_representative(); p
0 1 2 3 2 3 4
5 6 5 6 1 4 0
sage: p.stratum_component()
Q_3(4^2)^c

sage: Q = QuadraticStratum({12:1,-1:4}).unique_component()
sage: p = Q.permutation_representative()
sage: p
0 1 2 1 2 3 3 4 4 5 5 6 6 7
8 9 8 9 7 0
sage: p.stratum()
Q_3(12, -1^4)
surface_dynamics.flat_surfaces.quadratic_strata.GOQSC#

alias of GenusOneQuadraticStratumComponent

surface_dynamics.flat_surfaces.quadratic_strata.GTHQSC#

alias of GenusTwoHyperellipticQuadraticStratumComponent

surface_dynamics.flat_surfaces.quadratic_strata.GTNQSC#

alias of GenusTwoNonhyperellipticQuadraticStratumComponent

surface_dynamics.flat_surfaces.quadratic_strata.GZQSC#

alias of GenusZeroQuadraticStratumComponent

class surface_dynamics.flat_surfaces.quadratic_strata.GenusOneQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum([2],genus=1).permutation_representative()
0 1 2 2
1 3 3 0
sage: QuadraticStratum([3],genus=1).permutation_representative()
0 1 2 2 3 3
1 4 4 0
sage: QuadraticStratum([1,1],genus=1).permutation_representative()
0 1 2 3 3
2 1 4 4 0
sage: Q = QuadraticStratum([2,1],genus=1)
sage: Q.permutation_representative(alphabet='abcdef')
a b c c d e e
d b f f a

TESTS:

sage: from surface_dynamics import *

sage: QuadraticStratum([1],genus=1).permutation_representative()
Traceback (most recent call last):
...
EmptySetError: The stratum is empty

sage: Q = QuadraticStratum(2,-1,-1,0)
sage: p = Q.permutation_representative()
sage: p
0 1 2 3 3
2 4 4 0 1
sage: p.stratum() == Q
True
class surface_dynamics.flat_surfaces.quadratic_strata.GenusTwoHyperellipticQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

TESTS:

sage: from surface_dynamics import *

sage: Q = QuadraticStratum([1,1,1,1],genus=2) sage: H = Q.hyperelliptic_component() sage: H.permutation_representative() 0 1 2 3 1 4 5 2 6 5 4 6 3 0

sage: Q = QuadraticStratum([2,1,1],genus=2) sage: H = Q.hyperelliptic_component() sage: H.permutation_representative(alphabet=’abcdef’) a b c b d e f e d f c a

sage: Q = QuadraticStratum([2,2],genus=2) sage: H = Q.hyperelliptic_component() sage: H.permutation_representative() 0 1 2 1 3 4 3 4 2 0

class surface_dynamics.flat_surfaces.quadratic_strata.GenusTwoNonhyperellipticQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

TESTS:

sage: from surface_dynamics import *

sage: Q = QuadraticStratum([6],genus=2)
sage: N = Q.non_hyperelliptic_component()
sage: N.permutation_representative()
0 1 2 1 3
3 4 4 5 5 2 0
sage: Q = QuadraticStratum([3,3],genus=2)
sage: N = Q.non_hyperelliptic_component()
sage: N.permutation_representative()
0 1 2 1 3
4 3 5 5 4 6 6 2 0
class surface_dynamics.flat_surfaces.quadratic_strata.GenusZeroQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum(-1,-1,-1,-1).permutation_representative()
0 1 1
2 2 0
sage: QuadraticStratum(1,genus=0).permutation_representative()
0 1 1
2 2 3 3 4 4 0
sage: QuadraticStratum(2,genus=0).permutation_representative()
0 1 1
2 2 3 3 4 4 5 5 0
sage: QuadraticStratum([1,1],genus=0).permutation_representative()
0 1 1
2 2 3 4 4 5 5 3 6 6 0
sage: QuadraticStratum([2,1],genus=0).permutation_representative()
0 1 1
2 2 3 3 4 5 5 6 6 4 7 7 0
surface_dynamics.flat_surfaces.quadratic_strata.HQSC#

alias of HyperellipticQuadraticStratumComponent

class surface_dynamics.flat_surfaces.quadratic_strata.HyperellipticQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = QuadraticStratum([6],genus=2).hyperelliptic_component()
sage: cc.permutation_representative()
0 1 2 3 4 1
5 4 3 2 5 0
sage: cc = QuadraticStratum([3,3],genus=2).hyperelliptic_component()
sage: cc.permutation_representative()
0 1 2 3 4 5 1
6 5 4 3 2 6 0
sage: cc = QuadraticStratum(10,10).hyperelliptic_component()
sage: cc.permutation_representative()
0 1 2 3 4 5 6 1 7 8 9 10 11
11 10 9 8 7 12 6 5 4 3 2 12 0
surface_dynamics.flat_surfaces.quadratic_strata.IEQSC#

alias of IrregularExceptionalQuadraticStratumComponent

class surface_dynamics.flat_surfaces.quadratic_strata.IrregularExceptionalQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = QuadraticStratum(9,-1).irregular_component()
sage: p = cc.permutation_representative(); p
0 1 2 3 4 1 2 3 4 5
5 6 6 0
sage: p.stratum_component()  # optional
Q_3(9, -1)^irr

sage: cc = QuadraticStratum(6,3,-1).irregular_component()
sage: p = cc.permutation_representative(); p
0 1 2 3 4 5 1 2 3 4 5 6
6 7 7 0
sage: p.stratum_component()
Q_3(6, 3, -1)^irr

sage: cc = QuadraticStratum(12).irregular_component()
sage: p = cc.permutation_representative(); p
0 1 2 3 4 5 6 5
7 6 4 7 3 2 1 0
sage: p.stratum_component()
Q_4(12)^irr
surface_dynamics.flat_surfaces.quadratic_strata.NQSC#

alias of NonhyperellipticQuadraticStratumComponent

class surface_dynamics.flat_surfaces.quadratic_strata.NonhyperellipticQuadraticStratumComponent(stratum)[source]#

Bases: ConnectedQuadraticStratumComponent

Non hyperelliptic component of stratum of quadratic differentials.

surface_dynamics.flat_surfaces.quadratic_strata.QSC#

alias of QuadraticStratumComponent

surface_dynamics.flat_surfaces.quadratic_strata.QuadraticStrata(genus=None, dimension=None, min_nb_poles=None, max_nb_poles=None, nb_poles=None, fake_zeros=False)[source]#

Quadratic strata.

INPUT:

  • genus - a non negative integer or None

  • dimension - a non negative integer or None

  • min_nb_poles, max_nb_poles - the minimum and maximum number of poles allowed

  • nb_poles - integer - the number of poles (if the option is set then the options min_nb_poles and max_nb_poles are ignored)

  • fake_zeros - boolean - whether to allow fake zeros or not

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStrata(genus=2); Q
Quadratic strata of genus 2 surfaces
sage: Q.cardinality()
+Infinity
sage: i = iter(Q)
sage: next(i)
Q_2(2^2)
sage: next(i)
Q_2(2, 1^2)
sage: next(i)
Q_2(1^4)
sage: next(i)
Q_2(5, -1)

sage: Q = QuadraticStrata(dimension=5); Q
Quadratic strata of dimension 5

sage: Q = QuadraticStrata(genus=3,max_nb_poles=6); Q
Quadratic strata of genus 3 surfaces with at most 6 poles
sage: Q.cardinality()
463
sage: for q in Q: print(q)
Q_3(8)
Q_3(7, 1)
Q_3(6, 2)
...
Q_3(2^2, 1^10, -1^6)
Q_3(2, 1^12, -1^6)
Q_3(1^14, -1^6)

sage: Q = QuadraticStrata(genus=2,nb_poles=0); Q
Quadratic strata of genus 2 surfaces with no pole
sage: for q in Q: print(q)
Q_2(2^2)
Q_2(2, 1^2)
Q_2(1^4)


sage: Q = QuadraticStrata(dimension=7,min_nb_poles=1,max_nb_poles=3); Q
Quadratic strata of dimension 7 with at least 1 and at most 3 poles
sage: for q in Q: print(q)
Q_3(8, 1, -1)
Q_3(7, 2, -1)
Q_3(6, 3, -1)
Q_3(5, 4, -1)
Q_2(2, 1^3, -1)
Q_3(10, -1^2)
Q_2(4, 1^2, -1^2)
Q_2(3, 2, 1, -1^2)
Q_2(2^3, -1^2)
Q_2(6, 1, -1^3)
Q_2(5, 2, -1^3)
Q_2(4, 3, -1^3)

sage: Q = QuadraticStrata(dimension=6, genus=0)
sage: Q
Quadratic strata of genus 0 surfaces and dimension 6
sage: for q in Q: print(q)
Q_0(1^2, -1^6)
Q_0(3, -1^7)

sage: Q = QuadraticStrata(dimension=5, genus=1, fake_zeros=True, nb_poles=0)
sage: for q in Q: print(q)
class surface_dynamics.flat_surfaces.quadratic_strata.QuadraticStrata_class[source]#

Bases: Strata

Base class for strata of quadratic differentials.

class surface_dynamics.flat_surfaces.quadratic_strata.QuadraticStrata_d(dimension, min_nb_poles, max_nb_poles, fake_zeros)[source]#

Bases: QuadraticStrata_class

Strata with prescribed dimension.

EXAMPLES:

sage: from surface_dynamics import *

sage: for q in QuadraticStrata(dimension=5): print(q)
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)

sage: Q = QuadraticStrata(dimension=6,nb_poles=1); Q
Quadratic strata of dimension 6 with 1 pole
sage: for q in Q: print(q)
Q_3(9, -1)
Q_2(3, 1^2, -1)
Q_2(2^2, 1, -1)
class surface_dynamics.flat_surfaces.quadratic_strata.QuadraticStrata_g(genus, min_nb_poles=None, max_nb_poles=None)[source]#

Bases: QuadraticStrata_class

Stratas of genus g surfaces.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStrata(genus=3); Q
Quadratic strata of genus 3 surfaces
sage: Q.cardinality()
+Infinity
sage: i = iter(Q)
sage: next(i)
Q_3(8)

sage: Q = QuadraticStrata(genus=2,max_nb_poles=1); Q
Quadratic strata of genus 2 surfaces with at most 1 pole
sage: Q.list()
[Q_2(2^2), Q_2(2, 1^2), Q_2(1^4), Q_2(5, -1), Q_2(4, 1, -1), Q_2(3, 2, -1), Q_2(3, 1^2, -1), Q_2(2^2, 1, -1), Q_2(2, 1^3, -1), Q_2(1^5, -1)]

sage: Q = QuadraticStrata(genus=4,nb_poles=3); Q
Quadratic strata of genus 4 surfaces with 3 poles
sage: Q.cardinality()
176
an_element_()#

Return the first element of this list of strata.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStrata(genus=4); Q
Quadratic strata of genus 4 surfaces
sage: Q.first()
Q_4(12)

sage: Q = QuadraticStrata(genus=3,nb_poles=1); Q
Quadratic strata of genus 3 surfaces with 1 pole
sage: Q.first()
Q_3(9, -1)

sage: Q = QuadraticStrata(genus=3,min_nb_poles=2); Q
Quadratic strata of genus 3 surfaces with at least 2 poles
sage: Q.first()
Q_3(10, -1^2)
first()[source]#

Return the first element of this list of strata.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStrata(genus=4); Q
Quadratic strata of genus 4 surfaces
sage: Q.first()
Q_4(12)

sage: Q = QuadraticStrata(genus=3,nb_poles=1); Q
Quadratic strata of genus 3 surfaces with 1 pole
sage: Q.first()
Q_3(9, -1)

sage: Q = QuadraticStrata(genus=3,min_nb_poles=2); Q
Quadratic strata of genus 3 surfaces with at least 2 poles
sage: Q.first()
Q_3(10, -1^2)
last()[source]#

Return the last element of this list of strata.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStrata(genus=2, nb_poles=0); Q
Quadratic strata of genus 2 surfaces with no pole
sage: Q.last()
Q_2(1^4)

sage: Q = QuadraticStrata(genus=0); Q
Quadratic strata of genus 0 surfaces
sage: Q.last()
Traceback (most recent call last):
...
NotImplementedError: infinite list

TESTS:

sage: from surface_dynamics import *

sage: Q = QuadraticStrata(genus=1,nb_poles=2)
sage: Q.list()[-1] == Q.last()
True

sage: Q = QuadraticStrata(genus=1,max_nb_poles=2)
sage: Q.list()[-1] == Q.last()
True

sage: Q = QuadraticStrata(genus=0,nb_poles=10)
sage: Q.list()[-1] == Q.last()
True
class surface_dynamics.flat_surfaces.quadratic_strata.QuadraticStrata_gd(genus, dimension, min_nb_poles, max_nb_poles, fake_zeros)[source]#

Bases: QuadraticStrata_class

Quadratic strata with presrcribed genus and dimension.

class surface_dynamics.flat_surfaces.quadratic_strata.QuadraticStratum(zeros, nb_poles, nb_fake_zeros)[source]#

Bases: Stratum

Stratum of quadratic differentials.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStratum(15,-1,-1,-1); Q
Q_4(15, -1^3)
sage: Q.components()
[Q_4(15, -1^3)^c]

sage: Q = QuadraticStratum(6,6); Q
Q_4(6^2)
sage: Q.components()
[Q_4(6^2)^hyp, Q_4(6^2)^reg, Q_4(6^2)^irr]
dimension()[source]#

Returns the complex dimension of this stratum.

The complex dimension is the number of intervals minus one of any linear involution associated to this stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum({-1:4}).dimension()
2
genus()[source]#

Returns the genus.

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum(-1,-1,-1,-1).genus()
0
has_hyperelliptic_component()[source]#

Returns True if and only if self has a connected component which contains only hyperelliptic surfaces.

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum(2,2).has_hyperelliptic_component()
True
sage: QuadraticStratum(3,1).has_hyperelliptic_component()
False
has_non_hyperelliptic_component()[source]#

Test whether this stratum has a non hyperelliptic component.

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum(10,10).has_non_hyperelliptic_component()
True
sage: QuadraticStratum(6,6).has_non_hyperelliptic_component()
False
has_regular_and_irregular_components()[source]#

Test whether this component has a pair of regular, irregular components.

The list of strata of quadratic differentials that admit such a pair are:

in genus 3: Q(9,-1), Q(6,3,-1), Q(3,3,3,-1) in genus 4: Q(12), Q(9,3), Q(6,6), Q(6,3,3), Q(3,3,3,3)

EXAMPLES:

sage: from surface_dynamics import *

 sage: QuadraticStratum(9,-1).has_regular_and_irregular_components()
 True
 sage: QuadraticStratum(11,1).has_regular_and_irregular_components()
 False
hyperelliptic_component()[source]#

Returns the hyperelliptic component of self (or raise a ValueError).

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum(2,2).hyperelliptic_component()
Q_2(2^2)^hyp

sage: QuadraticStratum(3,1).hyperelliptic_component()
Traceback (most recent call last):
...
ValueError: the stratum has no hyperelliptic component
irregular_component()[source]#

Returns the irregular component of that stratum or raise a ValueError.

EXAMPLES:

sage: from surface_dynamics import *

 sage: QuadraticStratum(3,3,3,-1).irregular_component()
 Q_3(3^3, -1)^irr
 sage: QuadraticStratum(2,2).irregular_component()
 Traceback (most recent call last):
 ...
 ValueError: no irregular component for this stratum
nb_fake_zeros()[source]#

Return the number of fake zeros of this quadratic stratum.

nb_poles()[source]#

Return the number of poles of this quadratic stratum.

nb_zeros(poles=True, fake_zeros=True)[source]#

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum({-1:4}).nb_zeros()
4
sage: QuadraticStratum({-1:4,1:4}).nb_zeros()
8
non_hyperelliptic_component()[source]#

Returns the non hyperelliptic component of this stratum (or raise a ValueError).

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum(10,10).non_hyperelliptic_component()
Q_6(10^2)^nonhyp
sage: QuadraticStratum(2,2).non_hyperelliptic_component()
Traceback (most recent call last):
...
ValueError: no non hyperelliptic component
orientation_cover(fake_zeros=False)[source]#

Return the stratum of Abelian differentials which contains the set of orientation cover of quadratic differentials in this stratum.

OPTIONS:

  • fake_zeros - boolean - if True, add fake zeros which corresponds to the double cover of poles.

EXAMPLES:

sage: from surface_dynamics import *

sage: q = QuadraticStratum({4:1,-1:4}); q
Q_1(4, -1^4)
sage: a1 = q.orientation_cover(); a1
H_3(2^2)
sage: q.orientation_cover(fake_zeros=True)
H_3(2^2, 0^4)

For hyperelliptic strata (orientation cover of quadratic strata of the form Q(n,-1^{n+4})) the dimension coincide. From [Lan08] we know that it only happens for those ones:

sage: q = QuadraticStratum(4,genus=0); q
Q_0(4, -1^8)
sage: q.dimension()
7
sage: q.orientation_cover().dimension()
7

sage: q = QuadraticStratum(3,1,genus=0); q
Q_0(3, 1, -1^8)
sage: q.dimension()
8
sage: a = q.orientation_cover(); a
H_4(4, 2)
sage: a.dimension()
9

TESTS:

sage: QuadraticStratum({-1:4}).orientation_cover()
H_1(0)
random_cylindric_permutation()[source]#

Return a random cylindric permutation that belongs to this stratum.

EXAMPLES:

sage: from surface_dynamics import *

 sage: Q = QuadraticStratum(4,4)
 sage: Q.random_cylindric_permutation()  # random
 0 1 2 3 4 5 1 5
 2 6 3 6 4 0
rank()[source]#

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 QuadraticStratum, QuadraticStrata

sage: QuadraticStratum({-1: 4}).rank()
1
sage: QuadraticStratum({-1:4, 0:5}).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)
regular_component()[source]#

Returns the regular component of that stratum or raise a ValueError.

EXAMPLES:

sage: from surface_dynamics import *

 sage: QuadraticStratum(12).regular_component()
 Q_4(12)^reg
 sage: QuadraticStratum(2,2,2,2).regular_component()
 Traceback (most recent call last):
 ...
 ValueError: no regular component for this stratum
spin()[source]#

Return the spin structure (None, 0 or 1) of that component.

Any quadratic differential has a canonic double cover (called the orientation cover) which is a surface, generally of higher genera, with an Abelian differential. The spin structure of the quadratic differential is the spin structure of that double cover.

The spin is None if any degree of zero of the quadratic differential is congruent to 2 mod 4. Otherwise, denoting respectively k1 and k3 the number of degree of zero congruent to 1 and 3 modulo 4 we have

..MATH:

spin = ((k1-k3)/4) mod 2

The proof of that formula is the object of [Lan04].

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum(1,3).spin()
0
sage: QuadraticStratum(1,3,genus=1).spin()
1
sage: QuadraticStratum(2,2).spin() is None
True
zeros(poles=True, fake_zeros=True)[source]#

Returns the list of zeros of self.

EXAMPLES:

sage: from surface_dynamics import *

sage: QuadraticStratum({-1:4}).zeros()
(-1, -1, -1, -1)
sage: QuadraticStratum({1:8}).zeros()
(1, 1, 1, 1, 1, 1, 1, 1)

sage: QuadraticStratum({-1:4}).zeros(poles=False)
()
class surface_dynamics.flat_surfaces.quadratic_strata.QuadraticStratumComponent(stratum)[source]#

Bases: StratumComponent

Generic class for component of quadratic stratum.

lyapunov_exponents_H_minus(**kargs)[source]#

Compute the H^- Lyapunov exponents.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStratum({1:3, -1:3}).unique_component()
sage: Q.lyapunov_exponents_H_minus(nb_iterations=2**21) # abs tol .05
[1.000, 0.369, 0.176]

sage: R = QuadraticStratum([3,3,3,-1]).regular_component()
sage: R.lyapunov_exponents_H_minus(nb_iterations=2**21) # abs tol .05
[1.000, 0.328, 0.1899, 0.0820]
lyapunov_exponents_H_plus(*args, **kargs)[source]#

Compute the H^+ part of Lyapunov exponents spectrum.

All arguments and keywords are sent to ?

EXAMPLES:

sage: from surface_dynamics import *

sage: R = QuadraticStratum([3,3,3,-1]).regular_component()
sage: R.lyapunov_exponents_H_plus(nb_iterations=2**21) # abs tol .05
[0.596, 0.405, 0.202]
sage: sum(_) # abs tol .05
1.2

sage: R = QuadraticStratum([2,2,2,2]).unique_component()
sage: R.lyapunov_exponents_H_plus(nb_iterations=2**21) # abs tol .05
[0.651, 0.469, 0.243]
sage: sum(_) # abs tol .05
1.3636
one_cylinder_diagram()[source]#

Return a separatrix diagram with one cylinder that belongs to this component of stratum.

EXAMPLES:

sage: from surface_dynamics import *

sage: Q = QuadraticStratum({1:1,-1:5})
sage: c = Q.unique_component().one_cylinder_diagram()
sage: c
(0,0,1,1,2,2)-(3,3)
sage: c.stratum() == Q
True

sage: Q = QuadraticStratum(5,-1)
sage: c = Q.unique_component().one_cylinder_diagram()
sage: c
(0,1,1,2)-(3,0,3,2)
sage: c.stratum() == Q
True

sage: QuadraticStratum({-1:4}).unique_component().one_cylinder_diagram()
(0,0)-(1,1)
sage: QuadraticStratum({-1:4,0:1}).unique_component().one_cylinder_diagram()
(0,0)-(1,1,2,2)
orientation_cover_component(fake_zeros=False)[source]#

Return the connected component of Abelian stratum component which contains the set of orientation cover of quadratic differentials in this connected component.

ALGORITHM:

The spin only depends on the component and the only components for which the double cover belongs to a hyperelliptic component are Q(k,-1^k+4) and Q(2g-1,2g-1,-1,-1)^hyp

OPTIONS:

  • fake_zeros - boolean - if True, add fake zeros which corresponds to the double cover of poles.

EXAMPLES:

sage: from surface_dynamics import *

 sage: cc = QuadraticStratum(5,genus=0).unique_component()
 sage: cc.orientation_cover_component()
 H_4(6)^hyp

 sage: cc = QuadraticStratum(5,genus=1).unique_component()
 sage: cc.orientation_cover_component()
 H_4(6)^odd

 sage: cc = QuadraticStratum(5,genus=2).unique_component()
 sage: cc.orientation_cover_component()
 H_4(6)^even

 sage: cc = QuadraticStratum(1,1,genus=0).unique_component()
 sage: cc.orientation_cover_component()
 H_3(2^2)^odd

 sage: cc = QuadraticStratum(4,genus=0).unique_component()
 sage: cc.orientation_cover_component()
 H_3(2^2)^hyp

 sage: cc = QuadraticStratum(1,1,genus=1).unique_component()
 sage: cc.orientation_cover_component()
 H_3(2^2)^hyp
random_cylindric_permutation(nsteps=64)[source]#

Return a cylindric permutation of the form p = ((0,...),(..., 0)) where 0 can be any label.

EXAMPLES:

sage: from surface_dynamics import *

 sage: Q = QuadraticStratum({4:1,-1:4}); Q
 Q_1(4, -1^4)
 sage: c = Q.unique_component()
 sage: p = c.random_cylindric_permutation()
 sage: p.stratum_component()
 Q_1(4, -1^4)^c

 sage: Q = QuadraticStratum(6,6)
 sage: c_hyp, c_reg, c_irr = Q.components()
 sage: (c_hyp, c_reg, c_irr)
 (Q_4(6^2)^hyp, Q_4(6^2)^reg, Q_4(6^2)^irr)

 sage: all(c_hyp.random_cylindric_permutation().stratum_component() == c_hyp for _ in range(4))
 True
 sage: all(c_reg.random_cylindric_permutation().stratum_component() == c_reg for _ in range(4))
 True
 sage: all(c_irr.random_cylindric_permutation().stratum_component() == c_irr for _ in range(4))
 True
surface_dynamics.flat_surfaces.quadratic_strata.REQSC#

alias of RegularExceptionalQuadraticStratumComponent

class surface_dynamics.flat_surfaces.quadratic_strata.RegularExceptionalQuadraticStratumComponent(stratum)[source]#

Bases: QuadraticStratumComponent

This class is intended to be called internally rather than directly. Call only with appropriate parameters, in particular correct genus: no consistency check inside, no prediction as to what may happen otherwise.

permutation_representative(reduced=True, alphabet=None, relabel=True)[source]#

Returns a generalized permutation representative.

EXAMPLES:

sage: from surface_dynamics import *

sage: cc = QuadraticStratum(9,-1).regular_component()
sage: p = cc.permutation_representative(); p
0 1 2 1 2 3 3 4
5 6 5 6 4 0
sage: p.stratum_component()
Q_3(9, -1)^reg

sage: cc = QuadraticStratum(6,3,-1).regular_component()
sage: p = cc.permutation_representative(); p
0 1 2 3 1 2 4 4 5
6 7 6 7 3 5 0
sage: p.stratum_component()
Q_3(6, 3, -1)^reg

sage: cc = QuadraticStratum(12).regular_component()
sage: p = cc.permutation_representative(); p
0 1 2 1 2 3 4 3 4 5
5 6 7 6 7 0
sage: p.stratum_component()
Q_4(12)^reg

Masur Veech volumes#

Masur-Veech volumes of Abelian strata and their connected components

surface_dynamics.flat_surfaces.masur_veech_volumes.masur_veech_volume(C, rational, method)[source]#

Return the Masur-Veech volume of the stratum or component of stratum C.

INPUT:

  • rational (boolean) - if False (default) return the Masur-Veech volume and if True return the Masur-Veech volume divided by zeta(2g).

  • method - the method to use to compute the volume either

    • "table" - for a table lookup (all strata up to dimension 9 and some strata up to dimension 11)

    • "CMSZ" - the Chen-Möller-Sauvaget-Zagier recursion (currently only implemented for the principal stratum)

TESTS:

sage: from surface_dynamics import AbelianStratum
sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import masur_veech_volume

sage: H4 = AbelianStratum(4)
sage: masur_veech_volume(H4, False, 'table')
61/108864*pi^6
sage: masur_veech_volume(H4, False, 'CMSZ')
61/108864*pi^6
sage: masur_veech_volume(H4.hyperelliptic_component(), False, 'table')
1/6720*pi^6
sage: masur_veech_volume(H4.hyperelliptic_component(), False, 'CMSZ')
1/6720*pi^6
sage: masur_veech_volume(H4.odd_component(), False, 'table')
1/2430*pi^6
sage: masur_veech_volume(H4.odd_component(), False, 'CMSZ')
1/2430*pi^6

sage: H6 = AbelianStratum(6)
sage: all(masur_veech_volume(C, True, 'table') == masur_veech_volume(C, True, 'CMSZ') for C in H6.components())
True
surface_dynamics.flat_surfaces.masur_veech_volumes.minimal_strata_CMSZ(gmax, rational=False)[source]#

Return the volumes of cH(2g-2) for the genus g going from 1 up to gmax-1.

The algorithm is the one from Sauvaget [Sau18] involving an implicit equation. As explained in [CheMoeSauZag20], one could go through Lagrange inversion. Note that they miss factor 2 in their theorem 4.1.

EXAMPLES:

sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import minimal_strata_CMSZ
sage: minimal_strata_CMSZ(6, True)
[2, 3/4, 305/576, 87983/207360, 1019547/2867200]
sage: minimal_strata_CMSZ(6, False)
[1/3*pi^2,
 1/120*pi^4,
 61/108864*pi^6,
 12569/279936000*pi^8,
 12587/3311616000*pi^10]

sage: from surface_dynamics import AbelianStratum
sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import masur_veech_volume
sage: for rat in [True, False]:
....:     V0, V2, V4, V6 = minimal_strata_CMSZ(5, rational=rat)
....:     MV0 = masur_veech_volume(AbelianStratum(0), rat, 'table')
....:     assert V0 == MV0, (V0, MV0, rat)
....:     MV2 = masur_veech_volume(AbelianStratum(2), rat, 'table')
....:     assert V2 == MV2, (V2, MV2, rat)
....:     MV4 = masur_veech_volume(AbelianStratum(4), rat, 'table')
....:     assert V4 == MV4, (V4, MV4, rat)
....:     MV6 = masur_veech_volume(AbelianStratum(6), rat, 'table')
....:     assert V6 == MV6, (V6, MV6, rat)
surface_dynamics.flat_surfaces.masur_veech_volumes.minimal_strata_hyp(g, rational=False)[source]#

Return the volume of the hyperelliptic component H^{hyp}(2g-2).

The explicit formula appears in section 6.5 of [CheMoeSauZag20].

EXAMPLES:

sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import minimal_strata_hyp
sage: minimal_strata_hyp(2)
1/120*pi^4
sage: minimal_strata_hyp(4)
1/580608*pi^8
sage: minimal_strata_hyp(10)
1/137733277917118464000*pi^20
sage: minimal_strata_hyp(10, rational=True)
668525/10499279483305984
surface_dynamics.flat_surfaces.masur_veech_volumes.minimal_strata_spin_diff(gmax, rational=False)[source]#

Return the differences of volumes between even and odd components in H(2g-2) for the genus g going from 1 up to gmax-1.

If there are no even/odd components, the corresponding total volume is 0. Formulas are from [CheMoeSauZag20].

EXAMPLES:

sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import minimal_strata_spin_diff
sage: minimal_strata_spin_diff(5)
[-1/3*pi^2, -1/120*pi^4, -143/544320*pi^6, -15697/1959552000*pi^8]
sage: minimal_strata_spin_diff(5, rational=True)
[-2, -3/4, -143/576, -15697/207360]