unlisted
ubuntu2004from sage.rings.rational_field import QQ1from sage.matrix.constructor import matrix, vector2from sage.matrix.special import block_matrix34import admcycles.admcycles5from .admcycles import list_strata, generating_indices, pullback_matrix678def identify_class(tautring, d, pairfunction=None, pullfunction=None,9kappapsifunction=None, check=False):10r"""11Identify a tautological class in degree d by specifying its12intersection pairing with classes in complementary degree13and/or its pullback under boundary gluing morphisms.1415INPUT::1617- tautring (TautologicalRing) : ring containing the class that18is to be identified1920- d (integer): degree of the class2122- pairfunction (function, optional): function taking classes in23complementary degree and returning the intersection product with24the desired class2526- pullfunction (function, optional): function taking stable graphs27with at most two vertices and returning the prodtautclass obtained28by pulling back the desired class under the associated boundary29gluing map3031- kappapsifunction (function, optional): function taking as arguments32a list, dictionary and TautologicalClass (giving a polynomial in33kappa and psi-classes) and returning the intersection product of34the desired class with this polynomial (or None)3536- check (bool, default = False) : whether to use FZ relations to37verify that intersection numbers/pullbacks are consistent with38known tautological relations3940EXAMPLES::4142sage: from admcycles.identify_classes import identify_class43sage: from admcycles import TautologicalRing44sage: R = TautologicalRing(2, 1)45sage: cl = 3 * R.psi(1) -2 * R.kappa(1)46sage: def pairf(a):47....: return (a * cl).evaluate()48sage: cl2 = R.identify_class(1, pairfunction = pairf)49sage: cl == cl250True51sage: def pullf(gamma):52....: return gamma.boundary_pullback(cl)53....:54sage: cl3 = R.identify_class(1, pullfunction=pullf)55sage: cl == cl356True5758Here is some code to reconstruct the class 42*psi_1 on Mbar_0,6 from its intersection59numbers with psi-monomials (which have an explicit formula). Note that the associated60function kpfun is allowed to return None if kappa-classes show up::6162sage: R = TautologicalRing(0,6)63sage: def kpfun(kap, psi, cl):64....: if kap:65....: return None66....: b = vector(ZZ,[psi.get(i,0) for i in range(1,7)])+vector([1,0,0,0,0,0])67....: return 42*factorial(3)/prod(factorial(bi) for bi in b)68....:69sage: cl4 = R.identify_class(1, kappapsifunction=kpfun)70sage: cl4 == 42*R.psi(1)71True7273TESTS::7475sage: R = TautologicalRing(2, 1)76sage: def bad_pairf(a):77....: return (a * cl).evaluate() if not (a - R.kappa(3)).is_empty() else 078sage: R.identify_class(1, pairfunction = bad_pairf, check=True)79Traceback (most recent call last):80...81ValueError: intersection numbers or pullbacks are not consistent with FZ relations82"""83gens = tautring.basis(d)84ngens = len(gens)85d_dual = tautring.socle_degree() - d86M = matrix(QQ, 0, ngens)87v = []88rank_sufficient = (ngens == 0)89if pairfunction is not None and not rank_sufficient:90if check:91gens_dual = tautring.generators(d_dual)92else:93gens_dual = tautring.basis(d_dual)94ind_dcomp = tuple(generating_indices(tautring._g, tautring._n, d))95inters = tautring.pairing_matrix(d_dual, basis=not check, ind_dcomp=ind_dcomp)96M = block_matrix([[M], [inters]], subdivide=False)97v += [pairfunction(a) for a in gens_dual]98rank_sufficient = (M.rank() == ngens)99100if pullfunction is not None and not rank_sufficient:101moduli = tautring._moduli102graphs = [gam for gam in list_strata(tautring._g, tautring._n, 1)103if not gam.vanishes(moduli)]104if len(graphs) > 0 and graphs[0].num_verts() == 1:105irrgraph = graphs.pop(0)106graphs.append(irrgraph)107for gam in graphs:108pulls = pullback_matrix(tautring._g, tautring._n, d, bdry=gam)109# pulls = [gam.boundary_pullback(a).totensorTautbasis(d, vecout=True)110# for a in gens]111M = block_matrix([[M], [pulls]],112subdivide=False)113v += list(pullfunction(gam).totensorTautbasis(d, vecout=True))114rank_sufficient = (M.rank() == ngens)115if rank_sufficient and not check:116break117118if kappapsifunction is not None and not rank_sufficient:119for kappa, psi, cl in tautring.kappa_psi_polynomials(d_dual, True):120intnum = kappapsifunction(kappa, psi, cl)121if intnum is not None:122M = block_matrix(QQ, [[M], [matrix([[(c * cl).evaluate() for c in gens]])]], subdivide=False)123v.append(intnum)124rank_sufficient = (M.rank() == ngens)125if rank_sufficient and not check:126break127128if not rank_sufficient:129raise ValueError('Intersection numbers and/or pullbacks are ' +130'not enough to determine this class')131try:132w = M.solve_right(vector(QQ, v))133except ValueError:134raise ValueError('intersection numbers or pullbacks are not consistent with FZ relations')135return tautring.from_basis_vector(w, d)136137138def Pullback_Matrices(g, n, d, ind_list=None):139r"""140Compute the pullback matrices of given degree d and list of141boundary stratum.142143INPUT::144145146- ind_list (list): the list of indices of the boundary stratum,1470 indicates the first nontrivial graph148appearing in the generator149list of degree d tautological classes150151EXAMPLES::152153sage: from admcycles.identify_classes import Pullback_Matrices154sage: from admcycles import TautologicalRing155sage: Pullback_Matrices(1, 2, 1)156[157[1] [1]158[0], [1]159]160161"""162L1 = admcycles.admcycles.tautgens(g, n, d)163Listgen1 = admcycles.admcycles.generating_indices(g, n, d)164L2 = admcycles.admcycles.tautgens(g, n, 1)165166M_list = []167if not ind_list:168ind_list = range(len(L2) - n - 1)169170for a in ind_list:171b = a + n + 1172M0 = []173Q = None174if b == len(L2) - 1:175Q = list(L2[b].standard_markings()._terms)[0]176else:177Q = list(L2[b]._terms)[0]178179for i in Listgen1:180T = Q.boundary_pullback(L1[i])181M0 += [T.totensorTautbasis(d, vecout=True)]182M = matrix(M0)183M_list += [M]184return M_list185186187def solve_perfect_pairing(g, n, d, list_evaluate):188r"""189Identify a tautological class in degree d by specifying190its intersection pairing191with classes in complementary degree.192193INPUT::194195196- list_evaluate (list) : the list of intersection numbers197198- list_dual_classes (list): a list of classes of dual codimension199one wants to compute the intersection200(the program will complete the list201such that one obtain a full rank matrix)202203204EXAMPLES::205206sage: from admcycles.identify_classes import solve_perfect_pairing207sage: from admcycles import TautologicalRing208sage: R = TautologicalRing(1,3)209sage: cl = R.psi(1) -2 * R.kappa(1)210sage: def pairf(a):211....: return (a * cl).evaluate()212sage: cl2 = solve_perfect_pairing(1, 3, 1,213....: [pairf(x) for x in R.generators(2)])214sage: cl == cl2215True216217"""218d_dual = 3 * g - 3 + n - d219ind = admcycles.admcycles.generating_indices(g, n, d)220gen = admcycles.admcycles.tautgens(g, n, d)221gen_dual = admcycles.admcycles.tautgens(g, n, d_dual)222M_intpair = []223224for i in ind:225intersection_vector = [(gen[i] * X).evaluate() for X in gen_dual]226M_intpair.append(intersection_vector)227Sol = list(matrix(M_intpair).solve_left(matrix(list_evaluate)))[0]228output = sum(Sol[i] * gen[ind[i]] for i in range(0, len(ind)))229return output230231232def solve_clutch_pullback(g, n, d, bdiv_indices, pullback_classes):233r"""234Identify a tautological class in degree d by specifying its pullback235under boundary gluing morphisms.236237INPUT::238239240- bdiv_indices(list) : the list of indices of boundary241stratum(the first nontrivial graph in242tautgen list will be indexed243by 0) to which we will pullback244- pullback_classes(list) : the list of pullbacks of the tautological245class with respect to the bdiv listed246247EXAMPLES::248249sage: from admcycles.identify_classes import solve_clutch_pullback250sage: from admcycles import TautologicalRing251sage: R = TautologicalRing(1,3)252sage: stgraphs = [list(x._terms)[0] for x in R.generators(1)[4:]]253sage: cl = R.psi(1) -2 * R.kappa(1)254sage: def pullf(gr):255....: return gr.boundary_pullback(cl)256sage: cl2 = solve_clutch_pullback(1, 3, 1, range(len(stgraphs)),257....: [pullf(gr) for gr in stgraphs])258sage: cl == cl2259True260261"""262263if 2 * d > 2 * g - 2 + n:264print(" It may not work because the codim is too large")265ListV = [T.totensorTautbasis(d, vecout=True) for T in pullback_classes]266ListM = Pullback_Matrices(g, n, d)267ListM_1 = [ListM[i] for i in bdiv_indices]268Sol = SolveMultLin(ListM_1, ListV)269ind = admcycles.admcycles.generating_indices(g, n, d)270gen = admcycles.admcycles.tautgens(g, n, d)271output = sum(Sol[i] * gen[ind[i]] for i in range(len(ind)))272return output273274275def SolveMultLin(ListM, ListV):276277dim = ListM[0].nrows()278assert all(Q.nrows() == dim for Q in ListM)279NewM = []280NewV = []281for Q in ListM:282NewM += list(Q.transpose())283NewM = matrix(NewM).transpose()284for W in ListV:285NewV += list(W)286NewV = matrix([NewV])287result = NewM.solve_left(NewV)288L = list(result)289Sol = vector(L[0])290return Sol291292293