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

Multiscale compactification of veering triangulations #56

Open
wants to merge 160 commits into
base: master
Choose a base branch
from

Conversation

videlec
Copy link
Contributor

@videlec videlec commented Nov 7, 2024

The aim of this PR is to implement horizontal and vertical degenerations of veering triangulations and linear subvarieties. On a veering triangulation, a horizontal degeneration produces a veering triangulations with paired simple poles while a vertical one produces higher order poles. This PR also introduces a class for linear subvarieties (IrreducibleRealLinearSubvariety in veerer.linear_subvariety) which is a thin wrapper around a list of Delaunay-Strebel graph as well as a class for multiscale compactification (MultiscaleCompactification in veerer.linear_subvariety).

Todo

  • canonical node data for MultiscaleVeeringTriangulation (ie choose a canonical choice of identification of separatrices with half-edges and angle)
  • comparison of MultiscaleVeeringTriangulation (ie __eq__ and __ne__ methods)
  • make a MultiscaleVeeringTriangulation._check function that checks that
    • each zero and poles are used at most once in the nodes
    • global residue condition
  • make it possible to follow vertical separatrices along paths in the Delaunay-Strebel graph. One needs to be able to compute the encoding and behavior of separatrices when doing elementary steps
    • forward/backward flips
    • counter-clockwise/clockwise rotations
    • veering -> strebel
    • strebel -> veering
    • relabelling
  • use the above to compute the group of all permutations of separatrices generated by closed paths in the Delaunay-Strebel graph ("monodromy of the DS-graph")
  • use the above to implement horizontal nodes and prong matchings for LinearSubvariety (ie together with the DS-graph of each component, one needs a canonical multiscale representative)
  • merge SurfacePlot class replacement for GraphicalSurface sage-flatsurf#330 so that we can restore the plotting code (for holomorphic differentials)
  • implement meromorphic differentials sage-flatsurf#267 so that we can plot meromorphic differentials

Optimizations

  • compute the image of monodromy of a linear variety could be done by doing a single transport per edge of the graph. Namely we transport along a spanning tree in order to trivialize the bundle (and keep all mappings to the root). Then for each complementary edge, we use twice the already computed maps.
  • more reasonable pickling of automata (eg no need to store many times the base ring)
  • the bottleneck of the Delaunay-Strebel automaton computation are
    • VeeringTriangulationLinearFamily.best_relabelling
    • VeeringTriangulation.delaunay_cone
    • polyhedron.cone.Cone.affine_dimension (called from VeeringTriangulationLinearFamily.delaunay_flips)
      There are several things one might want to try:
    • use a "constraints" based representation for the subspace instead of the "generators" based one to avoid kernel computations (~10% of the time)
    • do linear optimization (to find a > 0 vector) instead of calling affine_dimension
  • calling affine_dimension when computing the set of delaunay flips

- In the Delaunay-Strebel graph we do not use anymore horizontal Strebel
  and vertical Strebel nor bacwkard moves. Instead we rely on a new move
  "rotate" that consists of a 180 degree rotations
- rely on sage DiGraph rather than dictionaries
  _forward_neighbors/_backward_neighbors

#build the degeneration
return MultiscaleVeeringTriangulation(vts,l_horiz,l_pm)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KaiFu2210 Why did you remove the two functions I introduced?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is codimension_one_horizontal_degenerations and codimension_one_vertical_degenerations?

@KaiFu2210
Copy link
Contributor

@videlec I'm very sorry for mistakenly overwriting the updates you made. Thank you for pointing it out. I’ll pull the latest version of the branch, carefully review the changes, and ensure my updates align with the current state. I’ll make the necessary adjustments and push the corrected version soon. Sorry again for the trouble.

@KaiFu2210
Copy link
Contributor

I modify the method degeneration, and I hope it is better now.

For the example in the method .codimension_one_vertical_degenerations, it seems that we need to add the horizontal residue conditions. The following is obtained by adding residue conditions to the veering triangulation in the example:

VeeringTriangulationLinearFamily("(~0,2,3)(~1,4,5)(~2,6,7)(~3,~5,8)(~4,9,10)(~6,11,12)(~7,13,14)(~8,~12,15)(~9,16,~15)(~11,17,18)(~14,~18,19)(~16,~17,20)(0:1)(1:1)(~10:1)(~13:1)(~19:1)(~20:1)", "BBRRRBBBRBBRRBRBRRBBB", [(1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 1, 1, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, -1, -1, -1, 0, 0, 1, 1), (0, 0, 0, 0, 1, 1, 0, 0, -1, 0, -1, 0, 0, -1, 1, 1, 1, 0, 0, -1, -1), (0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, -1, -1), (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, -1, 0, -1, 0, 0, 1, 1), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, -1, -1, -1), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1)])

@KaiFu2210
Copy link
Contributor

KaiFu2210 commented Jan 20, 2025

@videlec It seems that there might be an issue with the computation of SeparatrixMonodromy.infinite_cylinder_transport.

sage: vt = VeeringTriangulationLinearFamily("(0:1,1:1,2:1)(~0:1,~1:1,~2:1)", "RRR", [(1, 0, 0), (0, 1, 0), (0, 0, 1)])
sage: ds_graph = vt.delaunay_strebel_graph()
sage: path = LabelledDiGraphPath(ds_graph, 0, [0, -69, 69, 85, 21, -26, 26, 23, 33, -12])
sage: mono = SeparatrixMonodromy(ds_graph)
sage: vt.face_angle(1)
0
sage: h1 = mono.infinite_cylinder_transport(path, 1)
sage: vtt = ds_graph.vertex_label(path.end())
sage: vtt.face_angle(h1)

