Skip to content

Commit

Permalink
Merge pull request #46 from videlec/flatsurf-conversion
Browse files Browse the repository at this point in the history
functions for conversion from sage-flatsurf/pyflatsurf
  • Loading branch information
videlec authored Sep 20, 2024
2 parents f45f00b + 2221e14 commit 739dd00
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 75 deletions.
53 changes: 22 additions & 31 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,46 +13,37 @@ jobs:
strategy:
matrix:
include:
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,surface_dynamicsr"
- optionals: "sage"
sagelib: "9.3"
python: "3.9.2"
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,surface_dynamics"
sagelib: "9.4"
python: "3.9.5"
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,pynormaliz,surface_dynamics"
sagelib: "9.5"
python: "3.9.9"
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,pynormaliz,surface_dynamics"
sagelib: "9.6"
python: "3.10.5"
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,pynormaliz,surface_dynamics"
sagelib: "9.7"
python: "3.10.5"
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,pynormaliz,surface_dynamics"
sagelib: "9.8"
python: "3.10.5"
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,pynormaliz,surface_dynamics"
python: "3.9.15"
- optionals: "sage"
sagelib: "10.0"
python: "3.10.5"
python: "3.10.8"
- optionals: "sage,sage_flatsurf,pyeantic,pyintervalxt,pyflatsurf,pynormaliz,surface_dynamics"
sagelib: "10.4"
python: "3.12.15"
# Test optional dependencies in isolation
- optionals: "sage"
sagelib: "10.0"
python: "3.10.5"
sagelib: "10.4"
python: "3.12.15"
- optionals: "sage,sage_flatsurf"
sagelib: "10.0"
python: "3.10.5"
sagelib: "10.4"
python: "3.12.15"
- optionals: "sage,pyeantic"
sagelib: "10.0"
python: "3.10.5"
sagelib: "10.4"
python: "3.12.15"
- optionals: "sage,pyintervalxt"
sagelib: "10.0"
python: "3.10.5"
sagelib: "10.4"
python: "3.12.15"
- optionals: "sage,pynormaliz"
sagelib: "10.0"
python: "3.10.5"
sagelib: "10.4"
python: "3.12.15"
- optionals: "sage,surface_dynamics"
sagelib: "10.0"
python: "3.10.5"
sagelib: "10.4"
python: "3.12.15"
- optionals: "sage,pyflatsurf"
sagelib: "10.4"
python: "3.12.15"
steps:
- uses: actions/checkout@v2
with: { submodules: recursive }
Expand Down
4 changes: 2 additions & 2 deletions doc/source/veerer_demo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ train-tracks.
::

sage: # constructing veering triangulations from a component stratum
sage: Q = QuadraticStratum(3,3,3,3) # optional - surface_dynamics
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

Expand Down Expand Up @@ -343,7 +343,7 @@ filtering cylindrical (single test is cheap) ~2 sec for H(4)^hyp

::

