1 /*
2 	This program is free software; you can redistribute it and/or
3 	modify it under the terms of the GNU General Public License
4 	as published by the Free Software Foundation; either version 2
5 	of the License, or (at your option) any later version.
6 
7 	This program is distributed in the hope that it will be useful,
8 	but WITHOUT ANY WARRANTY; without even the implied warranty of
9 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 	GNU General Public License for more details.
11 
12 	You should have received a copy of the GNU General Public License
13 	along with this program; if not, write to the Free Software
14 	Foundation, Inc., 51 Franklin Street, Fifth Floor,
15 	Boston, MA  02110-1301, USA.
16 
17 	---
18 	Copyright (C) 2011 - 2015, Simon Hampe <simon.hampe@googlemail.com>
19 
20 	---
21 	Copyright (c) 2016-2021
22 	Ewgenij Gawrilow, Michael Joswig, and the polymake team
23 	Technische Universität Berlin, Germany
24 	https://polymake.org
25 
26 	Contains functions to compute tropical Hurwitz cycles.
27 	*/
28 
29 #include "polymake/client.h"
30 #include "polymake/Matrix.h"
31 #include "polymake/Rational.h"
32 #include "polymake/Vector.h"
33 #include "polymake/IncidenceMatrix.h"
34 #include "polymake/PowerSet.h"
35 #include "polymake/permutations.h"
36 #include "polymake/linalg.h"
37 #include "polymake/tropical/morphism_special.h"
38 #include "polymake/tropical/specialcycles.h"
39 #include "polymake/tropical/refine.h"
40 #include "polymake/tropical/convex_hull_tools.h"
41 #include "polymake/tropical/moduli_rational.h"
42 #include "polymake/tropical/thomog.h"
43 #include "polymake/tropical/morphism_thomog.h"
44 #include "polymake/TropicalNumber.h"
45 #include "polymake/tropical/misc_tools.h"
46 #include "polymake/polytope/convex_hull.h"
47 
48 namespace polymake { namespace tropical {
49 
50 struct HurwitzResult {
51   BigObject subdivision;
52   BigObject cycle;
53 };
54 
55 /**
56    @brief Takes a RationalCurve and a list of node indices. Then inserts additional leaves (starting from N_LEAVES+1) at these nodes and returns the resulting RationalCurve object
57    @param BigObject curve A RationalCurve object
58    @param Vector<Int> nodes A list of node indices of the curve
59 */
insert_leaves(BigObject curve,const Vector<Int> & nodes)60 BigObject insert_leaves(BigObject curve, const Vector<Int>& nodes)
61 {
62   // Extract values
63   Int max_leaf = curve.give("N_LEAVES");
64   IncidenceMatrix<> setsInc = curve.give("SETS");
65   Vector<Set<Int>> sets = incMatrixToVector(setsInc);
66   Vector<Rational> coeffs = curve.give("COEFFS");
67   IncidenceMatrix<> nodes_by_sets = curve.give("NODES_BY_SETS");
68   IncidenceMatrix<> nodes_by_leavesInc = curve.give("NODES_BY_LEAVES");
69   Vector<Set<Int> > nodes_by_leaves = incMatrixToVector(nodes_by_leavesInc);
70 
71   for (Int n_el = 0; n_el < nodes.dim(); ++n_el) {
72     Int n = nodes[n_el];
73     ++max_leaf;
74     // Easy case: There is already a leaf at this vertex
75     if (nodes_by_leaves[n].size() > 0) {
76       Int ref_leaf = *( nodes_by_leaves[n].begin());
77       for (Int s = 0; s < sets.dim(); ++s) {
78         if (sets[s].contains(ref_leaf)) {
79           sets[s] += max_leaf;
80         }
81       }
82     } //END if there is already a leaf
83     else {
84       // Normalize the sets at the node to point away from it. Order them in an arbitrary way
85       // Intersect the first two, I_1 and I_2: I_1 points away from the node, if and only if
86       // I_1 cap I_2 = empty or I_1. The subsequent sets I_k only have to fulfill
87       // I_k cap I_1 = empty
88       Vector<Int> adjacent_sets(nodes_by_sets.row(n));
89       Vector<Set<Int>> normalized_sets;
90       // FIXME: misuse of vector concatenation
91       Set<Int> first_inter = sets[adjacent_sets[0]] * sets[adjacent_sets[1]];
92       normalized_sets |=
93         (first_inter.size() == 0 || first_inter.size() == sets[adjacent_sets[0]].size()) ? sets[adjacent_sets[0]] : (sequence(1, max_leaf-1) - sets[adjacent_sets[0]]);
94       for (Int as = 1; as < adjacent_sets.dim(); ++as) {
95         Set<Int> subseq_inter = normalized_sets[0] * sets[adjacent_sets[as]];
96         normalized_sets |=
97           (subseq_inter.size() == 0)? sets[adjacent_sets[as]] : (sequence(1,max_leaf-1) - sets[adjacent_sets[as]]);
98       }
99       // Now for each set count, how many of the adjacent sets intersect it nontrivially
100       // It points away from the node, if and only if this number is 1 (otherwise its all)
101       for (Int s = 0; s < sets.dim(); ++s) {
102         Int inter_count = 0;
103         for (Int ns = 0; ns < normalized_sets.dim(); ++ns) {
104           if ((sets[s] * normalized_sets[ns]).size() > 0) ++inter_count;
105           if (inter_count > 1) break;
106         }
107         if (inter_count > 1) {
108           sets[s] += max_leaf;
109         }
110       }
111     } //END if there are only bounded edges
112 
113     nodes_by_leaves[n] += max_leaf;
114   } //END iterate nodes
115 
116   return BigObject("RationalCurve",
117                    "SETS", sets,
118                    "COEFFS", coeffs,
119                    "N_LEAVES", max_leaf);
120 }
121 
122 /**
123    @brief Takes a RationalCurve object and returns the rays v_I corresponding to its bounded edges as a matrix of row vectors in matroid coordinates (with leading coordinate 0).
124    @param BigObject curve A RationalCurve object
125    @return Matrix<Rational> The rays corresponding to the bounded edges
126 */
127 template <typename Addition>
edge_rays(BigObject curve)128 Matrix<Rational> edge_rays(BigObject curve)
129 {
130   IncidenceMatrix<> sets = curve.give("SETS");
131   Int n = curve.give("N_LEAVES");
132   Matrix<Rational> result(0, n*(n-3)/2 + 2);
133   for (Int s = 0; s < sets.rows(); ++s) {
134     BigObject rcurve("RationalCurve",
135                      "SETS", sets.minor(scalar2set(s), All),
136                      "N_LEAVES", n,
137                      "COEFFS", ones_vector<Rational>(1));
138     Vector<Rational> rray = call_function("matroid_coordinates_from_curve", mlist<Addition>(), rcurve);
139     result /= rray;
140   }
141   return result;
142 }
143 
144 /**
145    @brief Computes all ordered lists of k elements in {0,...,n-1}
146    @param Int n The size of the set {0,...,n-1}
147    @param Int k The size of the ordered subsets
148    @return Matrix<Int> All ordered k-sets as a list of row vectors, i.e. a matrix of dimension ( (n choose k) * k!) x k
149 */
ordered_k_choices(Int n,Int k)150 Matrix<Int> ordered_k_choices(Int n, Int k)
151 {
152   Matrix<Int> result(0,k);
153 
154   // Compute all k-choices of the set {0,..,n-1}
155   const auto kchoices = all_subsets_of_k(sequence(0, n), k);
156 
157   // Compute all permutations on a k-set
158   const auto kperm = all_permutations(k);
159 
160   for (const auto& kchoice : kchoices) {
161     Vector<Int> kvec(kchoice);
162     for (auto p = entire(kperm); !p.at_end(); ++p) {
163       result /= permuted(kvec, *p);
164     }
165   }
166 
167   return result;
168 }
169 
170 /**
171    @brief Takes a matrix and computes the gcd of the absolute values of the maximal minors
172 */
gcd_maxminor(const Matrix<Rational> & map)173 Integer gcd_maxminor(const Matrix<Rational>& map)
174 {
175   const auto r_choices = all_subsets_of_k(sequence(0, map.cols()), map.rows());
176   Integer g = 0;
177   for (const auto& r_choice : r_choices) {
178     g = gcd(g, Integer(det(map.minor(All, r_choice))));
179   }
180   return abs(g);
181 }
182 
183 /**
184    @brief This takes a list of cones (in terms of ray indices) and their weights and inserts another cone with given weight. If the new cone already exists in the list, the weight is added
185 */
insert_cone(Vector<Set<Int>> & cones,Vector<Integer> & weights,const Set<Int> & ncone,const Integer & nweight)186 void insert_cone(Vector<Set<Int>>& cones, Vector<Integer>& weights, const Set<Int>& ncone, const Integer& nweight)
187 {
188   Int ncone_index = -1;
189   for (Int c = 0; c < cones.dim(); ++c) {
190     if (ncone == cones[c]) {
191       ncone_index = c; break;
192     }
193   }
194   if (ncone_index == -1) {
195     cones |= ncone;
196     weights |= nweight;
197   } else if (weights.dim() > ncone_index) {
198     weights[ncone_index] += nweight;
199   }
200 }
201 
202 /**
203    @brief Checks whether the cone of the positive orthant intersects all of the hyperplanes defined by ev_maps.row(i) = p_i in its interior (i.e. is not contained in one of the half spaces >= pi / <= pi), where p_i = 1,2,... This can be used to check whether a choice of fixed vertices is valid (because the corresponding refinement has to have at least one interior cone for a generic choice of points p_i). In fact, this is equivalent to saying that each row of the matrix has at least one positive entry and that the hyperplanes intersect the orthant in a cone, s.t. for each entry _j there is at least one ray or vertex v s.t. v_j > 0.
204 */
is_valid_choice(const Matrix<Rational> & ev_maps)205 bool is_valid_choice(const Matrix<Rational>& ev_maps)
206 {
207   // Check if all maps have a positive entry.
208   for (Int r = 0; r < ev_maps.rows(); ++r) {
209     bool found_positive = false;
210     for (Int c = 0; c < ev_maps.cols(); ++c) {
211       if (ev_maps(r,c) > 0) {
212         found_positive = true; break;
213       }
214     }
215     if (!found_positive) return false;
216   }
217 
218   // Now compute the intersection of all hyperplanes with the positive orthant
219   Matrix<Rational> ineq = unit_matrix<Rational>(ev_maps.cols());
220   ineq = zero_vector<Rational>() | ineq;
221   Matrix<Rational> eq = ev_maps;
222   eq = - Vector<Rational>(sequence(1,ev_maps.rows())) | eq;
223   try {
224     Matrix<Rational> rays = polytope::enumerate_vertices(ineq, eq, false).first;
225     bool found_positive = false;
226     for (Int c = 1; c < rays.cols(); ++c) {
227       for (Int r = 0; r < rays.rows(); ++r) {
228         if (rays(r,c) > 0) {
229           found_positive = true; break;
230         }
231       }
232       if (!found_positive) return false;
233     }
234   }
235   catch(...) {
236     // This might happen, if the system has no solution
237     return false;
238   }
239   return true;
240 }
241 
242 /**
243    @brief Computes a subdivision of M_0,n containing H_k(degree) and (possibly) the cycle itself. The function returns a struct containing the subdivision as subobject "subdivision" and the Hurwitz cycle as subobject "cycle", both as BigObject. Optionally one can specify a RationalCurve object representing a ray around which the whole computation is performed locally (the vector is only for default initalization).
244 */
245 template <typename Addition>
hurwitz_computation(Int k,const Vector<Int> & degree,Vector<Rational> points,bool compute_cycle,BigObject local_restriction,bool output_progress)246 HurwitzResult hurwitz_computation(Int k, const Vector<Int>& degree, Vector<Rational> points, bool compute_cycle, BigObject local_restriction, bool output_progress)
247 {
248   // Make points default points ( = 0)
249   if (points.dim() < degree.dim() - 3- k) {
250     points = points | zero_vector<Rational>( degree.dim()-3-k-points.dim());
251   }
252   if (points.dim() > degree.dim() - 3 - k) {
253     points = points.slice(sequence(0,degree.dim()-3-k));
254   }
255 
256   Int n = degree.dim();
257   Int big_n = 2*n - k -2;
258   Int big_moduli_dim = big_n * (big_n - 3) / 2;//Affine ambient dimension of the stable maps.
259 
260   // Compute M_0,n and extract cones
261   BigObject m0n;
262   Vector<Rational> compare_vector;
263   bool restrict_local = local_restriction.valid();
264 
265   if (restrict_local) {
266     m0n = call_function("local_m0n", mlist<Addition>(), local_restriction);
267     compare_vector = call_function("matroid_coordinates_from_curve", mlist<Addition>(), local_restriction);
268     // We need to dehomogenize to make comparison possible.
269     compare_vector = tdehomog_vec(compare_vector);
270   } else {
271     m0n = call_function("m0n", mlist<Addition>(), n);
272   }
273 
274   IncidenceMatrix<> mn_cones = m0n.give("MAXIMAL_POLYTOPES");
275   IncidenceMatrix<> mn_restrict;
276   m0n.lookup("LOCAL_RESTRICTION") >> mn_restrict;
277 
278   // Create evaluation maps
279   Matrix<Rational> ev_maps(0, big_moduli_dim);
280   Matrix<Rational> rat_degree(n,0);
281   rat_degree |= degree;
282   Vector<Rational> zero_translate(2);
283   for (Int i = n+2; i <= 2*n-2-k; ++i) {
284     BigObject evi = evaluation_map<Addition>(n-2-k, thomog(rat_degree,0,false), i-n-1);
285     Matrix<Rational> evimatrix = evi.give("MATRIX");
286     // We take the representation of the evaluation map on charts 0 and 0.
287     evimatrix = tdehomog_morphism(evimatrix, zero_translate).first;
288     // ... and forget the xR-coordinate, as it is assumed to be always 0.
289     ev_maps /= (evimatrix.row(0).slice(sequence(0, evimatrix.cols()-1)));
290   }
291 
292   // Affine ambient dim of m0n
293   Int mn_ambient_dim = n*(n-3)/2;
294   // Will contain the rays/cones of the subdivided M_0,n (with leading coordinates)
295   Matrix<Rational> subdiv_rays(0,mn_ambient_dim);
296   Vector<Set<Int>> subdiv_cones;
297   Vector<Integer> subdiv_weights;
298 
299   // Will contain the rays/cones/weights of the Hurwitz cycle
300   Matrix<Rational> cycle_rays(0,mn_ambient_dim);
301   Vector<Set<Int>> cycle_cones;
302   Vector<Integer> cycle_weights;
303 
304   // Iterate all cones of M_0,n and compute their refinement as well as the
305   // Hurwitz cycle cones within
306   for (Int mc = 0; mc < mn_cones.rows(); ++mc) {
307     if (output_progress)
308       cout << "Refining cone " << mc << " of " << mn_cones.rows() << endl;
309 
310     // Extract the combinatorial type to compute evaluation maps
311     BigObject mc_type = call_function("rational_curve_from_cone", m0n, degree.dim(), mc);
312 
313     // This will be a model of the subdivided cone of M_0,n
314     Matrix<Rational> model_rays = unit_matrix<Rational>(degree.dim()-2);
315     Vector<Set<Int>> model_cones; model_cones |= sequence(0, degree.dim()-2);
316     // Translate the local restriction if necessary
317     Vector<Set<Int>> model_local_restrict;
318     if (restrict_local) {
319       Set<Int> single_index_set;
320       Matrix<Rational> erays = edge_rays<Addition>(mc_type);
321       for (Int er = 0; er < erays.rows(); ++er) {
322         if (tdehomog_vec(Vector<Rational>(erays.row(er))) == compare_vector) {
323           single_index_set += er; break;
324         }
325       }
326       model_local_restrict |= single_index_set;
327     }
328 
329     BigObject model_complex("Cycle", mlist<Addition>());
330     model_complex.take("VERTICES") << thomog(model_rays);
331     model_complex.take("MAXIMAL_POLYTOPES") << model_cones;
332     if (restrict_local) {
333       model_complex.take("LOCAL_RESTRICTION") << model_local_restrict;
334     }
335 
336     // Iterate over all possible ordered choices of (#vert-k)-subsets of nodes
337     Matrix<Int> fix_node_sets = ordered_k_choices(n-2, n-2-k);
338 
339     // We save the evaluation matrices for use in the computation
340     // of tropical weights in the Hurwitz cycle
341     Vector<Matrix<Rational> > evmap_list;
342 
343     for (Int nchoice = 0 ; nchoice < fix_node_sets.rows(); ++nchoice) {
344       // Compute combinatorial type obtained by adding further ends to chosen nodes
345       BigObject higher_type = insert_leaves(mc_type, fix_node_sets.row(nchoice));
346       // Convert evaluation maps to local basis of rays
347       Matrix<Rational> local_basis = tdehomog(edge_rays<Addition>(higher_type)).minor(All, range_from(1));
348       Matrix<Rational> converted_maps = ev_maps * T(local_basis);
349 
350       // Check if this choice of fixed vertices induces some valid Hurwitz type
351       // (in the generic case)
352       if (is_valid_choice(converted_maps)) {
353         evmap_list |= converted_maps;
354       }
355 
356       // Now refine along each evaluation map
357       for (Int evmap = 0; evmap < converted_maps.rows(); ++evmap) {
358         // Compute half-space fan induced by the equation ev_i >= / = / <= p_i
359         // Then refine the model cone along this halfspace
360         if (!is_zero(converted_maps.row(evmap))) {
361           // Create homogenized version of evaluation map
362           Vector<Rational> hom_converted_map = converted_maps.row(evmap);
363           // TODO: replace with sum()
364           hom_converted_map = ( - ones_vector<Rational>(hom_converted_map.dim()) * hom_converted_map) | hom_converted_map;
365 
366           BigObject evi_halfspace = halfspace_subdivision<Addition>(points[evmap],hom_converted_map,1);
367           model_complex = refinement(model_complex, evi_halfspace, false,false,false,true,false).complex;
368         }
369       } //END iterate evaluation maps
370     } //END iterate choices of fixed nodes
371 
372     // If we are actually computing the Hurwitz cycle, we take the evalutation map
373     // corresponding to each choice of vertex placement. We then compute the k-cones
374     // in the subdivision on which this map is (p_1,..,p_r) and add the gcd of the maximal minors of the
375     // matrix as tropical weight to these cones
376     IncidenceMatrix<> model_hurwitz_cones;
377     Vector<Integer> model_hurwitz_weights;
378     Matrix<Rational> model_hurwitz_rays;
379     Vector<Set<Int>> model_hurwitz_local;
380     if (compute_cycle) {
381       BigObject skeleton = call_function("skeleton_complex", model_complex, k, false);
382       // We go through all dimension - k cones of the subdivision
383       Matrix<Rational> k_rays = skeleton.give("VERTICES");
384       k_rays = tdehomog(k_rays);
385       IncidenceMatrix<> k_cones = skeleton.give("MAXIMAL_POLYTOPES");
386       model_hurwitz_weights = zero_vector<Integer>(k_cones.rows());
387       Set<Int> non_zero_cones;
388       for (Int m = 0; m < evmap_list.dim(); ++m) {
389         // Compute gcd of max-minors
390         Integer g = gcd_maxminor(evmap_list[m]);
391         for (Int c = 0; c < k_cones.rows(); ++c) {
392           // Check if ev maps to the p_i on this cone (rays have to be mapped to 0!)
393           bool maps_to_pi = true;
394           for (const Int c_elem : k_cones.row(c)) {
395             Vector<Rational> cmp_vector =
396               k_rays(c_elem, 0) == 1 ? points : zero_vector<Rational>(points.dim());
397             if (evmap_list[m] * k_rays.row(c_elem).slice(range_from(1)) != cmp_vector) {
398               maps_to_pi = false; break;
399             }
400           }
401           if (maps_to_pi) {
402             model_hurwitz_weights[c] += g;
403             if(g != 0) non_zero_cones += c;
404           }
405         }
406       } //END iterate evaluation maps
407       // Identify cones with non-zero weight and the rays they use
408       Set<Int> used_rays = accumulate(rows(k_cones.minor(non_zero_cones,All)),operations::add());
409       model_hurwitz_rays = Matrix<Rational>(k_rays.minor(used_rays,All));
410       model_hurwitz_cones = IncidenceMatrix<>(k_cones).minor(non_zero_cones,used_rays);
411       model_hurwitz_weights = model_hurwitz_weights.slice(non_zero_cones);
412     } //END compute hurwitz weights
413 
414     // Finally convert the model cones back to M_0,n-coordinates
415 
416     Matrix<Rational> model_subdiv_rays = model_complex.give("VERTICES");
417     model_subdiv_rays = tdehomog(model_subdiv_rays);
418     IncidenceMatrix<> model_subdiv_cones = model_complex.give("MAXIMAL_POLYTOPES");
419     Vector<Integer> model_subdiv_weights = ones_vector<Integer>(model_subdiv_cones.rows());
420     // If we want to compute the Hurwitz cycle, we take the k-cones instead
421 
422     for (Int i = 0; i <= 1; ++i) {
423       if (i == 1 && !compute_cycle) break;
424       Matrix<Rational> rays_to_convert = i==0 ? model_subdiv_rays : model_hurwitz_rays;
425       IncidenceMatrix<> cones_to_convert = i == 0 ? model_subdiv_cones: model_hurwitz_cones;
426       Vector<Integer> weights_to_convert = i == 0 ? model_subdiv_weights : model_hurwitz_weights;
427 
428       // First convert the rays back
429 
430       Matrix<Rational> model_conv_rays =
431         rays_to_convert.col(0) |
432         (rays_to_convert.minor(All, range_from(1)) *
433          tdehomog(edge_rays<Addition>(mc_type)).minor(All, range_from(1)));
434       Vector<Int> model_rays_perm  = insert_rays(i == 0? subdiv_rays : cycle_rays, model_conv_rays,false);
435       Map<Int, Int> ray_index_map;
436       for (Int mrp = 0; mrp < model_rays_perm.dim(); ++mrp) {
437         ray_index_map[mrp] = model_rays_perm[mrp];
438       }
439       // Then use the above index list to transform the cones
440       for (Int msc = 0; msc < cones_to_convert.rows(); ++msc) {
441         insert_cone(i == 0 ? subdiv_cones : cycle_cones,
442                     i == 0 ? subdiv_weights : cycle_weights,
443                     Set<Int>{ ray_index_map.map(cones_to_convert.row(msc)) },
444                     weights_to_convert[msc]);
445       }
446     }
447 
448   } //END iterate cones of M_0,n
449 
450   // Finally find the localizing ray in both complexes
451   Set<Int> subdiv_local;
452   Set<Int> cycle_local;
453   if (restrict_local) {
454     for (Int sr = 0; sr < subdiv_rays.rows(); ++sr) {
455       if (subdiv_rays.row(sr) == compare_vector) {
456         subdiv_local += sr; break;
457       }
458     }
459     for (Int cr = 0; cr < cycle_rays.rows(); ++cr) {
460       if (cycle_rays.row(cr) == compare_vector) {
461         cycle_local += cr; break;
462       }
463     }
464 
465     // Find vertex
466     for (Int sr = 0; sr < subdiv_rays.rows(); ++sr) {
467       if (subdiv_rays.row(sr) == unit_vector<Rational>(subdiv_rays.cols(),0)) {
468         subdiv_local += sr; break;
469       }
470     }
471     for (Int cr = 0; cr < cycle_rays.rows(); ++cr) {
472       if (cycle_rays.row(cr) == unit_vector<Rational>(cycle_rays.cols(),0)) {
473         cycle_local += cr; break;
474       }
475     }
476   } //END restrict
477 
478   BigObject result("Cycle", mlist<Addition>(),
479                    "VERTICES", thomog(subdiv_rays),
480                    "MAXIMAL_POLYTOPES", subdiv_cones,
481                    "WEIGHTS", subdiv_weights);
482   if (restrict_local)
483     result = call_function("local_restrict", result, IncidenceMatrix<>(1, subdiv_local.back()+1, &subdiv_local));
484 
485   BigObject cycle("Cycle", mlist<Addition>(),
486                   "VERTICES", thomog(cycle_rays),
487                   "MAXIMAL_POLYTOPES", cycle_cones,
488                   "WEIGHTS", cycle_weights);
489   if (restrict_local)
490     cycle = call_function("local_restrict", cycle, IncidenceMatrix<>(1, cycle_local.back()+1, &cycle_local));
491 
492   return { result, cycle };
493 }
494 
495 // Documentation see perl wrapper
496 template <typename Addition>
hurwitz_subdivision(Int k,const Vector<Int> & degree,const Vector<Rational> & points,OptionSet options)497 BigObject hurwitz_subdivision(Int k, const Vector<Int>& degree, const Vector<Rational>& points, OptionSet options)
498 {
499   return hurwitz_computation<Addition>(k,degree, points, false, BigObject(), options["Verbose"]).subdivision;
500 }
501 
502 // Documentation see perl wrapper
503 template <typename Addition>
hurwitz_cycle(Int k,const Vector<Int> & degree,const Vector<Rational> & points,OptionSet options)504 BigObject hurwitz_cycle(Int k, const Vector<Int>& degree, const Vector<Rational>& points, OptionSet options)
505 {
506   return hurwitz_computation<Addition>(k, degree, points, true, BigObject(), options["Verbose"]).cycle;
507 }
508 
509 // Documentation see perl wrapper
510 template <typename Addition>
hurwitz_pair(Int k,const Vector<Int> & degree,const Vector<Rational> & points,OptionSet options)511 ListReturn hurwitz_pair(Int k, const Vector<Int>& degree, const Vector<Rational>& points, OptionSet options)
512 {
513   const HurwitzResult r = hurwitz_computation<Addition>(k, degree, points, true, BigObject(), options["Verbose"]);
514   ListReturn l;
515   l << r.subdivision;
516   l << r.cycle;
517   return l;
518 }
519 
520 // Documentation see perl wrapper
521 template <typename Addition>
hurwitz_pair_local(Int k,const Vector<Int> & degree,BigObject local_restriction,OptionSet options)522 ListReturn hurwitz_pair_local(Int k, const Vector<Int>& degree, BigObject local_restriction, OptionSet options)
523 {
524   HurwitzResult r = hurwitz_computation<Addition>(k, degree, Vector<Rational>(), true, local_restriction, options["Verbose"]);
525   ListReturn l;
526   l << r.subdivision;
527   l << r.cycle;
528   return l;
529 }
530 
531 UserFunctionTemplate4perl("# @category Hurwitz cycles"
532                           "# This function computes a subdivision of M_0,n containing the Hurwitz cycle"
533                           "# H_k(x), x = (x_1,...,x_n) as a subfan. If k = n-4, this subdivision is the unique"
534                           "# coarsest subdivision fulfilling this property"
535                           "# @param Int k The dimension of the Hurwitz cycle, i.e. the number of moving vertices"
536                           "# @param Vector<Int> degree The degree x. Should add up to 0"
537                           "# @param Vector<Rational> points Optional. Should have length n-3-k. Gives the images of "
538                           "# the fixed vertices (besides the first one, which always goes to 0) as elements of R."
539                           "# If not given, all fixed vertices are mapped to 0"
540                           "# and the function computes the subdivision of M_0,n containing the recession fan of H_k(x)"
541                           "# @option Bool Verbose If true, the function outputs some progress information. True by default."
542                           "# @tparam Addition Min or Max, where the coordinates live."
543                           "# @return Cycle A subdivision of M_0,n",
544                           "hurwitz_subdivision<Addition>($,Vector<Int>;Vector<Rational> = new Vector<Rational>(),{Verbose=>1})");
545 
546 UserFunctionTemplate4perl("# @category Hurwitz cycles"
547                           "# This function computes the Hurwitz cycle H_k(x), x = (x_1,...,x_n)"
548                           "# @param Int k The dimension of the Hurwitz cycle, i.e. the number of moving vertices"
549                           "# @param Vector<Int> degree The degree x. Should add up to 0"
550                           "# @param Vector<Rational> points Optional. Should have length n-3-k. Gives the images of "
551                           "# the fixed vertices (besides 0). If not given all fixed vertices are mapped to 0"
552                           "# and the function computes the recession fan of H_k(x)"
553                           "# @option Bool Verbose If true, the function outputs some progress information. True by default."
554                           "# @tparam Addition Min or Max, where the coordinates live."
555                           "# @return Cycle<Addition> H_k(x), in homogeneous coordinates",
556                           "hurwitz_cycle<Addition>($,Vector<Int>;Vector<Rational> = new Vector<Rational>(),{Verbose=>1})");
557 
558 UserFunctionTemplate4perl("# @category Hurwitz cycles"
559                           "# This function computes hurwitz_subdivision and hurwitz_cycle at the same time, "
560                           "# returning the result in an array"
561                           "# @param Int k The dimension of the Hurwitz cycle, i.e. the number of moving vertices"
562                           "# @param Vector<Int> degree The degree x. Should add up to 0"
563                           "# @param Vector<Rational> points Optional. Should have length n-3-k. Gives the images of "
564                           "# the fixed vertices (besides 0). If not given all fixed vertices are mapped to 0"
565                           "# and the function computes the subdivision of M_0,n containing the recession fan of H_k(x)"
566                           "# @option Bool Verbose If true, the function outputs some progress information. True by default."
567                           "# @tparam Addition Min or Max, where the coordinates live."
568                           "# @return List( Cycle subdivision of M_0,n, Cycle Hurwitz cycle )",
569                           "hurwitz_pair<Addition>($,Vector<Int>;Vector<Rational> = new Vector<Rational>(),{Verbose=>1})");
570 
571 UserFunctionTemplate4perl("# @category Hurwitz cycles"
572                           "# Does the same as hurwitz_pair, except that no points are given and the user can give a "
573                           "# RationalCurve object representing a ray. If given, the computation"
574                           "# will be performed locally around the ray."
575                           "# @param Int k"
576                           "# @param Vector<Int> degree"
577                           "# @option Bool Verbose If true, the function outputs some progress information. True by default."
578                           "# @tparam Addition Min or Max, where the coordinates live."
579                           "# @param RationalCurve local_curve",
580                           "hurwitz_pair_local<Addition>($,Vector<Int>,RationalCurve,{Verbose=>1})");
581 
582 UserFunction4perl("# @category Abstract rational curves"
583                   "# Takes a RationalCurve and a list of node indices. Then inserts additional "
584                   "# leaves (starting from N_LEAVES+1) at these nodes and returns the resulting "
585                   "# RationalCurve object"
586                   "# @param RationalCurve curve A RationalCurve object"
587                   "# @param Vector<Int> nodes A list of node indices of the curve",
588                   &insert_leaves, "insert_leaves(RationalCurve,$)");
589 } }
590