Commit a114bfbb authored by Mark Bell's avatar Mark Bell

Merge branch 'master' of gitlab.com:videlec/veerer

parents ffc997e9 e3dbe8e1
Pipeline #54081339 failed with stage
in 11 minutes and 44 seconds
"""
Look at nice patterns of vertex cycles on a train-track.
We should probably be looking at nice patterns of *carried* curves!
"""
from veerer import *
from surface_dynamics import *
from sage.graphs.generic_graph_pyx import SubgraphSearch
def longest_chain(T):
'''Return the longest chain of vertex cycles on the veering triangulation T'''
cycles = T.vertex_cycles()
n = len(cycles)
adj = [x.intersection(y) for y in cycles for x in cycles]
I = matrix(ZZ, n, adj)
J = matrix(ZZ, n, [bool(x) for x in adj])
G = Graph(J)
m = 2
path = None
while True:
for V in SubgraphSearch(G, graphs.PathGraph(m), induced=True):
P = G.subgraph(V)
edges = P.edges(False)
if all(I[i,j] == 1 for (i,j) in edges):
print("found a path of length {}".format(m))
m += 1
path = edges[:]
break
else:
print("no path of length {}".format(m))
return path
r"""
The pseudo-Anosov abC on the torus.
The stratum is Q(1,1-,1,-1) but sadly we do not have the folded edges
by default. Also, this example has a symmetry that makes it live on
the sphere. We should figure out the quotient.
"""
import flipper
from veerer.layout import FlatVeeringTriangulationLayout
S = flipper.load("S_1_2")
f = S.mapping_class("abC")
V = FlatVeeringTriangulationLayout.from_pseudo_anosov(f)
V.flip(4)
V.flip(6)
V.flip(10)
V.flip(3)
V.flip(11)
V.flip(0)
......@@ -322,17 +322,7 @@ class Automaton(object):
sage: from surface_dynamics import *
sage: A = Automaton.from_stratum(AbelianStratum(2))
sage: A.statistics()
{0: 24,
1: 4,
2: 4,
48: 2,
80: 2,
112: 24,
113: 5,
114: 5,
120: 10,
125: 3,
126: 3}
{0: 24, 1: 4, 2: 4, 16: 28, 17: 5, 18: 5, 24: 10, 29: 3, 30: 3}
"""
from collections import defaultdict
d = defaultdict(int)
......
......@@ -26,10 +26,8 @@ SQUARETILED = 1 << 2
QUADRANGULABLE = 1 << 3
CYLINDRICAL = RED | BLUE
GEOMETRIC = 1 << 4
VBALANCED = 1 << 5
HBALANCED = 1 << 6
ST = SQUARETILED | GEOMETRIC | VBALANCED | HBALANCED
ST = SQUARETILED | GEOMETRIC
PROPERTIES_COLOURS = {
NONE : '#FFFFFF', # white
......@@ -43,12 +41,10 @@ PROPERTIES_COLOURS = {
}
def key_property(p):
return -((1<<8) * bool(p & BLUE) | \
(1<<7) * bool(p & RED) | \
(1<<6) * bool(p & SQUARETILED) | \
(1<<5) * bool(p & GEOMETRIC) | \
(1<<4) * bool(p & VBALANCED) | \
(1<<3) * bool(p & HBALANCED))
return -((1<<4) * bool(p & BLUE) | \
(1<<3) * bool(p & RED) | \
(1<<2) * bool(p & SQUARETILED) | \
(1<<1) * bool(p & GEOMETRIC))
def properties_to_string(p):
r"""
......@@ -58,7 +54,7 @@ def properties_to_string(p):
sage: from veerer.constants import *
sage: T = VeeringTriangulation("(0,1,8)(2,~7,~1)(3,~0,~2)(4,~5,~3)(5,6,~4)(7,~8,~6)", "BRRRRBRBR")
sage: properties_to_string(T.properties_code())
'red geometric h-balanced'
'red geometric'
sage: properties_to_string(ST|BLUE)
'blue square-tiled'
......@@ -92,13 +88,6 @@ def properties_to_string(p):
if p & GEOMETRIC:
s.append('geometric')
if p & VBALANCED and p & HBALANCED:
s.append('hv-balanced')
elif p & HBALANCED:
s.append('h-balanced')
elif p & VBALANCED:
s.append('v-balanced')
if s:
return ' '.join(s)
else:
......
......@@ -604,25 +604,61 @@ def perm_orbit(p, i):
j = p[j]
return res
def perm_on_list(p, t):
def perm_on_list(p, a, n=None, swap=None):
r"""
Action of the permutation ``p`` on the list ``t``.
Inplace action of permutation on list-like objects.
INPUT:
- ``p`` - permutation
- ``a`` - list, array
- ``n`` - (optional) size of permutation
- ``swap`` - (optional) a swap function
EXAMPLES::
sage: from veerer.permutation import perm_on_list
sage: perm_on_list([2,1,3,0], [2,1,2,0])
[3, 1, 3, 2]
sage: from veerer.permutation import *
sage: l = [0,1,2,3,4]
sage: p = [4,2,3,0,1]
sage: perm_on_list(p,l)
sage: l
[3, 4, 1, 2, 0]
Permutation action on matrix rows::
sage: m1 = matrix(ZZ, 5, 5, 1)
sage: m2 = matrix(ZZ, 5, 5, 1)
sage: m = matrix(ZZ, 5, 5, 1)
sage: p1 = perm_init([4,1,3,2,0])
sage: p2 = perm_init([1,0,3,4,2])
sage: perm_on_list(p1, m1, swap=sage.matrix.matrix0.Matrix.swap_rows)
sage: perm_on_list(p2, m2, swap=sage.matrix.matrix0.Matrix.swap_rows)
sage: perm_on_list(perm_compose(p1, p2), m, swap=sage.matrix.matrix0.Matrix.swap_rows)
sage: m == m2 * m1
True
"""
return [p[i] for i in t]
def perm_on_array(p, a):
n = len(p)
b = array('l', [-1]*n)
if n is None:
n = len(p)
seen = [False] * n
for i in range(n):
b[p[i]] = a[i]
return b
if seen[i]:
continue
seen[i] = True
j = p[i]
while seen[j] is False:
if swap:
swap(a, i, j)
else:
tmp = a[i]
a[i] = a[j]
a[j] = tmp
seen[j] = True
j = p[j]
# WARNING: this is NOT inplace
def perm_on_cyclic_list(p, t):
r"""
Action of the permutation ``p`` on the list ``t`` up to cyclic order.
......
......@@ -1145,7 +1145,7 @@ class Triangulation(object):
....: S.relabel(p)
....: assert S == T
The sphere example (3 symmetries)::
The sphere example (3 symmetries)::
sage: fp = array('l', [1, 2, 0])
sage: ep = array('l', [0, 1, 2])
......@@ -1160,12 +1160,24 @@ class Triangulation(object):
....: S = T.copy()
....: S.relabel(p)
....: assert S == T
An example with no automorphism::
sage: T = Triangulation("(0,1,2)(3,4,5)(~0,~3,6)")
sage: p = T._relabelling_from(0)
sage: T.relabel(p)
sage: for i in range(1, 9):
....: p = T._relabelling_from(i)
....: S = T.copy()
....: S.relabel(p)
....: S._check()
....: assert S != T
"""
n = self._n
ep = self._ep
vp = self._vp
k = 0 # current available label at the front.
k = 0 # current available label at the front.
m = n - 1 # current available label at the back.
relabelling = array('l', [-1] * n)
relabelling[start_edge] = 0
......
......@@ -54,6 +54,26 @@ def ppl_cone_from_hashable(args):
P.add_constraint(sum(coeff * ppl.Variable(i) for i,coeff in enumerate(constraint)) >= 0)
return P
def relabel_on_edges(ep, r, n, m):
r"""
- ep - edge permutation
- r - relabelling permutation
- n - num half edges
- m - num edges
"""
rr = [-1] * m
for i in range(m):
j = r[i]
k = r[ep[i]]
if j < k:
rr[i] = j
else:
rr[i] = k
return rr
class VeeringTriangulation(Triangulation):
r"""
Veering triangulation.
......@@ -92,7 +112,7 @@ class VeeringTriangulation(Triangulation):
sage: VeeringTriangulation.from_pseudo_anosov(h)
VeeringTriangulation("(0,~3,~1)...(12,~14,~10)(~2,~9,~4)", "RBRBRRBRBBBBRBR")
"""
__slots__ = ['_colouring', '__curver']
__slots__ = ['_colouring']
def __init__(self, triangulation, colouring, check=True):
Triangulation.__init__(self, triangulation, check=False)
......@@ -202,7 +222,7 @@ class VeeringTriangulation(Triangulation):
sage: o = Origami('(1,2)', '(1,3)')
sage: T = VeeringTriangulation.from_square_tiled(o)
sage: T
VeeringTriangulation("(0,1,2)(3,4,5)(6,7,8)(~8,~0,~7)(~6,~1,~5)(~4,~2,~3)", "RBBRBBRBB")
VeeringTriangulation("(0,1,2)(3,4,5)(6,7,8)(~8,~0,~7)(~6,~1,~5)(~4,~2,~3)", "RRBRRBRRB")
sage: o.stratum()
H_2(2)
sage: T.stratum()
......@@ -459,10 +479,6 @@ class VeeringTriangulation(Triangulation):
sage: T.to_curver()
[(~2, ~0, ~1), (0, 1, 2)]
"""
try:
return self.__curver
except AttributeError:
pass
require_package('curver', 'to_curver')
ep = self._ep
F = []
......@@ -748,7 +764,6 @@ class VeeringTriangulation(Triangulation):
print("Warning: alternating_square is not carefullly defined with GREEN/PURPLE edges")
return all(colours[f] != colours[(f+1) % 4] for f in range(4))
def vertex_cycles(self, slope=VERTICAL):
r"""
Return the vertex cycles as curves on the (curver) triangulation.
......@@ -766,7 +781,7 @@ class VeeringTriangulation(Triangulation):
"""
require_package('curver', 'vertex_cycles')
polytope = self.train_track_polytope(slope=slope)
rays = [gen for gen in polytope.generators() if gen.is_ray()]
rays = [g for g in polytope.generators() if g.is_ray()]
T = self.to_curver()
return [T.lamination([int(x) for x in ray.coefficients()]) for ray in rays]
......@@ -976,11 +991,16 @@ class VeeringTriangulation(Triangulation):
sage: T, s, t = VeeringTriangulations.L_shaped_surface(2, 3, 4, 5, 1, 2)
sage: Gx = matrix(ZZ, [s, t])
sage: for _ in range(10):
....: p = perm_random_centralizer(T.edge_permutation(copy=False))
....: p = T._relabelling_from(choice(range(9)))
....: T.relabel(p, Gx=Gx)
....: T._set_switch_conditions(T._tt_check, Gx.row(0), VERTICAL)
....: T._set_switch_conditions(T._tt_check, Gx.row(1), VERTICAL)
sage: from veerer.permutation import perm_random_centralizer
sage: T, s, t = VeeringTriangulations.L_shaped_surface(2, 3, 4, 5, 1, 2)
sage: Gx = matrix(ZZ, [s, t])
sage: p = [8, 7, 0, 6, 2, 5, 4, 3, 1]
Composing relabelings and permutation composition::
sage: from veerer.permutation import perm_compose
......@@ -1024,19 +1044,13 @@ class VeeringTriangulation(Triangulation):
if Lx:
raise NotImplementedError
if Gx:
seen = [False] * self.num_edges()
for c in perm_cycles(p):
c0 = self._norm(c[0])
seen[c0] = True
for i in range(1,len(c)):
ci = self._norm(c[i])
if seen[ci]:
break
seen[ci] = True
Gx.swap_columns(c0, ci)
m = self.num_edges()
rr = relabel_on_edges(self._ep, p, self._n, m)
for c in perm_cycles(rr, False, m):
for i in range(1, len(c)):
Gx.swap_columns(c[0], c[i])
Triangulation.relabel(self, p)
self._colouring = perm_on_array(p, self._colouring)
perm_on_list(p, self._colouring)
def _automorphism_good_starts(self):
r"""
......@@ -1170,7 +1184,8 @@ class VeeringTriangulation(Triangulation):
fp = perm_conjugate(self._fp, relabelling)
ep = perm_conjugate(self._ep, relabelling)
cols = perm_on_array(relabelling, self._colouring)
cols = self._colouring[:]
perm_on_list(relabelling, cols)
T = (cols, fp, ep)
if best is None or T == best:
......@@ -1189,6 +1204,31 @@ class VeeringTriangulation(Triangulation):
def best_relabelling(self, all=False):
r"""
EXAMPLES::
sage: from veerer import *
sage: T, s, t = VeeringTriangulations.L_shaped_surface(2, 3, 4, 5, 1, 2)
sage: Gx = matrix(ZZ, [s,t])
sage: Gx.echelonize()
sage: for i in range(9):
....: p = T._relabelling_from(i)
....: S = T.copy()
....: S.relabel(p)
....: S._check()
TESTS::
sage: from veerer import *
sage: from veerer.permutation import *
sage: T, s, t = VeeringTriangulations.L_shaped_surface(2, 3, 4, 5, 1, 2)
sage: Gx = matrix(ZZ, [s,t])
sage: Gx.echelonize()
sage: T._set_switch_conditions(T._tt_check, Gx.row(0), VERTICAL)
sage: T._set_switch_conditions(T._tt_check, Gx.row(1), VERTICAL)
sage: p = T._relabelling_from(8)
sage: T.relabel(p, Gx=Gx)
sage: T._set_switch_conditions(T._tt_check, Gx.row(0), VERTICAL)
sage: T._set_switch_conditions(T._tt_check, Gx.row(1), VERTICAL)
"""
best = None
if all:
......@@ -1199,7 +1239,8 @@ class VeeringTriangulation(Triangulation):
# relabelled data
fp = perm_conjugate(self._fp, relabelling)
ep = perm_conjugate(self._ep, relabelling)
cols = perm_on_array(relabelling, self._colouring)
cols = self._colouring[:]
perm_on_list(relabelling, cols)
T = (cols, fp, ep)
if best is None or T < best:
......@@ -1419,16 +1460,36 @@ class VeeringTriangulation(Triangulation):
....: T.relabel(p)
....: T.set_canonical_labels()
....: assert s0 == T.to_string()
When a linear space is passed, it is also set in canonical form::
sage: T, s, t = VeeringTriangulations.L_shaped_surface(2, 3, 4, 5, 1, 2)
sage: Gx = matrix(ZZ, [s, t])
sage: T.set_canonical_labels(Gx=Gx)
sage: T._set_switch_conditions(T._tt_check, Gx.row(0), VERTICAL)
sage: T._set_switch_conditions(T._tt_check, Gx.row(1), VERTICAL)
"""
if Lx:
raise NotImplementedError
elif Gx:
Gx.echelonize()
R, (cols, fp, ep) = self.best_relabelling(all=True)
self.relabel(R[0], Gx=Gx)
if len(R) == 1:
return
rbest = perm_invert(R[0])
ibest = 0
Gbest = Gx.__copy__()
Gtmp = Gx
for i in range(2, len(R)):
pass
self.relabel(perm_compose_10(R[i-1], R[i]), Gx=Gtmp)
Gtmp.echelonize()
if Gtmp < Gbest:
ibest = i
Gtmp, Gbest = Gbest, Gtmp
if ibest != len(R) - 1:
Gx.relabel(perm_invert(R[-1]), rbest)
else:
r, (cols, fp, ep) = self.best_relabelling()
self.relabel(r)
......@@ -1772,12 +1833,11 @@ class VeeringTriangulation(Triangulation):
sage: from veerer.constants import properties_to_string
sage: T = VeeringTriangulation("(0,1,8)(2,~7,~1)(3,~0,~2)(4,~5,~3)(5,6,~4)(7,~8,~6)", "BRRRRBRBR")
sage: T.properties_code()
81
17
sage: properties_to_string(81)
'red geometric h-balanced'
'red geometric'
"""
from .constants import (BLUE, RED, SQUARETILED, SQUARETILED, QUADRANGULABLE,
GEOMETRIC, VBALANCED, HBALANCED)
from .constants import BLUE, RED, SQUARETILED, QUADRANGULABLE, GEOMETRIC
code = 0
if self.is_square_tiled(RED):
......@@ -1794,22 +1854,14 @@ class VeeringTriangulation(Triangulation):
code |= BLUE
if self.is_geometric():
code |= GEOMETRIC
if self.is_balanced(VERTICAL):
code |= VBALANCED
if self.is_balanced(HORIZONTAL):
code |= HBALANCED
if code & BLUE and code & RED:
raise RuntimeError("found a blue and red triangulations!")
if code & SQUARETILED:
if not code & BLUE and not code & RED:
raise RuntimeError("square-tiled should be colored")
raise RuntimeError("square-tiled should be coloured")
if not code & GEOMETRIC:
raise RuntimeError("square-tiled should be geometric")
if not code & VBALANCED:
raise RuntimeError("square-tiled should be v-balanced")
if not code & HBALANCED:
raise RuntimeError("square-tiled should be h-balanced")
return code
......
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