sage: H = AbelianStratum(4).hyperelliptic_component() # optional - surface_dynamics
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
Expand Down
5 changes: 3 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ dependencies:
# Work around https://github.com/conda-forge/givaro-feedstock/issues/13
- givaro=4.1.1=h192cbe9_1
- sage-flatsurf # optional: sage_flatsurf
- pyeantic >=1.0.0,<2 # optional: pyeantic
- pyintervalxt >=3.1.0,<4 # optional: pyintervalxt
- pyeantic >=1,<2 # optional: pyeantic
- pyintervalxt >=3,<4 # optional: pyintervalxt
- pyflatsurf >=3.10.1,<4 # optional: pyflatsurf
# Work around https://github.com/conda-forge/pynormaliz-feedstock/issues/10 by pinning normaliz and pynormaliz
- pynormaliz 2.17 # optional: pynormaliz
- normaliz 3.9.4 # optional: pynormaliz
Expand Down
20 changes: 10 additions & 10 deletions veerer/automaton.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ class Automaton(object):
Exploring strata::
sage: from surface_dynamics import * # optional - surface_dynamics
sage: strata = [AbelianStratum(2), QuadraticStratum(2,-1,-1), # optional - surface_dynamics
....: QuadraticStratum(2,2), AbelianStratum(1,1)]
sage: from surface_dynamics import Stratum # optional - surface_dynamics
sage: strata = [Stratum([2], 1), Stratum([2,-1,-1], 2), # optional - surface_dynamics
....: Stratum([2,2], 2), Stratum([1,1], 1)]
sage: for stratum in strata: # optional - surface_dynamics
....: print(stratum)
....: vt = VeeringTriangulation.from_stratum(stratum)
Expand Down Expand Up @@ -466,13 +466,13 @@ def from_stratum(self, stratum, **kwds):
EXAMPLES::
sage: from veerer import *
sage: from surface_dynamics import * # optional - surface_dynamics
sage: CoreAutomaton.from_stratum(AbelianStratum(2)) # optional - surface_dynamics
sage: from surface_dynamics import Stratum # optional - surface_dynamics
sage: CoreAutomaton.from_stratum(Stratum([2], 1)) # optional - surface_dynamics
Core veering automaton with 86 vertices
sage: GeometricAutomaton.from_stratum(AbelianStratum(2)) # optional - surface_dynamics
sage: GeometricAutomaton.from_stratum(Stratum([2], 1)) # optional - surface_dynamics
Geometric veering automaton with 54 vertices
sage: Q = QuadraticStratum(8) # optional - surface_dynamics
sage: Q = Stratum([8], 2) # optional - surface_dynamics
sage: A = CoreAutomaton.from_stratum(Q, max_size=100) # optional - surface_dynamics
sage: A # optional - surface_dynamics
Partial core veering automaton with 101 vertices
Expand Down Expand Up @@ -956,11 +956,11 @@ def cylinder_diagrams(self, col=RED):
EXAMPLES::
sage: from veerer import RED, BLUE, GeometricAutomaton
sage: from surface_dynamics import AbelianStratum # optional - surface_dynamics
sage: A = GeometricAutomaton.from_stratum(AbelianStratum(2)) # optional - surface_dynamics
sage: from surface_dynamics import Stratum # optional - surface_dynamics
sage: A = GeometricAutomaton.from_stratum(Stratum([2], 1)) # optional - surface_dynamics
sage: len(A.cylinder_diagrams(RED)) # optional - surface_dynamics
2
sage: A = GeometricAutomaton.from_stratum(AbelianStratum(1, 1)) # optional - surface_dynamics
sage: A = GeometricAutomaton.from_stratum(Stratum([1, 1], 1)) # optional - surface_dynamics
sage: len(A.cylinder_diagrams(RED)) # optional - surface_dynamics
4
Expand Down
5 changes: 4 additions & 1 deletion veerer/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from sage.features import PythonModule