However, it raises the following error

Traceback (most recent call last)
...
ValueError: h=~0 not on a boundary face

Let me know if I misundestood anything.

@videlec
Copy link
Contributor Author

videlec commented Jan 20, 2025

@videlec It seems that there might be an issue with the computation of SeparatrixMonodromy.infinite_cylinder_transport.

This is definitely a bug! Thanks for reporting it. I will try to fix it.

@videlec
Copy link
Contributor Author

videlec commented Jan 20, 2025

This is already visible with the path of length one ("unstrebelization")

sage: path = ds_graph.path(1, [-69])
sage: ds_graph.vertex_label(path.start()).face_angle(1)
0
sage: h = mono.infinite_cylinder_transport(path, 1)
sage: ds_graph.vertex_label(path.end()).face_angle(h)
Traceback (most recent call last):
...
ValueError: h=~0 not on a boundary face

@videlec
Copy link
Contributor Author

videlec commented Jan 20, 2025

Should be fixed in 8cdbc82

@KaiFu2210
Copy link
Contributor

Should be fixed in 8cdbc82

Thanks! It works.

@videlec
Copy link
Contributor Author

videlec commented Jan 21, 2025

@kai I do not understand why you encode horizontal nodes with ((c0, h0), (c1, h1)) rather than (c, h0, h1). And actually I would not even include c but use a list of lists so that self._horizontal_nodes[level][c] is a list of (h0, h1) for the corresponding veering triangulation. What do you think?

@videlec
Copy link
Contributor Author

videlec commented Jan 21, 2025

@KaiFu2210 The code for _check_horizontal_residue_conditions can be done in fewer lines

        for level, nodes in enumerate(self._horizontal_nodes):
            for (c1, h1), (c2, h2) in nodes:
                c = c1  # c1 must be equal to c2!

                vt = self._veering_triangulations[level][c]
                v1 = vector(vt.base_ring(), vt.num_edges())
                for h in perm_orbit(vt._fp, h1):
                    v1[h // 2] += 1
                v2 = vector(vt.base_ring(), vt.num_edges())
                for h in perm_orbit(vt._fp, h2):
                    v2[h // 2] += 1

                gens = vt.generators_matrix()
                if gens * v1 != gens * v2:
                    raise ValueError(f"distinct residues at horizontal node ({c1}, {p1})-({c2}, {p2})")

And I suspect that there is a mistake in the current code as you wrote r[i, h // 2] = 1 #if f has face angle zero, the colors on the boundary must be the same but a given edge could appear twice on the same boundary.

@KaiFu2210
Copy link
Contributor

KaiFu2210 commented Jan 21, 2025

@videlec Thank you! You're absolutely right. I just realized that a horizontal node must be "inside" a common prime component, and I was about to ask you about this. I'll modify the encoding of horizontal nodes accordingly.

Thank you for pointing out the mistake and providing a correction for the check! You're correct that the current code for computing the residue is not accurate.

@videlec
Copy link
Contributor Author

videlec commented Jan 23, 2025

@KaiFu2210 Some more remarks about multiscale_veering_triangulation.py

  • Isn't your function def _num_vertical_separatrices_in_corner(vt, halfedge) a duplicate of VeeringTriangulation.def _num_vertical_separatrices_in_corner(vt, halfedge)?
  • I think the following input should be accepted MultiscaleVeeringTriangulation([vt]) (with the meaning that there is neither horizontal nor vertical node)
  • For vertical nodes why do you use ((l1, c1), h1, angle) rather than (l1, c1, h1, angle)? Also I do not think it is a good idea to store negative levels l1, l2 here. The prong matching is an internal data structure. Negative level is just a user convenience. In the string representation or input you are free to use non-positive levels. But for any attribute it is much simpler to keep them non-negative.
  • Similarly, each function which has a level in its list of argument should start with l = self._check_level(l). You could remove all occurrences of abs(l) or -abs(l).
  • To compute the face at a half-edge h, you can simply do perm_orbit(vt._fp, h). Similarly for a vertex perm_orbit(vt._vp, h). Though, note that perm_orbit will start with h and not the minimum of the cycle. It would be nice to add an extra option such as perm_orbit(p, i, n=-1, normalize=False) so that if normalize=True the output starts at the minimum.
  • The function prong_matching_map(self, prong) is not used anywhere
  • The function veering_triangulation_at_level(self, level) is not used anywhere

@videlec
Copy link
Contributor Author

videlec commented Jan 23, 2025

@KaiFu2210 And maybe for vertical nodes (with their prong matching) it would be simpler to use something similar to horizontal nodes. Namely they could be stored in a list organized by level/components. More precisely one could use prong_matchings = [vt_node_at_level0, vt_node_at_level1, ...] where vt_node_at_level0 is a list whose c-th item is the list of vertical nodes whose upper level is (0, c). With this storage, you can encode the node with (h0, a0, l1, c1, h1, a1). If needed, you can also have a "reversed" version which store the opposite orientation (namely at prong_matching_down[l][c] you would have the list of prongs with lower level l and component c).

This version has the advantage of making simpler any exploration of the multiscale differential (for example this would simplify a lot is_abelian).

To store horizontal and vertical node, it might even be more convenient to use directly a sage DiGraph (or a veerer LabelledDiGraph) with vertices (l, c) and edges

  • (l,c0) - (l,c1) for horizontal nodes (with label (h0, h1))
  • (l0, c0) - (l1, c1) for vertical nodes (with label (h0, a0, h1, a1))

…atching_map(self, prong)``, and ``veering_triangulation_at_level(self, level)``.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants