Veering triangulation demo¶
- Authors:
Vincent Delecroix
Saul Schleimer
- License:
CC BY-NC-SA 3.0
27 Aug. 2018 Toronto
20 Sept. 2018 Temple
25 Sept. 2018 Villetaneuse and CUNY
veerer
is a Python and SageMath library for exploration of veering
triangulations. It is written by
Mark Bell,
Vincent Delecroix and
Saul Schleimer. It is
part of a project that also involve
Vaibhav Gadre and
Rodolfo Gutiérrez-Romo, see
arXiv:1909.00890 [math.DS].
veerer
works in conjunction with
the Python library pplpy (rational polytope computations and linear optimiation). Note that it is shipped with SageMath (see below).
The Python library PyNormaliz (polytope, in particular over number fields).
The software SageMath (plotting, linear algebra and many other things)
The SageMath library surface_dynamics (for analyzing stratum components)
To import all features from veerer one usually starts with the following lines:
sage: from veerer import * # random output due to deprecation warnings from realalg
sage: from surface_dynamics import * # optional - surface_dynamics
To input a triangulation in the program one needs to specify a list of
triangles (i, j, k)
and the pairing of edges is by convention given
by i <-> ~i
. The veering coloring is then specified by a list of
colors.
sage: # standard torus made of two triangles
sage: faces0 = '(0,1,2)(~0,~1,~2)'
sage: colours0 = 'RRB'
sage: T0 = VeeringTriangulation(faces0, colours0)
sage: T0.genus()
1
sage: T0.angles()
[2]
sage: T0.stratum() # optional - surface_dynamics
H_1(0)
sage: # triangulation is core if it carries some flat structure
sage: T0.is_core()
True
sage: FS0 = T0.flat_structure_min()
sage: FS0.plot().show(figsize=5)
sage: FFS0 = T0.flat_structure_geometric_middle()
sage: FFS0.plot().show(figsize=5)
sage: # an Abelian genus 2 example
sage: faces1 = '(0, ~3, 4)(1, 2, ~7)(3, ~1, ~2)(5, ~8, ~4)(6, ~5, 8)(7, ~6, ~0)'
sage: colours1 = 'RBRRBRBRB'
sage: T1 = VeeringTriangulation(faces1, colours1)
sage: T1.angles()
[6]
sage: T1.stratum() # optional - surface_dynamics
H_2(2)
sage: FS1 = T1.flat_structure_min()
sage: FS1.plot().show(figsize=5)
sage: FFS1 = T1.flat_structure_geometric_middle()
sage: FFS1.plot().show(figsize=5)
sage: # a quadratic genus 1 example
sage: faces2 = '(0,1,2)(~0,~3,~8)(3,5,4)(~4,~1,~5)(6,7,8)(~6,9,~2)'
sage: colours2 = 'BRBRBBBRBR'
sage: T2 = VeeringTriangulation(faces2, colours2)
sage: T2.angles()
[3, 3, 1, 1]
sage: T2.stratum() # optional - surface_dynamics
Q_1(1^2, -1^2)
sage: FS2 = T2.flat_structure_min()
sage: FS2.plot().show(figsize=5) # not tested (warning from matplotlib)
Viewing train-tracks!¶
Recall that a veering triangulation is just a pair of transversal train-tracks.
sage: TT_horiz = FS1.plot(horizontal_train_track=True, edge_labels=False)
sage: TT_vert = FS1.plot(vertical_train_track=True, edge_labels=False)
sage: graphics_array([TT_horiz, TT_vert], 1, 2).show(figsize=6)
sage: # constructing veering triangulations from a component stratum
sage: Q = Stratum([3,3,3,3], 2) # optional - surface_dynamics
sage: Qreg = Q.regular_component() # optional - surface_dynamics
sage: Qirr = Q.irregular_component() # optional - surface_dynamics
sage: vt = VeeringTriangulation.from_stratum(Qreg) # optional - surface_dynamics
sage: vt.stratum() # optional - surface_dynamics
Q_4(3^4)
sage: vt = VeeringTriangulation.from_stratum(Qirr) # optional - surface_dynamics
sage: vt.stratum() # optional - surface_dynamics
Q_4(3^4)
sage: # constructing a veering triangulation from a pseudo-Anosov homeomorphism
sage: import flipper # optional - flipper
sage: S_2_1 = flipper.load('S_2_1') # optional - flipper
sage: h = S_2_1.mapping_class('abcD') # optional - flipper
sage: print(h.nielsen_thurston_type()) # optional - flipper
Pseudo-Anosov
sage: VeeringTriangulation.from_pseudo_anosov(h) # optional - flipper
VeeringTriangulation("(0,~3,~1)(1,2,14)(3,~5,~13)(4,~12,~8)(5,6,~11)(7,8,13)(9,~6,~7)(10,~0,11)(12,~14,~10)(~9,~4,~2)", "RBRBRRBRBBBBRBR")
Core vs not core¶
sage: # start from our surface in H(2) and let us flip some edges
sage: S = T1.copy(mutable=True)
sage: print(S.is_core())
True
sage: print(S.flippable_edges())
[0, 2, 3, 7, 8]
sage: S.flip(3, BLUE)
sage: print(S.is_core())
True
sage: print(S.flippable_edges())
[3, 7, 8]
sage: S.flip(8, BLUE)
sage: print(S.is_core())
True
sage: print(S.flippable_edges())
[3, 4, 7, 8]
sage: S.flip(4, RED)
sage: print(S.is_core())
True
sage: print(S.flippable_edges())
[4, 7]
sage: FS = S.flat_structure_min()
sage: FS.plot()
Graphics object consisting of 37 graphics primitives
sage: # in the geometric setting, the flipped edge is forced to be BLUE
sage: S.flip(7, RED)
sage: S.is_core()
False
sage: print(S.train_track_polytope(HORIZONTAL))
Cone of dimension 4 in ambient dimension 9 made of 5 facets (backend=ppl)
sage: print(S.train_track_polytope(VERTICAL))
Cone of dimension 3 in ambient dimension 9 made of 3 facets (backend=ppl)
sage: # check that we indeed started with a core veering triangulation
sage: print(T1.train_track_polytope(HORIZONTAL))
Cone of dimension 4 in ambient dimension 9 made of 4 facets (backend=ppl)
sage: print(T1.train_track_polytope(VERTICAL))
Cone of dimension 4 in ambient dimension 9 made of 5 facets (backend=ppl)
Geometric polytope¶
A triangulation is geometric if it is the L^infinity-Delaunay triangulation of some flat structure
sage: # triangulation of some flat structure
sage: T0.is_geometric()
True
The geometric polytope that parametrizes the geometric vectors is a sub-polytope of the product of the two train-track polytopes.
sage: print(T1.is_geometric())
True
sage: print(T1.geometric_polytope())
Cone of dimension 8 in ambient dimension 18 made of 13 facets (backend=ppl)
Core automaton¶
The core automaton of a given triangulations T_0 is the directed graph whose vertices are core veering triangulations that can be reached from T_0 by a sequence of flips and there is a directed edge T_i to T_j if T_j is obtained from T_i by a flip.
sage: # T0 was the torus example
sage: from veerer import CoreAutomaton
sage: A0 = CoreAutomaton(T0)
sage: A0
Core veering automaton with 2 vertices
sage: print(A0.num_states(), A0.num_transitions())
2 4
sage: print(sum(vt.is_geometric() for vt in A0))
2
sage: print(sum(vt.is_cylindrical() for vt in A0))
2
sage: # T1 was the genus 2 example in H(2)
sage: A1 = CoreAutomaton(T1)
sage: print(A1.num_states(), A1.num_transitions())
86 300
sage: print(sum(vt.is_geometric() for vt in A1))
54
sage: print(sum(vt.is_cylindrical() for vt in A1))
24
sage: # T2 was the genus 1 example in Q(1^2, -1^2)
sage: A2 = CoreAutomaton(T2)
sage: print(A2.num_states(), A2.num_transitions())
1074 3620
sage: print(sum(vt.is_geometric() for vt in A2))
270
sage: print(sum(vt.is_cylindrical() for vt in A2))
196
Some data (orientable case)¶
component |
dim |
core |
geometric |
cylindrical |
---|---|---|---|---|
H(0) |
2 |
2 |
2 |
2 |
H(2) |
4 |
86 |
54 |
24 |
H(1,1) |
5 |
876 |
396 |
136 |
H(4)^hyp |
6 |
9116 |
2916 |
636 |
H(4)^odd |
6 |
47552 |
35476 |
1970 |
H(2,2)^hyp |
7 |
111732 |
24192 |
3934 |
H(2,2)^odd |
7 |
874750 |
711568 |
12740 |
H(3,1) |
7 |
2011366 |
1317136 |
33164 |
To give an idea about the complexity and timings when generating the above data, here are the steps involved. The timings are for the stratum component H(4)^hyp that is the fourth row in the above array: - generating the core graph ~20 secs for H(4)^hyp (the graph has 9116 vertices and 44664 edges) - filtering the geometric triangulations (single test involves a polytope computation) ~20 secs for H(4)^hyp - filtering cylindrical (single test is cheap) ~2 sec for H(4)^hyp
sage: H = Stratum([4], 1).hyperelliptic_component() # optional - surface_dynamics
sage: V = VeeringTriangulation.from_stratum(H) # optional - surface_dynamics
sage: AV = CoreAutomaton(V) # long time - ~21 secs # optional - surface_dynamics
sage: print(AV.num_states()) # long time - ~150 µs # optional - surface_dynamics
9116
sage: sum(v.is_geometric() for v in AV) # long time - ~21 secs # optional - surface_dynamics
2916
sage: sum(v.is_cylindrical() for v in AV) # long time - ~1.5 secs # optional - surface_dynamics
636
License¶
This document is published under the Creative Commons CC BY-SA 3.0.