Commit 0245c9ee authored by Vincent Delecroix's avatar Vincent Delecroix

Geometric flip on linear subvarieties

... with the hope to compute GL(2,R)-orbit closures
parent 0542e788
......@@ -8,7 +8,9 @@ from __future__ import absolute_import
from .constants import RED, BLUE, HORIZONTAL, VERTICAL
from .triangulation import Triangulation
from .veering_triangulation import VeeringTriangulation
from .cover import TriangulationCover
from .veering_triangulation import VeeringTriangulation, VeeringTriangulations
from .measured_train_track import MeasuredTrainTrack
from .automaton import Automaton
from .env import sage
......
......@@ -27,7 +27,7 @@ try:
except ImportError:
ppl = None
msg = {
error_msg = {
'sage': 'the function {} can only be called when running inside of Sage. See http://www.sagemath.org/',
'surface_dynamics': 'the function {} only works when the package surface_dynamics is installed. See https://pypi.org/project/surface_dynamics/ for instructions.',
......@@ -37,13 +37,15 @@ msg = {
'pplpy': 'the function {} only works when the package pplpy is installed. See https://pypi.org/project/pplpy/ for instructions.'
}
mods = {
'sage': sage is not None,
'flipper': flipper is not None,
'ppl': ppl is not None,
'surface_dynamics': surface_dynamics is not None
missing_mods = {
'sage': sage is None,
'flipper': flipper is None,
'ppl': ppl is None,
'surface_dynamics': surface_dynamics is None
}
# TODO: use the traceback to find out who called this function!
# https://docs.python.org/2/library/traceback.html#traceback-examples
def require_package(mod_name, caller):
if mods[mod_name] is None:
if missing_mods[mod_name]:
raise ValueError(error_msg.format(caller))
......@@ -9,6 +9,7 @@ Note:
"""
import math
import itertools
from sage.structure.sequence import Sequence
......@@ -164,16 +165,13 @@ class FlatVeeringTriangulationLayout:
- ``blue_cylinders`` and ``red_cylinders`` - optional list of edges
"""
if isinstance(triangles, Triangulation):
self._triangulation = triangles.copy()
else:
self._triangulation = Triangulation(triangles)
self._triangulation = Triangulation(triangles)
n = self._triangulation.num_half_edges()
m = self._triangulation.num_edges()
if len(vectors) == m:
ep = self._triangulation._ep
ep = self._triangulation.edge_permutation(copy=False)
for e in range(m):
E = ep[e]
if e != E and E < m:
......@@ -215,15 +213,16 @@ class FlatVeeringTriangulationLayout:
self._triangulation._check()
n = self._triangulation.num_half_edges()
ep = self._triangulation._ep
ep = self._triangulation.edge_permutation(copy=False)
vectors = self._vectors
for a in range(n):
A = ep[a]
u = self._vectors[a]
v = self._vectors[A]
u = vectors[a]
v = vectors[A]
if u != v and u != -v:
raise ValueError('ep[%s] = %s but vec[%s] = %s' % (a, u, A, v))
vectors = self._vectors
for a,b,c in self._triangulation.faces():
va = vectors[a]
vb = vectors[b]
......@@ -781,3 +780,62 @@ class FlatVeeringTriangulationLayout:
G.set_aspect_ratio(1)
G.axes(False)
return G
def train_track(self, slope=VERTICAL):
r"""
Return the measured train-track corresponding to the vertical
(or horizontal) direction.
EXAMPLES::
sage: from veerer import *
sage: T = VeeringTriangulation("(0,1,2)(~0,~1,3)", "BRRR")
sage: F = T.flat_structure_min()
sage: F.train_track()
MeasuredTrainTrack(Triangulation("(0,1,2)(3,~0,~1)"), (1, 1, 2, 2, 1, 1))
sage: F.train_track(HORIZONTAL)
MeasuredTrainTrack(Triangulation("(0,1,2)(3,~0,~1)"), (1, 2, 1, 1, 2, 1))
"""
from .measured_train_track import MeasuredTrainTrack
if slope == VERTICAL:
return MeasuredTrainTrack(self._triangulation, [x.abs() for x,y in self._vectors])
elif slope == HORIZONTAL:
return MeasuredTrainTrack(self._triangulation, [y.abs() for x,y in self._vectors])
def plot_orbit(self, p, n, slope=VERTICAL, **kwds):
r"""
Plot a piece of orbit of the vertical flow.
EXAMPLES::
sage: from veerer import *
sage: T = VeeringTriangulation("(0,1,2)(~0,~1,3)", "BRRR")
sage: F = T.flat_structure_min()
sage: F.plot() + F.plot_orbit((0,1/4),4)
Graphics object consisting of 19 graphics primitives
"""
G = Graphics()
if slope == HORIZONTAL:
raise NotImplementedError
tt = self.train_track(slope)
L = tt.lengths()
V = self._vectors
O = [q for q in itertools.islice(tt.orbit(p), 2*n)]
if self._pos is None:
self.set_pos()
for i in range(n):
i1, x1 = O[2*i]
i2, x2 = O[2*i+1]
p1 = self._pos[i1]
p2 = self._pos[i2]
G += line2d([p1 + x1 / L[i1] * V[i1], p2 + x2 / L[i2] * V[i2]], **kwds)
return G
from sage.categories.fields import Fields
from sage.structure.sequence import Sequence
from .triangulation import Triangulation
_Fields = Fields()
class MeasuredTrainTrack(object):
r"""
Train-track endowed with a transverse measure.
"""
def __init__(self, triangulation, lengths, base_ring=None):
self._triangulation = Triangulation(triangulation)
n = self._triangulation.num_half_edges()
m = self._triangulation.num_edges()
ep = self._triangulation.edge_permutation(copy=False)
if len(lengths) == m:
for e in range(m):
E = ep[e]
if e != E and E < m:
raise ValueError("edge perm not in standard form")
lengths = list(lengths) + [lengths[ep[e]] for e in range(m,n)]
if len(lengths) != n:
raise ValueError('wrong number of vectors')
if base_ring is None:
lengths = Sequence(lengths)
base_ring = lengths.universe()
lengths = list(lengths)
else:
lengths = [base_ring.coerce(l) for l in lengths]
self._base_ring = base_ring
self._lengths = tuple(lengths)
fp = self._triangulation.face_permutation(copy=False)
for e in range(n):
E = ep[e]
if self._lengths[e] != self._lengths[E]:
raise ValueError("non-compatible length data")
# we record below whether the given size is (horizontally) big or not
self._edge_type = [None] * n
for a in range(n):
b = fp[a]
c = fp[b]
if lengths[a] >= lengths[b] and lengths[a] >= lengths[c]:
if lengths[a] != lengths[b] + lengths[c]:
raise ValueError("non-compatible length data")
self._edge_type[a] = 0
self._edge_type[b] = 1
self._edge_type[c] = 2
def lengths(self):
return self._lengths
def __repr__(self):
return "MeasuredTrainTrack({}, {})".format(
self._triangulation, self._lengths)
def __call__(self, p, iterations=1):
r"""
p = (i,x) where
i = half-edge
x = value
EXAMPLES::
sage: from veerer import *
sage: v0 = vector((1, 0, 1, 1))
sage: v1 = vector((0, 1, 1, 1))
sage: t = Triangulation("(0,1,2)(~0,~1,3)")
sage: tt = MeasuredTrainTrack(t, 2*v0 + 3*v1)
sage: tt((2,3/2))
(4, 3/2)
sage: tt((2,3/2),2) == tt((4,3/2))
True
sage: tt((2,3/2),5) == tt((4,3/2),4)
True
"""
it = self.orbit(p)
for _ in range(2*iterations):
next(it)
return next(it)
def orbit(self, p):
r"""
Return an iterator through the (infinite) orbit of p.
(intermediate steps are yielded as well)
"""
n = self._triangulation.num_half_edges()
ep = self._triangulation.edge_permutation(copy=False)
fp = self._triangulation.face_permutation(copy=False)
L = self._lengths
i, x = p
while True:
assert 0 <= i < n
assert 0 < x < self._lengths[i]
yield (i,x)
# 1. cross the tripode (first involution)
if self._edge_type[i] == 0:
# big edge
b = i
s1 = fp[b]
s2 = fp[s1]
if x < L[s2]:
i = s2
x = L[s2] - x
else:
i = s1
x = L[s1] + L[s2] - x
elif self._edge_type[i] == 1:
# first small edge
s1 = i
s2 = fp[s1]
b = fp[s2]
i = b
x = L[s1] + L[s2] - x
elif self._edge_type[i] == 2:
# second small edge
s2 = i
b = fp[s2]
s1 = fp[b]
i = b
x = L[s2] - x
yield (i,x)
# 2. pass through the edges (second involution)
i = ep[i]
x = L[i] - x
......@@ -1056,4 +1056,3 @@ def perms_canonical_labels(p, e=None):
m_win = m_test
return c_win, m_win
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment