| Download
Project: admcycles
Views: 724Visibility: Unlisted (only visible to those who know the link)
Image: ubuntu2004# This file was *autogenerated* from the file DR.sage1from __future__ import absolute_import, print_function2import itertools3from six.moves import range45from copy import copy67from sage.misc.cachefunc import cached_function8from sage.rings.all import PolynomialRing, ZZ9from sage.rings.rational_field import QQ10from sage.arith.misc import factorial, binomial, bernoulli, multinomial11from sage.matrix.constructor import matrix, Matrix12from sage.combinat.all import Combinations, IntegerVectors, Partitions, Permutations, Subsets13from sage.functions.other import floor, ceil14from sage.symbolic.ring import SR15from sage.modules.free_module_element import vector16from sage.modules.free_module import span17from sage.misc.getusage import get_memory_usage1819# Sage code by Aaron Pixton ([email protected])20#21# This file contains code to compute the double ramification cycle and simplify22# it using the 3-spin tautological relations.23#24# The functions are nearly all undocumented. The main function to use to25# compute DR cycles is the following:26# - DR_compute(g,r,n,dvector,kval=0,moduli_type=MODULI_ST):27# g = genus28# r = cohomological degree (set to g for the actual DR cycle, should give29# tautological relations for r > g)30# n = number of marked points31# dvector = vector of weights to place on the marked points, should have32# sum zero in the case of the DR cycle33# kval: 0 by default (DR cycles), can be set to other integers to twist34# by copies of the log canonical bundle (e.g. 1 for differentials)35# moduli_type: MODULI_ST by default (moduli of stable curves), can be36# set to moduli spaces containing less of the boundary (e.g.37# MODULI_CT for compact type) to compute there instead38#39# Example: to compute the genus 1 DR cycle with weight vector (2,-2):40#41# sage: DR_compute(1,1,2,(2,-2))42# (0, 2, 2, 0, -1/24)43#44# The function returns a vector of rational numbers giving the coefficients45# of the standard tautological generators (xi_Gamma)_*(kappa-psi monomial).46# To see how the generators are ordered, you can view a list of them by the47# command:48#49# sage: list_strata(1,1,2)50# generator 051# [ -1 1 2]52# [X + 1 1 1]53# -------------------------54# generator 155# [ -1 1 2]56# [ 1 X + 1 1]57# -------------------------58# generator 259# [ -1 1 2]60# [ 1 1 X + 1]61# -------------------------62# generator 363# [-1 1 2 0]64# [ 0 1 1 1]65# [ 1 0 0 1]66# -------------------------67# generator 468# [-1 0 1 2]69# [ 0 2 1 1]70# -------------------------71#72# Here each generator is represented by an augmented vertex-edge incidence73# matrix:74# - each row after the first one corresponds to a vertex75# - each column after the first one corresponds to an edge or leg76# - the first column gives the genera of the vertices77# - the first row gives the markings on the legs78# - the other cells are 0 if the vertex and edge/leg are not incident79# 1 if the vertex and edge/leg are incident once80# 2 if the edge is a loop at the vertex81# - entries with polynomials in X describe kappa/psi decorations:82# - in the first column, each X^n term corresponds to a kappa_n at that83# vertex84# - in other locations, each X term corresponds to a psi at that half-edge85# - at loops, 2 + aX + bX^2 corresponds to having psi^a on one side of the86# loop and psi^b on the other87#88# In the example above, the five classes described on R^1(Mbar_{1,2}) are:89# kappa_1, psi_1, psi_2, delta_{12}, delta_{irr}.90# (Here by delta_{irr} we mean the pushforward of 1 under the gluing map91# Mbar_{0,4} -> Mbar_{1,2}, so twice the class of the physical locus.)92#93#94# There are a couple other functions that might be convenient when computing95# DR cycles:96# - DR_sparse: same as DR_compute except that it returns the answer as a97# sparse vector, e.g.98# sage: DR_sparse(1,1,2,(2,-2))99# [[1, 2], [2, 2], [4, -1/24]]100# - DR_reduced: same as DR_compute except that it only requires two arguments101# (g and dvector) and simplifies the answer using the 3-spin102# tautological relations, e.g.103# sage: DR_reduced(1,(2,-2))104# (0, 0, 0, 4, 1/8)105106107R = PolynomialRing(ZZ, 1, order='lex', names=('X',))108X = R.gen()109A_list = [ZZ(factorial(6*n))/(factorial(3*n)*factorial(2*n))110for n in range(100)]111B_list = [ZZ(factorial(6*n+1))/((6*n-1)*factorial(3*n)*factorial(2*n))112for n in range(100)]113MODULI_SMALL = -1114MODULI_SM = 0115MODULI_RT = 1116MODULI_CT = 2117MODULI_ST = 3118ENABLE_DPRINT = True119ENABLE_DSAVE = False120121122def dprint(string, *args):123if ENABLE_DPRINT:124print(string % args)125126127def dsave(string, *args):128if ENABLE_DSAVE:129save(0, string % args)130131132class Graph:133def __init__(self, M=None, genus_list=None):134if M:135self.M = copy(M)136elif genus_list:137self.M = matrix(R, len(genus_list)+1,1381, [-1]+genus_list)139else:140self.M = matrix(R, 1, 1, -1)141142def num_vertices(self):143return self.M.nrows() - 1144145def num_edges(self):146return self.M.ncols() - 1147148def h1(self):149return self.M.ncols() - self.M.nrows() + 1150151def add_vertex(self, g):152self.M = self.M.stack(matrix(1, self.M.ncols()))153self.M[-1, 0] = g154155def add_edge(self, i1, i2, marking=0):156self.M = self.M.augment(matrix(self.M.nrows(), 1))157self.M[0, -1] = marking158if i1 > 0:159self.M[i1, -1] += 1160if i2 > 0:161self.M[i2, -1] += 1162163def del_vertex(self, i):164self.M = self.M[:i].stack(self.M[(i + 1):])165166def del_edge(self, i):167if i == self.num_edges():168self.M = self.M[0:, :i]169else:170self.M = self.M[0:, :i].augment(self.M[0:, (i + 1):])171172def compute_degree_vec(self):173self.degree_vec = [0 for i in range(1, self.M.nrows())]174for i in range(1, self.M.nrows()):175for j in range(1, self.M.ncols()):176self.degree_vec[i - 1] += self.M[i, j][0]177178def degree(self, i):179return self.degree_vec[i - 1]180181def split_vertex(self, i, row1, row2):182self.M = self.M.stack(matrix(2, self.M.ncols(), row1+row2))183self.add_edge(self.M.nrows()-2,184self.M.nrows()-1)185self.del_vertex(i)186187def set_target_parity(self):188self.target_parity = 0189for i in range(1, self.M.nrows()):190local_parity = 1 + self.M[i, 0][0]191for j in range(1, self.M.ncols()):192local_parity += self.M[i, j][1] + self.M[i, j][2]193for j in range(1, self.M[i, 0].degree()+1):194local_parity += j*self.M[i, 0][j]195local_parity %= 2196self.target_parity += (local_parity << (i-1))197198def replace_vertex_with_graph(self, i, G):199nv = self.num_vertices()200ne = self.num_edges()201# i should have degree d, there should be no classes near i, and G should have markings 1,...,d and genus equal to the genus of i202hedge_list = []203for k in range(1, self.M.ncols()):204for j in range(self.M[i, k][0]):205hedge_list.append(k)206self.del_vertex(i)207for j in range(G.num_edges() - len(hedge_list)):208self.add_edge(0, 0)209for j in range(G.num_vertices()):210self.add_vertex(G.M[j+1, 0])211col = ne+1212for k in range(1, G.M.ncols()):213if G.M[0, k] > 0:214mark = ZZ(G.M[0, k])215for j in range(G.num_vertices()):216if self.M[nv+j, hedge_list[mark-1]] == 0:217self.M[nv+j, hedge_list[mark-1]] = G.M[j+1, k]218elif G.M[j+1, k] != 0:219a = self.M[nv+j, hedge_list[mark-1]][1]220b = G.M[j+1, k][1]221self.M[nv+j, hedge_list[mark-1]] = 2 + \222max(a, b)*X + min(a, b)*X**2223else:224for j in range(G.num_vertices()):225self.M[nv+j, col] = G.M[j+1, k]226col += 1227228def compute_invariant(self):229nr, nc = self.M.nrows(), self.M.ncols()230self.invariant = [[self.M[i, 0], [], [], [231[] for j in range(1, nr)]] for i in range(1, nr)]232for k in range(1, nc):233L = [i for i in range(1, nr)234if self.M[i, k] != 0]235if len(L) == 1:236if self.M[0, k] != 0:237self.invariant[L[0] -2381][2].append((self.M[0, k], self.M[L[0], k]))239else:240self.invariant[L[0]-1][1].append(self.M[L[0], k])241else:242self.invariant[L[0]-1][3][L[1]-1].append((self.M[L[0], k],243self.M[L[1], k]))244self.invariant[L[1]-1][3][L[0]-1].append((self.M[L[1], k],245self.M[L[0], k]))246for i in range(1, nr):247self.invariant[i - 1][3] = [term for term in self.invariant[i - 1][3]248if len(term)]249for k in range(len(self.invariant[i - 1][3])):250self.invariant[i - 1][3][k].sort()251self.invariant[i -2521][3][k] = tuple(self.invariant[i - 1][3][k])253self.invariant[i - 1][3].sort()254self.invariant[i - 1][3] = tuple(self.invariant[i - 1][3])255self.invariant[i - 1][2].sort()256self.invariant[i - 1][2] = tuple(self.invariant[i - 1][2])257self.invariant[i - 1][1].sort()258self.invariant[i - 1][1] = tuple(self.invariant[i - 1][1])259self.invariant[i - 1] = tuple(self.invariant[i - 1])260vertex_invariants = [[i, self.invariant[i-1]]261for i in range(1, nr)]262self.invariant.sort()263self.invariant = tuple(self.invariant)264vertex_invariants.sort(key=lambda x: x[1])265self.vertex_groupings = []266for i in range(nr-1):267if i == 0 or vertex_invariants[i][1] != vertex_invariants[i-1][1]:268self.vertex_groupings.append([])269self.vertex_groupings[-1].append(270vertex_invariants[i][0])271272def purify(self):273for i in range(self.M.nrows()):274for j in range(self.M.ncols()):275self.M[i, j] = R(self.M[i, j][0])276277def contract(self, i, vlist, elist):278# assumes graph is undecorated279if self.M[0, i] != 0:280print("ERROR: cannot contract a marking")281return282S = [row for row in range(2831, self.M.nrows()) if self.M[row, i] != 0]284if len(S) == 1:285self.M[S[0], 0] += 1286self.del_edge(i)287elist = elist[:(i-1)] + elist[i:]288else:289self.del_edge(i)290elist = elist[:(i-1)] + elist[i:]291self.add_vertex(0)292self.M[-1] += self.M[S[0]]293self.M[-1] += self.M[S[1]]294self.del_vertex(S[1])295self.del_vertex(S[0])296vlist = vlist[:(S[0]-1)] + vlist[S[0]:(S[1]-1)] + \297vlist[S[1]:] + [vlist[S[0]-1] + vlist[S[1]-1]]298return vlist, elist299300301def graph_isomorphic(G1, G2):302if G1.invariant != G2.invariant:303return False304else:305return isomorphic(G1.M, G2.M, G1.vertex_groupings, G2.vertex_groupings)306307308def isomorphic(M1, M2, group1, group2):309nr, nc = M1.nrows(), M1.ncols()310PermList = [Permutations(list(range(len(group)))) for group in group1]311for sigma_data in itertools.product(*PermList):312sigma = [0 for i in range(nr - 1)]313for i in range(len(group1)):314for j in range(len(group1[i])):315sigma[group1[i][j] - 1] = group2[i][sigma_data[i][j]]316good = True317for i in range(1, nr):318ii = sigma[i-1]319for j in range(1, i):320jj = sigma[j-1]321L1 = []322for k in range(1, nc):323if M1[i, k] != 0 and M1[j, k] != 0:324L1.append([M1[i, k], M1[j, k]])325L1.sort()326L2 = []327for k in range(1, nc):328if M2[ii, k] != 0 and M2[jj, k] != 0:329L2.append([M2[ii, k], M2[jj, k]])330L2.sort()331if L1 != L2:332good = False333break334if good is False:335break336if good:337return True338return False339340341def graph_count_automorphisms(G, vertex_orbits=False):342return count_automorphisms(G.M, G.vertex_groupings, vertex_orbits)343344345def count_automorphisms(M, grouping, vertex_orbits=False):346nr, nc = M.nrows(), M.ncols()347count = ZZ.zero()348PermList = [Permutations(list(range(len(group)))) for group in grouping]349if vertex_orbits:350isom_list = []351for sigma_data in itertools.product(*PermList):352sigma = [0 for i in range(nr-1)]353for i in range(len(grouping)):354for j in range(len(grouping[i])):355sigma[grouping[i][j]-1] = grouping[i][sigma_data[i][j]]356good = True357for i in range(1, nr):358ii = sigma[i-1]359for j in range(1, i):360jj = sigma[j-1]361L1 = []362for k in range(1, nc):363if M[i, k] != 0 and M[j, k] != 0:364L1.append([M[i, k], M[j, k]])365L1.sort()366L2 = []367for k in range(1, nc):368if M[ii, k] != 0 and M[jj, k] != 0:369L2.append([M[ii, k], M[jj, k]])370L2.sort()371if L1 != L2:372good = False373break374if good is False:375break376if good:377count += 1378if vertex_orbits:379isom_list.append(sigma)380381if vertex_orbits:382orbit_list = []383vertices_used = []384while len(vertices_used) < nr - 1:385i = [ii for ii in range(1, nr) if ii not in vertices_used][0]386orbit = []387for sigma in isom_list:388if sigma[i - 1] not in orbit:389orbit.append(sigma[i - 1])390vertices_used.append(sigma[i - 1])391orbit.sort()392orbit_list.append(orbit)393return orbit_list394395for i in range(1, nr):396for k in range(1, nc):397if M[i, k][0] == 2 and M[i, k][1] == M[i, k][2]:398count *= 2399L = []400for k in range(1, nc):401if M[i, k] != 0:402if sum(1 for j in range(1, nr) if M[j, k] != 0) == 1:403L.append([M[0, k], M[i, k]])404count *= aut(L)405406for j in range(1, i):407L = []408for k in range(1, nc):409if M[i, k] != 0 and M[j, k] != 0:410L.append([M[i, k], M[j, k]])411count *= aut(L)412return count413414415def graph_list_isomorphisms(G1, G2, only_one=False):416if G1.invariant != G2.invariant:417return []418else:419return list_isomorphisms(G1.M, G2.M, G1.vertex_groupings, G2.vertex_groupings, only_one)420421422def list_isomorphisms(M1, M2, group1, group2, only_one=False):423# Warning: does not count loops!424# If this is too slow, we can probably improve by caching a list of automorphisms and applying those to the first isom found.425nr, nc = M1.nrows(), M2.ncols()426PermList = [Permutations(list(range(len(group)))) for group in group1]427isom_list = []428for sigma_data in itertools.product(*PermList):429sigma = [0 for i in range(nr - 1)]430for i in range(len(group1)):431for j in range(len(group1[i])):432sigma[group1[i][j] - 1] = group2[i][sigma_data[i][j]]433good = True434for i in range(1, nr):435ii = sigma[i-1]436for j in range(1, i):437jj = sigma[j-1]438L1 = []439for k in range(1, nc):440if M1[i, k] != 0 and M1[j, k] != 0:441L1.append([M1[i, k], M1[j, k]])442L1.sort()443L2 = []444for k in range(1, nc):445if M2[ii, k] != 0 and M2[jj, k] != 0:446L2.append([M2[ii, k], M2[jj, k]])447L2.sort()448if L1 != L2:449good = False450break451if not good:452break453if good:454cols1 = [[M1[i, j] for i in range(nr)] for j in range(1, nc)]455cols2 = [[M2[0, j]] + [M2[sigma[i - 1], j] for i in range(1, nr)]456for j in range(1, nc)]457edge_group1 = []458edge_group2 = []459used1 = []460for j in range(1, nc):461if j not in used1:462edge_group1.append([])463edge_group2.append([])464for k in range(1, nc):465if cols1[k-1] == cols1[j-1]:466edge_group1[-1].append(k)467used1.append(k)468if cols2[k-1] == cols1[j-1]:469edge_group2[-1].append(k)470edge_PermList = [Permutations(471list(range(len(edge_group)))) for edge_group in edge_group1]472for edge_sigma_data in itertools.product(*edge_PermList):473edge_sigma = [0 for i in range(nc - 1)]474for i in range(len(edge_group1)):475for j in range(len(edge_group1[i])):476edge_sigma[edge_group1[i][j] -4771] = edge_group2[i][edge_sigma_data[i][j]]478isom_list.append([sigma, edge_sigma])479if only_one:480return isom_list481return isom_list482483484def aut(L):485"""486Return the cardinality of the automorphism group of the list ``L``.487488EXAMPLES::489490sage: from admcycles.DR import aut491sage: aut([])4921493sage: aut([4,1,3,2])4941495sage: aut([4,5,6,5,4,4,6])49624497"""498if not L:499return ZZ.one()500L.sort()501total = ZZ.one()502n = 1503last = L[0]504for l in L[1:]:505if l == last:506n += 1507total *= n508else:509n = 1510last = l511return total512513514def degenerate(G_list, moduli_type=MODULI_ST):515mod_size = moduli_type + 1516if moduli_type == MODULI_SMALL:517mod_size = MODULI_SM + 1518G_list_new = [[] for i in range(mod_size)]519for which_type in range(mod_size):520for G in G_list[which_type]:521for i in range(1, G.num_vertices()+1):522row = list(G.M[i])523m = row[0] + sum(row)524if m < 4:525continue526row1 = [0 for j in range(len(row))]527while [2 * x for x in row1] <= row:528if row1[0] == 1 and moduli_type <= MODULI_RT:529break530if row1[0] + sum(row1) >= 2 and row1[0] + sum(row1) <= m - 2:531row2 = [row[j] - row1[j] for j in range(len(row))]532G_copy = Graph(G.M)533G_copy.split_vertex(i, row1, row2)534new_type = which_type535if new_type == MODULI_SM:536new_type = MODULI_RT537if new_type == MODULI_RT and row1[0] > 0:538new_type = MODULI_CT539G_list_new[new_type].append(G_copy)540row1[-1] += 1541for j in range(1, len(row)):542if row1[-j] <= row[-j]:543break544row1[-j] = 0545row1[-j-1] += 1546for i in range(mod_size):547G_list_new[i] = remove_isomorphic(G_list_new[i])548return G_list_new549550551def dim_form(g, n, moduli_type=MODULI_ST):552g = ZZ(g)553n = ZZ(n)554if moduli_type == MODULI_ST:555return 3 * g - 3 + n556if moduli_type == MODULI_CT:557return 2 * g - 3 + n558if moduli_type == MODULI_RT:559if g > 0:560return g - 2 + n561else:562return n - 3563if moduli_type == MODULI_SM:564if n == 0:565return g - 2566elif g >= 1:567return g - 1568else:569return ZZ.zero()570if moduli_type == MODULI_SMALL:571return ZZ(1000)572return 3 * g - 3 + n573574575def decorate(G_list, r, moduli_type=MODULI_ST):576mod_size = moduli_type + 1577if moduli_type == MODULI_SMALL:578mod_size = MODULI_SM + 1579G_list_new = [[] for i in range(mod_size)]580for which_type in range(mod_size):581for G in G_list[which_type]:582G_deco = [[] for i in range(mod_size)]583G.compute_degree_vec()584nr, nc = G.M.nrows(), G.M.ncols()585two_list = []586one_list = []587for i in range(1, nr):588for j in range(1, nc):589if G.M[i, j] == 2:590two_list.append([i, j])591elif G.M[i, j] == 1:592one_list.append([i, j])593a = nr-1594b = len(two_list)595c = len(one_list)596dims = [[dim_form(G.M[i + 1, 0][0], G.degree(i+1), mod_type)597for i in range(a)] for mod_type in range(mod_size)]598for vec in IntegerVectors(r, a+b+c):599new_type = which_type600if moduli_type > MODULI_SMALL:601test_dims = vec[:a]602for i in range(b):603test_dims[two_list[i][0] - 1] += vec[a + i]604for i in range(c):605test_dims[one_list[i][0] - 1] += vec[a + b + i]606for mod_type in range(which_type, mod_size):607for i in range(a):608if test_dims[i] > dims[mod_type][i]:609new_type = mod_type + 1610break611if new_type > moduli_type:612continue613S_list = []614for i in range(a):615S_list.append(Partitions(vec[i]))616for i in range(a, a+b):617S_list.append(618[[vec[i]-j, j] for j in range(floor(vec[i]/ZZ(2) + 1))])619S = itertools.product(*S_list)620for vec2 in S:621G_copy = Graph(G.M)622for i in range(a):623for j in vec2[i]:624G_copy.M[i + 1, 0] += X**j625for i in range(a, a+b):626G_copy.M[two_list[i-a][0], two_list[i-a]627[1]] += vec2[i][0]*X + vec2[i][1]*X**2628for i in range(c):629G_copy.M[one_list[i][0],630one_list[i][1]] += vec[i+a+b]*X631G_deco[new_type].append(G_copy)632for mod_type in range(mod_size):633G_list_new[mod_type] += remove_isomorphic(G_deco[mod_type])634return G_list_new635636637def remove_isomorphic(G_list):638G_list_new = []639inv_dict = {}640count = 0641for G1 in G_list:642G1.compute_invariant()643if G1.invariant not in inv_dict:644inv_dict[G1.invariant] = []645good = True646for i in inv_dict[G1.invariant]:647if graph_isomorphic(G1, G_list_new[i]):648good = False649break650if good:651G_list_new.append(G1)652inv_dict[G1.invariant].append(count)653count += 1654return G_list_new655656657def num_strata(g, r, markings=(), moduli_type=MODULI_ST):658return len(all_strata(g, r, markings, moduli_type))659660661def num_pure_strata(g, r, markings=(), moduli_type=MODULI_ST):662return len(all_pure_strata(g, r, markings, moduli_type))663664665def single_stratum(num, g, r, markings=(), moduli_type=MODULI_ST):666return all_strata(g, r, markings, moduli_type)[num]667668669def single_pure_stratum(num, g, r, markings=(), moduli_type=MODULI_ST):670return all_pure_strata(g, r, markings, moduli_type)[num]671672673@cached_function674def autom_count(num, g, r, markings=(), moduli_type=MODULI_ST):675return graph_count_automorphisms(single_stratum(num, g, r, markings, moduli_type))676677678@cached_function679def pure_strata_autom_count(num, g, r, markings=(), moduli_type=MODULI_ST):680return graph_count_automorphisms(single_pure_stratum(num, g, r, markings, moduli_type))681682683@cached_function684def unpurify_map(g, r, markings=(), moduli_type=MODULI_ST):685unpurify = {}686pure_strata = [all_pure_strata(g, r0, markings, moduli_type)687for r0 in range(r+1)]688impure_strata = all_strata(g, r, markings, moduli_type)689for i, strati in enumerate(impure_strata):690G = Graph(strati.M)691G.purify()692r0 = G.num_edges() - len(markings)693found = False694for j in range(len(pure_strata[r0])):695if G.M == pure_strata[r0][j].M:696G_key = (r0, j)697found = True698break699if not found:700print("ERROR! Purification failed.")701if G_key not in unpurify:702unpurify[G_key] = []703unpurify[G_key].append(i)704return unpurify705706707@cached_function708def all_strata(g, r, markings=(), moduli_type=MODULI_ST):709mod_size = moduli_type + 1710if moduli_type == MODULI_SMALL:711mod_size = MODULI_SM + 1712big_list = [[] for i in range(mod_size)]713for loops in range(g+1):714if loops == 1 and moduli_type <= MODULI_CT:715break716if loops > r:717break718for edges in range(r-loops+1):719if edges == 1 and moduli_type <= MODULI_SM:720break721G = Graph()722G.add_vertex(g-loops)723for k in range(loops):724G.add_edge(1, 1)725for k in markings:726G.add_edge(1, 0, k)727GGG = [[] for i in range(mod_size)]728if loops == 0:729if edges == 0:730GGG[MODULI_SM] = [G]731else:732GGG[MODULI_RT] = [G]733else:734GGG[MODULI_ST] = [G]735for k in range(edges):736GGG = degenerate(GGG, moduli_type)737GGG = decorate(GGG, r-loops-edges, moduli_type)738for i in range(mod_size):739big_list[i] += GGG[i]740combined_list = []741for i in range(mod_size):742combined_list += big_list[i]743for G in combined_list:744G.compute_degree_vec()745G.set_target_parity()746return combined_list747748749@cached_function750def all_pure_strata(g, r, markings=(), moduli_type=MODULI_ST):751big_list = [[] for i in range(moduli_type+1)]752for loops in range(g+1):753if loops == 1 and moduli_type <= MODULI_CT:754break755if loops > r:756break757for edges in range(r-loops, r-loops+1):758if edges >= 1 and moduli_type <= MODULI_SM:759break760G = Graph()761G.add_vertex(g-loops)762for k in range(loops):763G.add_edge(1, 1)764for k in markings:765G.add_edge(1, 0, k)766G.compute_invariant()767GGG = [[] for i in range(moduli_type+1)]768if loops == 0:769if edges == 0:770GGG[MODULI_SM] = [G]771else:772GGG[MODULI_RT] = [G]773else:774GGG[MODULI_ST] = [G]775for k in range(edges):776GGG = degenerate(GGG, moduli_type)777for i in range(moduli_type+1):778big_list[i] += GGG[i]779combined_list = []780for i in range(moduli_type+1):781combined_list += big_list[i]782return combined_list783784############################785786787def C_coeff(m, term):788n = term - m // 3789if n < 0:790return 0791if m % 3 == 0:792return A_list[n]793else:794return B_list[n]795796797@cached_function798def dual_C_coeff(i, j, parity):799total = ZZ.zero()800k = parity % 2801while k // 3 <= i:802if k % 3 != 2:803total += (-1)**(k // 3) * C_coeff(k, i) * C_coeff(-2 - k, j)804k += 2805return total806807808def poly_to_partition(F):809mmm = F.degree()810target_partition = []811for i in range(1, mmm+1):812for j in range(F[i]):813target_partition.append(i)814return tuple(target_partition)815816817@cached_function818def kappa_coeff(sigma, kappa_0, target_partition):819total = ZZ.zero()820num_ones = sum(1 for i in sigma if i == 1)821for i in range(0, num_ones+1):822for injection in Permutations(list(range(len(target_partition))), len(sigma)-i):823term = binomial(num_ones, i)*binomial(kappa_0 +824len(target_partition) + i-1, i)*factorial(i)825for j in range(len(sigma)-i):826term *= C_coeff(sigma[j+i], target_partition[injection[j]])827for j in range(len(target_partition)):828if j in injection:829continue830term *= C_coeff(0, target_partition[j])831total += term832total = (-1)**(len(target_partition)+len(sigma)) * \833total/aut(list(target_partition))834return total835836837@cached_function838def FZ_kappa_factor(num, sigma, g, r, markings=(), moduli_type=MODULI_ST):839G = single_stratum(num, g, r, markings, moduli_type)840L = []841nv = G.num_vertices()842for i in range(1, nv+1):843L.append((2 * G.M[i, 0][0] + G.degree(i) -8442, G.M[i, 0] - G.M[i, 0][0]))845LL = []846tau = []847for i in range(nv):848mini = -1849for j in range(nv):850if (i == 0 or L[j] > LL[-1] or L[j] == LL[-1] and j > tau[-1]) and (mini == -1 or L[j] < L[mini]):851mini = j852tau.append(mini)853LL.append(L[mini])854factor_dict = FZ_kappa_factor2(tuple(LL), sigma)855factor_vec = [0 for i in range(1 << nv)]856for parity_key in factor_dict:857parity = 0858for i in range(nv):859if parity_key[i] == 1:860parity += 1 << tau[i]861factor_vec[parity] = factor_dict[parity_key]862return factor_vec863864865@cached_function866def FZ_marking_factor(num, marking_vec, g, r, markings=(), moduli_type=MODULI_ST):867G = single_stratum(num, g, r, markings, moduli_type)868nv = G.num_vertices()869ne = G.num_edges()870num_parities = ZZ(2) ** nv871PPP_list = []872for marks in marking_vec:873PPP_list.append(Permutations(marks[1]))874PPP = itertools.product(*PPP_list)875marking_factors = [0 for i in range(num_parities)]876incident_vertices = []877for mark_type in marking_vec:878incident_vertices.append([])879for k in range(1, ne+1):880if G.M[0, k] == mark_type[0]:881for i in range(1, nv+1):882if G.M[i, k] != 0:883incident_vertices[-1].append((i - 1, G.M[i, k][1]))884break885for perms in PPP:886parity = 0887marking_factor = 1888for marks_index in range(len(marking_vec)):889for count in range(len(incident_vertices[marks_index])):890marking_factor *= C_coeff(perms[marks_index][count],891incident_vertices[marks_index][count][1])892parity ^= (perms[marks_index][count] %893ZZ(2)) << incident_vertices[marks_index][count][0]894marking_factors[parity] += marking_factor895return marking_factors896897898@cached_function899def FZ_kappa_factor2(L, sigma):900nv = len(L)901mmm = max((0,)+sigma)902sigma_grouped = [0 for i in range(mmm)]903for i in sigma:904sigma_grouped[i-1] += 1905S_list = []906for i in sigma_grouped:907S_list.append(IntegerVectors(i, nv))908S = itertools.product(*S_list)909kappa_factors = {}910for parity in itertools.product(*[(0, 1) for i in range(nv)]):911kappa_factors[tuple(parity)] = 0912for assignment in S:913assigned_sigma = [[] for j in range(nv)]914for i in range(mmm):915for j in range(nv):916for k in range(assignment[i][j]):917assigned_sigma[j].append(i+1)918sigma_auts = 1919parity = [0 for i in range(nv)]920kappa_factor = ZZ.one()921for j in range(nv):922sigma_auts *= aut(assigned_sigma[j])923parity[j] += sum(assigned_sigma[j])924parity[j] %= ZZ(2)925kappa_factor *= kappa_coeff(926tuple(assigned_sigma[j]), L[j][0], poly_to_partition(L[j][1]))927kappa_factors[tuple(parity)] += kappa_factor/sigma_auts928return kappa_factors929930931@cached_function932def FZ_hedge_factor(num, g, r, markings=(), moduli_type=MODULI_ST):933G = single_stratum(num, g, r, markings, moduli_type)934nv = G.num_vertices()935num_parities = ZZ(2) ** nv936ne = G.num_edges()937edge_list = []938for k in range(1, ne+1):939if G.M[0, k] == 0:940edge_list.append([k])941for i in range(1, nv+1):942if G.M[i, k] != 0:943edge_list[-1].append(i)944if G.M[i, k][0] == 2:945edge_list[-1].append(i)946hedge_factors = [0 for i in range(num_parities)]947for edge_parities in itertools.product(*[[0, 1] for i in edge_list]):948parity = 0949for i in range(len(edge_list)):950if edge_parities[i] == 1:951parity ^= 1 << (edge_list[i][1]-1)952parity ^= 1 << (edge_list[i][2]-1)953hedge_factor = 1954for i in range(len(edge_list)):955if edge_list[i][1] == edge_list[i][2]:956hedge_factor *= dual_C_coeff(G.M[edge_list[i][1], edge_list[i][0]][1],957G.M[edge_list[i][1], edge_list[i][0]][2], edge_parities[i] % ZZ(2))958else:959hedge_factor *= dual_C_coeff(G.M[edge_list[i][1], edge_list[i][0]][1],960G.M[edge_list[i][2], edge_list[i][0]][1], edge_parities[i] % ZZ(2))961hedge_factors[parity] += hedge_factor962return hedge_factors963964965@cached_function966def FZ_coeff(num, FZ_param, g, r, markings=(), moduli_type=MODULI_ST):967sigma = FZ_param[0]968marking_vec = FZ_param[1]969G = single_stratum(num, g, r, markings, moduli_type)970nv = G.num_vertices()971graph_auts = autom_count(num, g, r, markings, moduli_type)972h1_factor = ZZ(2) ** G.h1()973num_parities = ZZ(2) ** nv974975marking_factors = FZ_marking_factor(976num, marking_vec, g, r, markings, moduli_type)977kappa_factors = FZ_kappa_factor(num, sigma, g, r, markings, moduli_type)978hedge_factors = FZ_hedge_factor(num, g, r, markings, moduli_type)979980total = ZZ.zero()981for i in range(num_parities):982if marking_factors[i] == 0:983continue984for j in range(num_parities):985total += marking_factors[i]*kappa_factors[j] * \986hedge_factors[i ^ j ^ G.target_parity]987988total /= h1_factor*graph_auts989return total990991992@cached_function993def interior_FZ(g, r, markings=(), moduli_type=MODULI_ST):994ngen = num_strata(g, r, markings, moduli_type)995relations = []996FZpl = FZ_param_list(3 * r - g - 1, markings)997for FZ_param in FZpl:998relation = [FZ_coeff(i, FZ_param, g, r, markings, moduli_type)999for i in range(ngen)]1000relations.append(relation)1001return relations100210031004def possibly_new_FZ(g, r, n=0, moduli_type=MODULI_ST):1005m = 3 * r - g - 1 - n1006if m < 0:1007return []1008dprint("Start FZ (%s,%s,%s,%s): %s", g, r, n, moduli_type,1009floor(get_memory_usage()))1010markings = (1,) * n1011ngen = num_strata(g, r, markings, moduli_type)1012relations = []1013for i in range(m + 1):1014if m - i % 2:1015continue1016for sigma in Partitions(i):1017# TODO: the line above should iterate directly over the set1018# of partitions with all parts of size = 1 (mod 3)1019if any(j % 3 != 1 for j in sigma):1020continue1021if n > 0:1022FZ_param = (tuple(sigma), ((1, markings),))1023else:1024FZ_param = (tuple(sigma), ())1025relation = []1026for j in range(ngen):1027coeff = FZ_coeff(j, FZ_param, g, r, markings, moduli_type)1028if coeff != 0:1029relation.append([j, coeff])1030relations.append(relation)1031dprint("End FZ (%s,%s,%s,%s): %s", g, r, n, moduli_type,1032floor(get_memory_usage()))1033return relations103410351036@cached_function1037def boundary_FZ(g, r, markings=(), moduli_type=MODULI_ST):1038if moduli_type <= MODULI_SM:1039return []1040generators = all_strata(g, r, markings, moduli_type)1041ngen = len(generators)1042relations = []1043for r0 in range(1, r):1044strata = all_strata(g, r0, markings, moduli_type)1045for G in strata:1046vertex_orbits = graph_count_automorphisms(G, True)1047for i in [orbit[0] for orbit in vertex_orbits]:1048good = True1049for j in range(G.M.ncols()):1050if R(G.M[i, j][0]) != G.M[i, j]:1051good = False1052break1053if good:1054g2 = G.M[i, 0][0]1055if 3 * (r - r0) < g2 + 1:1056continue1057d = G.degree(i)1058if dim_form(g2, d, moduli_type) < r-r0:1059continue1060strata2 = all_strata(1061g2, r-r0, tuple(range(1, d+1)), moduli_type)1062which_gen_list = [-1 for num in range(len(strata2))]1063for num in range(len(strata2)):1064G_copy = Graph(G.M)1065G_copy.replace_vertex_with_graph(i, strata2[num])1066which_gen_list[num] = num_of_stratum(1067G_copy, g, r, markings, moduli_type)1068rFZpl = reduced_FZ_param_list(1069G, i, g2, d, 3 * (r - r0) - g2 - 1)1070ccccc = 01071for FZ_param in rFZpl:1072relation = [0] * ngen1073for num in range(len(strata2)):1074if which_gen_list[num] != -1:1075relation[which_gen_list[num]] += FZ_coeff(num, FZ_param, g2, r-r0, tuple(1076range(1, d+1)), moduli_type)1077relations.append(relation)1078ccccc += 11079return relations108010811082def list_all_FZ(g, r, markings=(), moduli_type=MODULI_ST):1083relations = copy(interior_FZ(g, r, markings, moduli_type))1084if moduli_type > MODULI_SM:1085relations += boundary_FZ(g, r, markings, moduli_type)1086if not relations:1087ngen = num_strata(g, r, markings, moduli_type)1088relations.append([0 for i in range(ngen)])1089return relations109010911092def reduced_FZ_param_list(G, v, g, d, n):1093params = FZ_param_list(n, tuple(range(1, d+1)))1094graph_params = []1095M = matrix(R, 2, d + 1)1096M[0, 0] = -11097for i in range(1, d+1):1098M[0, i] = i1099for p in params:1100G_copy = Graph(G.M)1101M[1, 0] = -g-11102for j in p[0]:1103M[1, 0] += X**j1104for i in range(1, d + 1):1105M[1, i] = 1 + p[1][i-1][1][0]*X1106G_p = Graph(M)1107G_copy.replace_vertex_with_graph(v, G_p)1108graph_params.append([p, G_copy])1109params_reduced = []1110graphs_seen = []1111for x in graph_params:1112x[1].compute_invariant()1113good = True1114for GG in graphs_seen:1115if graph_isomorphic(x[1], GG):1116good = False1117break1118if good:1119graphs_seen.append(x[1])1120params_reduced.append(x[0])1121return params_reduced112211231124def FZ_param_list(n, markings=()):1125if n < 0:1126return []1127final_list = []1128mmm = max((0,)+markings)1129markings_grouped = [0 for i in range(mmm)]1130for i in markings:1131markings_grouped[i-1] += 11132markings_best = []1133for i in range(mmm):1134if markings_grouped[i] > 0:1135markings_best.append([i+1, markings_grouped[i]])1136for j in range(floor(n/ZZ(2) + 1)):1137for n_vec in IntegerVectors(n-2 * j, 1 + len(markings_best)):1138S_list = [[list(sigma) for sigma in Partitions(n_vec[0])1139if not any(l % 3 == 2 for l in sigma)]]1140# TODO: the line above should iterate directly over the set1141# of partitions with no parts of size = 2 (mod 3)1142for i in range(len(markings_best)):1143S_list.append(Partitions(1144n_vec[i+1]+markings_best[i][1], length=markings_best[i][1]).list())1145S_list[-1] = [[k - 1 for k in sigma] for sigma in S_list[-1]1146if sum(1 for l in sigma if (l % 3) == 0) == 0]1147for S in itertools.product(*S_list):1148final_list.append((tuple(S[0]), tuple([(markings_best[k][0], tuple(1149S[k+1])) for k in range(len(markings_best))])))1150return final_list115111521153def FZ_matrix(g, r, markings=(), moduli_type=MODULI_ST):1154return matrix(list_all_FZ(g, r, markings, moduli_type))11551156#####################################115711581159@cached_function1160def contraction_table(g, r, markings=(), moduli_type=MODULI_ST):1161contraction_dict = {}1162pure_strata = [all_pure_strata(g, r0, markings, moduli_type)1163for r0 in range(r+1)]1164for r0 in range(r+1):1165for ii in range(len(pure_strata[r0])):1166G = pure_strata[r0][ii]1167S = [j for j in range(1, G.M.ncols()) if G.M[0, j] == 0]1168contractions = {}1169for edge_subset in itertools.product(*[[0, 1] for i in range(r0)]):1170key = tuple(i for i in range(1171r0) if edge_subset[i] == 0)1172A = [S[i] for i in key]1173A.reverse()1174vlist = [[i] for i in range(1, G.M.nrows())]1175elist = list(range(1, G.M.ncols()))1176Gcopy = Graph(G.M)1177for i in A:1178vlist, elist = Gcopy.contract(i, vlist, elist)1179Gcopy.compute_invariant()1180rnew = r0 - len(A)1181contraction_result = []1182for i in range(len(pure_strata[rnew])):1183L = graph_list_isomorphisms(1184pure_strata[rnew][i], Gcopy, True)1185if L:1186contraction_result.append((rnew, i))1187contraction_result.append(L[0])1188break1189contraction_result.append((vlist, elist))1190contractions[key] = contraction_result11911192for edge_assignment in itertools.product(*[[0, 1, 2] for i in range(r0)]):1193if sum(1 for i in edge_assignment if i == 1) > r-r0:1194continue1195key1 = tuple(i for i in range(1196r0) if edge_assignment[i] == 0)1197B = [S[i]1198for i in range(r0) if edge_assignment[i] == 1]1199key2 = tuple(i for i in range(1200r0) if edge_assignment[i] == 2)1201if key1 > key2:1202continue1203contract1 = contractions[key1]1204contract2 = contractions[key2]1205dict_key = [contract1[0], contract2[0]]1206dict_entry = [contract1[1], contract2[1]]1207if dict_key[0] > dict_key[1]:1208dict_key.reverse()1209dict_entry.reverse()1210dict_entry = [(r0, ii), B, contract2[2],1211contract1[2]] + dict_entry1212else:1213dict_entry = [(r0, ii), B, contract1[2],1214contract2[2]] + dict_entry1215dict_key = tuple(dict_key)1216if dict_key not in contraction_dict:1217contraction_dict[dict_key] = []1218contraction_dict[dict_key].append(dict_entry)1219if dict_key[0] == dict_key[1]:1220contraction_dict[dict_key].append(1221dict_entry[:2] + [dict_entry[3], dict_entry[2], dict_entry[5], dict_entry[4]])1222return contraction_dict122312241225@cached_function1226def multiply(r1, i1, r2, i2, g, rmax, markings=(), moduli_type=MODULI_ST):1227unpurify = unpurify_map(g, r1+r2, markings, moduli_type)1228gens = all_strata(g, r1+r2, markings, moduli_type)1229ngens = num_strata(g, r1+r2, markings, moduli_type)1230answer = [0 for i in range(ngens)]1231pure_strata = [all_pure_strata(g, r, markings, moduli_type)1232for r in range(rmax+1)]1233contraction_dict = contraction_table(g, rmax, markings, moduli_type)1234G1 = single_stratum(i1, g, r1, markings, moduli_type)1235G2 = single_stratum(i2, g, r2, markings, moduli_type)1236G1copy = Graph(G1.M)1237G2copy = Graph(G2.M)1238G1copy.purify()1239G2copy.purify()1240pure_r1 = G1copy.num_edges() - len(markings)1241pure_r2 = G2copy.num_edges() - len(markings)1242found = False1243for i in range(len(pure_strata[pure_r1])):1244if G1copy.M == pure_strata[pure_r1][i].M:1245G1_key = (pure_r1, i)1246found = True1247break1248if not found:1249print("ERROR! Purification failed.")1250found = False1251for i in range(len(pure_strata[pure_r2])):1252if G2copy.M == pure_strata[pure_r2][i].M:1253G2_key = (pure_r2, i)1254found = True1255break1256if not found:1257print("ERROR! Purification failed.")1258if G1_key > G2_key:1259return multiply(r2, i2, r1, i1, g, rmax, markings, moduli_type)12601261if (G1_key, G2_key) not in contraction_dict:1262return answer1263for L in contraction_dict[(G1_key, G2_key)]:1264H = pure_strata[L[0][0]][L[0][1]]1265Hloops = []1266if moduli_type > MODULI_CT:1267for i in range(1, H.M.nrows()):1268for j in range(1, H.M.ncols()):1269if H.M[i, j][0] == 2:1270Hloops.append((i, j))1271auts = pure_strata_autom_count(1272L[0][1], g, L[0][0], markings, moduli_type)1273B = L[1]1274if len(B) == pure_r1 and len(B) == pure_r2:1275auts *= 21276aut_cosets1 = automorphism_cosets(i1, g, r1, markings, moduli_type)1277aut_cosets2 = automorphism_cosets(i2, g, r2, markings, moduli_type)1278auts /= aut_cosets1[0]*aut_cosets2[0]1279for isom1 in aut_cosets1[1]:1280for isom2 in aut_cosets2[1]:1281Hcopy = Graph(H.M)1282vmap1 = [0 for i in range(G1.M.nrows())]1283for i in range(1, G1.M.nrows()):1284vmap1[i] = L[2][0][L[4][0][isom1[0]1285[i-1]-1]-1]1286emap1 = [0 for i in range(G1.M.ncols())]1287for i in range(1, G1.M.ncols()):1288emap1[i] = L[2][1][L[4][1][isom1[1]1289[i-1]-1]-1]1290vmap2 = [0 for i in range(G2.M.nrows())]1291for i in range(1, G2.M.nrows()):1292vmap2[i] = L[3][0][L[5][0][isom2[0]1293[i-1]-1]-1]1294emap2 = [0 for i in range(G2.M.ncols())]1295for i in range(1, G2.M.ncols()):1296emap2[i] = L[3][1][L[5][1][isom2[1]1297[i-1]-1]-1]12981299psilooplist = []1300psiindexlist = []1301loop_factor = ZZ.one()1302for i in range(1, G1.M.nrows()):1303for j in range(1, G1.M.ncols()):1304if G1.M[i, j][0] != 0:1305if G1.M[i, j][0] == 1:1306if G1.M[i, j][1] != 0:1307jj = emap1[j]1308for ii in vmap1[i]:1309if H.M[ii, jj] != 0:1310Hcopy.M[ii, jj] += G1.M[i, j][1]*X1311break1312elif G1.M[i, j][1] == 0:1313loop_factor *= 21314else:1315jj = emap1[j]1316psilooplist.append([[G1.M[i, j][1], G1.M[i, j][2]], [1317G1.M[i, j][2], G1.M[i, j][1]]])1318psiindexlist.append([jj])1319for ii in vmap1[i]:1320for k in range(H.M[ii, jj][0]):1321psiindexlist[-1].append(ii)1322for i in range(1, G2.M.nrows()):1323for j in range(1, G2.M.ncols()):1324if G2.M[i, j][0] != 0:1325if G2.M[i, j][0] == 1:1326if G2.M[i, j][1] != 0:1327if G2.M[i, j][0] == 1:1328jj = emap2[j]1329for ii in vmap2[i]:1330if H.M[ii, jj] != 0:1331Hcopy.M[ii,1332jj] += G2.M[i, j][1]*X1333break1334elif G2.M[i, j][1] == 0:1335loop_factor *= 21336else:1337jj = emap2[j]1338psilooplist.append([[G2.M[i, j][1], G2.M[i, j][2]], [1339G2.M[i, j][2], G2.M[i, j][1]]])1340psiindexlist.append([jj])1341for ii in vmap2[i]:1342for k in range(H.M[ii, jj][0]):1343psiindexlist[-1].append(ii)13441345Klocationlist = []1346Kindexlist = []1347for i in range(1, G1.M.nrows()):1348for r in range(1, rmax+1):1349for k in range(G1.M[i, 0][r]):1350Klocationlist.append(vmap1[i])1351Kindexlist.append(r)1352for i in range(1, G2.M.nrows()):1353for r in range(1, rmax+1):1354for k in range(G2.M[i, 0][r]):1355Klocationlist.append(vmap2[i])1356Kindexlist.append(r)13571358psilist = []1359for j in B:1360S = [i for i in range(1, H.M.nrows()) if H.M[i, j][0] != 0]1361if len(S) == 2:1362psilist.append([[S[0], j], [S[1], j]])1363else:1364psilooplist.append([[0, 1], [1, 0]])1365psiindexlist.append([j, S[0], S[0]])13661367for psiloopvals in itertools.product(*psilooplist):1368for Klocs in itertools.product(*Klocationlist):1369for psilocs in itertools.product(*psilist):1370Hcopycopy = Graph(Hcopy.M)1371for i in range(len(psiindexlist)):1372Hcopycopy.M[psiindexlist[i][1],1373psiindexlist[i][0]] += psiloopvals[i][0]*X1374if psiindexlist[i][1] == psiindexlist[i][2]:1375Hcopycopy.M[psiindexlist[i][1],1376psiindexlist[i][0]] += psiloopvals[i][1]*X**21377else:1378Hcopycopy.M[psiindexlist[i][2],1379psiindexlist[i][0]] += psiloopvals[i][1]*X1380for i in range(len(Kindexlist)):1381Hcopycopy.M[Klocs[i],13820] += X**Kindexlist[i]1383for i in psilocs:1384Hcopycopy.M[i[0], i[1]] += X1385for k in Hloops:1386if Hcopycopy.M[k][2] > Hcopycopy.M[k][1]:1387Hcopycopy.M[k] += (Hcopycopy.M[k]1388[2] - Hcopycopy.M[k][1])*(X - X**2)1389Hcopycopy.compute_invariant()1390for which_gen in unpurify[L[0]]:1391if graph_isomorphic(Hcopycopy, gens[which_gen]):1392answer[which_gen] += (-1)**len(B) * \1393loop_factor/auts1394break1395return answer139613971398def check_associativity(g, r1, r2, r3, markings=(), moduli_type=MODULI_ST):1399ngens1 = num_strata(g, r1, markings, moduli_type)1400ngens2 = num_strata(g, r2, markings, moduli_type)1401ngens3 = num_strata(g, r3, markings, moduli_type)1402print("%s*%s*%s = %s associators to compute:" %1403(ngens1, ngens2, ngens3, ngens1*ngens2*ngens3))1404count = 01405for i1 in range(ngens1):1406for i2 in range(ngens2):1407for i3 in range(ngens3):1408a = multiply(r1, i1, r2, i2, g, r1+r2 +1409r3, markings, moduli_type)1410answer1 = vector(1411[0 for i in range(num_strata(g, r1+r2+r3, markings, moduli_type))])1412for j in range(num_strata(g, r1+r2, markings, moduli_type)):1413if a[j] == 0:1414continue1415answer1 += a[j]*vector(multiply(r1+r2, j, r3,1416i3, g, r1+r2+r3, markings, moduli_type))1417a = multiply(r1, i1, r3, i3, g, r1+r2 +1418r3, markings, moduli_type)1419answer2 = vector(1420[0 for i in range(num_strata(g, r1+r2+r3, markings, moduli_type))])1421for j in range(num_strata(g, r1+r3, markings, moduli_type)):1422if a[j] == 0:1423continue1424answer2 += a[j]*vector(multiply(r1+r3, j, r2,1425i2, g, r1+r2+r3, markings, moduli_type))1426if answer1 != answer2:1427print("Error: %s %s %s" % (i1, i2, i3))1428count += 11429if count % 100 == 0:1430print("%s done" % count)143114321433def gorenstein_precompute(g, r1, markings=(), moduli_type=MODULI_ST):1434r3 = dim_form(g, len(markings), moduli_type)1435r2 = r3 - r11436all_strata(g, r1, markings, moduli_type)1437all_strata(g, r2, markings, moduli_type)1438contraction_table(g, r3, markings, moduli_type)1439unpurify_map(g, r3, markings, moduli_type)144014411442def pairing_matrix(g, r1, markings=(), moduli_type=MODULI_ST):1443r3 = dim_form(g, len(markings), moduli_type)1444r2 = r3-r11445ngens1 = num_strata(g, r1, markings, moduli_type)1446ngens2 = num_strata(g, r2, markings, moduli_type)1447ngens3 = num_strata(g, r3, markings, moduli_type)1448socle_evaluations = [socle_evaluation(1449i, g, markings, moduli_type) for i in range(ngens3)]1450pairings = [[0 for i2 in range(ngens2)] for i1 in range(ngens1)]1451sym = bool(r1 == r2)1452for i1 in range(ngens1):1453for i2 in range(ngens2):1454if sym and i1 > i2:1455pairings[i1][i2] = pairings[i2][i1]1456continue1457L = multiply(r1, i1, r2, i2, g, r3, markings, moduli_type)1458pairings[i1][i2] = sum([L[k]*socle_evaluations[k]1459for k in range(ngens3)])1460return pairings146114621463@cached_function1464def pairing_submatrix(S1, S2, g, r1, markings=(), moduli_type=MODULI_ST):1465r3 = dim_form(g, len(markings), moduli_type)1466r2 = r3-r11467# ngens1 = num_strata(g, r1, markings, moduli_type)1468# ngens2 = num_strata(g, r2, markings, moduli_type)1469ngens3 = num_strata(g, r3, markings, moduli_type)1470socle_evaluations = [socle_evaluation(1471i, g, markings, moduli_type) for i in range(ngens3)]1472pairings = [[0 for i2 in S2] for i1 in S1]1473sym = bool(r1 == r2 and S1 == S2)1474for i1 in range(len(S1)):1475for i2 in range(len(S2)):1476if sym and i1 > i2:1477pairings[i1][i2] = pairings[i2][i1]1478continue1479L = multiply(r1, S1[i1], r2, S2[i2], g, r3, markings, moduli_type)1480pairings[i1][i2] = sum([L[k]*socle_evaluations[k]1481for k in range(ngens3)])1482return pairings14831484#####################################148514861487def betti(g, r, marked_points=(), moduli_type=MODULI_ST):1488"""1489This function returns the predicted rank of the codimension r grading1490of the tautological ring of the moduli space of stable genus g curves1491with marked points labeled by the multiset marked_points.14921493g and r should be nonnegative integers and marked_points should be a1494tuple of positive integers.14951496The parameter moduli_type determines which moduli space to use:1497- MODULI_ST: all stable curves (this is the default)1498- MODULI_CT: curves of compact type1499- MODULI_RT: curves with rational tails1500- MODULI_SM: smooth curves15011502EXAMPLES::15031504sage: from admcycles.DR import betti15051506Check rank R^3(bar{M}_2) = 1::15071508sage: betti(2,3)1509115101511Check rank R^2(bar{M}_{2,3}) = 44::15121513sage: betti(2,2,(1,2,3))15144415151516Check rank R^2(bar{M}_{2,3})^{S_3} = 20::15171518sage: betti(2,2,(1,1,1))15192015201521Check rank R^2(bar{M}_{2,3})^{S_2} = 32 (S_2 interchanging markings 1 and 2)::15221523sage: betti(2,2,(1,1,2))15243215251526Check rank R^2(M^c_4) = rank R^3(M^c_4) = 6::15271528sage: from admcycles.DR import MODULI_CT, MODULI_RT, MODULI_SM1529sage: betti(4,2,(),MODULI_CT)153061531sage: betti(4,3,(),MODULI_CT)1532615331534We 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.1535Indeed, betti(17,8,(1,1),MODULI_RT) = 122 and betti(17,9,(1,1),MODULI_RT)=1231536Similarly, we have rank R^9(M_{20,1}) = 75 < rank R^10(M_{20,1}) = 761537Indeed, betti(20,9,(1,),MODULI_SM) = 75 and betti(20,10,(1,),MODULI_SM) = 76.1538"""1539L = list_all_FZ(g, r, marked_points, moduli_type)1540L.reverse()1541return (len(L[0]) - compute_rank(L))154215431544def gorenstein(g, r, marked_points=(), moduli_type=MODULI_ST):1545"""1546This function returns the rank of the codimension r grading of the1547Gorenstein quotient of the tautological ring of the moduli space of genus g1548curves with marked points labeled by the multiset marked_points.15491550g and r should be nonnegative integers and marked_points should be a1551tuple of positive integers.15521553The parameter moduli_type determines which moduli space to use:1554- MODULI_ST: all stable curves (this is the default)1555- MODULI_CT: curves of compact type1556- MODULI_RT: curves with rational tails15571558EXAMPLES::15591560sage: from admcycles.DR import gorenstein15611562Check rank Gor^3(bar{M}_{3}) = 10::15631564sage: gorenstein(3,3)15651015661567Check rank Gor^2(bar{M}_{2,2}) = 14::15681569sage: gorenstein(2,2,(1,2))15701415711572Check rank Gor^2(bar{M}_{2,2})^{S_2} = 11::15731574sage: gorenstein(2,2,(1,1))15751115761577Check rank Gor^2(M^c_{4}) = 6::15781579sage: from admcycles.DR import MODULI_CT, MODULI_RT15801581sage: gorenstein(4,2,(),MODULI_CT)1582615831584Check rank Gor^4(M^rt_{8,2}) = 22::15851586sage: gorenstein(8,4,(1,2),MODULI_RT)1587221588"""1589gorenstein_precompute(g, r, marked_points, moduli_type)1590r3 = dim_form(g, len(marked_points), moduli_type)1591r2 = r3-r1592S1 = good_generator_list(g, r, marked_points, moduli_type)1593S2 = good_generator_list(g, r2, marked_points, moduli_type)1594M = pairing_submatrix(tuple(S1), tuple(S2), g, r,1595marked_points, moduli_type)1596return matrix(M).rank()15971598#####################################159916001601def compute_rank(L):1602count = 01603for i in range(len(L)):1604S = [j for j in range(len(L[0])) if L[i][j] != 0]1605if not S:1606continue1607count += 11608j = S[0]1609T = [ii for ii in range(i+1, len(L))1610if L[ii][j] != 0]1611for k in S[1:]:1612rat = L[i][k]/L[i][j]1613for ii in T:1614L[ii][k] -= rat*L[ii][j]1615for ii in range(i+1, len(L)):1616L[ii][j] = 01617return count161816191620def choose_orders_sparse(D, nrows, ncols):1621row_nums = [0 for i in range(nrows)]1622col_nums = [0 for j in range(ncols)]1623for key in D:1624row_nums[key[0]] += 11625col_nums[key[1]] += 11626row_order = list(range(nrows))1627col_order = list(range(ncols))1628row_order.sort(key=lambda x: row_nums[x])1629col_order.sort(key=lambda x: col_nums[x])1630return row_order, col_order163116321633def choose_orders(L):1634rows = len(L)1635if rows == 0:1636return [], []1637cols = len(L[0])1638row_nums = [0 for i in range(rows)]1639col_nums = [0 for j in range(cols)]1640for i in range(rows):1641for j in range(cols):1642if L[i][j] != 0:1643row_nums[i] += 11644col_nums[j] += 11645row_order = list(range(rows))1646col_order = list(range(cols))1647row_order.sort(key=lambda x: row_nums[x])1648col_order.sort(key=lambda x: col_nums[x])1649return row_order, col_order165016511652def compute_rank2(L, row_order, col_order):1653count = 01654for irow in range(len(row_order)):1655i = row_order[irow]1656S = [j for j in col_order if L[i][j] != 0]1657if not S:1658continue1659count += 11660j = S[0]1661T = [ii for ii in row_order[irow+1:]1662if L[ii][j] != 0]1663for k in S[1:]:1664rat = L[i][k]/L[i][j]1665for ii in T:1666L[ii][k] -= rat*L[ii][j]1667for ii in T:1668L[ii][j] = 01669return count16701671####################################167216731674def socle_evaluation(num, g, markings=(), moduli_type=MODULI_ST):1675answer = 11676G = single_stratum(num, g, dim_form(1677g, len(markings), moduli_type), markings, moduli_type)1678for i in range(1, G.M.nrows()):1679g0 = G.M[i, 0][0]1680psilist = []1681for j in range(1, G.M.ncols()):1682if G.M[i, j][0] > 0:1683psilist.append(G.M[i, j][1])1684if G.M[i, j][0] == 2:1685psilist.append(G.M[i, j][2])1686n0 = len(psilist)1687dim0 = dim_form(g0, n0, moduli_type)1688kappalist = []1689for j in range(1, dim0+1):1690for k in range(G.M[i, 0][j]):1691kappalist.append(j)1692if sum(psilist)+sum(kappalist) != dim0:1693print("ERROR: wrong dim")1694return1695answer *= socle_formula(g0, psilist, kappalist, moduli_type)1696return answer169716981699def socle_formula(g, psilist, kappalist, moduli_type=MODULI_ST):1700if moduli_type == MODULI_CT or g == 0:1701return CTconst(g)*CTsum(psilist, kappalist)1702if moduli_type <= MODULI_SM or moduli_type == MODULI_RT:1703return RTsum(g, psilist, kappalist)1704if moduli_type == MODULI_ST:1705return STsum(psilist, kappalist)170617071708def setparts_recur(symlist, progress):1709if not symlist:1710return [progress]1711l = []1712for i in Combinations(symlist[1:]):1713j = [symlist[0]]+i1714if progress and j < progress[-1]:1715continue1716cur = 01717new_symlist = []1718for k in range(len(symlist)):1719if cur < len(j) and symlist[k] == j[cur]:1720cur += 11721else:1722new_symlist.append(symlist[k])1723l += setparts_recur(new_symlist, progress+[j])1724return l172517261727def setparts_with_auts(symlist):1728l = setparts_recur(symlist, [])1729a = aut(symlist)1730ll = []1731for i in l:1732b = aut(i)1733for j in i:1734b *= aut(j)1735ll.append([i, a/b])1736return ll173717381739def multi2(g, sigma):1740sigma.sort()1741if sigma[0] == 0:1742total = ZZ.zero()1743for i in range(len(sigma) - 1):1744sigmacopy = sigma[1:]1745if sigmacopy[i] > 0:1746sigmacopy[i] -= 11747total += multi2(g, sigmacopy)1748return total1749term = factorial(2 * g - 3 + len(sigma))1750term *= ZZ(2 * g - 1).multifactorial(2)1751term /= factorial(2 * g - 1)1752for i in sigma:1753term /= ZZ(2 * i - 1).multifactorial(2)1754return term175517561757def STsum(psilist, kappalist):1758kappalist.sort()1759total = 01760for i in setparts_with_auts(kappalist):1761total += (-1)**(len(i[0])) * i[1] * \1762STrecur([1 + sum(j) for j in i[0]] + psilist)1763return total*(-1)**(len(kappalist))176417651766def RTsum(g, psilist, kappalist):1767kappalist.sort()1768total = ZZ.zero()1769for i0, i1 in setparts_with_auts(kappalist):1770total += (-1) ** len(i0) * i1 * \1771multi2(g, [1 + sum(j) for j in i0] + psilist)1772return total * (-1)**(len(kappalist))177317741775def CTsum(psilist, kappalist):1776kappalist.sort()1777total = ZZ.zero()1778for i0, i1 in setparts_with_auts(kappalist):1779total += (-1)**len(i0) * i1 * \1780multinomial([1 + sum(j) for j in i0] + psilist)1781return total * (-1)**len(kappalist)178217831784def CTconst(g):1785return abs((ZZ(2) ** (ZZ(2) * g-1)-1)*bernoulli(ZZ(2) * g))/(ZZ(2) ** (ZZ(2) * g-1)*factorial(ZZ(2) * g))178617871788def STrecur(psi):1789return STrecur_calc(tuple(sorted(psi)))179017911792@cached_function1793def STrecur_calc(psi):1794"""1795INPUT: a sorted tuple of (nonegative ?) integers17961797OUTPUT: a rational1798"""1799if not psi:1800return ZZ.one()1801s = sum(psi)1802n = len(psi)1803if (s - n) % 3:1804return ZZ.zero()1805if psi[0] == 0:1806if s == 0 and n == 3:1807return ZZ.one()1808total = ZZ.zero()1809psi_end = list(psi[1:])1810for i in range(n - 1):1811psicopy = list(psi_end)1812if psicopy[i] > 0:1813psicopy[i] -= 11814total += STrecur(psicopy)1815return total18161817g = ZZ(s - n) // 3 + 1 # in ZZ1818d = ZZ(psi[-1])1819total = ZZ.zero()18201821psicopy = [0, 0, 0, 0] + list(psi)1822psicopy[-1] += 11823total += (2 * d + 3) / 12 * STrecur(psicopy)18241825psicopy = [0, 0, 0] + list(psi)1826total -= (2 * g + n - 1) / 6 * STrecur(psicopy)18271828for I in Subsets(list(range(n - 1))):1829psi3 = [0, 0] + [psi[i] for i in I]1830x = STrecur(psi3)1831if x == 0:1832continue1833psi1 = [0, 0] + [psi[i] for i in range(n - 1) if i not in I] + [d + 1]1834psi2 = list(psi1[1:])1835psi2[-1] = d1836total += ((2 * d + 3)*STrecur(psi1) -1837(2 * g + n - 1)*STrecur(psi2)) * x1838total /= (2 * g + n - 1) * (2 * g + n - 2)1839return total184018411842@cached_function1843def good_generator_list(g, r, markings=(), moduli_type=MODULI_ST):1844gens = all_strata(g, r, markings, moduli_type)1845good_gens = []1846ngens = len(gens)1847for num in range(ngens):1848G = gens[num]1849good = True1850for i in range(1, G.M.nrows()):1851g = G.M[i, 0][0]1852codim = 01853for d in range(1, r + 1):1854if G.M[i, 0][d] != 0:1855if 3 * d > g:1856good = False1857break1858codim += d*G.M[i, 0][d]1859if not good:1860break1861for j in range(1, G.M.ncols()):1862codim += G.M[i, j][1]1863codim += G.M[i, j][2]1864if codim > 0 and codim >= g:1865good = False1866break1867if good:1868good_gens.append(num)1869return good_gens187018711872@cached_function1873def automorphism_cosets(num, g, r, markings=(), moduli_type=MODULI_ST):1874G = single_stratum(num, g, r, markings, moduli_type)1875pureG = Graph(G.M)1876pureG.purify()1877pureG.compute_invariant()1878pure_auts = graph_list_isomorphisms(pureG, pureG)1879num_pure = len(pure_auts)1880impure_auts = graph_list_isomorphisms(G, G)1881num_impure = len(impure_auts)1882chosen_auts = []1883used_auts = []1884v = G.num_vertices()1885e = G.num_edges()1886for i in range(num_pure):1887if i not in used_auts:1888chosen_auts.append(pure_auts[i])1889for g in impure_auts:1890sigma = [[pure_auts[i][0][g[0][k]-1]1891for k in range(v)], [pure_auts[i][1][g[1][k]-1] for k in range(e)]]1892for ii in range(num_pure):1893if pure_auts[ii] == sigma:1894used_auts.append(ii)1895break1896return [num_impure, chosen_auts]18971898#############################################189919001901def FZ_rels(g, r, markings=(), moduli_type=MODULI_ST):1902return span(FZ_matrix(g, r, markings, moduli_type)).basis()190319041905def goren_rels(g, r, markings=(), moduli_type=MODULI_ST):1906gorenstein_precompute(g, r, markings, moduli_type)1907r3 = dim_form(g, len(markings), moduli_type)1908r2 = r3-r1909S1 = list(range(num_strata(g, r, markings, moduli_type)))1910S2 = good_generator_list(g, r2, markings, moduli_type)1911M = pairing_submatrix(S1, S2, g, r, markings, moduli_type)1912return Matrix(M).kernel().basis()191319141915@cached_function1916def kappa_conversion(sigma):1917answer = []1918for spart in setparts_with_auts(list(sigma)):1919coeff = spart[1]1920poly = R(0)1921for part in spart[0]:1922coeff *= factorial(len(part) - 1)1923poly += X**sum(part)1924answer.append([poly, coeff])1925return answer192619271928@cached_function1929def kappa_conversion_inverse(sigma):1930answer = []1931for spart in setparts_with_auts(list(sigma)):1932coeff = spart[1]*(-1)**(len(sigma)-len(spart[0]))1933poly = R(0)1934for part in spart[0]:1935poly += X**sum(part)1936answer.append([poly, coeff])1937return answer193819391940@cached_function1941def convert_to_monomial_basis(num, g, r, markings=(), moduli_type=MODULI_ST):1942answer = []1943G = single_stratum(num, g, r, markings, moduli_type)1944genus_vec = []1945kappa_vec = []1946for i in range(1, G.M.nrows()):1947genus_vec.append(G.M[i, 0][0])1948kappa_vec.append([])1949for j in range(1, r+1):1950for k in range(G.M[i, 0][j]):1951kappa_vec[-1].append(j)1952kappa_vec[-1] = kappa_conversion(1953tuple(kappa_vec[-1]))1954for choice in itertools.product(*kappa_vec):1955coeff = 11956GG = Graph(G.M)1957for i in range(1, G.M.nrows()):1958GG.M[i, 0] = genus_vec[i - 1] + choice[i - 1][0]1959coeff *= choice[i - 1][1]1960answer.append((num_of_stratum(GG, g, r, markings, moduli_type), coeff))1961return answer196219631964@cached_function1965def convert_to_pushforward_basis(num, g, r, markings=(), moduli_type=MODULI_ST):1966answer = []1967G = single_stratum(num, g, r, markings, moduli_type)1968genus_vec = []1969kappa_vec = []1970for i in range(1, G.M.nrows()):1971genus_vec.append(G.M[i, 0][0])1972kappa_vec.append([])1973for j in range(1, r+1):1974for k in range(G.M[i, 0][j]):1975kappa_vec[-1].append(j)1976kappa_vec[-1] = kappa_conversion_inverse(1977tuple(kappa_vec[-1]))1978for choice in itertools.product(*kappa_vec):1979coeff = 11980GG = Graph(G.M)1981for i in range(1, G.M.nrows()):1982GG.M[i, 0] = genus_vec[i-1] + \1983choice[i-1][0]1984coeff *= choice[i-1][1]1985answer.append((num_of_stratum(GG, g, r, markings, moduli_type), coeff))1986return answer198719881989def convert_vector_to_monomial_basis(vec, g, r, markings=(), moduli_type=MODULI_ST):1990l = len(vec)1991vec2 = [0 for i in range(l)]1992for i in range(l):1993if vec[i] != 0:1994for x in convert_to_monomial_basis(i, g, r, markings, moduli_type):1995vec2[x[0]] += x[1]*vec[i]1996return vec2199719981999def convert_vector_to_pushforward_basis(vec, g, r, markings=(), moduli_type=MODULI_ST):2000l = len(vec)2001vec2 = [0 for i in range(l)]2002for i in range(l):2003if vec[i] != 0:2004for x in convert_to_pushforward_basis(i, g, r, markings, moduli_type):2005vec2[x[0]] += x[1]*vec[i]2006return vec2200720082009def kappa_multiple(vec, which_kappa, g, r, n=0, moduli_type=MODULI_ST):2010vec2 = []2011for x in vec:2012for y in single_kappa_multiple(x[0], which_kappa, g, r, n, moduli_type):2013vec2.append([y[0], x[1]*y[1]])2014vec2 = simplify_sparse(vec2)2015return vec2201620172018def psi_multiple(vec, which_psi, g, r, n=0, moduli_type=MODULI_ST):2019vec2 = []2020for x in vec:2021for y in single_psi_multiple(x[0], which_psi, g, r, n, moduli_type):2022vec2.append([y[0], x[1]*y[1]])2023vec2 = simplify_sparse(vec2)2024return vec2202520262027def insertion_pullback(vec, g, r, n=0, new_mark=1, moduli_type=MODULI_ST):2028vec2 = []2029for x in vec:2030for y in single_insertion_pullback(x[0], g, r, n, new_mark, moduli_type):2031vec2.append([y[0], x[1]*y[1]])2032vec2 = simplify_sparse(vec2)2033return vec2203420352036def insertion_pullback2(vec, g, r, n=0, new_mark=1, moduli_type=MODULI_ST):2037vec2 = []2038for x in vec:2039for y in single_insertion_pullback2(x[0], g, r, n, new_mark, moduli_type):2040vec2.append([y[0], x[1]*y[1]])2041vec2 = simplify_sparse(vec2)2042return vec2204320442045@cached_function2046def strata_invariant_lookup(g, r, markings=(), moduli_type=MODULI_ST):2047inv_dict = {}2048L = all_strata(g, r, markings, moduli_type)2049for i in range(len(L)):2050if L[i].invariant not in inv_dict:2051inv_dict[L[i].invariant] = []2052inv_dict[L[i].invariant].append(i)2053return inv_dict205420552056@cached_function2057def num_of_stratum(G, g, r, markings=(), moduli_type=MODULI_ST):2058G.compute_invariant()2059L = all_strata(g, r, markings, moduli_type)2060LL = strata_invariant_lookup(g, r, markings, moduli_type)20612062# for debugging purposes2063try:2064x = LL[G.invariant]2065except KeyError:2066print("num_of_stratum(G={}, g={}, r={}, markings={}, moduli_type={}".format(2067G, g, r, markings, moduli_type))2068print("G.invariant = {}".format(G.invariant))2069print("LL.keys() = ")2070for l in LL:2071print(l)2072raise20732074if len(x) == 1:2075return x[0]2076for i in x:2077if graph_isomorphic(G, L[i]):2078return i2079print("ERROR")2080print((g, r, markings, moduli_type))2081print(G.M)208220832084@cached_function2085def single_psi_multiple(num, which_psi, g, r, n=0, moduli_type=MODULI_ST):2086markings = tuple(range(1, n+1))2087G = single_stratum(num, g, r, markings, moduli_type)2088answer = []2089for j in range(1, G.M.ncols()):2090if G.M[0, j] == which_psi:2091good_j = j2092break2093for i in range(1, G.M.nrows()):2094if G.M[i, good_j] != 0:2095deg = 02096dim_used = 02097for j in range(1, r+1):2098dim_used += j*G.M[i, 0][j]2099for j in range(1, G.M.ncols()):2100dim_used += G.M[i, j][1] + G.M[i, j][2]2101deg += G.M[i, j][0]2102if dim_used < dim_form(G.M[i, 0][0], deg, moduli_type):2103GG = Graph(G.M)2104GG.M[i, good_j] += X2105answer.append(2106(num_of_stratum(GG, g, r+1, markings, moduli_type), 1))2107break2108return answer210921102111@cached_function2112def single_kappa_multiple(num, which_kappa, g, r, n=0, moduli_type=MODULI_ST):2113markings = tuple(range(1, n+1))2114G = single_stratum(num, g, r, markings, moduli_type)2115answer = []2116for i in range(1, G.M.nrows()):2117deg = 02118dim_used = 02119for j in range(1, r+1):2120dim_used += j*G.M[i, 0][j]2121for j in range(1, G.M.ncols()):2122dim_used += G.M[i, j][1] + G.M[i, j][2]2123deg += G.M[i, j][0]2124if dim_used + which_kappa <= dim_form(G.M[i, 0][0], deg, moduli_type):2125GG = Graph(G.M)2126GG.M[i, 0] += X**which_kappa2127answer.append((num_of_stratum(GG, g, r+which_kappa,2128markings, moduli_type), 1))2129for j in range(1, r+1):2130if G.M[i, 0][j] > 0:2131GG = Graph(G.M)2132GG.M[i, 0] += X**(j+which_kappa)2133GG.M[i, 0] -= X**j2134answer.append((num_of_stratum(2135GG, g, r+which_kappa, markings, moduli_type), -G.M[i, 0][j]))2136return answer21372138# Only doing this for markings=list(range(1,n+1)) right now.2139# Also, this function uses the monomial basis.214021412142def single_kappa_psi_multiple(num, kappa_partition, psi_exps, g, r, n=0, moduli_type=MODULI_ST):2143markings = tuple(range(1, n+1))2144G = single_stratum(num, g, r, markings, moduli_type)2145GG = Graph(G.M)2146for j in range(1, G.M.ncols()):2147if GG.M[0, j] != 0:2148for i in range(1, G.M.nrows()):2149if GG.M[i, j] != 0:2150GG.M[i, j] += psi_exps[GG.M[0, j][0]-1]*X2151break2152rnew = r+sum(kappa_partition)+sum(psi_exps)2153answer = []2154kappa_options = [list(range(1, G.M.nrows()))2155for i in range(len(kappa_partition))]2156for kappa_distrib in itertools.product(*kappa_options):2157GGG = Graph(GG.M)2158for i in range(len(kappa_partition)):2159GGG.M[kappa_distrib[i], 0] += X**(kappa_partition[i])2160is_bad = False2161for i in range(1, GGG.M.nrows()):2162deg = 02163dim_used = 02164for j in range(1, rnew+1):2165dim_used += j*GGG.M[i, 0][j]2166for j in range(1, GGG.M.ncols()):2167dim_used += GGG.M[i, j][1] + GGG.M[i, j][2]2168deg += GGG.M[i, j][0]2169if dim_used > dim_form(GGG.M[i, 0][0], deg, moduli_type):2170is_bad = True2171break2172if is_bad:2173continue2174answer.append(2175(num_of_stratum(GGG, g, rnew, markings, moduli_type), 1))2176return answer217721782179@cached_function2180def single_insertion_pullback(num, g, r, n=0, new_mark=1, moduli_type=MODULI_ST):2181markings = tuple(range(1, n+1))2182new_markings = tuple(range(1, n+2))2183G = single_stratum(num, g, r, markings, moduli_type)2184answer = []2185for i in range(1, G.M.nrows()):2186GG = Graph(G.M)2187for j in range(1, G.M.ncols()):2188if GG.M[0, j][0] >= new_mark:2189GG.M[0, j] += 12190GG.add_edge(i, 0, new_mark)2191answer.append(2192(num_of_stratum(GG, g, r, new_markings, moduli_type), 1))2193for j in range(1, r+1):2194for k in range(GG.M[i, 0][j]):2195GGG = Graph(GG.M)2196GGG.M[i, 0] -= X**j2197GGG.M[i, -1] += j*X2198answer.append(2199(num_of_stratum(GGG, g, r, new_markings, moduli_type), -1))2200if moduli_type <= MODULI_SM:2201continue2202for j in range(1, G.M.ncols()):2203if G.M[i, j][0] == 1:2204if G.M[i, j][1] >= 1:2205x = G.M[i, j][1]2206GGG = Graph(GG.M)2207row1 = [GG.M[i, k] for k in range(GG.M.ncols())]2208row2 = [0 for k in range(GG.M.ncols())]2209row1[j] = 02210row1[-1] = 02211row2[j] = 12212row2[-1] = 12213GGG.split_vertex(i, row1, row2)2214GGG.M[-2, -22151] += (x-1)*X2216answer.append(2217(num_of_stratum(GGG, g, r, new_markings, moduli_type), -1))2218if G.M[i, j][0] == 2:2219if G.M[i, j][1] >= 1 or G.M[i, j][2] >= 1:2220x = G.M[i, j][1]2221y = G.M[i, j][2]2222row1 = [GG.M[i, k] for k in range(GG.M.ncols())]2223row2 = [0 for k in range(GG.M.ncols())]2224row1[j] = 02225row1[-1] = 02226row2[j] = 12227row2[-1] = 12228if y >= 1:2229row1[j] = 1 + x*X2230GGG = Graph(GG.M)2231GGG.split_vertex(i, row1, row2)2232GGG.M[-2, -22331] += (y-1)*X2234answer.append(2235(num_of_stratum(GGG, g, r, new_markings, moduli_type), -1))2236if x >= 1:2237row1[j] = 1 + y*X2238GGG = Graph(GG.M)2239GGG.split_vertex(i, row1, row2)2240GGG.M[-2, -22411] += (x-1)*X2242answer.append(2243(num_of_stratum(GGG, g, r, new_markings, moduli_type), -1))2244return answer224522462247@cached_function2248def single_insertion_pullback2(num, g, r, n=0, new_mark=1, moduli_type=MODULI_ST):2249markings = tuple(range(1, n+1))2250new_markings = tuple(range(1, n+2))2251G = single_stratum(num, g, r, markings, MODULI_SMALL)2252answer = []2253for i in range(1, G.M.nrows()):2254GG = Graph(G.M)2255for j in range(1, G.M.ncols()):2256if GG.M[0, j][0] >= new_mark:2257GG.M[0, j] += 12258GG.add_edge(i, 0, new_mark)2259answer.append(2260(num_of_stratum(GG, g, r, new_markings, moduli_type), 1))2261for j in range(1, r+1):2262for k in range(GG.M[i, 0][j]):2263GGG = Graph(GG.M)2264GGG.M[i, 0] -= X**j2265GGG.M[i, -1] += j*X2266answer.append(2267(num_of_stratum(GGG, g, r, new_markings, moduli_type), -1))2268if moduli_type <= MODULI_SM:2269continue2270for j in range(1, G.M.ncols()):2271if G.M[i, j][0] == 1:2272if G.M[i, j][1] >= 1:2273x = G.M[i, j][1]2274GGG = Graph(GG.M)2275row1 = [GG.M[i, k] for k in range(GG.M.ncols())]2276row2 = [0 for k in range(GG.M.ncols())]2277row1[j] = 02278row1[-1] = 02279row2[j] = 12280row2[-1] = 12281GGG.split_vertex(i, row1, row2)2282GGG.M[-2, -22831] += (x-1)*X2284answer.append(2285(num_of_stratum(GGG, g, r, new_markings, moduli_type), -1))2286return answer228722882289def num_new_rels(g, r, n=0, moduli_type=MODULI_ST):2290return len(choose_basic_rels(g, r, n, moduli_type))229122922293@cached_function2294def choose_basic_rels(g, r, n=0, moduli_type=MODULI_ST):2295if 3 * r < g + n + 1:2296return []2297sym_ngen = num_strata(g, r, tuple([1 for i in range(n)]), moduli_type)2298if moduli_type == MODULI_SMALL and r > dim_form(g, n, MODULI_SM):2299sym_possible_rels = [[[i, 1]] for i in range(sym_ngen)]2300else:2301sym_possible_rels = possibly_new_FZ(g, r, n, moduli_type)2302if not sym_possible_rels:2303return []2304dprint("Start basic_rels (%s,%s,%s,%s): %s", g, r,2305n, moduli_type, floor(get_memory_usage()))2306previous_rels = derived_rels(g, r, n, moduli_type)2307nrels = len(previous_rels)2308dprint("%s gens, %s oldrels", sym_ngen, nrels)2309D = {}2310for i in range(nrels):2311for x in previous_rels[i]:2312D[i, x[0]] = x[1]2313if nrels > 0:2314row_order, col_order = choose_orders_sparse(D, nrels, sym_ngen)2315previous_rank = compute_rank_sparse(D, row_order, col_order)2316dprint("rank %s", previous_rank)2317else:2318previous_rank = 02319row_order = []2320col_order = list(range(sym_ngen))2321answer = []2322for j in range(len(sym_possible_rels)):2323for x in sym_possible_rels[j]:2324D[nrels, x[0]] = x[1]2325row_order.append(nrels)2326nrels += 12327if compute_rank_sparse(D, row_order, col_order) > previous_rank:2328answer.append(unsymmetrize_vec(sym_possible_rels[j], g, r, tuple(2329range(1, n+1)), moduli_type))2330previous_rank += 12331dprint("rank %s", previous_rank)2332dprint("End basic_rels (%s,%s,%s,%s): %s", g, r,2333n, moduli_type, floor(get_memory_usage()))2334dprint("%s,%s,%s,%s: rank %s", g, r, n,2335moduli_type, sym_ngen-previous_rank)2336if moduli_type > -1:2337dsave("sparse-%s,%s,%s,%s|%s,%s,%s", g, r, n, moduli_type,2338len(answer), sym_ngen-previous_rank, floor(get_memory_usage()))2339# if moduli_type >= 0 and sym_ngen-previous_rank != betti(g,r,tuple([1 for i in range(n)]),moduli_type):2340# dprint("ERROR: %s,%s,%s,%s",g,r,n,moduli_type)2341# return2342return answer234323442345def recursive_betti(g, r, markings=(), moduli_type=MODULI_ST):2346"""2347EXAMPLES::23482349sage: from admcycles.DR import recursive_betti2350sage: recursive_betti(2, 3) # not tested2351?2352"""2353dprint("Start recursive_betti (%s,%s,%s,%s): %s", g, r,2354markings, moduli_type, floor(get_memory_usage()))2355n = len(markings)2356if r > dim_form(g, n, moduli_type):2357return 02358ngen = num_strata(g, r, markings, moduli_type)2359dprint("%s gens", ngen)2360relations = []2361partial_sym_map = partial_symmetrize_map(g, r, markings, moduli_type)2362for rel in choose_basic_rels(g, r, n, moduli_type):2363rel2 = []2364for x in rel:2365rel2.append([partial_sym_map[x[0]], x[1]])2366rel2 = simplify_sparse(rel2)2367relations.append(rel2)2368for rel in interior_derived_rels(g, r, n, moduli_type):2369rel2 = []2370for x in rel:2371rel2.append([partial_sym_map[x[0]], x[1]])2372rel2 = simplify_sparse(rel2)2373relations.append(rel2)2374dprint("%s gens, %s rels so far", ngen, len(relations))2375dprint("Middle recursive_betti (%s,%s,%s,%s): %s", g, r,2376markings, moduli_type, floor(get_memory_usage()))2377if moduli_type > MODULI_SM:2378for r0 in range(1, r):2379strata = all_strata(g, r0, markings, moduli_type)2380for G in strata:2381vertex_orbits = graph_count_automorphisms(G, True)2382for i in [orbit[0] for orbit in vertex_orbits]:2383good = True2384for j in range(G.M.ncols()):2385if R(G.M[i, j][0]) != G.M[i, j]:2386good = False2387break2388if good:2389g2 = G.M[i, 0][0]2390if 3 * (r - r0) < g2 + 1:2391continue2392d = G.degree(i)2393if dim_form(g2, d, moduli_type) < r-r0:2394continue2395strata2 = all_strata(2396g2, r-r0, tuple(range(1, d+1)), moduli_type)2397which_gen_list = [2398-1 for num in range(len(strata2))]2399for num in range(len(strata2)):2400G_copy = Graph(G.M)2401G_copy.replace_vertex_with_graph(i, strata2[num])2402which_gen_list[num] = num_of_stratum(2403G_copy, g, r, markings, moduli_type)2404rel_list = copy(choose_basic_rels(2405g2, r-r0, d, moduli_type))2406rel_list += interior_derived_rels(g2,2407r-r0, d, moduli_type)2408for rel0 in rel_list:2409relation = []2410for x in rel0:2411num = x[0]2412if which_gen_list[num] != -1:2413relation.append(2414[which_gen_list[num], x[1]])2415relation = simplify_sparse(relation)2416relations.append(relation)2417dprint("%s gens, %s rels", ngen, len(relations))2418dsave("sparse-%s-gens-%s-rels", ngen, len(relations))2419dprint("Middle recursive_betti (%s,%s,%s,%s): %s", g, r,2420markings, moduli_type, floor(get_memory_usage()))2421relations = remove_duplicates(relations)2422nrels = len(relations)2423dprint("%s gens, %s distinct rels", ngen, nrels)2424dsave("sparse-%s-distinct-rels", nrels)2425rank = 02426D = {}2427for i, reli in enumerate(relations):2428for x in reli:2429D[i, x[0]] = x[1]2430if nrels:2431row_order, col_order = choose_orders_sparse(D, nrels, ngen)2432rank = compute_rank_sparse(D, row_order, col_order)2433dsave("sparse-answer-%s", ngen-rank)2434return ngen - rank243524362437def subsequences(seq, l):2438"""2439Return all subsequences of length ``l`` a list ``seq``.24402441EXAMPLES::24422443sage: from admcycles.DR import subsequences2444sage: subsequences([2,3,5,7],2)2445[[2, 3], [2, 5], [2, 7], [3, 5], [3, 7], [5, 7]]2446sage: subsequences([4,3,2,1],2)2447[[4, 3], [4, 2], [4, 1], [3, 2], [3, 1], [2, 1]]2448"""2449S = tuple(range(len(seq)))2450return [[seq[i] for i in subset] for subset in Subsets(S, l)]245124522453@cached_function2454def pullback_derived_rels(g, r, n=0, moduli_type=MODULI_ST):2455if r == 0:2456return []2457dprint("Start pullback_derived (%s,%s,%s,%s): %s", g,2458r, n, moduli_type, floor(get_memory_usage()))2459answer = []2460for n0 in range(n):2461if dim_form(g, n0, moduli_type) >= r:2462basic_rels = choose_basic_rels(g, r, n0, moduli_type)2463for rel in basic_rels:2464for vec in subsequences(list(range(1, n+1)), n-n0):2465rel2 = copy(rel)2466for i in range(n-n0):2467rel2 = insertion_pullback(2468rel2, g, r, n0+i, vec[i], moduli_type)2469answer.append(rel2)2470else:2471basic_rels = choose_basic_rels(g, r, n0, MODULI_SMALL)2472k = r - dim_form(g, n0, moduli_type)2473for rel in basic_rels:2474for vec in subsequences(list(range(1, n0+k-1 + 1)), k-1):2475for vec2 in subsequences(list(range(1, n+1)), n-n0-k+1):2476rel2 = copy(rel)2477for i in range(k-1):2478rel2 = insertion_pullback(2479rel2, g, r, n0+i, vec[i], MODULI_SMALL)2480rel2 = insertion_pullback2(2481rel2, g, r, n0+k-1, vec2[0], moduli_type)2482for i in range(n-n0-k):2483rel2 = insertion_pullback(2484rel2, g, r, n0+k+i, vec2[i+1], moduli_type)2485answer.append(rel2)2486dprint("End pullback_derived (%s,%s,%s,%s): %s", g,2487r, n, moduli_type, floor(get_memory_usage()))2488return answer248924902491@cached_function2492def interior_derived_rels(g, r, n=0, moduli_type=MODULI_ST):2493dprint("Start interior_derived (%s,%s,%s,%s): %s", g,2494r, n, moduli_type, floor(get_memory_usage()))2495answer = copy(pullback_derived_rels(g, r, n, moduli_type))2496for r0 in range(r):2497pullback_rels = copy(choose_basic_rels(g, r0, n, moduli_type))2498pullback_rels += pullback_derived_rels(g, r0, n, moduli_type)2499for rel in pullback_rels:2500for i in range(r-r0+1):2501for sigma in Partitions(i):2502for tau in IntegerVectors(r-r0-i, n):2503rel2 = copy(rel)2504rcur = r02505for m in range(n):2506for mm in range(tau[m]):2507rel2 = psi_multiple(2508rel2, m+1, g, rcur, n, moduli_type)2509rcur += 12510for m in sigma:2511rel2 = kappa_multiple(2512rel2, m, g, rcur, n, moduli_type)2513rcur += m2514answer.append(rel2)2515dprint("End interior_derived (%s,%s,%s,%s): %s", g,2516r, n, moduli_type, floor(get_memory_usage()))2517return answer251825192520@cached_function2521def symmetrize_map(g, r, markings=(), moduli_type=MODULI_ST):2522markings2 = tuple([1 for i in markings])2523gens = all_strata(g, r, markings, moduli_type)2524map = []2525for G in gens:2526GG = Graph(G.M)2527for i in range(1, GG.M.ncols()):2528if GG.M[0, i][0] > 0:2529GG.M[0, i] = R(1)2530map.append(num_of_stratum(GG, g, r, markings2, moduli_type))2531return map253225332534@cached_function2535def partial_symmetrize_map(g, r, markings=(), moduli_type=MODULI_ST):2536markings1 = tuple(range(1, len(markings)+1))2537gens = all_strata(g, r, markings1, moduli_type)2538map = []2539for G in gens:2540GG = Graph(G.M)2541for i in range(1, GG.M.ncols()):2542if GG.M[0, i][0] > 0:2543GG.M[0, i] = R(markings[GG.M[0, i][0]-1])2544map.append(num_of_stratum(GG, g, r, markings, moduli_type))2545return map254625472548@cached_function2549def unsymmetrize_map(g, r, markings=(), moduli_type=MODULI_ST):2550markings2 = tuple([1 for i in markings])2551sym_map = symmetrize_map(g, r, markings, moduli_type)2552map = [[] for i in range(num_strata(g, r, markings2, moduli_type))]2553for i in range(len(sym_map)):2554map[sym_map[i]].append(i)2555return map255625572558def unsymmetrize_vec(vec, g, r, markings=(), moduli_type=MODULI_ST):2559unsym_map = unsymmetrize_map(g, r, markings, moduli_type)2560vec2 = []2561for x in vec:2562aut = len(unsym_map[x[0]])2563for j in unsym_map[x[0]]:2564vec2.append([j, QQ((x[1], aut))])2565vec2 = simplify_sparse(vec2)2566return vec2256725682569def derived_rels(g, r, n=0, moduli_type=MODULI_ST):2570dprint("Start derived (%s,%s,%s,%s): %s", g, r,2571n, moduli_type, floor(get_memory_usage()))2572markings = tuple([1 for _ in range(n)])2573# generators = all_strata(g, r, markings, moduli_type)2574sym_map = symmetrize_map(g, r, tuple(range(1, n+1)), moduli_type)2575answer = []2576for rel in interior_derived_rels(g, r, n, moduli_type):2577rel2 = []2578for x in rel:2579rel2.append([sym_map[x[0]], x[1]])2580rel2 = simplify_sparse(rel2)2581answer.append(rel2)2582if moduli_type <= MODULI_SM:2583return answer2584for r0 in range(1, r):2585strata = all_strata(g, r0, markings, moduli_type)2586for G in strata:2587vertex_orbits = graph_count_automorphisms(G, True)2588for i in [orbit[0] for orbit in vertex_orbits]:2589good = True2590for j in range(G.M.ncols()):2591if R(G.M[i, j][0]) != G.M[i, j]:2592good = False2593break2594if good:2595g2 = G.M[i, 0][0]2596if 3 * (r - r0) < g2 + 1:2597continue2598d = G.degree(i)2599if dim_form(g2, d, moduli_type) < r-r0:2600continue2601strata2 = all_strata(2602g2, r-r0, tuple(range(1, d+1)), moduli_type)2603which_gen_list = [2604-1 for num in range(len(strata2))]2605for num in range(len(strata2)):2606G_copy = Graph(G.M)2607G_copy.replace_vertex_with_graph(i, strata2[num])2608which_gen_list[num] = num_of_stratum(2609G_copy, g, r, markings, moduli_type)2610rel_list = copy(choose_basic_rels(2611g2, r-r0, d, moduli_type))2612rel_list += interior_derived_rels(g2, r-r0, d, moduli_type)2613for rel0 in rel_list:2614relation = []2615for x0, x1 in rel0:2616if which_gen_list[x0] != -1:2617relation.append([which_gen_list[x0], x1])2618relation = simplify_sparse(relation)2619answer.append(relation)2620answer = remove_duplicates(answer)2621dprint("End derived (%s,%s,%s,%s): %s", g, r, n,2622moduli_type, floor(get_memory_usage()))2623return answer262426252626def remove_duplicates(L):2627"""2628Remove duplicate elements in a list ``L``.26292630One cannot use ``set(L)`` because the elements of ``L`` are not hashable.26312632INPUT:26332634- ``L`` -- a list26352636OUTPUT:26372638a list26392640EXAMPLES::26412642sage: from admcycles.DR import remove_duplicates2643sage: remove_duplicates([4,7,6,4,3,3,4,2,2,1])2644[1, 2, 3, 4, 6, 7]2645"""2646if not L:2647return L2648L.sort()2649LL = [L[0]]2650for i, Li in enumerate(L[1:]):2651if Li != L[i]:2652LL.append(Li)2653return LL265426552656def simplify_sparse(vec):2657vec.sort()2658vec2 = []2659last_index = None2660for x in vec:2661if x[0] == last_index:2662if vec2[-1][1] == -x[1]:2663vec2 = vec2[:-1]2664last_index = None2665else:2666vec2[-1][1] += x[1]2667else:2668vec2.append(x)2669last_index = x[0]2670return vec2267126722673def compute_rank_sparse(D, row_order, col_order):2674count = 02675nrows = len(row_order)2676ncols = len(col_order)2677row_order_rank = [-1 for i in range(nrows)]2678col_order_rank = [-1 for i in range(ncols)]2679for i in range(nrows):2680row_order_rank[row_order[i]] = i2681for i in range(ncols):2682col_order_rank[col_order[i]] = i26832684row_contents = [set() for i in range(nrows)]2685col_contents = [set() for i in range(ncols)]2686for x in D:2687row_contents[x[0]].add(x[1])2688col_contents[x[1]].add(x[0])26892690for i in row_order:2691S = []2692for j in row_contents[i]:2693S.append(j)2694if not S:2695continue2696count += 12697S.sort(key=lambda x: col_order_rank[x])2698j = S[0]2699T = []2700for ii in col_contents[j]:2701if row_order_rank[ii] > row_order_rank[i]:2702T.append(ii)2703for k in S[1:]:2704rat = QQ((D[i, k], D[i, j]))2705for ii in T:2706if (ii, k) not in D:2707D[ii, k] = 02708row_contents[ii].add(k)2709col_contents[k].add(ii)2710D[ii, k] -= rat*D[ii, j]2711if D[ii, k] == 0:2712D.pop((ii, k))2713row_contents[ii].remove(k)2714col_contents[k].remove(ii)2715for ii in T:2716D.pop((ii, j))2717row_contents[ii].remove(j)2718col_contents[j].remove(ii)2719return count27202721##########################################272227232724def veto_for_DR(num, g, r, markings=(), moduli_type=MODULI_ST):2725G = single_stratum(num, g, r, markings, moduli_type)2726nr = G.M.nrows()2727nc = G.M.ncols()2728marked_vertices = []2729for i in range(1, nr):2730if G.M[i, 0] != R(G.M[i, 0][0]):2731return True2732for j in range(1, nc):2733if G.M[i, j][0] == 2:2734return True2735if G.M[0, j] != 0 and G.M[i, j] != 0:2736marked_vertices.append(i)2737for ii in range(1, nr):2738S = set(marked_vertices)2739S.add(ii)2740did_something = True2741while did_something:2742did_something = False2743for i in tuple(S):2744if i == ii:2745continue2746for j in range(1, nc):2747if G.M[i, j] != 0:2748for i2 in range(1, nr):2749if G.M[i2, j] != 0 and i2 not in S:2750S.add(i2)2751did_something = True2752if len(S) < nr-1:2753return True2754return False275527562757def find_nonsep_pairs(num, g, r, markings=(), moduli_type=MODULI_ST):2758G = single_stratum(num, g, r, markings, moduli_type)2759nr = G.M.nrows()2760nc = G.M.ncols()2761answer = []2762for i1 in range(1, nr):2763for i2 in range(1, i1):2764found_edge = False2765for j in range(1, nc):2766if G.M[i1, j] != 0 and G.M[i2, j] != 0:2767found_edge = True2768break2769if not found_edge:2770continue2771S = set([i1])2772did_something = True2773while did_something:2774did_something = False2775for i3 in tuple(S):2776for j in range(1, nc):2777if G.M[i3, j] != 0:2778for i4 in range(1, nr):2779if G.M[i4, j] != 0 and i4 not in S and (i3 != i1 or i4 != i2):2780S.add(i4)2781did_something = True2782if i2 in S:2783answer.append([i2, i1])2784return answer27852786# assumes r <= 4 for now278727882789def DR_coeff_is_known(num, g, r, markings=(), moduli_type=MODULI_ST):2790return r <= 427912792# old stuff2793G = single_stratum(num, g, r, markings, moduli_type)2794nr = G.M.nrows()2795nc = G.M.ncols()2796nonsep_pairs = find_nonsep_pairs(num, g, r, markings, moduli_type)2797if len(nonsep_pairs) > 3:2798return False2799if len(nonsep_pairs) == 3:2800i1 = nonsep_pairs[0][0]2801i2 = nonsep_pairs[0][1]2802i3 = nonsep_pairs[2][1]2803jlist = []2804for j in range(1, nc):2805if len([1 for i in [i1, i2, i3] if G.M[i, j] != 0]) == 2:2806jlist.append(j)2807if len(jlist) > 3:2808return False2809for j in jlist:2810for i in [i1, i2, i3]:2811if G.M[i, j][1] != 0:2812return False28132814return True28152816# this stuff is old, keeping it around for now just in case2817for j in range(1, nc):2818ilist = []2819for i in range(1, nr):2820if G.M[i, j] != 0:2821ilist.append(i)2822if len(ilist) == 1:2823continue2824ii1 = ilist[0]2825ii2 = ilist[1]2826jlist = []2827for jj in range(1, nc):2828if G.M[ii1, jj] != 0 and G.M[ii2, jj] != 0:2829jlist.append(jj)2830if len(jlist) == 1 or jlist[0] != j:2831continue2832count = len(jlist)2833for ii in [ii1, ii2]:2834for jj in jlist:2835count += G.M[ii, jj][1]2836if count > 3:2837return False2838return True28392840# next function doesn't work on arbitrary graphs yet, see above function284128422843def DR_coeff(num, g, r, n=0, dvector=(), moduli_type=MODULI_ST):2844markings = tuple(range(1, n+1))2845G = single_stratum(num, g, r, markings, moduli_type)2846nr = G.M.nrows()2847nc = G.M.ncols()2848answer = QQ((1, autom_count(num, g, r, markings, moduli_type)))28492850def balance(ilist):2851bal = [0 for i1 in ilist]2852for j1 in range(1, nc):2853if G.M[0, j1] != 0:2854for i3 in range(1, nr):2855if G.M[i3, j1] != 0:2856S = set([i3])2857did_something = True2858while did_something:2859did_something = False2860for i4 in tuple(S):2861for j2 in range(1, nc):2862if G.M[i4, j2] != 0:2863for i5 in range(1, nr):2864if G.M[i5, j2] != 0 and i5 not in S and (i4 not in ilist or i5 not in ilist):2865S.add(i5)2866did_something = True2867for kk, ikk in enumerate(ilist):2868if ikk in S:2869bal[kk] += dvector[G.M[0, j1][0] - 1]2870return bal28712872def poly4(a, b, c):2873return (ZZ.one() / 420)*(-15 * (a**8 + b**8 + c**8)+40 * (a**7 * b+a**7 * c+b**7 * a+b**7 * c+c**7 * a+c**7 * b)-28 * (a**6 * b**2 + a**6 * c**2 + b**6 * a**2 + b**6 * c**2 + c**6 * a**2 + c**6 * b**2)-112 * (a**6 * b*c+b**6 * a*c+c**6 * a*b)+84 * (a**5 * b**2 * c+a**5 * c**2 * b+b**5 * a**2 * c+b**5 * c**2 * a+c**5 * a**2 * b+c**5 * b**2 * a)-70 * (a**4 * b**2 * c**2 + b**4 * a**2 * c**2 + c**4 * a**2 * b**2))28742875nonsep_pairs = find_nonsep_pairs(num, g, r, markings, moduli_type)2876if len(nonsep_pairs) == 4:2877cycle = [nonsep_pairs[0][0], nonsep_pairs[0]2878[1], 0, 0]2879for i in range(1, 4):2880for j in range(2):2881if nonsep_pairs[i][j] == cycle[0]:2882cycle[3] = nonsep_pairs[i][1 - j]2883if nonsep_pairs[i][j] == cycle[1]:2884cycle[2] = nonsep_pairs[i][1 - j]2885dbal = balance(cycle)2886a = dbal[0]2887b = dbal[0] + dbal[1]2888c = dbal[0] + dbal[1] + dbal[2]2889answer *= poly4(a, b, c)2890elif len(nonsep_pairs) == 3:2891i1 = nonsep_pairs[0][0]2892i2 = nonsep_pairs[0][1]2893i3 = nonsep_pairs[2][1]2894cycle = [i1, i2, i3]2895cycle4 = cycle + [cycle[0]]2896dbal = balance(cycle)2897dbal4 = dbal + [dbal[0]]2898done = False2899for k in range(3):2900jlist = [j for j in range(1, nc) if (2901G.M[cycle4[k], j] != 0 and G.M[cycle4[k+1], j] != 0)]2902if len(jlist) == 2:2903answer *= -ZZ.one() / 6 * \2904poly4(0, dbal4[k], -dbal4[k+1])2905done = True2906elif len(jlist) == 1:2907if G.M[cycle4[k], jlist[0]][1] + G.M[cycle4[k+1], jlist[0]][1] > 0:2908answer *= -ZZ.one() / 2 * \2909poly4(0, dbal4[k], -dbal4[k+1])2910done = True2911if not done:2912answer *= (dbal[0]**6 + dbal[1]**6 + dbal[2]**6 -291310 * dbal[0]**2 * dbal[1]**2 * dbal[2]**2)/ZZ(30)29142915for j in range(1, nc):2916ilist = []2917for i in range(1, nr):2918if G.M[i, j] != 0:2919ilist.append(i)2920if len(ilist) == 1:2921x = G.M[ilist[0], j][1]2922answer /= factorial(x)2923answer *= dvector[G.M[0, j][0] -29241]**(ZZ(2) * x)2925continue2926if ilist in nonsep_pairs:2927continue2928ii1 = ilist[0]2929ii2 = ilist[1]2930jlist = []2931for jj in range(1, nc):2932if G.M[ii1, jj] != 0 and G.M[ii2, jj] != 0:2933jlist.append(jj)2934if len(jlist) == 1:2935x1 = G.M[ii1, j][1]2936x2 = G.M[ii2, j][1]2937answer *= -12938answer /= factorial(x1)2939answer /= factorial(x2)2940answer /= x1+x2+12941answer *= balance([ii1, ii2])[0]**(ZZ(2) *2942(x1+x2+1))2943continue2944elif len(jlist) == 2:2945if jlist[0] != j:2946continue2947xvec = [G.M[ii1, jlist[0]][1], G.M[ii1, jlist[1]][1],2948G.M[ii2, jlist[0]][1], G.M[ii2, jlist[1]][1]]2949x = sum(xvec)2950if x == 0:2951answer *= -ZZ.one() / 62952answer *= balance([ii1, ii2])[0]**42953elif x == 1:2954answer *= -ZZ.one() / 302955answer *= balance([ii1, ii2])[0]**62956elif x == 2:2957if xvec in [[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 2]]:2958answer *= -ZZ.one() / 1682959elif xvec in [[1, 1, 0, 0], [0, 0, 1, 1], [1, 0, 0, 1], [0, 1, 1, 0]]:2960answer *= -ZZ.one() / 2802961elif xvec in [[1, 0, 1, 0], [0, 1, 0, 1]]:2962answer *= -ZZ.one() / 842963answer *= balance([ii1, ii2])[0]**82964continue2965elif len(jlist) == 3:2966if jlist[0] != j:2967continue2968xvec = [G.M[ii1, jlist[0]][1], G.M[ii1, jlist[1]][1], G.M[ii1, jlist[2]]2969[1], G.M[ii2, jlist[0]][1], G.M[ii2, jlist[1]][1], G.M[ii2, jlist[2]][1]]2970x = sum(xvec)2971if x == 0:2972answer *= -ZZ.one() / 902973answer *= balance([ii1, ii2])[0]**62974elif x == 1:2975answer *= -ZZ.one() / 8402976answer *= balance([ii1, ii2])[0]**82977continue2978elif len(jlist) == 4:2979if jlist[0] != j:2980continue2981answer *= -ZZ.one() / 25202982answer *= balance([ii1, ii2])[0]**82983return answer298429852986def DR_uncomputed(g, r, markings, moduli_type=MODULI_ST):2987#markings = tuple(range(1,n+1))2988for i in range(num_strata(g, r, markings, moduli_type)):2989if not veto_for_DR(i, g, r, markings, moduli_type) and not DR_coeff_is_known(i, g, r, markings, moduli_type):2990print(i)2991print(single_stratum(i, g, r, markings, moduli_type).M)2992print("---------------------")299329942995def reduce_with_rels(B, vec):2996vec2 = copy(vec)2997for row in B:2998for i in range(len(row)):2999if row[i] != 0:3000if vec2[i] != 0:3001vec2 -= QQ((vec2[i], row[i]))*row3002break3003return vec2300430053006def DR_coeff_setup(num, g, r, n=0, dvector=(), kval=0, moduli_type=MODULI_ST):3007markings = tuple(range(1, n+1))3008G = single_stratum(num, g, r, markings, moduli_type)3009nr = G.M.nrows()3010nc = G.M.ncols()3011edge_list = []3012exp_list = []3013scalar_factor = ZZ.one() / \3014autom_count(num, g, r, markings, moduli_type)3015for i in range(1, nr):3016for j in range(1, G.M[i, 0].degree()+1):3017scalar_factor /= factorial(G.M[i, 0][j])3018scalar_factor /= factorial(j)**G.M[i, 0][j]3019scalar_factor *= (-1)**G.M[i, 0][j]3020scalar_factor *= (kval**2)**(j * G.M[i, 0][j])3021given_weights = [-kval*(2*G.M[i+1, 0][0] - 2 + sum([G.M[i+1][j][0]3022for j in range(1, nc)])) for i in range(nr-1)]3023for j in range(1, nc):3024ilist = [i for i in range(1, nr)3025if G.M[i, j] != 0]3026if G.M[0, j] == 0:3027if len(ilist) == 1:3028i1 = ilist[0]3029i2 = ilist[0]3030exp1 = G.M[i1, j][1]3031exp2 = G.M[i1, j][2]3032else:3033i1 = ilist[0]3034i2 = ilist[1]3035exp1 = G.M[i1, j][1]3036exp2 = G.M[i2, j][1]3037edge_list.append([i1-1, i2-1])3038exp_list.append(exp1 + exp2 + 1)3039scalar_factor /= - \3040factorial(exp1)*factorial(exp2)*(exp1+exp2+1)3041else:3042exp1 = G.M[ilist[0], j][1]3043scalar_factor *= dvector[G.M[0, j][0] -30441]**(ZZ(2) * exp1)/factorial(exp1)3045given_weights[ilist[0] -30461] += dvector[G.M[0, j][0] - 1]3047return edge_list, exp_list, given_weights, scalar_factor304830493050def DR_coeff_new(num, g, r, n=0, dvector=(), kval=0, moduli_type=MODULI_ST):3051markings = tuple(range(1, n+1))3052G = single_stratum(num, g, r, markings, moduli_type)3053nr = G.M.nrows()3054nc = G.M.ncols()3055edge_list, exp_list, given_weights, scalar_factor = DR_coeff_setup(3056num, g, r, n, dvector, kval, moduli_type)3057m0 = ceil(sum([abs(i) for i in dvector])/ZZ(2)) + g*abs(kval)3058h0 = nc - nr - n + 13059deg = 2 * sum(exp_list)3060mrange = list(range(m0 + 1, m0 + deg + 2))3061mvalues = []3062for m in mrange:3063total = 03064for weight_data in itertools.product(*[list(range(m)) for i in range(len(edge_list))]):3065vertex_weights = copy(given_weights)3066for i in range(len(edge_list)):3067vertex_weights[edge_list[i][0]] += weight_data[i]3068vertex_weights[edge_list[i][1]] -= weight_data[i]3069if any(i % m for i in vertex_weights):3070continue3071term = 13072for i in range(len(edge_list)):3073term *= weight_data[i]**(ZZ(2) * exp_list[i])3074total += term3075mvalues.append(QQ((total, m**h0)))3076mpoly = interpolate(mrange, mvalues)3077return mpoly.subs(X=0)*scalar_factor307830793080def DR_coeff_setup_m(m, num, g, r, n=0, dvector=(), kval=0, moduli_type=MODULI_ST):3081markings = tuple(range(1, n+1))3082G = single_stratum(num, g, r, markings, moduli_type)3083nr = G.M.nrows()3084nc = G.M.ncols()3085edge_list = []3086exp_list = []3087scalar_factor = ZZ.one() / \3088autom_count(num, g, r, markings, moduli_type)3089for i in range(1, nr):3090for j in range(1, G.M[i, 0].degree()+1):3091scalar_factor /= factorial(G.M[i, 0][j])3092scalar_factor /= factorial(j)**G.M[i, 0][j]3093scalar_factor *= (-1)**G.M[i, 0][j]3094scalar_factor *= (kval**2 - kval*m + m**2 /3095ZZ(6))**(j*G.M[i, 0][j])3096given_weights = [-kval*(ZZ(2) * G.M[i+1, 0][0] - ZZ(2) + sum(3097[G.M[i+1][j][0] for j in range(1, nc)])) for i in range(nr-1)]3098for j in range(1, nc):3099ilist = [i for i in range(1, nr)3100if G.M[i, j] != 0]3101if G.M[0, j] == 0:3102if len(ilist) == 1:3103i1 = ilist[0]3104i2 = ilist[0]3105exp1 = G.M[i1, j][1]3106exp2 = G.M[i1, j][2]3107else:3108i1 = ilist[0]3109i2 = ilist[1]3110exp1 = G.M[i1, j][1]3111exp2 = G.M[i2, j][1]3112edge_list.append([i1-1, i2-1])3113exp_list.append(exp1 + exp2 + 1)3114scalar_factor /= - \3115factorial(exp1)*factorial(exp2)*(exp1+exp2+1)3116else:3117exp1 = G.M[ilist[0], j][1]3118dval = dvector[G.M[0, j][0] - 1]3119if dval < 0:3120dval = dval + m3121scalar_factor *= (dval**2 - dval*m + m**2 /3122ZZ(6))**(exp1)/factorial(exp1)3123given_weights[ilist[0] -31241] += dvector[G.M[0, j][0] - 1]3125return edge_list, exp_list, given_weights, scalar_factor312631273128def DR_coeff_m(m, num, g, r, n=0, dvector=(), kval=0, moduli_type=MODULI_ST):3129markings = tuple(range(1, n+1))3130G = single_stratum(num, g, r, markings, moduli_type)3131nr = G.M.nrows()3132nc = G.M.ncols()3133edge_list, exp_list, given_weights, scalar_factor = DR_coeff_setup_m(3134m, num, g, r, n, dvector, kval, moduli_type)3135h0 = nc - nr - n + 13136total = ZZ.zero()3137for weight_data in itertools.product(*[list(range(m)) for i in range(len(edge_list))]):3138vertex_weights = copy(given_weights)3139for i in range(len(edge_list)):3140vertex_weights[edge_list[i][0]] += weight_data[i]3141vertex_weights[edge_list[i][1]] -= weight_data[i]3142if any(i % m for i in vertex_weights):3143continue3144term = 13145for i in range(len(edge_list)):3146dval = weight_data[i]3147term *= (dval**2 - dval*m + m**2 / ZZ(6))**exp_list[i]3148total += term3149total /= m**h03150total *= scalar_factor3151return total315231533154def interpolate(A, B):3155X = SR.var('X')3156l = len(A)3157poly = 03158M = []3159for i in range(l):3160M.append(vector([a**i for a in A]))3161M.append(vector(B))3162ker = Matrix(M).kernel().basis()[0]3163for i in range(l):3164poly += (QQ(-ker[i])/QQ(ker[-1]))*X**i3165return poly316631673168def DR_compute(g, r, n=0, dvector=(), kval=0, moduli_type=MODULI_ST):3169answer = []3170markings = tuple(range(1, n+1))3171for i in range(num_strata(g, r, markings, moduli_type)):3172answer.append(DR_coeff_new(i, g, r, n, dvector, kval, moduli_type))3173return vector(answer)/ZZ(2) ** r317431753176def DR_compute_m(m, g, r, n=0, dvector=(), kval=0, moduli_type=MODULI_ST):3177answer = []3178markings = tuple(range(1, n+1))3179for i in range(num_strata(g, r, markings, moduli_type)):3180answer.append(DR_coeff_m(m, i, g, r, n, dvector, kval, moduli_type))3181return vector(answer)318231833184def DR_sparse(g, r, n=0, dvector=(), kval=0, moduli_type=MODULI_ST):3185"""3186Same as :func:`DR_compute` except that it returns the answer as a3187sparse vector.31883189EXAMPLES::31903191sage: from admcycles.DR import DR_sparse3192sage: DR_sparse(1,1,2,(2,-2))3193[[1, 2], [2, 2], [4, -1/24]]3194"""3195vec = DR_compute(g, r, n, dvector, kval, moduli_type)3196return [[i, veci] for i, veci in enumerate(vec) if veci != 0]319731983199def DR_psi_check(g, n, dvector, which_psi):3200vec = DR_sparse(g, g, n, dvector, 0)3201r = g3202while r < 3 * g - 3 + n:3203vec = psi_multiple(vec, which_psi, g, r, n)3204r += 13205total = ZZ.zero()3206for a, b in vec:3207total += b * socle_evaluation(a, g, tuple(range(1, n + 1)))3208return total / 2**g320932103211def DR_reduced(g, dvector=()):3212"""3213Same as :func:`DR_compute` except that it only requires two arguments3214(g and dvector) and simplifies the answer using the 3-spin3215tautological relations.32163217EXAMPLES::32183219sage: from admcycles.DR import DR_reduced3220sage: DR_reduced(1,(2,-2))3221(0, 0, 0, 4, 1/8)3222"""3223g = ZZ(g)3224n = len(dvector)3225r = g3226kval = ZZ(sum(dvector) / (2 * g - 2 + n))3227vec = DR_compute(g, r, n, dvector, kval)3228vec = vector(QQ, (QQ(a) for a in vec))3229rels = FZ_rels(g, r, tuple(range(1, n + 1)))3230return reduce_with_rels(rels, vec)323132323233def list_strata(g, r, n=0, moduli_type=MODULI_ST):3234"""3235Displays the list of all strata.32363237EXAMPLES::32383239sage: from admcycles.DR import list_strata3240sage: list_strata(1,1,2)3241generator 03242[ -1 1 2]3243[X + 1 1 1]3244------------------------------3245generator 13246[ -1 1 2]3247[ 1 X + 1 1]3248------------------------------3249generator 23250[ -1 1 2]3251[ 1 1 X + 1]3252------------------------------3253generator 33254[-1 1 2 0]3255[ 0 1 1 1]3256[ 1 0 0 1]3257------------------------------3258generator 43259[-1 0 1 2]3260[ 0 2 1 1]3261------------------------------3262"""3263L = all_strata(g, r, tuple(range(1, n + 1)), moduli_type)3264for i, Li in enumerate(L):3265print("generator %s" % i)3266print(Li.M)3267print("-" * 30)326832693270