-------------------------------------------------------------- -------------------------------------------------------------- -- -- -- Macaulay2 program to compute instanton invariants -- -- -- -- By Thomas Koeppe, -- -- strongly inspired by the original work of Irena Swanson, -- -- based on the work of Elizabeth Gasparim and herself. -- -- -- -- This version is for O(-1)+O(-1), dated 2007-10-01. -- -- -- -- -- -- Description -- -- ----------- -- -- -- -- Let E be a rank-2 bundle over the total space of the -- -- flop O(-1)+O(-1) on CP^1, which is a complex 3-manifold -- -- and an algebraic variety. By contracting the zero-sec- -- -- tion, one obtains a (singular) complex 3-fold X. -- -- -- -- E is an algebraic extension of an algebraic line bundle, -- -- and we assume c_1(E)=0. Thus E is given by the transi- -- -- tion matrix / z^j p \ -- -- \ 0 z^-j / , where p is a polynomial in -- -- z, z^-1, u_1 and u_2, where (z,u_1, u_2) and -- -- (z^-1, z u_1, z u_2) are the two af. charts of the flop. -- -- -- -- The program computes the instanton width and height of -- -- the bundle E. The input data is p for the extension -- -- class and j for the splitting type. -- -- j : integer >= 0 -- -- p : polynomial in Rbase = QQ[z,z^-1,u1,u2] -- -- -- -- Usage: iWidth(p, j) -- -- iHeight(p, j) -- -- -- -- See http://www.maths.ed.ac.uk/~s0571100/Instanton/ -- -- for details and papers. -- -- -- -------------------------------------------------------------- -------------------------------------------------------------- -- -- Basic objects: The base ring and the ring Rbase = basering[z,z^-1,u1,u2]. -- baseRing = QQ Rbase = baseRing[z, u1, u2, MonomialOrder => GroupLex => 1, Degrees => { {1,0,0}, {0,1,0}, {0,0,1} } ] -- -- ... and the ring on the contracted space: -- -- x_i = z^i u1, y_i = z^i u2. -- S = baseRing[x_0, x_1, y_0, y_1]/(x_1 * y_0 - x_0 * y_1) -- -- Some test polynomials. -- -- -- Starting with the bundle E on the flop with splitting type j and extension class p, -- we need to construct a generic section (a,b) of E and find the terms for which -- (a,b) is holomorphic in (z,u1,u2) and T(a,b) is holomorphic in (z^-1,z u1, z u2). -- -- The function "makeSectionsAndRing" makes a generic section (a,b) with enough -- terms that allow the computation of the module of sections. -- -- Technical point: The coefficients are in fact treated as symbols in a new ring -- R = baseRing[z,z^1,u1,u2, a..., b...]. The return value is thus the list -- { variables, p in terms of R, a, b}. -- makeSectionsAndRing = (p, j, Verbose) -> ( if (class j =!= ZZ) or (j < 0) then ( print "Error! j must be a non-negative integer."; return null; ); if (class p =!= Rbase) then ( print "Error! p must be a polynomial in Rbase (i.e. in u and z, z^-1)."; return null; ); -- We need the maximal and minimal degrees of p in u and z: minZ := min apply(terms p, i -> (exponents i)_0_0); maxZ := max apply(terms p, i -> (exponents i)_0_0); minU1 := min apply(terms p, i -> (exponents i)_0_1); maxU1 := max apply(terms p, i -> (exponents i)_0_1); minU2 := min apply(terms p, i -> (exponents i)_0_2); maxU2 := max apply(terms p, i -> (exponents i)_0_2); if Verbose then ( print "The polynomial p has {min deg u1, max deg u1, min deg u2, max deg u2, min deg z, max deg z} = "; print {minU1, maxU1, minU2, maxU2, minZ, maxZ}; ); -- A section is of the form -- __ / u2^t u1^r z^s \ / 0 \ -- (a, b) = \ a | | + b | | . -- /_ trs \ 0 / trs \ u2^t u1^r z^s / -- aMax := max(j, maxU1, maxU2) + min(minU1,minU2); bMax := aMax-min(minU1,minU2); --aMax - maxU; if p == 0_Rbase then (minU1 = 0; minU2 = 0; bMax = 0; aMax = j); aIndex1 := toList flatten apply(min(minU1,minU2), rho -> flatten toList apply(0..(rho-j), s -> toList apply(0..rho, r -> (rho-r, r, s)))); aIndex2 := toList flatten apply(min(minU1,minU2)..aMax, rho -> flatten toList apply(0..max(rho-j, (rho-min(minU1,minU2) + j + max(maxZ,0))), s -> toList apply(0..rho, r -> (rho-r, r, s)))); aIndex := aIndex1 | aIndex2; bIndex := toList flatten apply(0..bMax, rho -> flatten toList apply(0..(rho+j), s -> toList apply(0..rho, r -> (rho-r, r, s)))); --toList flatten apply(0..bMax, r -> toList apply(0..(r+j), s -> (r, s))); aVars := apply(aIndex, i -> a_i); bVars := apply(bIndex, i -> b_i); -- Construct the actual section from the generating elements. R := baseRing[Z, U1, U2, reverse(bVars | aVars), MonomialOrder => GroupLex => 1]; aPoly := sum apply(aIndex, i -> a_i * U2_R^(i_0) * U1_R^(i_1) * Z_R^(i_2) ); bPoly := sum apply(bIndex, i -> b_i * U2_R^(i_0) * U1_R^(i_1) * Z_R^(i_2) ); -- We extract the variables bVars|aVars from the new ring R again, -- but this time they are elements of the ring R, not just symbols. allVars := apply(numgens R - 3, i -> R_(i+3)); -- We need to express the extension class in the new ring R F := map(R, Rbase, {Z, U1, U2}); if Verbose then ( print "Considering the following coefficients:"; print allVars; ); -- The return value is a list of -- { all coefficients, -- { the extension class, now as a polynomial in the ring with coefficients, -- { the generic section (a, b). return {allVars, F(p), aPoly, bPoly}; ) -- -- After plugging the generic section into the transition function, we look at -- the first coordinate fTv := z^j a + p b, which must be holomorphic in z^-1 and z^k u. -- (We already know that the second coordinate, z^-j b, is holomorphic, since it -- was constructed to be so.) -- -- The following function, "getRelations", looks at all terms of fTv, and for -- those which are not holomorphic it stores the coefficient as a relation. -- getRelations = (fTv) -> ( R := ring fTv; rels := ideal (0_R); -- We need a set of all triples of coefficients (t,r,s) that occur in fTv: expSet := set apply(terms fTv, i -> [(exponents i)_0_0, (exponents i)_0_1, (exponents i)_0_2]); -- For each pair, look at the term in u^r z^s; if it is not holomorphic, store it: for S in (toList expSet) do ( degU1 := S_1; degU2 := S_2; degZ := S_0; -- The holomorphicity condition: if degZ <= (degU1+degU2) then continue; term := sum select(terms fTv, i -> ((exponents i)_0_0 == degZ) and (exponents i)_0_1 == degU1 and (exponents i)_0_2 == degU2); rel := term // (Z^degZ * U1^degU1 * U2^degU2 * leadCoefficient(term)); rels = rels + ideal(rel); ); return rels; ) -- -- In order to consider the space of sections as a module over S, we need -- to express polynomials in (z,u1,u2) as polynomials in (x_i = u1 z^i, y_i = u2 z^i). -- -- The function "piStar" takes a polynomial in (z,u1,u2) and expresses it in Rbase. -- piStar = (p) -> ( res := 0_S; for t in terms p do ( degU1 := (exponents t)_0_1; degU2 := (exponents t)_0_2; degZ := (exponents t)_0_0; fctr := 1_S; if degZ > (degU1+degU2) then ( << "Warning: piStar is ignoring term " << t << "!"; print ""; continue; ); tmp := min(degZ, degU1); fctr = fctr * x_1^tmp; degZ = degZ - tmp; degU1 = degU1 - tmp; tmp = min(degZ, degU2); fctr = fctr * y_1^tmp; degZ = degZ - tmp; degU2 = degU2 - tmp; assert(degZ == 0); fctr = fctr * x_0^degU1 * y_0^degU2; res = res + fctr * leadCoefficient(t); ); return res; ); makeModule = (aPoly, bPoly, allVars) -> ( Smodule := image matrix{{0_S}, {0_S}}; toZero := apply(allVars, i -> i => 0); -- In the sequel, all terms in u1,u2,z are projected to {x_i,y_i}-space, -- where x_i = u1*z^i and y_i = u2*z^i. -- To ensure this is faithful, we premultiply aPoly and bPoly by sufficiently high -- powers of u1, which should result in an isomorphic module. uexp := max apply( (exponents aPoly)|(exponents bPoly), i -> i_0 - i_1); uexp2 := ceiling (uexp/2); << "Multiplying by " << u1^uexp2 * u2^uexp2; print ""; VList = {}; aPoly = aPoly * U1^uexp2 * U2^uexp2; bPoly = bPoly * U1^uexp2 * U2^uexp2; for i in allVars do ( taPoly := substitute(aPoly, i => 1); tbPoly := substitute(bPoly, i => 1); taPoly = substitute(taPoly, toZero); tbPoly = substitute(tbPoly, toZero); vecab := matrix{{piStar(taPoly)}, {piStar(tbPoly)}}; VList = VList | {vecab}; Smodule = Smodule + image vecab; ); return (presentation image mingens Smodule); ); qLength = (A) -> ( B := kernel transpose A; Q := (kernel transpose presentation B) / (image transpose gens B); return (degree Q); ) iWidth = {Trunc => true, Verbose => true} >> opts -> (p, j) -> ( if (class j =!= ZZ) or (j < 0) then ( print "Error! j must be a non-negative integer."; return null; ); if (class p =!= Rbase) then ( print "Error! p must be a polynomial in Rbase (i.e. in u and z, z^-1)."; return null; ); secResult := makeSectionsAndRing(p, j, opts.Verbose); allVars := secResult_0; pp := secResult_1; aPoly := secResult_2; bPoly := secResult_3; R := ring aPoly; fTv := Z_R^j * aPoly + pp * bPoly; relRes := getRelations(fTv); doSubst := apply(flatten entries mingens relRes, i -> ((leadTerm i)//leadCoefficient(leadTerm i)) => ((leadTerm(i)-i)//leadCoefficient(leadTerm i))); if opts.Verbose then ( print "Will enact the following substitutions:"; print doSubst; print ""; ); for i in doSubst do ( aPoly = substitute(aPoly, i); bPoly = substitute(bPoly, i); ); A := makeModule(aPoly, bPoly, allVars); return {qLength A, A}; ) -- -- The "height" is the size of H^1, i.e. the space of 1-cocycles. -- A 1-cocycle can be written as (a,0) with -- -- j-2 j-2-t -1 -- ___ ___ ___ -- \ \ \ s r t -- a = / / / a z u1 u2 . -- --- --- --- trs -- t=0 r=0 s=kr-j+1 -- -- The cocyle (a,0) is cohomologous to -- -- / a \ / X \ / z^-j A - p B \ -- | | + | | + | | ... (*) , -- \ 0 / \ Y / \ z^j B / -- -- where X,Y are holomorphic in (z,u1,u2) and A,B in (z^-1, z u1, z u2). -- -- To compute the height, one needs to count the number of nontrivial monomial -- cocyles and subtract the number of relations of the form (*) imposed by p. -- -- The return value is a list -- {height, generators, relations, #generators, #relations} . -- iHeight = method(); iHeight(Rbase, ZZ) := (p, j) -> ( if (class j =!= ZZ) or (j < 0) then ( print "Error! j must be a non-negative integer."; return null; ); if (class p =!= Rbase) then ( print "Error! p must be a polynomial in RbaseW1 (i.e. in u1, u2 and z, z^-1)."; return null; ); -- Idea: to check if a monomial cocycle "a" is a coboundary, we check whether -- there exists a "b" holomorphic in (z^-1, zu1, zu2) such that "p * b - a" is -- holorphic on V. -- First, we only need to consider "b" in a certain range, depending on minUV: minUV := 0; if (p != 0_Rbase) then ( minUV = sum min apply(terms p, i -> (exponents i)_0_{1,2}) ; ); bMax := floor(j-2) - minUV; bIndex := flatten toList apply(0..bMax, t -> flatten toList apply(0..bMax-t, r -> flatten toList apply(-j .. r+t, s -> [t,r,s]))); -- Next, we make "b". [SPURIOS::Note that we don't need the actual coefficients, only the monomials.] bVars := apply(bIndex, i -> b_i); Rvar := baseRing[reverse(bVars)]; R := Rvar[Z, U1, U2, MonomialOrder => GroupLex => 1]; F := map(R, Rbase, {Z, U1, U2}); G := map(Rbase, R, {z, u1, u2}); bPoly := sum apply(bIndex, i -> b_i * U1_R^(i_0) * U2_R^(i_1) * Z_R^(i_2) ); -- Now the test: If "p*b" and "a" have a term in common, we can cancel the term. -- Practically this means that we remove the term from "a" and "p*b", i.e. -- "for each term in a, remove all terms of the same degree from p*b": -- Also, this has to be done for all possible monomial cycles "a". -- If the remaining terms of (p*b,0) are not null-cohomologous, we obtain non-trivial -- cocycle generators and relations among them. pb := bPoly * F(p); aList := flatten toList apply(0..floor(j-2), t -> flatten toList apply(0..floor(j-2) - t, r -> flatten toList apply(r+t-j+1 .. -1, s -> u1^r * u2^t * z^s))); aNonTrivials := {}; aRelations := {}; for aCycle in aList do ( expA := flatten exponents aCycle; -- To begin, find all terms in "p*b" that cancel "a" pbpruned := select(terms pb, i->((flatten exponents leadMonomial i)_0 == expA_0 and (flatten exponents leadMonomial i)_1 == expA_1 and (flatten exponents leadMonomial i)_2 == expA_2)); if (pbpruned == {}) then ( -- If there are none, (a,0) is a non-trivial cocycle... aNonTrivials = aNonTrivials | {aCycle}; continue; ) else ( -- ... but if there are, we need all the terms in bPoly which are relevant: leftbcoeffs := flatten apply(pbpruned, t -> terms leadCoefficient t); leftp := sum flatten apply(leftbcoeffs, i -> select(terms bPoly, j -> leadCoefficient j == (i/(leadCoefficient i)) ) ); leftpb := leftp * F(p); -- Remove all terms from leftpb that are cancelled by aCycle, but store them, too: aCycleR := select(terms leftpb, i -> leadMonomial i == F(aCycle)); leftpb = leftpb - sum select(terms leftpb, i->((flatten exponents i)_0 == expA_0 and (flatten exponents i)_1 == expA_1 and (flatten exponents i)_2 == expA_2)); -- All holomorphic (in (z,u)) terms can be removed: leftpb = leftpb - sum select(terms leftpb, i -> ((flatten exponents i)_0 >= 0)); -- It remains to check whether (z^j leftpb) is holomorphic in (z^-1, z u1, z u2): leftovers := select(terms leftpb, i -> ( (j + (flatten exponents i)_0) > (flatten exponents i)_1 + (flatten exponents i)_2 )); if (sum leftovers != 0) then ( aNonTrivials = aNonTrivials | {aCycle}; -- We only store the monomial terms of the relations, not the actual relations; -- this saves us from exporting all the coefficient symbols of R. --aRelations = aRelations | {{aCycle} | apply(leftovers, i -> G(leadMonomial i))}; aRelations = aRelations | {sum(aCycleR | apply(leftovers, i -> i))}; ) ); ); return {length aNonTrivials - length aRelations, aNonTrivials, aRelations, length aNonTrivials, length aRelations}; ) -- -- For O(-1)+O(-1): Generate all monomial extensions -- makeFlopExts = (j,eps) -> ( out := flatten toList apply(eps..2*j-3+eps, t -> flatten toList apply(1-eps..2*j-2-t, r -> flatten toList apply(t+r-j+1..j-1, s -> (t,r,s)))); return apply(out, i -> z^(i_2) * u1^(i_1) * u2^(i_0)); )