Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

functions for conversion from sage-flatsurf/pyflatsurf #46

Merged
merged 16 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading