unlisted
ubuntu2004r"""1Spin Stratum: A stratum with signature of even type will has spin structure, i.e.2its connected components can be partitioned to two non-empty sets.34cf. [KZ03]_ and [Boi15]_56"""78from copy import deepcopy9import sage.misc.persist1011from sage.rings.all import QQ12from sage.matrix.constructor import matrix, vector13from sage.misc.cachefunc import cached_function14from sage.combinat.all import SetPartitions1516import admcycles.admcycles17import admcycles.stratarecursion1819import admcycles.diffstrata.levelgraph20import admcycles.diffstrata.bic21import admcycles.diffstrata.stratatautring22import admcycles.diffstrata.embeddedlevelgraph2324from admcycles.stable_graph import StableGraph25from admcycles.diffstrata.generalisedstratum import GeneralisedStratum26from admcycles.diffstrata.additivegenerator import AdditiveGenerator27from admcycles.diffstrata.elgtautclass import ELGTautClass28from admcycles.diffstrata.sig import Signature2930from admcycles.identify_classes import SolveMultLin313233def Spin_strataclass(sig, res_cond=[]):34r"""35Compute the spin stratum class of given signature of even type (may36have paired simple poles) and residue conditions.3738INPUT:3940- sig (tuple)41- res_cond (list): It is a list of lists corresponding to residue42conditions. For example, sig=(4,-2,-1,-1) with the43simple poles being paired. Then44res_cond=[[(0,2), (0,3)]]. Here the zero indicate45the components of a generalized stratum.4647EXAMPLES::4849sage: from admcycles.diffstrata.spinstratum import Spin_strataclass50sage: Spin_strataclass((2,2)).basis_vector()51(159/4, -179/48, -7/24, -7/24, -131/48, -23/24, -131/48, 149/24, -83/16, 271/48, 77/48, 77/48, -193/8, -185/48, 127/48, 395/48, 221/48, -73/8, -185/48, 127/48, 395/48, 221/48, -73/8, -185/48, -41/48, 389/48, 389/48, -23/8, 51/8, -139/16, -323/16, 1/8, -25/4, -11/4, -11/4, -23/4, 973/48, 37/96, -5/2, 23/96, 23/96, -25/32)525354"""55X = SpinStratum([Signature(sig)], res_cond=res_cond)56A = AG_with_spin(X, ((), 0))57E = ELGT_with_spin(X, [(1, A)])58return E.to_prodtautclass_spin().pushforward()596061#######################################################################62#######################################################################63# Define the class of spin strata #####################################64#######################################################################6566class SpinStratum(GeneralisedStratum):6768def __init__(self, sig_list, res_cond=None, pair_res_cond=None):69r"""70A stratum can have spin structure if there are pairs of simple poles,71such that their residues r_i + r_i+1 = 0. In this code, we only handle the72cases of at most 1 pair of simple poles.7374INPUT:7576- sig_list (list): a list of tuples indicating the signatures77of the components of a generalised stratum7879- res_cond (list): a list whose entries are lists corresponding80to residue conditions8182EXAMPLES::8384sage: from admcycles.diffstrata.spinstratum import SpinStratum85sage: from admcycles.diffstrata.sig import Signature86sage: X = SpinStratum([Signature((4,-2,-1,-1))],87....: res_cond=[[(0,2),(0,3)]])8889"""9091super().__init__(sig_list, res_cond)9293if res_cond:94self._res_cond = res_cond95else:96self._res_cond = []97if pair_res_cond:98self.pair_res_cond = pair_res_cond99else:100self.pair_res_cond = []101self.odd_sing_list = []102for i in range(0, len(self._sig_list)):103for j in range(0, len(sig_list[i].sig)):104if sig_list[i].sig[j] % 2 != 0:105self.odd_sing_list.append((i, j))106107self.sim_pole_list = list(self.simple_poles())108self.sim_pole_list.sort()109self.hor_edge = []110self.eff_hor_edge = []111self.eff_pair_res = []112113if self.odd_sing_list != [] and pair_res_cond is None:114self.is_legal()115116def __repr__(self):117return "SpinStratum(sig_list=%r,res_cond=%r)" % (118self._sig_list, self._res_cond)119120def __str__(self):121rep = ''122if self._h0 > 1:123rep += 'Product of Strata with spin:\n'124else:125rep += 'Spin Stratum: '126for sig in self._sig_list:127rep += repr(sig.sig) + '\n'128rep += 'with residue conditions: '129if not self._res_cond:130rep += repr([]) + '\n'131for res in self._res_cond:132rep += repr(res) + '\n'133return rep134135def is_legal(self):136r"""137This is just a method for initializing a spin stratum, checking whether138the stratum really has spin structure.139140EXAMPLES::141142sage: from admcycles.diffstrata.spinstratum import SpinStratum143sage: from admcycles.diffstrata.sig import Signature144sage: X = SpinStratum([Signature((4,-2,-2))])145sage: X = SpinStratum([Signature((4,-3,-1))])146Traceback (most recent call last):147...148ValueError: The Stratum does not have spin components149sage: X = SpinStratum([Signature((4,-2,-1,-1))])150sage: X = SpinStratum([Signature((4,-1,-1,-1,-1))])151Traceback (most recent call last):152...153NotImplementedError: We can only handle one pair of simple poles154155"""156157if len(self.odd_sing_list) - len(self.sim_pole_list) > 0:158raise ValueError("The Stratum does not have spin components")159elif len(self.sim_pole_list) > 0:160t = len(self.sim_pole_list)161if t > 2:162raise NotImplementedError("We can only handle " +163"one pair of simple poles")164if not t % 2 == 0:165raise ValueError("The Stratum does not have spin components")166167M1 = self.smooth_LG.residue_matrix_from_RT168if self.res_cond != []:169M2 = M1.stack(self.matrix_from_res_conditions(self.res_cond))170else:171M2 = M1172a = 0173b = M2.rank()174c = M1.rank()175176for q in range(0, t - 1):177for q1 in range(q + 1, t):178if self.sim_pole_list[q][0] != self.sim_pole_list[q1][0]:179res = [self.sim_pole_list[q], self.sim_pole_list[q1]]180T = self.matrix_from_res_conditions(res)181M0 = M2.stack(T)182a = M0.rank()183if a > b:184continue185else:186self.hor_edge.append([self.sim_pole_list[q],187self.sim_pole_list[q1]])188sim_pole_list_partitons = SetPartitions(t, [2 for i in189range(0, int(t / 2))]190).list()191rc = []192for part in sim_pole_list_partitons:193pair_res_cond_temp = []194for q in part:195w = list(q)196pair_res_cond_temp.append([self.sim_pole_list[i - 1]197for i in w])198199M0 = M2.stack(self.matrix_from_res_conditions(200pair_res_cond_temp))201a = M0.rank()202if a > b:203continue204else:205self.pair_res_cond = pair_res_cond_temp206rc = pair_res_cond_temp + deepcopy(self._res_cond)207break208209if self.pair_res_cond is None:210raise ValueError("The Stratum does not have spin components")211if t == 1 and a == 1:212self._res_cond = []213elif not self.is_empty():214new_rc = []215for j, q in enumerate(rc):216rk = M1.stack(self.matrix_from_res_conditions([q])).rank()217if rk > c:218M1 = M1.stack(self.matrix_from_res_conditions([q]))219c += 1220if q in self.pair_res_cond:221self.eff_pair_res.append(j)222new_rc.append(q)223new_rc.reverse()224self._res_cond = new_rc225return226227def remove_pair_res(self, psis=None):228r"""229This method will return the psi polynomial of the stratum in the230tautological ring of ambient stratum (without a residue condition231on the pair of simple poles. The formula follows Sauvaget-19 and we pick232the leg of a simple pole for the elimination of psi class.233234Only the BICs, which have some odd enhancement (so odd even are half235half), or still preserve the residue condition of the pair of236simple poles, are left. Hence, one can237still recursively compute the spin classes.238239INPUT:240241- psis (list): a list of dicts indicating the psi polynomial242243EXAMPLES::244245246sage: from admcycles.diffstrata.spinstratum import SpinStratum247sage: from admcycles.diffstrata.sig import Signature248sage: from admcycles.admcycles import psiclass249sage: X = SpinStratum([Signature((4,-2,-1,-1))],res_cond=[[(0,2),(0,3)]])250sage: cl1 = X.remove_pair_res().to_prodtautclass_spin().pushforward()251sage: (psiclass(1,1,4)**2*cl1).evaluate()2525/24253254"""255if not self.eff_pair_res == []:256# print("removing pair res")257res_cond = deepcopy(self._res_cond)258lost_rc = res_cond.pop()259leg = lost_rc[0]260new_stratum = SpinStratum(self._sig_list, res_cond,261pair_res_cond=self.pair_res_cond)262new_AG = new_stratum.additive_generator(((), 0), psis)263elgt = new_AG.as_taut() * (new_stratum.res_stratum_class(lost_rc) +264new_stratum.xi_with_leg() -265new_stratum.xi_with_leg(leg))266temp_psi_list = []267for a in elgt._psi_list:268if all(kappa % 2 != 0269for e, kappa in a[1]._G.LG.prongs_list()):270temp_psi_list.append(a)271psi_list = [(c, AG_with_spin(new_stratum,272AG._enh_profile, AG._leg_dict))273for c, AG in temp_psi_list]274elgt_odd_enh = ELGT_with_spin(new_stratum, psi_list)275# print(str(elgt_odd_enh))276result = elgt_odd_enh277return result278else:279raise NotImplementedError280281def smooth_con_stratum_prodtautclass(self):282r"""283To compute the spin stratum class of a connected stratum. The output will be a284product tautological class. By making use of standised signature, we will do285the core computation in the function smooth_stratum_standard().286287EXAMPLES::288289sage: from admcycles.diffstrata.spinstratum import SpinStratum290sage: from admcycles.diffstrata.sig import Signature291sage: X=SpinStratum([Signature((4,0,-2))])292sage: X.smooth_con_stratum_prodtautclass().pushforward().basis_vector()293(-63/2, 21/2, -20, -63/2, -37/2, 38, 61/2, 61/2, 147/2, 29, 57/2, 29, -41, -60, 21, -63/2, -42, 61/2, -41, -139/2, 147/2, 63/2, -147/2, 21/2, 0, -21/2, -7, -21/2, -19/2, 19/2, 21/2, -21/2, 1, -21/2, 0, 0, 21/2, 21/2, -7, 1, -1, -1, 0, 7)294295"""296res_cond = self._res_cond297sig = self._sig_list[0].sig298g = self._sig_list[0].g299LG = self.smooth_LG.LG300stgraph0 = LG.stgraph301302if all(x == 0 for x in sig): # it is just g=1 and the stratum class is just fundclass of M_1,n303t = deepcopy(smooth_stratum_standard(sig))304if all(w == 0 for w in t[3]):305result = admcycles.admcycles.prodtautclass(stgraph0, terms=[])306else:307ind = admcycles.admcycles.generating_indices(t[0], t[1], t[2])308gen = admcycles.admcycles.tautgens(t[0], t[1], t[2])309result = sum([t[3][i] * gen[ind[i]]310for i in range(0, len(t[3]))]).toprodtautclass()311return result312313L = standardise_sig(sig, res_cond) # We use the standardised signature314simplified = L[0]315num_of_reg = L[1]316legs = {x2: x1 for x1, x2 in L[2].items()}317new_rc = L[3]318319# The stratum classes of signature with 0s are essentially just the320# forgetful pullback of stratum class of signature without 0s.321# We use the function smooth_stratum_standard to do the pullbacks solving.322323t = deepcopy(smooth_stratum_standard(simplified, tuple(new_rc)))324if all(w == 0 for w in t[3]):325cl = admcycles.admcycles.fundclass(g, len(simplified))326else:327ind = admcycles.admcycles.generating_indices(t[0], t[1], t[2])328gen = admcycles.admcycles.tautgens(t[0], t[1], t[2])329cl = sum([t[3][i] * gen[ind[i]] for i in range(0, len(t[3]))])330if num_of_reg != 0:331cl = cl.forgetful_pullback([len(simplified) + i332for i in range(1, L[1] + 1)])333result = cl.rename_legs(legs, inplace=False).toprodtautclass()334# print(str(legs)+ "\n"+ str(cl) + "\n" + str(result))335return result336337#######################################################################338#######################################################################339# Define the spin version additive generators #########################340#########################################341# * the spin taut class of those enhanced level graphs with some even342# enhancement are just considered as zero in this algorithm, because343# the pushforward of them to \bar M_g,n will be zero.344#######################################################################345346347class AG_with_spin (AdditiveGenerator):348349def __init__(self, X, enh_profile, leg_dict=None):350assert isinstance(X, SpinStratum)351super().__init__(X, enh_profile, leg_dict)352self.X = X353354def __repr__(self):355return "AG_with_spin(X=%r,enh_profile=%r,leg_dict=%r)"\356% (self._X, self._enh_profile, self._leg_dict)357358def __str__(self):359str = ""360if self._leg_dict is not None:361for l in self._leg_dict:362str += "Spin Psi class %r with exponent %r on level %r * "\363% (l, self._leg_dict[l], self._level_dict[l])364str += "Graph %r" % (self._enh_profile,)365return str366367def to_prodtautclass_spin(self, rearrange_markings=True):368r"""369This function is to compute the product tautological class of an370additive generator with spin. It is basically the same as371toprodtautclass, but just includes more case divisions.372373EXAMPLES::374375sage: from admcycles.diffstrata.spinstratum import SpinStratum,AG_with_spin376sage: from admcycles.diffstrata.sig import Signature377sage: X = SpinStratum([Signature((4,-2))])378sage: AG_with_spin(X, ((1,),0)).to_prodtautclass_spin()379Outer graph : [1, 0] [[3, 4], [1, 2, 5, 6]] [(3, 5), (4, 6)]380Vertex 0 :381Graph : [1] [[1, 2]] []382Polynomial : -1/2383Vertex 1 :384Graph : [0] [[1, 2, 3, 4]] []385Polynomial : psi_4386<BLANKLINE>387<BLANKLINE>388Vertex 0 :389Graph : [1] [[1, 2]] []390Polynomial : -1/2391Vertex 1 :392Graph : [0, 0] [[2, 3, 11], [1, 4, 12]] [(11, 12)]393Polynomial : 3394<BLANKLINE>395<BLANKLINE>396Vertex 0 :397Graph : [1] [[1, 2]] []398Polynomial : -1/2399Vertex 1 :400Graph : [0, 0] [[3, 4, 11], [1, 2, 12]] [(11, 12)]401Polynomial : -3402403"""404LG = self._G.LG405stgraph = LG.stgraph406407# If the level graph has any edge with positive even enhancement,408# half of the prong matchings give an even spin curve and half of409# them give an odd spin curve410if any(kappa % 2 == 0 for e, kappa in LG.prongs_list()):411return admcycles.admcycles.prodtautclass(stgraph, terms=[])412413# Check whether the prodtautclass will be zero414# If any level has extra freedom of scaling, the class will be zero on415# moduli space of curves.416if any(self.level(l).zeroStratumClass()417for l in range(self.codim + 1)):418if rearrange_markings:419stgraph = self._G.relabel(self._G.standard_markings(), tidyup=False).LG.stgraph420return admcycles.admcycles.prodtautclass(stgraph, terms=[])421422# To handle the case that the stratum is connected423if len(LG.genera) == 1:424adm_psis = admcycles.admcycles.decstratum(stgraph,425psi=self.leg_dict)426adm_psis_taut = admcycles.admcycles.tautclass([adm_psis])427428# To handle the case that the genus is 0 and there are no429# simple poles.430if LG.genera[0] == 0 and self.X.sim_pole_list == []:431stratum_class = AdditiveGenerator(self.X, ((), 0)).as_taut()432stratum_class = stratum_class.to_prodtautclass().pushforward()433protaut = [adm_psis_taut * stratum_class]434result = admcycles.admcycles.prodtautclass(stgraph,435protaut=protaut)436return result437438# To handle the case that there are only two poles which are a pair439# of simple poles.440if (self.X.res_cond == [] or441len(self.X.eff_pair_res) < len(self.X.pair_res_cond)):442stratum_class = self.X.smooth_con_stratum_prodtautclass()443stratum_class = stratum_class.pushforward()444protaut = [stratum_class * adm_psis_taut]445result = admcycles.admcycles.prodtautclass(stgraph,446protaut=protaut)447return result448449# To resolve residue condition of a pair of simple poles if the450# residue condition is extra.451elif (self.X.eff_pair_res != [] and452len(self.X.eff_pair_res) == len(self.X.pair_res_cond)):453Q = self.X.remove_pair_res()454total = Q.to_prodtautclass_spin().pushforward()455protaut = [adm_psis_taut * total]456result = admcycles.admcycles.prodtautclass(stgraph,457protaut=protaut)458return result459460# Now it processes to break down the level graph into level461# stratum and resolve the residue conditions (non simple poles).462# Then it computes the result by level clutching.463# The level graph that can come to this stage will have only odd464# enhancements or the stratum is not connected, i.e. no vertical edges.465# In the both cases, the spin class depends on the spin class on466# each level.467468alpha = []469vertices = []470for l in range(self.codim + 1):471psis = self.psis_on_level(l)472level = self.level(l)473level = addspin(level) # level stratum with spin structure474475if (level.eff_pair_res != [] and476len(level.eff_pair_res) == len(level.pair_res_cond)):477# To remove residue condition on a pair of simple poles on478# a disconnected stratum.479ptc = level.remove_pair_res(psis).to_prodtautclass_spin()480else:481T = level.remove_res_cond(psis)482ptc = ELGT_addspin(T).to_prodtautclass_spin()483# print(str(ptc0))484# print(str(ptc1))485alpha.append(ptc)486vertices.append(LG.verticesonlevel(LG.internal_level_number(l)))487488if rearrange_markings: # if we want the labels of stgraph correspond to the markings489prodtautst = self._G.relabel(self._G.standard_markings(), tidyup=False).LG.stgraph490prod = admcycles.admcycles.prodtautclass(prodtautst)491492else:493prod = admcycles.admcycles.prodtautclass(stgraph)494495# To clutch the level stratum classes together496for l, ptc in enumerate(alpha):497prod = prod.factor_pullback(vertices[l], ptc)498499return self.stack_factor * prod500501502def standardise_sig(sig, res_cond=[]):503r"""504To standardise the arrangement of entries in the signature, such that it go from low to high and all the 0s505are placed at the right end. This is just to reduce the required memory and time to compute the stratum classes.506It returns5075081. the simplified sig (0s removed);5092. number of 0s;5103. the leg_dict of rearrangement;5114. new res_cond512513INPUT:514515- sig (tuple): a tuple of integers516- res_cond (list, default=[]): the list of res_cond517518EXAMPLES::519520sage: from admcycles.diffstrata.spinstratum import standardise_sig521sage: standardise_sig((2,4,-1,0,-1), res_cond=[[(0,2),(0,4)]])522[(-1, -1, 2, 4), 1, {1: 3, 2: 4, 3: 1, 4: 5, 5: 2}, [((0, 0), (0, 1))]]523524"""525res = deepcopy(res_cond)526new_rc = []527l = list(set(sig))528g = Signature(sig).g529l.sort()530t = list(sig)531freq = {x: t.count(x) for x in l}532counter = deepcopy(freq)533standard_sig_without_regular = []534535for x in l:536if x != 0:537standard_sig_without_regular += freq[x] * [x]538m = len(standard_sig_without_regular)539if g == 0 and m < 3:540standard_sig_without_regular += (3 - m) * [0]541542leg_dict = {}543for i in range(0, len(sig)):544if sig[i] == 0:545p = sum([f for j, f in freq.items() if j != 0])546leg_dict[i + 1] = p + freq[0] - counter[0] + 1547counter[0] -= 1548if sig[i] != 0:549p = sum([f for j, f in freq.items() if (j != 0 and j < sig[i])])550leg_dict[i + 1] = p + freq[sig[i]] - counter[sig[i]] + 1551counter[sig[i]] -= 1552output = []553output.append(tuple(standard_sig_without_regular))554if 0 in l:555if g == 0 and m < 3:556output.append(freq[0] - 3 + m)557else:558output.append(freq[0])559else:560output.append(0)561output.append(leg_dict)562563for r in res:564w = []565for q in r:566a = (0, leg_dict[q[1] + 1] - 1)567w.append(a)568new_rc.append(tuple(w))569output.append(new_rc)570return output571572573@cached_function574def smooth_stratum_standard(sig, res_cond=()):575r"""576This function is to compute the spin stratum class of a standardised577signature i.e. it is ordered and has no 0s (or all are 0s), also the578stratum has only one component. The results are cached.579580EXAMPLES::581582sage: from admcycles.diffstrata.spinstratum import smooth_stratum_standard583sage: smooth_stratum_standard((-1,-1,4))584[2,5853,5862,587(0, 0, 4, 0, -11/2, -12, 0, -7/2, 0, 1/2, 35/2, 4, 0, -12, 0, 0, 0, -2, 19/2, 0, 7/2, 0, 0, 0, 2, 0, -7/2, 0, 2, -2, 5/2, -13/2, 9/2, 8, 0, 0, 0, 17/2, -11, 2, -2, -9/2, 0, 2)]588589590"""591assert (sum([x for x in sig]) == -2 and len(sig) == 3) or all(j == 0 for j in sig) or all(j != 0 for j in sig)592593if res_cond != ():594rc = []595for q in res_cond:596res_single_cond = [t for t in q]597rc.append(res_single_cond)598X = SpinStratum([Signature(sig)], rc)599else:600X = SpinStratum([Signature(sig)])601602# LG = X.smooth_LG.LG603# stgraph = LG.stgraph604g = X._sig_list[0].g605n = X._sig_list[0].n606r = 0607if any(x < 0 for x in sig):608r = len(res_cond) + 1609k = g + r - 1610# The codim we are dealing with for computation of stratum class.611612# length=len(admcycles.admcycles.generating_indices(g,n,k))613check_basic = is_base_case(sig, g, n, k)614615# To check whether the stratum class is the base cases616if check_basic != []:617return check_basic618619# Solve the pullback equations620ListM = Pullback_Matrices(g, n, r)621prodtaut_list = bdry_pullback_classify(X)622tensorTaut_list = []623for i, u in enumerate(prodtaut_list):624if u != []:625t = sum(u)626v = vector(t.totensorTautbasis(k, vecout=True))627tensorTaut_list.append(v)628else:629length = len(ListM[i][0])630v = vector(QQ, length)631tensorTaut_list.append(v)632633sol_inTautbasis = SolveMultLin(ListM, tensorTaut_list)634return [g, n, k, sol_inTautbasis]635636# To give the stratum classes with spin for the easy cases.637638639def is_base_case(sig, g, n, k):640if g == 0:641if all(q % 2 == 0 for q in sig):642return [g, n, k, vector([QQ(1)])]643644# case of (0,-1,-1)645if n == 3:646return [g, n, k, vector([-QQ(1)])]647648# case of (2k,-2k,-1,-1)649if n == 4:650result = admcycles.admcycles.psiclass(1, 0, 4).basis_vector()651return [g, n, k, result]652653if g == 1:654if all(t == 0 for t in sig):655return [g, n, k, vector([-QQ(1)])]656657if g == 2 and n == 1:658return [g, n, k, vector([QQ(1) / 2, -QQ(7) / 2, QQ(1) / 2])]659660return []661662663def bdry_pullback_classify(stratum):664X = stratum665sig = X._sig_list[0].sig666g = X._sig_list[0].g667n = X._sig_list[0].n668# r = 0669# if any(m < 0 for m in sig):670# r = len(X.res_cond) + 1671# k = g + r - 1672Agraphs = admcycles.admcycles.list_strata(g, n, 1)673if g != 0 and n >= 3:674Agraphs = [G for i, G in enumerate(Agraphs) if i != 0]675else:676G = Agraphs[0].copy()677G.tidy_up()678Agraphs[0] = G679680bddiv_codim1_LG_prodtautclass_list = [[] for G in Agraphs]681bic_stgraph = [bic.relabel(bic.standard_markings(), tidyup=False) for bic in X.bics]682683for j, G in enumerate(Agraphs):684sig0 = [sig[i - 1] for i in G._legs[0] if i < n + 1]685node_sing = 2 * G._genera[0] - 2 - sum(sig0)686687if node_sing == -1:688sig0.append(-1)689sig1 = [sig[i - 1] for i in G._legs[1] if i < n + 1] + [-1]690new_sig_list = [sig0, sig1]691splt_st0 = GeneralisedStratum([Signature(tuple(new_sig_list[0]))])692splt_st1 = GeneralisedStratum([Signature(tuple(new_sig_list[1]))])693elgt0 = splt_st0.additive_generator(((), 0)).as_taut()694elgt1 = splt_st1.additive_generator(((), 0)).as_taut()695st0_spin = ELGT_addspin(elgt0).to_prodtautclass_spin()696st1_spin = ELGT_addspin(elgt1).to_prodtautclass_spin()697prodtaut = admcycles.admcycles.prodtautclass(G)698699# Note that for a horizontal one edge graph, the splitting of the700# two vertices will give rise to extra symplectic basis and thus701# if sum of spins are odd (even), then the horizontal graph702# has spin even(odd).703clutch = prodtaut.factor_pullback([0], st0_spin)704clutch = clutch.factor_pullback([1], -st1_spin)705bddiv_codim1_LG_prodtautclass_list[j].append(clutch)706707else:708if len(G._genera) == 1:709sig_new = ([sig[i - 1] for i in G._legs[0] if i < n + 1] +710[-1, -1])711Y = SpinStratum([Signature(tuple(sig_new))],712res_cond=[[(0, n), (0, n + 1)]])713elgt = Y.additive_generator(((), 0)).as_taut()714prodtaut = admcycles.admcycles.prodtautclass(G)715716stratum_class = ELGT_addspin(elgt).to_prodtautclass_spin()717Intersect = prodtaut.factor_pullback([0], stratum_class)718# print(str(Intersect))719bddiv_codim1_LG_prodtautclass_list[j].append(Intersect)720for num, bic in enumerate(bic_stgraph):721stgraph = bic.LG.stgraph722a = G._edges[0][0]723b = G._edges[0][1]724725Astructure_list = admcycles.admcycles.Astructures(stgraph, G)726727if Astructure_list != []:728# print(str(Astructure_list))729AG = AG_addspin(X.additive_generator(((num,), 0)))730prodtaut_temp = AG.to_prodtautclass_spin()731# print(str(prodtaut_temp))732ell = bic.ell733for w in Astructure_list:734G_no_edge = StableGraph(G._genera, G._legs, [])735image_half_edges = [(w[1][e[0]], w[1][e[1]])736for e in G._edges]737st_edges_new = [e for e in stgraph._edges if738(e not in image_half_edges) and739((e[1], e[0]) not in image_half_edges)]740st_new = StableGraph(stgraph._genera,741stgraph._legs, st_edges_new)742prodtaut = admcycles.admcycles.prodtautclass(st_new, prodtaut_temp.terms)743# print(str(G_no_edge)+"\n"+str(st_new))744E_temp = prodtaut.partial_pushforward(G_no_edge,745w[0], w[1])746E = admcycles.admcycles.prodtautclass(G, E_temp.terms)747# print(str(E_temp)+"\n" +str(E))748kappa_e = bic.LG.prong((w[1][a], w[1][b]))749Intersect = QQ(ell / kappa_e) * E750bddiv_codim1_LG_prodtautclass_list[j].append(Intersect)751752return bddiv_codim1_LG_prodtautclass_list753754755# To generate a list of matrices of the clutching pullback maps.756@cached_function757def Pullback_Matrices(g, n, r):758k = g + r - 1759L1 = admcycles.admcycles.tautgens(g, n, k)760Listgen1 = admcycles.admcycles.generating_indices(g, n, k)761762graph_list = admcycles.admcycles.list_strata(g, n, 1)763if g != 0 and n >= 3:764graph_list = [G for i, G in enumerate(graph_list) if i != 0]765766M_list = []767for G in graph_list:768M0 = []769if len(G._genera) == 1:770G = G.copy()771G.tidy_up()772for i in Listgen1:773T = G.boundary_pullback(L1[i])774M0 = M0 + [T.totensorTautbasis(k, vecout=True)]775M = matrix(M0)776M_list.append(M)777return M_list778779780#######################################################################781#######################################################################782# Define the spin version ELGTautClass ################################783#######################################################################784785786class ELGT_with_spin (ELGTautClass):787788def __init__(self, X, psi_list):789assert isinstance(X, SpinStratum)790super().__init__(X, psi_list)791self.X = X792793def __repr__(self):794return "ELGT_SpinClass(X=%r,psi_list=%r)"\795% (self._X, self._psi_list)796797def __str__(self):798str = "ELGT_SpinClass on %s\n" % self._X799for coeff, psi in self._psi_list:800str += "%s * %s + \n" % (coeff, psi)801return str802803def to_prodtautclass_spin(self):804G = self.X.smooth_LG805# print(str(G))806stgraph = G.LG.stgraph807total = admcycles.admcycles.prodtautclass(stgraph, terms=[])808for c, AG in self._psi_list:809legdictlen = len(AG._G.dmp)810ptc = AG.to_prodtautclass_spin()811vertex_map = {}812for v, _ in enumerate(G.LG.genera):813mp_on_stratum = G.dmp[G.LG.legs[v][0]]814l_AG = AG._G.dmp_inv[mp_on_stratum]815LG = AG._G.LG816v_AG = LG.vertex(l_AG)817UG_v = LG.UG_vertex(v_AG)818T = LG.UG_without_infinity()819T = T.connected_component_containing_vertex(UG_v)820for w, g, kind in T:821if kind != 'LG':822continue823vertex_map[w] = v824leg_map = {i: i for i in range(1, legdictlen + 1)}825# print(str(stgraph)+"\n"+ str(leg_map)+ "\n"+ str(vertex_map)+ "\n" + str(self)+826# "\n" + str(ptc))827pf = ptc.partial_pushforward(stgraph, vertex_map, leg_map)828# print(str(pf) + "\n" + str(ptc)+ "\n" + str(c))829total += c * pf830return total831832833#############################################################################834# Some useful functions #####################################################835#############################################################################836837838# turn a ELGTautClass to spin version839840def ELGT_addspin(elgt):841X = SpinStratum(elgt._X._sig_list, elgt._X._res_cond)842psi_list = [(c, AG_addspin(AG)) for c, AG in elgt._psi_list]843return ELGT_with_spin(X, psi_list)844845846# turn a AdditiveGenerator to spin version847848def AG_addspin(ag):849assert isinstance(ag, AdditiveGenerator)850X = addspin(ag._X)851return AG_with_spin(X, ag._enh_profile, ag._leg_dict)852853854# turn a stratum to spin version855856def addspin(stratum):857assert isinstance(stratum, GeneralisedStratum)858return SpinStratum(stratum._sig_list, stratum._res_cond)859860861def save_spin_stratum():862cachedict = dict(smooth_stratum_standard.cache)863sage.misc.persist.save(cachedict, 'spin_stratum_cache')864865866def load_spin_stratum():867cachedict = sage.misc.persist.load('spin_stratum_cache.sobj')868for a, b in cachedict.items():869smooth_stratum_standard.set_cache(b, *a[0])870871872