unlisted
ubuntu2004r"""1Faber-Zagier relations and pairing in tautological ring2"""3from copy import copy4import itertools56from sage.misc.cachefunc import cached_function7from sage.modules.free_module import span8from sage.rings.integer_ring import ZZ9from sage.rings.rational_field import QQ10from sage.matrix.constructor import matrix11from sage.functions.other import floor12from sage.combinat.partition import Partitions13from sage.combinat.integer_vector import IntegerVectors14from sage.combinat.permutation import Permutations1516from .algebra import multiply, insertion_pullback, kappa_multiple, psi_multiple, get_marks17from .graph import all_strata, num_strata, contraction_table, unpurify_map, single_stratum, autom_count, graph_count_automorphisms, R, X, Graph, num_of_stratum, graph_isomorphic18from .evaluation import socle_evaluation19from .moduli import MODULI_SM, MODULI_ST, MODULI_SMALL, dim_form20from .utils import get_memory_usage, dprint, remove_duplicates, subsequences, A_list, B_list, aut, simplify_sparse212223def gorenstein_precompute(g, r1, markings=(), moduli_type=MODULI_ST):24r3 = dim_form(g, len(markings), moduli_type)25r2 = r3 - r126all_strata(g, r1, markings, moduli_type)27all_strata(g, r2, markings, moduli_type)28contraction_table(g, r3, markings, moduli_type)29unpurify_map(g, r3, markings, moduli_type)303132def pairing_matrix(g, r1, markings=(), moduli_type=MODULI_ST):33r"""34Return the pairing matrix for the given genus, degree, markings and35moduli type.3637EXAMPLES::3839sage: from admcycles.DR import pairing_matrix40sage: pairing_matrix(1, 1, (1, 1))41[[1/4, 1/6, 1/12, 2], [1/6, 1/12, 0, 2], [1/12, 0, -1/12, 2], [2, 2, 2, 0]]42"""43r3 = dim_form(g, len(markings), moduli_type)44r2 = r3 - r145ngens1 = num_strata(g, r1, markings, moduli_type)46ngens2 = num_strata(g, r2, markings, moduli_type)47ngens3 = num_strata(g, r3, markings, moduli_type)48socle_evaluations = [socle_evaluation(49i, g, markings, moduli_type) for i in range(ngens3)]50pairings = [[0 for i2 in range(ngens2)] for i1 in range(ngens1)]51sym = bool(r1 == r2)52for i1 in range(ngens1):53for i2 in range(ngens2):54if sym and i1 > i2:55pairings[i1][i2] = pairings[i2][i1]56continue57L = multiply(r1, i1, r2, i2, g, r3, markings, moduli_type)58pairings[i1][i2] = sum([L[k] * socle_evaluations[k]59for k in range(ngens3)])60return pairings616263@cached_function64def pairing_submatrix(S1, S2, g, r1, markings=(), moduli_type=MODULI_ST):65r3 = dim_form(g, len(markings), moduli_type)66r2 = r3 - r167# ngens1 = num_strata(g, r1, markings, moduli_type)68# ngens2 = num_strata(g, r2, markings, moduli_type)69ngens3 = num_strata(g, r3, markings, moduli_type)70socle_evaluations = [socle_evaluation(71i, g, markings, moduli_type) for i in range(ngens3)]72pairings = [[0 for i2 in S2] for i1 in S1]73sym = bool(r1 == r2 and S1 == S2)74for i1 in range(len(S1)):75for i2 in range(len(S2)):76if sym and i1 > i2:77pairings[i1][i2] = pairings[i2][i1]78continue79L = multiply(r1, S1[i1], r2, S2[i2], g, r3, markings, moduli_type)80pairings[i1][i2] = sum([L[k] * socle_evaluations[k]81for k in range(ngens3)])82return pairings838485def betti(g, r, marked_points=(), moduli_type=MODULI_ST):86"""87This function returns the predicted rank of the codimension r grading88of the tautological ring of the moduli space of stable genus g curves89with marked points labeled by the multiset marked_points.9091g and r should be nonnegative integers and marked_points should be a92tuple of positive integers.9394The parameter moduli_type determines which moduli space to use:95- MODULI_ST: all stable curves (this is the default)96- MODULI_CT: curves of compact type97- MODULI_RT: curves with rational tails98- MODULI_SM: smooth curves99100EXAMPLES::101102sage: from admcycles.DR import betti103104Check rank R^3(bar{M}_2) = 1::105106sage: betti(2, 3)1071108109Check rank R^2(bar{M}_{2,3}) = 44::110111sage: betti(2, 2, (1,2,3)) # long time11244113114Check rank R^2(bar{M}_{2,3})^{S_3} = 20::115116sage: betti(2, 2, (1,1,1)) # long time11720118119Check rank R^2(bar{M}_{2,3})^{S_2} = 32 (S_2 interchanging markings 1 and 2)::120121sage: betti(2, 2, (1,1,2)) # long time12232123124Check rank R^2(M^c_4) = rank R^3(M^c_4) = 6::125126sage: from admcycles.DR import MODULI_CT, MODULI_RT, MODULI_SM127sage: betti(4, 2, (), MODULI_CT)1286129sage: betti(4, 3, (), MODULI_CT) # long time1306131132We can use this to check that rank R^8(M^rt_{17,2})^(S_2)=122 < R^9(M^rt_{17,2})^(S_2) = 123.133Indeed, betti(17,8,(1,1),MODULI_RT) = 122 and betti(17,9,(1,1),MODULI_RT)=123134Similarly, we have rank R^9(M_{20,1}) = 75 < rank R^10(M_{20,1}) = 76135Indeed, betti(20,9,(1,),MODULI_SM) = 75 and betti(20,10,(1,),MODULI_SM) = 76.136"""137L = list_all_FZ(g, r, marked_points, moduli_type)138L.reverse()139return (len(L[0]) - compute_rank(L))140141142def gorenstein(g, r, marked_points=(), moduli_type=MODULI_ST):143"""144This function returns the rank of the codimension r grading of the145Gorenstein quotient of the tautological ring of the moduli space of genus g146curves with marked points labeled by the multiset marked_points.147148g and r should be nonnegative integers and marked_points should be a149tuple of positive integers.150151The parameter moduli_type determines which moduli space to use:152- MODULI_ST: all stable curves (this is the default)153- MODULI_CT: curves of compact type154- MODULI_RT: curves with rational tails155156EXAMPLES::157158sage: from admcycles.DR.relations import gorenstein159160Check rank Gor^3(bar{M}_{3}) = 10::161162sage: gorenstein(3, 3) # long time16310164165Check rank Gor^2(bar{M}_{2,2}) = 14::166167sage: gorenstein(2, 2, (1,2)) # long time16814169170Check rank Gor^2(bar{M}_{2,2})^{S_2} = 11::171172sage: gorenstein(2, 2, (1,1)) # long time17311174175Check rank Gor^2(M^c_{4}) = 6::176177sage: from admcycles.DR import MODULI_CT, MODULI_RT178179sage: gorenstein(4, 2, (), MODULI_CT) # long time1806181182Check rank Gor^4(M^rt_{8,2}) = 22::183184sage: gorenstein(8, 4, (1,2), MODULI_RT) # long time18522186"""187gorenstein_precompute(g, r, marked_points, moduli_type)188r3 = dim_form(g, len(marked_points), moduli_type)189r2 = r3 - r190S1 = good_generator_list(g, r, marked_points, moduli_type)191S2 = good_generator_list(g, r2, marked_points, moduli_type)192M = pairing_submatrix(tuple(S1), tuple(S2), g, r,193marked_points, moduli_type)194return matrix(M).rank()195196197def recursive_betti(g, r, markings=(), moduli_type=MODULI_ST):198"""199EXAMPLES::200201sage: from admcycles.DR.relations import recursive_betti202sage: recursive_betti(2, 3) # not tested203?204"""205from .utils import dprint, dsave206dprint("Start recursive_betti (%s,%s,%s,%s): %s", g, r,207markings, moduli_type, floor(get_memory_usage()))208n = len(markings)209if r > dim_form(g, n, moduli_type):210return 0211ngen = num_strata(g, r, markings, moduli_type)212dprint("%s gens", ngen)213relations = []214partial_sym_map = symmetrize_map(g, r, get_marks(n, 0), markings, moduli_type)215for rel in [unsymmetrize_vec(br, g, r, get_marks(n, 0), moduli_type)216for br in choose_basic_rels(g, r, n, moduli_type)]:217rel2 = []218for x in rel:219rel2.append([partial_sym_map[x[0]], x[1]])220rel2 = simplify_sparse(rel2)221relations.append(rel2)222for rel in interior_derived_rels(g, r, n, 0, moduli_type):223rel2 = []224for x in rel:225rel2.append([partial_sym_map[x[0]], x[1]])226rel2 = simplify_sparse(rel2)227relations.append(rel2)228dprint("%s gens, %s rels so far", ngen, len(relations))229dprint("Middle recursive_betti (%s,%s,%s,%s): %s", g, r,230markings, moduli_type, floor(get_memory_usage()))231if moduli_type > MODULI_SM:232for r0 in range(1, r):233strata = all_strata(g, r0, markings, moduli_type)234for G in strata:235vertex_orbits = graph_count_automorphisms(G, True)236for i in [orbit[0] for orbit in vertex_orbits]:237good = True238for j in range(G.M.ncols()):239if R(G.M[i, j][0]) != G.M[i, j]:240good = False241break242if good:243g2 = G.M[i, 0][0]244if 3 * (r - r0) < g2 + 1:245continue246d = G.degree(i)247if dim_form(g2, d, moduli_type) < r - r0:248continue249strata2 = all_strata(250g2, r - r0, tuple(range(1, d + 1)), moduli_type)251which_gen_list = [252-1 for num in range(len(strata2))]253for num in range(len(strata2)):254G_copy = Graph(G.M)255G_copy.replace_vertex_with_graph(i, strata2[num])256which_gen_list[num] = num_of_stratum(257G_copy, g, r, markings, moduli_type)258rel_list = [unsymmetrize_vec(br, g2, r - r0,259get_marks(d, 0), moduli_type) for br in260choose_basic_rels(g2, r - r0, d, moduli_type)]261rel_list += interior_derived_rels(g2,262r - r0, d, 0, moduli_type)263for rel0 in rel_list:264relation = []265for x in rel0:266num = x[0]267if which_gen_list[num] != -1:268relation.append(269[which_gen_list[num], x[1]])270relation = simplify_sparse(relation)271relations.append(relation)272dprint("%s gens, %s rels", ngen, len(relations))273dsave("sparse-%s-gens-%s-rels", ngen, len(relations))274dprint("Middle recursive_betti (%s,%s,%s,%s): %s", g, r,275markings, moduli_type, floor(get_memory_usage()))276relations = remove_duplicates(relations)277nrels = len(relations)278dprint("%s gens, %s distinct rels", ngen, nrels)279dsave("sparse-%s-distinct-rels", nrels)280rank = 0281D = {}282for i, reli in enumerate(relations):283for x in reli:284D[i, x[0]] = x[1]285if nrels:286row_order, col_order = choose_orders_sparse(D, nrels, ngen)287rank = compute_rank_sparse(D, row_order, col_order)288dsave("sparse-answer-%s", ngen - rank)289return ngen - rank290291292def FZ_rels(g, r, markings=(), moduli_type=MODULI_ST):293r"""294EXAMPLES::295296sage: from admcycles.DR.relations import FZ_rels297sage: FZ_rels(2, 2)298[299(1, 0, 0, 0, 0, 0, -1/20, -1/480),300(0, 1, 0, 0, 0, 0, -5/24, -1/96),301(0, 0, 1, 0, 0, 0, -1/24, 0),302(0, 0, 0, 1, 0, 0, -1/24, 0),303(0, 0, 0, 0, 1, 0, -1, -1/12),304(0, 0, 0, 0, 0, 1, -1, -1/24)305]306"""307return span(FZ_matrix(g, r, markings, moduli_type)).basis()308309310# remove this and use rels_matrix instead?311def FZ_matrix(g, r, markings=(), moduli_type=MODULI_ST):312r"""313EXAMPLES::314315sage: from admcycles.DR.relations import FZ_matrix316sage: from admcycles.DR.moduli import MODULI_SM, MODULI_RT, MODULI_CT, MODULI_ST317sage: FZ_matrix(2, 2)318[ 60 -60 84 0 6 0 0 0]319[ 473760 -100512 33984 -10080 6624 -10080 -288 -72]320[ 115920 -12240 13536 -5040 1584 -5040 -144 -36]321[ 0 0 102 -30 0 0 -3 0]322[ 0 0 30 42 0 0 -3 0]323[ 0 0 0 0 66 -60 -6 -3]324[ 0 0 0 0 15 6 -21 -3/2]325326sage: FZ_matrix(2, 2, (1,), MODULI_CT)327[ 30 -30 30 0 42 0 0 0]328[ 441000 -78120 61200 -138600 37296 -7920 -42840 1368]329[ 204120 -27864 -39312 98280 20304 9072 -37800 -3672]330[ 0 0 -30 30 0 42 0 0]331[ 71820 -7020 9720 -41580 9288 -3240 -18900 756]332[ 13860 -900 -2520 16380 2520 3528 -16380 -1764]333[ 0 0 0 0 66 -30 -30 -6]334[ 0 0 0 0 15 21 -15 -21]335[ 0 0 0 0 15 -15 21 -21]336337sage: FZ_matrix(3, 2, (1, 2), MODULI_RT)338[-251370 27162 -34020 -34020 145530 18900 145530 18036 -69930]339[ -56700 4860 10584 -7560 -49140 -7560 41580 -8424 34020]340[ -56700 4860 -7560 10584 41580 -7560 -49140 -8424 34020]341[ -6930 450 1260 1260 -8190 1764 -8190 900 -6930]342[ -6930 450 -900 -900 6930 900 6930 900 -6930]343344sage: FZ_matrix(3, 2, (1, 1), MODULI_SM)345[-125685 13581 -34020 145530 9450]346[ -56700 4860 3024 -7560 -7560]347[ -3465 225 1260 -8190 882]348[ -3465 225 -900 6930 450]349"""350return matrix(list_all_FZ(g, r, markings, moduli_type))351352353def FZ_methods_sanity_check(g, r, n, moduli_type):354r"""355Check whether computing the FZ-relations via Pixton's 3-spin formula and356by using new relations give the same result.357358TESTS::359360sage: import itertools361sage: from admcycles.DR import FZ_methods_sanity_check, MODULI_SM, MODULI_RT, MODULI_CT, MODULI_ST362sage: gn = [(0, 5), (1, 1), (1, 2), (1, 3), (2, 2), (3, 0), (4, 1)]363sage: degrees = [0, 1, 2, 3]364sage: moduli = [MODULI_SM, MODULI_RT, MODULI_CT, MODULI_ST]365sage: for (g, n), r, moduli_type in itertools.product(gn, degrees, moduli): # long time366....: if not FZ_methods_sanity_check(g, r, n, moduli_type):367....: print("ERROR: g={}, r={}, n={}, moduli_type={}".format(g, r, n, moduli_type))368369sage: all(FZ_methods_sanity_check(9, i, 0, MODULI_SM) for i in range(10)) # long time370True371"""372def echelon_without_zeros(M):373M.echelonize()374for i, r in enumerate(M.rows()):375if r.is_zero():376return M.matrix_from_rows(range(i))377return M378379spin3 = rels_matrix(g, r, n, 0, moduli_type, True)380newrels = rels_matrix(g, r, n, 0, moduli_type, False)381return echelon_without_zeros(spin3) == echelon_without_zeros(newrels)382383384def list_all_FZ(g, r, markings=(), moduli_type=MODULI_ST):385relations = copy(interior_FZ(g, r, markings, moduli_type))386if moduli_type > MODULI_SM:387relations += boundary_FZ(g, r, markings, moduli_type)388if not relations:389ngen = num_strata(g, r, markings, moduli_type)390relations.append([0 for i in range(ngen)])391return relations392393394def reduced_FZ_param_list(G, v, g, d, n):395params = FZ_param_list(n, tuple(range(1, d + 1)))396graph_params = []397M = matrix(R, 2, d + 1)398M[0, 0] = -1399for i in range(1, d + 1):400M[0, i] = i401for p in params:402G_copy = Graph(G.M)403M[1, 0] = -g - 1404for j in p[0]:405M[1, 0] += X**j406for i in range(1, d + 1):407M[1, i] = 1 + p[1][i - 1][1][0] * X408G_p = Graph(M)409G_copy.replace_vertex_with_graph(v, G_p)410graph_params.append([p, G_copy])411params_reduced = []412graphs_seen = []413for x in graph_params:414x[1].compute_invariant()415good = True416for GG in graphs_seen:417if graph_isomorphic(x[1], GG):418good = False419break420if good:421graphs_seen.append(x[1])422params_reduced.append(x[0])423return params_reduced424425426def FZ_param_list(n, markings=()):427r"""428EXAMPLES::429430sage: from admcycles.DR.relations import FZ_param_list431sage: FZ_param_list(3, ())432[((3,), ()), ((1, 1, 1), ()), ((1,), ())]433"""434if n < 0:435return []436final_list = []437mmm = max((0,) + markings)438markings_grouped = [0 for i in range(mmm)]439for i in markings:440markings_grouped[i - 1] += 1441markings_best = []442for i in range(mmm):443if markings_grouped[i] > 0:444markings_best.append([i + 1, markings_grouped[i]])445for j in range(n // 2 + 1):446for n_vec in IntegerVectors(n - 2 * j, 1 + len(markings_best)):447S_list = [[list(sigma) for sigma in Partitions(n_vec[0])448if not any(l % 3 == 2 for l in sigma)]]449# TODO: the line above should iterate directly over the set450# of partitions with no parts of size = 2 (mod 3)451for i in range(len(markings_best)):452S_list.append(Partitions(453n_vec[i + 1] + markings_best[i][1], length=markings_best[i][1]).list())454S_list[-1] = [[k - 1 for k in sigma] for sigma in S_list[-1]455if sum(1 for l in sigma if (l % 3) == 0) == 0]456for S in itertools.product(*S_list):457final_list.append((tuple(S[0]), tuple([(markings_best[k][0], tuple(458S[k + 1])) for k in range(len(markings_best))])))459return final_list460461462def C_coeff(m, term):463n = term - m // 3464if n < 0:465return 0466if m % 3 == 0:467return A_list[n]468else:469return B_list[n]470471472@cached_function473def dual_C_coeff(i, j, parity):474total = ZZ.zero()475k = parity % 2476while k // 3 <= i:477if k % 3 != 2:478total += (-1)**(k // 3) * C_coeff(k, i) * C_coeff(-2 - k, j)479k += 2480return total481482483def poly_to_partition(F):484mmm = F.degree()485target_partition = []486for i in range(1, mmm + 1):487for j in range(F[i]):488target_partition.append(i)489return tuple(target_partition)490491492@cached_function493def kappa_coeff(sigma, kappa_0, target_partition):494total = ZZ.zero()495num_ones = sum(1 for i in sigma if i == 1)496for i in range(0, num_ones + 1):497for injection in Permutations(list(range(len(target_partition))), len(sigma) - i):498term = (ZZ(num_ones).binomial(i) *499ZZ(kappa_0 + len(target_partition) + i - 1).binomial(i) *500ZZ(i).factorial())501for j in range(len(sigma) - i):502term *= C_coeff(sigma[j + i], target_partition[injection[j]])503for j in range(len(target_partition)):504if j in injection:505continue506term *= C_coeff(0, target_partition[j])507total += term508total = (-1)**(len(target_partition) + len(sigma)) * \509total / aut(list(target_partition))510return total511512513@cached_function514def FZ_kappa_factor(num, sigma, g, r, markings=(), moduli_type=MODULI_ST):515G = single_stratum(num, g, r, markings, moduli_type)516L = []517nv = G.num_vertices()518for i in range(1, nv + 1):519L.append((2 * G.M[i, 0][0] + G.degree(i) -5202, G.M[i, 0] - G.M[i, 0][0]))521LL = []522tau = []523for i in range(nv):524mini = -1525for j in range(nv):526if (i == 0 or L[j] > LL[-1] or L[j] == LL[-1] and j > tau[-1]) and (mini == -1 or L[j] < L[mini]):527mini = j528tau.append(mini)529LL.append(L[mini])530factor_dict = FZ_kappa_factor2(tuple(LL), sigma)531factor_vec = [0 for i in range(1 << nv)]532for parity_key in factor_dict:533parity = 0534for i in range(nv):535if parity_key[i] == 1:536parity += 1 << tau[i]537factor_vec[parity] = factor_dict[parity_key]538return factor_vec539540541@cached_function542def FZ_marking_factor(num, marking_vec, g, r, markings=(), moduli_type=MODULI_ST):543G = single_stratum(num, g, r, markings, moduli_type)544nv = G.num_vertices()545ne = G.num_edges()546num_parities = ZZ(2) ** nv547PPP_list = []548for marks in marking_vec:549PPP_list.append(Permutations(marks[1]))550PPP = itertools.product(*PPP_list)551marking_factors = [0 for i in range(num_parities)]552incident_vertices = []553for mark_type in marking_vec:554incident_vertices.append([])555for k in range(1, ne + 1):556if G.M[0, k] == mark_type[0]:557for i in range(1, nv + 1):558if G.M[i, k] != 0:559incident_vertices[-1].append((i - 1, G.M[i, k][1]))560break561for perms in PPP:562parity = 0563marking_factor = 1564for marks_index in range(len(marking_vec)):565for count in range(len(incident_vertices[marks_index])):566marking_factor *= C_coeff(perms[marks_index][count],567incident_vertices[marks_index][count][1])568parity ^= (perms[marks_index][count] %569ZZ(2)) << incident_vertices[marks_index][count][0]570marking_factors[parity] += marking_factor571return marking_factors572573574@cached_function575def FZ_kappa_factor2(L, sigma):576nv = len(L)577mmm = max((0,) + sigma)578sigma_grouped = [0 for i in range(mmm)]579for i in sigma:580sigma_grouped[i - 1] += 1581S_list = []582for i in sigma_grouped:583S_list.append(IntegerVectors(i, nv))584S = itertools.product(*S_list)585kappa_factors = {}586for parity in itertools.product(*[(0, 1) for i in range(nv)]):587kappa_factors[tuple(parity)] = 0588for assignment in S:589assigned_sigma = [[] for j in range(nv)]590for i in range(mmm):591for j in range(nv):592for k in range(assignment[i][j]):593assigned_sigma[j].append(i + 1)594sigma_auts = 1595parity = [0 for i in range(nv)]596kappa_factor = ZZ.one()597for j in range(nv):598sigma_auts *= aut(assigned_sigma[j])599parity[j] += sum(assigned_sigma[j])600parity[j] %= ZZ(2)601kappa_factor *= kappa_coeff(602tuple(assigned_sigma[j]), L[j][0], poly_to_partition(L[j][1]))603kappa_factors[tuple(parity)] += kappa_factor / sigma_auts604return kappa_factors605606607@cached_function608def FZ_hedge_factor(num, g, r, markings=(), moduli_type=MODULI_ST):609G = single_stratum(num, g, r, markings, moduli_type)610nv = G.num_vertices()611num_parities = ZZ(2) ** nv612ne = G.num_edges()613edge_list = []614for k in range(1, ne + 1):615if G.M[0, k] == 0:616edge_list.append([k])617for i in range(1, nv + 1):618if G.M[i, k] != 0:619edge_list[-1].append(i)620if G.M[i, k][0] == 2:621edge_list[-1].append(i)622hedge_factors = [0 for i in range(num_parities)]623for edge_parities in itertools.product(*[[0, 1] for i in edge_list]):624parity = 0625for i in range(len(edge_list)):626if edge_parities[i] == 1:627parity ^= 1 << (edge_list[i][1] - 1)628parity ^= 1 << (edge_list[i][2] - 1)629hedge_factor = 1630for i in range(len(edge_list)):631if edge_list[i][1] == edge_list[i][2]:632hedge_factor *= dual_C_coeff(G.M[edge_list[i][1], edge_list[i][0]][1],633G.M[edge_list[i][1], edge_list[i][0]][2], edge_parities[i] % ZZ(2))634else:635hedge_factor *= dual_C_coeff(G.M[edge_list[i][1], edge_list[i][0]][1],636G.M[edge_list[i][2], edge_list[i][0]][1], edge_parities[i] % ZZ(2))637hedge_factors[parity] += hedge_factor638return hedge_factors639640641@cached_function642def FZ_coeff(num, FZ_param, g, r, markings=(), moduli_type=MODULI_ST):643r"""644EXAMPLES::645646sage: from admcycles.DR.graph import num_strata647sage: from admcycles.DR.moduli import MODULI_ST648sage: from admcycles.DR.relations import FZ_coeff649sage: [FZ_coeff(i, ((3,), ()), 2, 2, (), MODULI_ST) for i in range(num_strata(2, 2))]650[60, -60, 84, 0, 6, 0, 0, 0]651sage: [FZ_coeff(i, ((1, 1, 1), ()), 2, 2, (), MODULI_ST) for i in range(num_strata(2, 2))]652[473760, -100512, 33984, -10080, 6624, -10080, -288, -72]653sage: [FZ_coeff(i, ((1,), ()), 2, 2, (), MODULI_ST) for i in range(num_strata(2, 2))]654[115920, -12240, 13536, -5040, 1584, -5040, -144, -36]655"""656sigma = FZ_param[0]657marking_vec = FZ_param[1]658G = single_stratum(num, g, r, markings, moduli_type)659nv = G.num_vertices()660graph_auts = autom_count(num, g, r, markings, moduli_type)661h1_factor = ZZ(2) ** G.h1()662num_parities = ZZ(2) ** nv663664marking_factors = FZ_marking_factor(665num, marking_vec, g, r, markings, moduli_type)666kappa_factors = FZ_kappa_factor(num, sigma, g, r, markings, moduli_type)667hedge_factors = FZ_hedge_factor(num, g, r, markings, moduli_type)668669total = ZZ.zero()670for i in range(num_parities):671if marking_factors[i] == 0:672continue673for j in range(num_parities):674total += marking_factors[i] * kappa_factors[j] * \675hedge_factors[i ^ j ^ G.target_parity]676677total /= h1_factor * graph_auts678return total679680681@cached_function682def interior_FZ(g, r, markings=(), moduli_type=MODULI_ST):683r"""684EXAMPLES::685686sage: from admcycles.DR.relations import interior_FZ687sage: interior_FZ(2, 2)688[[60, -60, 84, 0, 6, 0, 0, 0],689[473760, -100512, 33984, -10080, 6624, -10080, -288, -72],690[115920, -12240, 13536, -5040, 1584, -5040, -144, -36]]691"""692ngen = num_strata(g, r, markings, moduli_type)693relations = []694FZpl = FZ_param_list(3 * r - g - 1, markings)695for FZ_param in FZpl:696relation = [FZ_coeff(i, FZ_param, g, r, markings, moduli_type)697for i in range(ngen)]698relations.append(relation)699return relations700701702def possibly_new_FZ(g, r, n=0, moduli_type=MODULI_ST):703m = 3 * r - g - 1 - n704if m < 0:705return []706dprint("Start FZ (%s,%s,%s,%s): %s", g, r, n, moduli_type,707floor(get_memory_usage()))708markings = (1,) * n709ngen = num_strata(g, r, markings, moduli_type)710relations = []711for i in range(m + 1):712if (m - i) % 2:713continue714for sigma in Partitions(i):715# TODO: the line above should iterate directly over the set716# of partitions with all parts of size = 1 (mod 3)717if any(j % 3 != 1 for j in sigma):718continue719if n > 0:720FZ_param = (tuple(sigma), ((1, markings),))721else:722FZ_param = (tuple(sigma), ())723relation = []724for j in range(ngen):725coeff = FZ_coeff(j, FZ_param, g, r, markings, moduli_type)726if coeff != 0:727relation.append([j, coeff])728relations.append(relation)729dprint("End FZ (%s,%s,%s,%s): %s", g, r, n, moduli_type,730floor(get_memory_usage()))731return relations732733734@cached_function735def boundary_FZ(g, r, markings=(), moduli_type=MODULI_ST):736r"""737EXAMPLES::738739sage: from admcycles.DR.relations import boundary_FZ740sage: boundary_FZ(2, 2)741[[0, 0, 102, -30, 0, 0, -3, 0],742[0, 0, 30, 42, 0, 0, -3, 0],743[0, 0, 0, 0, 66, -60, -6, -3],744[0, 0, 0, 0, 15, 6, -21, -3/2]]745"""746if moduli_type <= MODULI_SM:747return []748generators = all_strata(g, r, markings, moduli_type)749ngen = len(generators)750relations = []751for r0 in range(1, r):752strata = all_strata(g, r0, markings, moduli_type)753for G in strata:754vertex_orbits = graph_count_automorphisms(G, True)755for i in [orbit[0] for orbit in vertex_orbits]:756good = True757for j in range(G.M.ncols()):758if R(G.M[i, j][0]) != G.M[i, j]:759good = False760break761if good:762g2 = G.M[i, 0][0]763if 3 * (r - r0) < g2 + 1:764continue765d = G.degree(i)766if dim_form(g2, d, moduli_type) < r - r0:767continue768strata2 = all_strata(769g2, r - r0, tuple(range(1, d + 1)), moduli_type)770which_gen_list = [-1 for num in range(len(strata2))]771for num in range(len(strata2)):772G_copy = Graph(G.M)773G_copy.replace_vertex_with_graph(i, strata2[num])774which_gen_list[num] = num_of_stratum(775G_copy, g, r, markings, moduli_type)776rFZpl = reduced_FZ_param_list(777G, i, g2, d, 3 * (r - r0) - g2 - 1)778ccccc = 0779for FZ_param in rFZpl:780relation = [0] * ngen781for num in range(len(strata2)):782if which_gen_list[num] != -1:783relation[which_gen_list[num]] += FZ_coeff(num, FZ_param, g2, r - r0, tuple(784range(1, d + 1)), moduli_type)785relations.append(relation)786ccccc += 1787return relations788789790def rels_matrix(g, r, n, symm, moduli_type, usespin):791r"""792Returns a matrix containing all FZ-relations for given ``g``, ``r``, ``n``, ``moduli_type``.793The relations are invariant under the symmetry action on the first ``symm`` points.794When ``usespin`` is True the relations are computed using Pixton's 3-spin formula.795When ``usespin`` is False the relations are computed by deriving old relations and796combining them with (possibly) new relations.797798TESTS::799800sage: from admcycles.DR import rels_matrix801sage: sum(rels_matrix(2, 2, 4, 2, 1, False).echelon_form().column(-1)) # long time80238803sage: from admcycles.DR import rels_matrix, MODULI_RT, betti804sage: def betti2(g, n, r):805....: M = rels_matrix(g, r, n, n, MODULI_RT, False)806....: return M.ncols() - M.rank()807sage: [betti2(5, 2, i) for i in range(6)] # long time808[1, 3, 6, 6, 3, 1]809sage: [betti(5, i, (1, 1), MODULI_RT) for i in range(6)] # long time810[1, 3, 6, 6, 3, 1]811812Check for https://gitlab.com/modulispaces/admcycles/-/issues/105::813814sage: from admcycles.DR import MODULI_ST815sage: rels_matrix(9, 3, 0, 0, MODULI_ST, False).ncols()816356817"""818# m = get_memory_usage()819if usespin:820if symm != 0:821print("FZ_matrix not implemented with symmetry")822return823rel = matrix(list_all_FZ(g, r, get_marks(n, symm), moduli_type))824# dprint("memory diff matrix computation for g = %s, n = %s, r = %s, moduli_type = %s, 3spin = %s : %s",825# g, r, n, moduli_type, usespin, floor(get_memory_usage() - m))826return rel827drels = derived_rels(g, r, n, symm, moduli_type)828pnrels = possibly_new_FZ(g, r, n, moduli_type)829if symm != n:830if symm == 0:831pnrels = [unsymmetrize_vec(p, g, r, get_marks(n, symm),832moduli_type) for p in pnrels]833else:834pnrels = [partial_unsymmetrize_vec(p, g, r, get_marks(n, symm),835get_marks(n, n), moduli_type) for p in pnrels]836allrels = drels + pnrels837ngen = num_strata(g, r, get_marks(n, symm), moduli_type)838rel = matrix(QQ, len(allrels), ngen, sparse=True)839for i, r in enumerate(allrels):840for (j, c) in r:841rel[i, j] = c842# dprint("memory diff relation matrix computation for g = %s, n = %s, r = %s, moduli_type = %s, 3spin = %s: %s",843# g, r, n, moduli_type, usespin, floor(get_memory_usage() - m))844return rel845846847@cached_function848def pullback_derived_rels(g, r, n, symm, moduli_type=MODULI_ST):849r"""850Returns a list of relations that are derived from relations with851less points by pulling back along the forgetfulmap that forgets a point.852"""853if r == 0:854return []855dprint("Start pullback_derived (%s,%s,%s,%s): %s", g,856r, n, moduli_type, floor(get_memory_usage()))857answer = []858for n0 in range(n):859if dim_form(g, n0, moduli_type) >= r:860basic_rels = choose_basic_rels(g, r, n0, moduli_type)861for rel in basic_rels:862for vec in subsequences(n, n - n0, symm):863local_symm = max(symm, 1) - vec.count(1)864if local_symm < n0:865rel2 = partial_unsymmetrize_vec(rel, g, r, get_marks(n0, local_symm),866get_marks(n0, n0), moduli_type)867else:868rel2 = copy(rel)869for i in range(n - n0):870rel2 = insertion_pullback(871rel2, vec[i], g, r, n0 + i, local_symm, moduli_type, False)872if vec[i] == 1:873local_symm += 1874answer.append(simplify_sparse(rel2))875else:876if moduli_type == MODULI_ST and not ((g == 0 and n0 < 3) or (g == 1 and n0 == 0)):877continue878basic_rels = choose_basic_rels(g, r, n0, MODULI_SMALL)879k = r - dim_form(g, n0, moduli_type)880for rel in basic_rels:881for vec2 in subsequences(n, n - n0 - k + 1, symm):882local_symm2 = max(symm, 1) - vec2.count(1)883for vec in subsequences(n0 + k - 1, k - 1, local_symm2):884local_symm = max(local_symm2, 1) - vec.count(1)885if local_symm < n0:886rel2 = partial_unsymmetrize_vec(rel, g, r, get_marks(n0, local_symm),887get_marks(n0, n0), MODULI_SMALL)888else:889rel2 = copy(rel)890for i in range(k - 1):891rel2 = insertion_pullback(892rel2, vec[i], g, r, n0 + i, local_symm, MODULI_SMALL, False)893if vec[i] == 1:894local_symm += 1895local_symm = local_symm2896rel2 = insertion_pullback(897rel2, vec2[0], g, r, n0 + k - 1, local_symm, moduli_type, True)898if vec2[0] == 1:899local_symm += 1900for i in range(n - n0 - k):901rel2 = insertion_pullback(902rel2, vec2[i + 1], g, r, n0 + k + i, local_symm, moduli_type, False)903if vec2[i + 1] == 1:904local_symm += 1905answer.append(simplify_sparse(rel2))906dprint("End pullback_derived (%s,%s,%s,%s): %s", g,907r, n, moduli_type, floor(get_memory_usage()))908answer = remove_duplicates(answer)909return answer910911912@cached_function913def interior_derived_rels(g, r, n, symm, moduli_type=MODULI_ST):914r"""915Returns a list of relations that are derived from relations with916lower codimension by multlication with psi- and kappa-classes.917"""918dprint("Start interior_derived (%s,%s,%s,%s): %s", g,919r, n, moduli_type, floor(get_memory_usage()))920answer = copy(pullback_derived_rels(g, r, n, symm, moduli_type))921for r0 in range(r):922local_symm = max(symm - (r - r0), 0)923if local_symm < symm:924symm_map = symmetrize_map(g, r, get_marks(n, local_symm), get_marks(n, symm), moduli_type)925pullback_rels = [partial_unsymmetrize_vec(v, g, r0, get_marks(n, local_symm), get_marks(n, n), moduli_type) for v in choose_basic_rels(g, r0, n, moduli_type)]926pullback_rels += pullback_derived_rels(g, r0, n, local_symm, moduli_type)927for rel in pullback_rels:928for i in range(r - r0 + 1):929for sigma in Partitions(i):930for tau in IntegerVectors(r - r0 - i, n - local_symm):931rel2 = copy(rel)932rcur = r0933for m in range(n - local_symm):934for mm in range(tau[m]):935rel2 = psi_multiple(936rel2, get_marks(n, local_symm)[-m - 1], g, rcur, n, local_symm, moduli_type)937rcur += 1938for m in sigma:939rel2 = kappa_multiple(940rel2, m, g, rcur, n, local_symm, moduli_type)941rcur += m942if local_symm < symm:943rel2 = [[symm_map[y[0]], y[1]] for y in rel2]944answer.append(simplify_sparse(rel2))945dprint("End interior_derived (%s,%s,%s,%s): %s", g,946r, n, moduli_type, floor(get_memory_usage()))947answer = remove_duplicates(answer)948return answer949950951@cached_function952def symmetrize_map(g, r, markings, symm_markings, moduli_type):953r"""954Returns the map for symmetrizing a stratum by replacing its ``markings`` with ``symm_markings``.955Requires ``symm_markings`` to be more symmetrized than ``markings``.956"""957gens = all_strata(g, r, markings, moduli_type)958dif = markings.count(1) - 2959symm_map = []960for G in gens:961GG = Graph(G.M)962for i in range(1, GG.M.ncols()):963if GG.M[0, i][0] > 0:964GG.M[0, i] = R(symm_markings[GG.M[0, i][0] + dif])965symm_map.append(num_of_stratum(GG, g, r, symm_markings, moduli_type))966return symm_map967968969@cached_function970def partial_unsymmetrize_map(g, r, markings, symm_markings, moduli_type):971r"""972Returns map that replaces a stratum with ``markings`` by a linear973combination of strata with ``symm_markings``.974975This function is an inverse of :func:`symmetrize_map`. The coefficient of976each stratum in the output is the size of its orbit under the corresponding977symmetric action. Requires ``symm_markings`` to be more symmetrized than978``markings``.979"""980target_symm = markings.count(1)981symm = symm_markings.count(1)982n = len(markings)983if target_symm == symm:984print("this should not be happening?")985return -1986if target_symm + 1 < symm:987return [partial_unsymmetrize_vec(us, g, r, markings, get_marks(n, target_symm + 1), moduli_type) for us in partial_unsymmetrize_map(g, r, get_marks(n, target_symm + 1), symm_markings, moduli_type)]988gens = all_strata(g, r, markings, moduli_type)989orbits = {}990for i in range(len(gens)):991if i in orbits.keys():992continue993orbits[i] = 1994G = gens[i]995for j in range(1, G.M.ncols()):996if G.M[0, j][0] == 2:997pt2 = j998break999for j in range(1, G.M.ncols()):1000if G.M[0, j][0] == 1:1001GG = Graph(G.M)1002GG.M[0, j] += 11003GG.M[0, pt2] -= 11004num = num_of_stratum(GG, g, r, markings, moduli_type)1005if num in orbits.keys():1006orbits[num] = orbits[num] + 11007else:1008orbits[num] = 11009symm_map = symmetrize_map(g, r, markings, symm_markings, moduli_type)1010result = [[] for i in range(num_strata(g, r, symm_markings, moduli_type))]1011for k in orbits.keys():1012result[symm_map[k]].append([k, orbits[k]])1013return result101410151016def partial_unsymmetrize_vec(vec, g, r, markings, symm_markings, moduli_type):1017r"""1018Applies partial_symmetrize_map to a relation to calculate its unsymmetrized version.1019"""1020if markings == symm_markings:1021return vec1022unsym_map = partial_unsymmetrize_map(g, r, markings, symm_markings, moduli_type)1023vec2 = []1024for x in vec:1025aut = 01026for j in unsym_map[x[0]]:1027aut += j[1]1028for j in unsym_map[x[0]]:1029vec2.append([j[0], x[1] * j[1] / QQ(aut)])1030vec2 = simplify_sparse(vec2)1031return vec2103210331034# this is faster than partial_unsymmetrize_map when both are defined1035@cached_function1036def unsymmetrize_map(g, r, markings=(), moduli_type=MODULI_ST):1037r"""1038Does the same as partial_unsymmetrize_map but is faster.1039Only works for unsymmetrizing from complete symmetry.1040"""1041markings2 = tuple([1 for i in markings])1042sym_map = symmetrize_map(g, r, markings, get_marks(len(markings), len(markings)), moduli_type)1043map = [[] for i in range(num_strata(g, r, markings2, moduli_type))]1044for i in range(len(sym_map)):1045map[sym_map[i]].append(i)1046return map104710481049def unsymmetrize_vec(vec, g, r, markings=(), moduli_type=MODULI_ST):1050unsym_map = unsymmetrize_map(g, r, markings, moduli_type)1051vec2 = []1052for x in vec:1053aut = len(unsym_map[x[0]])1054for j in unsym_map[x[0]]:1055vec2.append([j, x[1] / QQ(aut)])1056vec2 = simplify_sparse(vec2)1057return vec2105810591060def derived_rels(g, r, n, symm, moduli_type=MODULI_ST):1061r"""1062Returns a list of relations that are derived from relations with1063lower genus, codimension, and/or number of points.1064This is done by taking a Graph and inserting a relation at a vertex.1065"""1066dprint("Start derived (%s,%s,%s,%s): %s", g, r,1067n, moduli_type, floor(get_memory_usage()))1068if dim_form(g, n, moduli_type) < r:1069return []1070markings = get_marks(n, symm)1071answer = copy(interior_derived_rels(g, r, n, symm, moduli_type))1072if moduli_type <= MODULI_SM:1073return answer1074for r0 in range(1, r):1075strata = all_strata(g, r0, markings, moduli_type)1076for G in strata:1077vertex_orbits = graph_count_automorphisms(G, True)1078for i in [orbit[0] for orbit in vertex_orbits]:1079good = True1080for j in range(G.M.ncols()):1081if R(G.M[i, j][0]) != G.M[i, j]:1082good = False1083break1084if good:1085localsymm = 01086for j in range(G.M.ncols()):1087if G.M[i, j][0] == 1 and G.M[0, j][0] == 1:1088localsymm += 11089g2 = G.M[i, 0][0]1090if 3 * (r - r0) < g2 + 1:1091continue1092d = G.degree(i)1093if dim_form(g2, d, moduli_type) < r - r0:1094continue1095strata2 = all_strata(1096g2, r - r0, get_marks(d, localsymm), moduli_type)1097which_gen_list = [1098-1 for num in range(len(strata2))]1099for num in range(len(strata2)):1100G_copy = Graph(G.M)1101G_copy.replace_vertex_with_graph(i, strata2[num])1102which_gen_list[num] = num_of_stratum(1103G_copy, g, r, markings, moduli_type)1104rel_list = [partial_unsymmetrize_vec(br, g2, r - r0, get_marks(d, localsymm), get_marks(d, d), moduli_type) for br in choose_basic_rels(g2, r - r0, d, moduli_type)]1105rel_list += interior_derived_rels(g2, r - r0, d, localsymm, moduli_type)1106for rel0 in rel_list:1107relation = []1108for x0, x1 in rel0:1109if which_gen_list[x0] != -1:1110relation.append([which_gen_list[x0], x1])1111relation = simplify_sparse(relation)1112answer.append(relation)1113answer = remove_duplicates(answer)1114dprint("End derived (%s,%s,%s,%s): %s", g, r, n,1115moduli_type, floor(get_memory_usage()))1116return answer111711181119@cached_function1120def choose_basic_rels(g, r, n, moduli_type):1121r"""1122Return a basis of new relations of the tautological ring invariant under symmetry.11231124EXAMPLES::11251126sage: from admcycles.DR.moduli import MODULI_SM, MODULI_RT, MODULI_CT, MODULI_ST1127sage: from admcycles.DR.relations import choose_basic_rels1128sage: choose_basic_rels(2, 2, 0, MODULI_ST)1129[[[0, 115920],1130[1, -12240],1131[2, 13536],1132[3, -5040],1133[4, 1584],1134[5, -5040],1135[6, -144],1136[7, -36]]]1137"""1138if 3 * r < g + n + 1:1139return []1140sym_ngen = num_strata(g, r, tuple([1 for i in range(n)]), moduli_type)1141if moduli_type == MODULI_SMALL and r > dim_form(g, n, MODULI_SM):1142sym_possible_rels = [[[i, 1]] for i in range(sym_ngen)]1143else:1144sym_possible_rels = possibly_new_FZ(g, r, n, moduli_type)1145if not sym_possible_rels:1146return []1147dprint("Start basic_rels (%s,%s,%s,%s): %s", g, r,1148n, moduli_type, floor(get_memory_usage()))1149previous_rels = derived_rels(g, r, n, n, moduli_type)1150nrels = len(previous_rels)1151dprint("%s gens, %s oldrels", sym_ngen, nrels)1152D = {}1153for i in range(nrels):1154for x in previous_rels[i]:1155D[i, x[0]] = x[1]1156if nrels > 0:1157row_order, col_order = choose_orders_sparse(D, nrels, sym_ngen)1158previous_rank = compute_rank_sparse(D, row_order, col_order)1159dprint("rank %s", previous_rank)1160else:1161previous_rank = 01162row_order = []1163col_order = list(range(sym_ngen))1164answer = []1165for j in range(len(sym_possible_rels)):1166for x in sym_possible_rels[j]:1167D[nrels, x[0]] = x[1]1168row_order.append(nrels)1169nrels += 11170if compute_rank_sparse(D, row_order, col_order) > previous_rank:1171answer.append(sym_possible_rels[j])1172previous_rank += 11173dprint("rank %s", previous_rank)1174dprint("End basic_rels (%s,%s,%s,%s): %s", g, r,1175n, moduli_type, floor(get_memory_usage()))1176dprint("%s,%s,%s,%s: rank %s", g, r, n,1177moduli_type, sym_ngen - previous_rank)1178# if moduli_type > -1:1179# dsave("sparse-%s,%s,%s,%s|%s,%s,%s", g, r, n, moduli_type,1180# len(answer), sym_ngen - previous_rank, floor(get_memory_usage()))1181# if moduli_type >= 0 and sym_ngen-previous_rank != betti(g,r,tuple([1 for i in range(n)]),moduli_type):1182# dprint("ERROR: %s,%s,%s,%s",g,r,n,moduli_type)1183# return1184return answer118511861187# TODO: use matrix(D, sparse=True).rank()1188# be careful that building the matrix is what costs most of the time!1189def compute_rank_sparse(D, row_order, col_order):1190r"""1191Return the rank of the sparse matrix ``D`` given as a dictionary.11921193EXAMPLES::11941195sage: from admcycles.DR.relations import compute_rank_sparse1196sage: compute_rank_sparse({(0, 1): 1, (1, 0): 2}, [0 ,1], [0, 1])119721198"""1199count = 01200nrows = len(row_order)1201ncols = len(col_order)1202row_order_rank = [-1 for i in range(nrows)]1203col_order_rank = [-1 for i in range(ncols)]1204for i in range(nrows):1205row_order_rank[row_order[i]] = i1206for i in range(ncols):1207col_order_rank[col_order[i]] = i12081209row_contents = [set() for i in range(nrows)]1210col_contents = [set() for i in range(ncols)]1211for x in D:1212row_contents[x[0]].add(x[1])1213col_contents[x[1]].add(x[0])12141215for i in row_order:1216S = []1217for j in row_contents[i]:1218S.append(j)1219if not S:1220continue1221count += 11222S.sort(key=lambda x: col_order_rank[x])1223j = S[0]1224T = []1225for ii in col_contents[j]:1226if row_order_rank[ii] > row_order_rank[i]:1227T.append(ii)1228for k in S[1:]:1229rat = D[i, k] / QQ(D[i, j])1230for ii in T:1231if (ii, k) not in D:1232D[ii, k] = 01233row_contents[ii].add(k)1234col_contents[k].add(ii)1235D[ii, k] -= rat * D[ii, j]1236if D[ii, k] == 0:1237D.pop((ii, k))1238row_contents[ii].remove(k)1239col_contents[k].remove(ii)1240for ii in T:1241D.pop((ii, j))1242row_contents[ii].remove(j)1243col_contents[j].remove(ii)1244return count124512461247def num_new_rels(g, r, n=0, moduli_type=MODULI_ST):1248return len(choose_basic_rels(g, r, n, moduli_type))124912501251def goren_rels(g, r, markings=(), moduli_type=MODULI_ST):1252r"""1253Return the kernel of the pairing in degree ``r``.12541255EXAMPLES::12561257sage: from admcycles.DR.relations import goren_rels1258sage: goren_rels(3, 2) # long time1259[1260(1, 0, 0, -41/21, 4/35, 0, 0, 0, -5/42, 41/504, 1/105, -11/140, 1/5040),1261(0, 1, 0, -89/7, -11/35, 0, 0, 0, -5/7, 103/168, -1/7, -47/70, -1/140),1262(0, 0, 1, -1, -7/5, 0, 0, 0, 0, 0, -1/10, 0, 0),1263(0, 0, 0, 0, 0, 1, 0, 0, 0, -1/24, 0, 0, 0),1264(0, 0, 0, 0, 0, 0, 1, 0, 0, -1/24, 0, 0, 0),1265(0, 0, 0, 0, 0, 0, 0, 1, -2, 1, -7/5, -7/5, -1/10)1266]1267"""1268gorenstein_precompute(g, r, markings, moduli_type)1269r3 = dim_form(g, len(markings), moduli_type)1270r2 = r3 - r1271S1 = tuple(range(num_strata(g, r, markings, moduli_type)))1272S2 = tuple(good_generator_list(g, r2, markings, moduli_type))1273M = pairing_submatrix(S1, S2, g, r, markings, moduli_type)1274return matrix(M).kernel().basis()127512761277@cached_function1278def good_generator_list(g, r, markings=(), moduli_type=MODULI_ST):1279r"""1280Return a subset of indices whose corresponding strata generate1281the ``r``-th degree part of the tautological ring.12821283EXAMPLES::12841285sage: from admcycles.DR.moduli import MODULI_SM, MODULI_RT, MODULI_CT, MODULI_ST1286sage: from admcycles.DR.relations import good_generator_list1287sage: good_generator_list(3, 1, (), MODULI_ST)1288[0, 1, 2]1289sage: good_generator_list(3, 2, (), MODULI_ST)1290[1, 3, 4, 8, 9, 10, 11, 12]1291sage: good_generator_list(3, 3, (), MODULI_ST)1292[9, 22, 30, 31, 32, 35, 36, 37, 38, 39]1293sage: good_generator_list(3, 4, (), MODULI_ST)1294[86, 87, 109, 110, 111, 112, 113, 114, 117, 118, 119, 120]1295sage: good_generator_list(3, 5, (), MODULI_ST)1296[237, 238, 239, 257, 258, 259, 260, 261]1297sage: good_generator_list(3, 6, (), MODULI_ST)1298[373, 374, 375, 376, 377]1299"""1300gens = all_strata(g, r, markings, moduli_type)1301good_gens = []1302ngens = len(gens)1303for num in range(ngens):1304G = gens[num]1305good = True1306for i in range(1, G.M.nrows()):1307g = G.M[i, 0][0]1308codim = 01309for d in range(1, r + 1):1310if G.M[i, 0][d] != 0 and 3 * d > g:1311good = False1312break1313codim += d * G.M[i, 0][d]1314if not good:1315break1316for j in range(1, G.M.ncols()):1317codim += G.M[i, j][1]1318codim += G.M[i, j][2]1319if codim > 0 and codim >= g:1320good = False1321break1322if good:1323good_gens.append(num)1324return good_gens132513261327def choose_orders_sparse(D, nrows, ncols):1328row_nums = [0 for i in range(nrows)]1329col_nums = [0 for j in range(ncols)]1330for key in D:1331row_nums[key[0]] += 11332col_nums[key[1]] += 11333row_order = list(range(nrows))1334col_order = list(range(ncols))1335row_order.sort(key=lambda x: row_nums[x])1336col_order.sort(key=lambda x: col_nums[x])1337return row_order, col_order133813391340def choose_orders(L):1341rows = len(L)1342if rows == 0:1343return [], []1344cols = len(L[0])1345row_nums = [0 for i in range(rows)]1346col_nums = [0 for j in range(cols)]1347for i in range(rows):1348for j in range(cols):1349if L[i][j] != 0:1350row_nums[i] += 11351col_nums[j] += 11352row_order = list(range(rows))1353col_order = list(range(cols))1354row_order.sort(key=lambda x: row_nums[x])1355col_order.sort(key=lambda x: col_nums[x])1356return row_order, col_order135713581359# TODO: use matrix(L).rank()1360# be careful that building the matrix is what costs most of the time!1361def compute_rank(L):1362r"""1363Return the rank of the matrix ``L`` given as a list of lists.13641365EXAMPLES::13661367sage: from admcycles.DR.relations import compute_rank1368sage: compute_rank([[1, 2], [3, 4]])136921370sage: compute_rank([[1, 2], [2, 4]])137111372sage: compute_rank([[0, 0], [0, 0]])137301374"""1375count = 01376for i in range(len(L)):1377S = [j for j in range(len(L[0])) if L[i][j] != 0]1378if not S:1379continue1380count += 11381j = S[0]1382T = [ii for ii in range(i + 1, len(L))1383if L[ii][j] != 0]1384for k in S[1:]:1385rat = L[i][k] / L[i][j]1386for ii in T:1387L[ii][k] -= rat * L[ii][j]1388for ii in range(i + 1, len(L)):1389L[ii][j] = 01390return count139113921393def compute_rank2(L, row_order, col_order):1394count = 01395for irow in range(len(row_order)):1396i = row_order[irow]1397S = [j for j in col_order if L[i][j] != 0]1398if not S:1399continue1400count += 11401j = S[0]1402T = [ii for ii in row_order[irow + 1:]1403if L[ii][j] != 0]1404for k in S[1:]:1405rat = L[i][k] / L[i][j]1406for ii in T:1407L[ii][k] -= rat * L[ii][j]1408for ii in T:1409L[ii][j] = 01410return count141114121413