flatsurf_feature = PythonModule(
sage_flatsurf_feature = PythonModule(
"flatsurf", url="https://flatsurf.github.io/sage-flatsurf/#installation"
)
surface_dynamics_feature = PythonModule(
Expand All @@ -16,6 +16,9 @@
curver_feature = PythonModule(
"curver", url="https://curver.readthedocs.io/en/master/user/install.html"
)
pyflatsurf_feature = PythonModule(
"pyflatsurf", url="https://github.com/flatsurf/flatsurf"
)
pynormaliz_feature = PythonModule(
"PyNormaliz", url="https://github.com/Normaliz/PyNormaliz"
)
208 changes: 208 additions & 0 deletions veerer/flatsurf_conversion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
r"""
Conversions from pyflatsurf and sage-flatsurf to veerer.
"""

from array import array

from sage.matrix.constructor import matrix

from .features import sage_flatsurf_feature, pyflatsurf_feature
from .triangulation import Triangulation
from .veering_triangulation import VeeringTriangulation
from .linear_family import VeeringTriangulationLinearFamily


def oriented_slope(a, rotate=1):
r"""
Return either ``(1, 1)``, ``(1, -1)``, ``(-1, 1)`` or ``(-1, -1)``.
If ``rotate`` is set to ``1`` then consider the edge as if it was rotated counterclockwise
infinitesimally (to make horizontal edges positive slopes and vertical edges negative
slopes). If it is set to ``-1`` then the rotation is in clockwise direction. If it is
set to ``0`` then return ``0`` on horizontal and vertical.
EXAMPLES::
sage: from veerer.flatsurf_conversion import oriented_slope
sage: oriented_slope((1, 1))
(1, 1)
sage: oriented_slope((-1, 1))
(-1, 1)
sage: oriented_slope((-1, -1))
(-1, -1)
sage: oriented_slope((1, -1))
(1, -1)
sage: oriented_slope((1, 0))
(1, 1)
sage: oriented_slope((0, 1))
(-1, 1)
sage: oriented_slope((-1, 0))
(-1, -1)
sage: oriented_slope((0, -1))
(1, -1)
sage: oriented_slope((1, 0), rotate=-1)
(1, -1)
sage: oriented_slope((0, 1), rotate=-1)
(1, 1)
sage: oriented_slope((-1, 0), rotate=-1)
(-1, 1)
sage: oriented_slope((0, -1), rotate=-1)
(-1, -1)
sage: oriented_slope((1, 0), rotate=0)
0
sage: oriented_slope((0, 1), rotate=0)
0
sage: oriented_slope((-1, 0), rotate=0)
0
sage: oriented_slope((0, -1), rotate=0)
0
sage: oriented_slope((0, 0))
Traceback (most recent call last):
...
ValueError: zero vector
"""
x, y = a
if not x and not y:
raise ValueError("zero vector")
if (x > 0 and y > 0):
return (1, 1)
if (x < 0 and y < 0):
return (-1, -1)
if (x > 0 and y < 0):
return (1, -1)
if (x < 0 and y > 0):
return (-1, 1)

if rotate == 0:
return 0
if rotate == 1:
if x > 0:
return (1, 1)
if y > 0:
return (-1, 1)
if x < 0:
return (-1, -1)
if y < 0 :
return (1, -1)
if rotate == -1:
if x > 0:
return (1, -1)
if y > 0:
return (1, 1)
if x < 0:
return (-1, 1)
if y < 0:
return (-1, -1)
raise ValueError("invalid argument rotate={}".format(rotate))


def pyflatsurf_surface_to_veerer_veering_triangulation(surface):
r"""
Convert a pyflatsurf surface in a veering triangulation.
Note that the flatstructure is lost in the process.
EXAMPLES::
sage: from veerer.flatsurf_conversion import pyflatsurf_surface_to_veerer_veering_triangulation
sage: from flatsurf import Polygon, similarity_surfaces # optional - sage_flatsurf pyflatsurf
sage: P = Polygon(angles=(1,1,1,7), lengths=(3, 2)) # optional - sage_flatsurf pyflatsurf
sage: S1 = similarity_surfaces.billiard(P).minimal_cover("translation").erase_marked_points() # optional - sage_flatsurf pyflatsurf
sage: S2 = S1.l_infinity_delaunay_triangulation() # optional - sage_flatsurf pyflatsurf
sage: S2.is_veering_triangulated() # optional - sage_flatsurf pyflatsurf
True
sage: S3 = S2.pyflatsurf().codomain().flat_triangulation() # optional - sage_flatsurf pyflatsurf
sage: pyflatsurf_surface_to_veerer_veering_triangulation(S3) # optional - sage_flatsurf pyflatsurf
(VeeringTriangulation("(0,1,2)(3,4,~0)(5,6,~1)(7,8,~2)(9,~3,10)(11,~8,~4)(12,13,~5)(14,15,~6)(16,~11,~10)(17,18,~12)(19,20,~13)(~20,~15,~18)(~19,~16,~17)(~14,~7,~9)", "BRRRRRBRBBBRBRRRRRBBR"), [-1, -1, 1, 1, ..., -1, 1, 1])
"""
pyflatsurf_feature.require()

faces = surface.faces()
n = 3 * faces.size()
ep = array('i', [n - i - 1 for i in range(n)])
fp = array('i', [-1] * n)
slopes = [None] * n
x_orientation = [None] * n
for face in faces:
a, b, c = face
va = surface.fromHalfEdge(a)
sa = oriented_slope((va.x(), va.y()))
vb = surface.fromHalfEdge(b)
sb = oriented_slope((vb.x(), vb.y()))
vc = surface.fromHalfEdge(c)
sc = oriented_slope((vc.x(), vc.y()))
a = a.id()
b = b.id()
c = c.id()
if a < 0 :
a = n + a
elif a > 0:
a = a - 1
if b < 0:
b = n + b
elif b > 0:
b = b - 1
if c < 0:
c = n + c
elif c > 0:
c = c - 1
fp[a] = b
fp[b] = c
fp[c] = a
x_orientation[a] = sa[0]
slopes[a] = sa[0] * sa[1]
x_orientation[b] = sb[0]
slopes[b] = sb[0] * sb[1]
x_orientation[c] = sc[0]
slopes[c] = sc[0] * sc[1]

colors = "".join("R" if x == 1 else "B" for x in slopes)
t = Triangulation.from_face_edge_perms(fp, ep)
return VeeringTriangulation(t, colors), x_orientation


def sage_flatsurf_orbit_closure_to_veerer_linear_family(orbit_closure):
r"""
Conversion of sage-flatsurf ``GL2ROrbitClosure`` to veerer ``VeeringTriangulationLinearFamily``.
EXAMPLES::
sage: from veerer.flatsurf_conversion import sage_flatsurf_orbit_closure_to_veerer_linear_family
sage: from flatsurf import Polygon, similarity_surfaces, GL2ROrbitClosure # optional - sage_flatsurf pyflatsurf
sage: P = Polygon(angles=(1,1,1,7), lengths=(3, 2)) # optional - sage_flatsurf pyflatsurf
sage: S1 = similarity_surfaces.billiard(P).minimal_cover("translation").erase_marked_points() # optional - sage_flatsurf pyflatsurf
sage: S2 = S1.l_infinity_delaunay_triangulation() # optional - sage_flatsurf pyflatsurf
sage: O = GL2ROrbitClosure(S2) # optional - sage_flatsurf pyflatsurf
sage: for d in O.decompositions(4): # optional - sage_flatsurf pyflatsurf
....: O.update_tangent_space_from_flow_decomposition(d)
....: if O.dimension() == 4:
....: break
sage: F = sage_flatsurf_orbit_closure_to_veerer_linear_family(O) # optional - sage_flatsurf pyflatsurf
sage: F.base_ring() # optional - sage_flatsurf pyflatsurf
Number Field in c0 with defining polynomial x^2 - x - 1 with c0 = 1.618033988749895?
sage: F # optional - sage_flatsurf pyflatsurf
VeeringTriangulationLinearFamily("(0,1,2)(3,4,~0)(5,6,~1)(7,8,~2)(9,~3,10)(11,~8,~4)(12,13,~5)(14,15,~6)(16,~11,~10)(17,18,~12)(19,20,~13)(~20,~15,~18)(~19,~16,~17)(~14,~7,~9)", "BRRRRRBRBBBRBRRRRRBBR", [(1, 0, 1, 0, 1, c0, c0, 0, -1, -c0, -c0, 0, c0, 0, c0, 2*c0, c0, 0, c0, -c0, c0), (0, 1, 1, 0, 0, c0, c0 - 1, 0, -1, -1, -1, -1, 1, c0 - 1, 1, c0, 0, -c0 + 1, -c0 + 2, -c0 + 1, 2*c0 - 2), (0, 0, 0, 1, 1, 0, 0, 0, 0, -c0, -c0 + 1, 1, 0, 0, c0, c0, c0, c0 - 1, c0 - 1, -1, 1), (0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, c0 - 1, c0 - 1, c0 - 1, -c0 + 1)])
"""
sage_flatsurf_feature.require()

vt, x_orientation = pyflatsurf_surface_to_veerer_veering_triangulation(orbit_closure._surface)

# build generators for the tangent space
phi = orbit_closure.V2.base_ring().coerce_embedding()
K = phi.codomain()
subspace = []
for i in range(orbit_closure._U_rank):
v = orbit_closure.lift(orbit_closure._U[i])
v = [x_orientation[j] * phi(v[j]) for j in range(len(v))]
subspace.append(v)

R = orbit_closure.field_of_definition()
if orbit_closure.base_ring() != R:
subspace = matrix(orbit_closure.base_ring(), subspace).echelon_form().change_ring(R)
return VeeringTriangulationLinearFamily(vt, subspace)
10 changes: 5 additions & 5 deletions veerer/tatami_decomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,21 @@ def tatami_decomposition(rectangles, base_ring=None):
sage: from veerer.constants import LEFT, RIGHT
sage: r0 = ((1, RIGHT, 1), (1, RIGHT, 0), (0, LEFT, 0), (0, LEFT, 1), (3, RIGHT, 2), (3, RIGHT, 1), (0, RIGHT, 2), (0, RIGHT, 1))
sage: r1 = ((3, LEFT, 0), (3, LEFT, 2), (0, LEFT, 1), (0, LEFT, 2), (3, RIGHT, 1), (1, LEFT, 1), (0, RIGHT, 1), (0, RIGHT, 0))
sage: tatami_decomposition([r0, r1]) # optional: sage_flatsurf
sage: tatami_decomposition([r0, r1]) # optional - sage_flatsurf
Translation Surface built from a square and a rectangle
TESTS::
sage: tatami_decomposition([r0, r1], ZZ) # optional: sage_flatsurf
sage: tatami_decomposition([r0, r1], ZZ) # optional - sage_flatsurf
Translation Surface built from a square and a rectangle
sage: tatami_decomposition([r0, r1], QQ) # optional: sage_flatsurf
sage: tatami_decomposition([r0, r1], QQ) # optional - sage_flatsurf
Translation Surface built from a square and a rectangle
sage: tatami_decomposition([r0, r1], AA) # optional: sage_flatsurf
sage: tatami_decomposition([r0, r1], AA) # optional - sage_flatsurf
Translation Surface built from a square and a rectangle
sage: r0 = ((1, RIGHT, AA(1)), (1, RIGHT, 0), (0, LEFT, 0), (0, LEFT, 1), (3, RIGHT, 2), (3, RIGHT, 1), (0, RIGHT, 2), (0, RIGHT, 1))
sage: r1 = ((3, LEFT, 0), (3, LEFT, 2), (0, LEFT, 1), (0, LEFT, 2), (3, RIGHT, 1), (1, LEFT, 1), (0, RIGHT, 1), (0, RIGHT, 0))
sage: tatami_decomposition([r0, r1]) # optional: sage_flatsurf
sage: tatami_decomposition([r0, r1]) # optional - sage_flatsurf
Translation Surface built from a square and a rectangle
"""
if base_ring is None:
Expand Down
Loading

0 comments on commit 739dd00

Please sign in to comment.