/* ================================================================================================ This part contains all (auxiliary) functions that we need to determine the admissible numerical data of threefolds isogenous to a product in particular: i) a function to compute the types Ti and ii) an implementation of Conder's table, which reports the upper bound of the order of a group acting faithfully on a compact Riemann surface of genus g > 1 (in terms of g) for all genera in the range 2 <=g<=301 ================================================================================================= */ /* Let "T:=[h; m1,..., mr]" be a type. The script "Theta" determines the rational number Theta(T) */ Theta:= function(T) h:=T[1]; t:= 2*h -2; for i in [2..#T] do m:=T[i]; t:= t + 1 - 1/m; end for; return t; end function; /* The script "OrderedSeq" transforms a (multi-) set or a sequence into an ordered sequence. */ OrderedSeq:=function(mset) seq:=[ ]; while #mset ne 0 do Append(~seq, Minimum(mset)); Exclude(~mset, Minimum(mset)); end while; return seq; end function; /* The script "MinRam" returns the minimum length of a type T=[h; m1,...,mr] depending on h: Recall that a Galois cover C --> C/G, where g(C)>1, is ramified in at least i) three points if h:=g(C/G)=0, ii) one point if h=1 and iii) zero points if h>1. */ MinRam:=function(h) if h eq 0 then return 3; elif h eq 1 then return 1; else return 0; end if; end function; /* The script "ListOfTypes" determines the set of types T=[h; m1,..., mr] such that: i) the mi's are bounded by 4g + 2 (Wiman), ii) the mi's are divisors of GOrd and d, iii) the length r of T is bounded from above according to Proposition 4.8 iv) and form below by "MinRam(h)" iv) Hurwitz' formula 2g-2 = GOrd*Theta(T) holds. */ ListOfTypes:=function(GOrd,g,d,h) Types:= {}; Orders:={k: k in Divisors(Gcd(GOrd,d)) | 2 le k and k le 4*g +2}; MaxRam:= Max(Floor(4*(g-1)/GOrd -4*h + 4),0); for r in [MinRam(h).. MaxRam] do M:=Multisets({ x : x in Orders},r); for mset in M do T:=[h] cat OrderedSeq(mset); if GOrd*Theta(T) eq (2*g-2) then Include(~Types,T) ; end if; end for; end for; return Types; end function; /* The script "ThetaMin" returns for a fixed h (the genus of the quotient surface) the minimal value of Theta that can be realized with a suitable type of the form T =[h; m1,..., mr] */ ThetaMin:=function(h) val:=0; L:=[1/42,1/2]; if h le 1 then val:=L[h+1]; else val:=2*h-2; end if; return val; end function; /* Using the script "Conder", we can decide if a natural number "GOrd" (a group order) is less or equal to the maximum order of a group that can act on a compact Riemann surface of genus g (where g > 1): for g between 2 and 301, we check if GOrd is less or equal to the value in Conder's table, for g > 301 we simply check if Hurwitz' bound is fulfilled. True or false is returned accordingly. */ Conder:=function(GOrd,g) test:=true; CondersList:=[48,168,120,192,150,504,336,320,432,240,120,360,1092,504,720,1344, 168,720,228,480,1008,192,216,720,750,624,1296,672,264,720,372,1536,1320,544,672, 1728,444,912,936,960,410,1512,516,1320,2160,384,408,1920,1176,1200,2448,832,456, 1296,1320,1344,1368,928,504,1440,732,1488,1512,3072,1014,576,804,2448,660,672, 710,2160,876,1776,1800,912,1176,1872,948,1536,3888,1312,696,4032,1200,2064,712, 2640,744,3600,2184,768,2232,768,3420,3840,1164,2352,1320,2400,1010,4896,1236, 2496,2016,1696,888,5184,1308,2640,2664,2688,936,3420,936,1856,9828,960,1734,2880, 5808,2928,1080,1488,1500,3024,1524,10752,3096,2080,1310,3960,1596,3216,6480,2176, 1128,1152,1668,2184,1144,1152,1352,6912,12180,3504,3528,2368,1224,3600,1812,3648, 2448,1320,1550,3744,1884,3792,1288,3840,1320,3888,1956,2624,6600,1344,1368,8064, 4056,2720,6840,2064,1416,1856,3000,2640,1432,2848,1464,8640,2172,4368,4392,1600, 1512,4464,1512,1536,4536,2640,1910,5760,2316,4656,3420,4704,1608,2640,2388,4800, 4824,3232,1656,7344,2050,4944,1672,4368,2904,5040,2532,3392,1720,1728,1800,6480, 2604,5232,5256,5280,1800,5328,2676,5376,5400,3616,1848,6840,2748,6072,3276,3712, 1896,11232,1896,1920,5688,2176,1944,9600,2892,5808,11664,3904,4116,2624,2964,5952, 2008,12000,2510,6048,12144,6096,4896,12288,2088,6192,3108,4160,3132,2112,2136,7920, 2200,6384,2152,3216,2184,5040,3252,4896,6552,4384,3750,2304,3324,6672,6696,2688, 2810,2304,3396,2400,10260,4368,2328,13824,13872,4640,6984,4672,2376,7056,2376,7104, 3888,4768,4056,9000]; if g le 301 then if GOrd gt CondersList[g-1] then test:=false; end if; else if GOrd gt 84*(g-1) then test:=false; end if; end if; return test; end function; /* ================================================================================================ This file is used to determine the character of the representation "phi" on the holomorphic 1-forms from a generating vector V (corresponding to the Galois cover C --> C/G) with the help of the Chevalley-Weil formula (Theorem 2.8). ==================================================================================================*/ /* Let X be a character of the group G and g be a group element. The script "pol" determines the characteristic polynomial of "rho(g)", where "rho" is a representation affording the character X. The coefficients of the characteristic polynomial are determined from the power sums of the eigenvalues X(g^i) by the MAGMA function "PowerSumToCoefficients" (cf. Computational Remark 2.9).*/ pol:=function(X,g) d:=Degree(X); L:=[]; for i in [1..d] do Append(~L,X(g^i)); end for; return Polynomial(PowerSumToCoefficients(L)); end function; /* Recall that the roots of pol(X,g) are of the form exp(a*2*pi*i/n), where 0 <= a <= n-1 and n is the order of g. The script "ListNa" produces the list of elements of the form [a,Na], where exp(a*2*pi*i/n) is a root of pol(X,g) with multiplicity Na and 0 <= a <= n-1 (see Definition 2.7).*/ ListNa:=function(pol,n) L:=[]; F:=CyclotomicField(n); z:=F.1; // z is equal to exp(2*pi*i/n) for r in Roots(Polynomial(F,pol),F) do for a in [0..n-1] do if r[1] eq z^a then Append(~L,[a,r[2]]); break a; end if; end for; end for; return L; end function; /* The script "Chev_Weil" is an implementation of the Chevalley-Weil formula: it is used to determine the multiplicity of a given irreducible non-trivial character X of G inside the character of the representation "phi" from a corresponding generating vector V=(h1,...,hr,a1,b1,...,ah,bh) of type T=[h; m1,...,mr]. Recall that the multiplicity of the trivial character is equal to h (the genus of the quotient surface), for this reason we only allow non-trivial irreducible characters X as an input.*/ ChevWeil:=function(V,T,X,G) h:=T[1]; ram:=[V[i] : i in [1..#T-1]]; // ram is the ramification part of V i.e. (h1,...,hr) mult:=(h-1)*X(Id(G)); for g in ram do n:=Order(g); for t in ListNa(pol(X,g),n) do mult:=t[1]*t[2]/n + mult; end for; end for; return mult; end function; /* With the next script "chi_phi" we determine the character of the representation "phi": we simply run over all irreducible characters X of G, compute the multiplicity m of X in the character of "phi" and sum up the characters m*X. As already mentioned, the trivial character is contained precisely h-times. This is the initial value of the summation i.e. we just have to consider the non-trivial characters of G, where we can compute the multiplicities using the script "Chev_Weil" from above.*/ chi_phi:=function(G,V,T) CT:=CharacterTable(G); h:=T[1]; char:= h*CT[1]; // CT[1] is the trivial character of G for i in [2..#CT] do X:=CT[i]; m:=ChevWeil(V,T,X,G); char:=char + m*X; end for; return char; end function; /* ================================================================================================= This part of the program is used to compute the Hodge numbers of a threefold X isogenous to a product of curves cf. Theorem 3.7. ================================================================================================= */ /* The script "HodgeDiamondInvarG0" determines the dimensions of the subspaces of invariant classes: H^{p,q}(C1 x C2 x C3)^G0 for (p,q) = (3,0), (2,0), (1,0), and (2,1). */ HodgeDiamondInvarG0:=function(G0,X1,X2,X3) p:=PrincipalCharacter(G0); X1bar:=ComplexConjugate(X1); X2bar:=ComplexConjugate(X2); X3bar:=ComplexConjugate(X3); chi10:=X1 + X2 + X3; chi20:=X1*X2 + X1*X3 + X2*X3; chi30:=X1*X2*X3; chi11:=X1bar*X2 + X1*X2bar + X1bar*X3 + X1*X3bar + X2bar*X3 + X2*X3bar + 3*p; chi21:=X1bar*X2*X3 + X1*X2bar*X3 + X1*X2*X3bar + 2*(X1 + X2 + X3); h10:=InnerProduct(chi10,p); h20:=InnerProduct(chi20,p); h30:=InnerProduct(chi30,p); h11:=InnerProduct(chi11,p); h21:=InnerProduct(chi21,p); return [h30, h20, h10, h11, h21]; end function; /* The script "HodgeDiamondUnmixed" determines the Hodge diamond of a threefold isogenous to a product of unmixed type from an algebraic datum (G,V1,V2,V3) and the types Ti of the generating vectors Vi. */ HodgeDiamondUnmixed:=function(G,V1,V2,V3,T1,T2,T3) X1:=chi_phi(G,V1,T1); X2:=chi_phi(G,V2,T2); X3:=chi_phi(G,V3,T3); return HodgeDiamondInvarG0(G,X1,X2,X3); end function; /* =========================================================================================== In this file we provide a function which determines for a given finite group G and for a given type T the set of all generating vectors V for G of type T. Moreover, we provide an implementation of the action of the Braid group on the set of these generating vectors and, in the case that the types are [1; m] or [1; m, m], also the action of the full mapping class group. Recall that different generating vectors may determine threefolds with the same invariants. This happens if (but not only if) they differ by the actions from above. =========================================================================================== */ /* The script "ElsOfOrd" returns the set of elements of the group G of order d. */ ElsOfOrd:=func; /* Let G be a finite group and T=[h;m1,...,mr] be a type. The script "TuplesOfGivenOrder" creates the set of all elements of the form (h1,...,hr,a1,b1,...,ah,bh), where hi is an element of G of order mi and ai, bi are arbitrary elements of G. */ TuplesOfGivenOrders:=function(G,T) h:=T[1]; SEQ1:=[ ]; for i in [1..#T-1] do El:=ElsOfOrd(G,T[i+1]); if IsEmpty(El) then return {}; else Append(~SEQ1,El); end if; end for; SEQ2:=[ ]; for i in [1..2*h] do Append(~SEQ2,Set(G)); end for; return CartesianProduct(SEQ1 cat SEQ2); end function; /* Let V=(h1,...,hr,a1,b1,...,ah,bh) be a tuple in the output of "TuplesOfGivenOrders(G,T)". The script "ProductOne" decides if the product h1*...*hr*[a1,b1]*...*[ah,bh] is trivial or not. True or false is returned accordingly. */ ProductOne:=function(V,T,G); test:=false; p:=Id(G); h:=T[1]; for i in [1..#T-1] do p:=p*V[i]; end for; for i in [1..h] do a:=V[2*(i-1) + #T]; b:=V[2*i-1+#T]; p:=p*a*b*a^-1*b^-1; end for; if p eq Id(G) then test:=true; end if; return test; end function; /* The next script allows us to test if a group G admits a generating vector V of type T. If a generating vector exists, then the function returns true and V, otherwise it returns false and the empty set. */ ExistVectGens:=function(G,T) n:=#G; OneGV:={}; cands:= TuplesOfGivenOrders(G,T); for cand in cands do V:=[g : g in cand]; if ProductOne(V,T,G) then if #sub eq n then Include(~OneGV,V); break cand; end if; end if; end for; return not IsEmpty(OneGV), OneGV; end function; /* The script "VectGens" determines the set of all generating vectors for the group G of type T. */ VectGens:=function(G,T) n:=#G; Vect:={}; cands:= TuplesOfGivenOrders(G,T); for cand in cands do V:=[g : g in cand]; if ProductOne(V,T,G) then if #sub eq n then Include(~Vect,V); end if; end if; end for; return Vect; end function; /* Given a generating vector V=(h1,...,hr,a1,b1,...,ah,bh) and an integer 1<= i <= r-1, the script "HurwitzMove" performs the i-th Braid move i.e. it returns the generating vector (h1,...,h(i-1),hi*h(i+1)*hi^-1,hi,h(i+2)...,hr,a1,b1,...,ah,bh). */ BraidMove:=function(V,i) c:=V[i]*V[i+1]*V[i]^-1; return Insert(Remove(V,i+1),i,c); end function; /* Let V be a generating vector of type T for the group G. The script "BraidOrbit" determines the orbit of V under the action of the braid group Br. To spare memory only the elements in the orbit whose entries have increasing order are returned. */ BraidOrbit:=function(V,T) orb:={ }; sortorb:={ }; Trash:={V}; repeat ExtractRep(~Trash,~gens); Include(~orb, gens); for i in [1..#T-2] do newgens:=BraidMove(gens,i); if newgens notin orb then Include(~Trash, newgens); end if; end for; until IsEmpty(Trash); for gens in orb do test:=true; for k in [1..#T-2] do if Order(gens[k]) gt Order(gens[k+1]) then test:=false; break k; end if; end for; if test then Include(~sortorb, gens); end if; end for; return sortorb; end function; /* Let V be a generating vector of type [1; m] or of type [1; m, m]. The script "MapGroupOrbit" determines the orbit of V under the action of the mapping class group. If the parameter "switch" is equal to 1, the case [1; m] is considered and otherwise the case [1; m, m]. Note that the action of the mapping class group is generated by 2 respectively 4 moves, wich are performed by the subscript "Moves". */ Moves:=function(V,switch) if switch eq 1 then t1:=[V[1],V[2]*V[1],V[3]]; t2:=[V[1]*V[2]^-1,V[2],V[3]]; M:={t1,t2}; else t1:=[V[1],V[2]*V[1],V[3],V[4]]; t2:=[V[1]*V[2]^-1,V[2],V[3],V[4]]; t3:=[V[2]^-1*V[3]*V[1],V[2],V[3],((V[4]^V[1])^V[2])^(V[1]^-1)]; t4:=[V[1]^-1,V[2]^-1,(V[4]^V[1])^V[2],(V[3]^V[2])^V[1]]; M:={t1,t2,t3,t4}; end if; return M; end function; MapGroupOrbit:=function(V,switch) orb:={}; Trash:={V}; repeat ExtractRep(~Trash,~gens); Include(~orb, gens); for newgens in Moves(gens,switch) do if newgens notin orb then Include(~Trash, newgens); end if; end for; until IsEmpty(Trash); return orb; end function; /* Let V be a generating vector for G of type T. The script "OrbitSwitch" decides which group action is applied: if the type of V is of the form [1,m] or [1,m,m], then the action of the full mapping class group is used, otherwise only the braid group is taken into account. */ OrbitSwitch:=function(V,T) h:=T[1]; if #T eq 2 and h eq 1 then orb:=MapGroupOrbit(V,1); elif #T eq 3 and h eq 1 and T[2] eq T[3] then orb:=MapGroupOrbit(V,2); else orb:=BraidOrbit(V,T); end if; return orb; end function; /* Let G be a finite group and T=[h; m1,..., mr] be a type. i) if T is of the form [h;-] (i.e. no ramification part), then the script "GenVecRep" returns a generating vector for G of type T, in case such a vector exists and otherwise the empty set. ii) if T is not of the form [h;-], then the script "GenVecRep" returns a representative for each orbit of the action of the mapping class group, respectively the braid group, on the set of all generating vectors for G of type T. */ GenVecRep:=function(G,T) h:=T[1]; if #T eq 1 then test, Repres:=ExistVectGens(G,T); else; gens:=VectGens(G,T); Repres:={}; while not IsEmpty(gens) do V:=Rep(gens); Include(~Repres,V); orb:=OrbitSwitch(V,T); for W in orb do Exclude(~gens, W); end for; end while; end if; return Repres; end function; /* ======================================================================================= With this part of the program we check the freeness condition ======================================================================================== */ /* The script "StabSet" determines the stabilizer set of a generating vector V of type T for the group G (cf. Definition 2.4). */ StabSet:= function(V,T,G) h:=T[1]; Set:={Id(G)}; for i in [1..#T-1] do g:=V[i]; for n in [1..Order(g)] do Set := Set join Conjugates(G,g^n) ; end for; end for; return Set; end function; /* The script "SmoothUnmixed" decides if the intersection of the three stabilizer sets is trivial. True or false is returned accordingly. */ SmoothUnmixed:=function(G,V1,V2,V3,T1,T2,T3) test:=true; stab1:=StabSet(V1,T1,G); stab2:=StabSet(V2,T2,G); stab3:=StabSet(V3,T3,G); if #(stab1 meet stab2 meet stab3) gt 1 then test:=false; end if; return test; end function; /* ===================================================================================================== This part of the code contains the main routine to classify threefolds isogenous to a product in the unmixed case, under the assumption that the G-action is absolutely faithful. ===================================================================================================== /* /* The script "AdNDunmixed" is used to determine the set of admissible numerical data for a given negative integer "chi" (see the algorithm in Chapter 3). The strategy is the following: 1) we run through the admissible group orders GOrd 2) for each GOrd we determine the triples of the form [g1,g2,g3], where gi>=2 are integers (g1 <= g2 <=g3) such that: i) (g1-1)(g2-1)(g3-1)=-chi*GOrd and ii) GOrd is less or equal to the maximum order of the automorphism group of a curve of genus gi i.e. the function "Conder(GOrd,gi)" returns true. The set, where these triples are stored is called "Generas". 3) for each triple [g1,g2,g3] in the set "Generas" we run through the admissible genera hi of the quotients curves Ci/G. They are bounded in terms of g_[i+1] and g_[i+2] (the bracket [-] denotes the residue mod 3). 4) for those combinations of h1, h2 and h3 which fulfill the inequality from Proposition 4.8, we determine the admissible types Ti i.e. "ListOfTypes(GOrd,gi,(g[i+1]-1)*(g[i+2]-1),hi)" and form all possible tuples [GOrd,T1,T2,T3]. The tuples [GOrd,T1,T2,T3], where the groups of order GOrd are not contained in the Database of Small groups are collected in the file "ExcepUnmixed(chi)". The remaining tuples are returned, lexicographically ordered, as the output of the script. */ AdNDunmixed:=function(chi) F:="ExcepUnmixed" cat IntegerToString(chi) cat ".txt"; fprintf F, "Unmixed case, chi=%o and absolutely faithful G-action.\n\n\n Exceptional numerical data:\n\n\n", chi; b:=Floor(168*Sqrt(-21*chi)); // bound for GOrd according to Corollary 3.0.7. SetAdUnmixed:={}; for GOrd in [1..b] do Generas:={}; Divi:=Divisors(-chi*GOrd); for n1 in [1..#Divi] do for n2 in [n1..#Divi] do d1:=Divi[n1]; d2:=Divi[n2]; d3:=-chi*GOrd/(d1*d2); if d3 in IntegerRing() and d3 ge d2 then d3:=IntegerRing()!d3; if Conder(GOrd,d1+1) and Conder(GOrd,d2+1) and Conder(GOrd,d3+1) then Include(~Generas,[d1+1,d2+1,d3+1]); end if; end if; end for; end for; for gens in Generas do g1:=gens[1]; g2:=gens[2]; g3:=gens[3]; maxh1:=Floor(1-chi/((g2-1)*(g3-1))); maxh2:=Floor(1-chi/((g1-1)*(g3-1))); maxh3:=Floor(1-chi/((g1-1)*(g2-1))); for h1 in [0..maxh1] do for h2 in [0..maxh2] do for h3 in [0..maxh3] do if GOrd^2 le -8*chi/(ThetaMin(h1)*ThetaMin(h2)*ThetaMin(h3)) then for T1 in ListOfTypes(GOrd,g1,(g2-1)*(g3-1),h1) do for T2 in ListOfTypes(GOrd,g2,(g1-1)*(g3-1),h2) do for T3 in ListOfTypes(GOrd,g3,(g1-1)*(g2-1),h3) do D:=[[GOrd]] cat OrderedSeq([T1,T2,T3]); if IsInSmallGroupDatabase(GOrd) then Include(~SetAdUnmixed,D); else fprintf F, "D=%o\n\n", D; end if; end for; end for; end for; end if; end for; end for; end for; end for; end for; return OrderedSeq(SetAdUnmixed); end function; /* The script "ClassifyUnmixed" determines for a given negative integer "chi" all threefolds isogenous to a product of unmixed type with "chi(O_X)=chi". The strategy is the following: 1) we call the function "AdNDunmixed(chi)" which creates the set of admissible numerical data [GOrd,T1,T2,T3]. 2) for each [GOrd,T1,T2,T3], we run through the groups G of order GOrd and verify if G admits a generating vector Vi of type Ti for all i=1,2 and 3. For those groups passing this test, we determine a set of representatives of generating vectors Vi of type Ti calling the function "GenVecRep(G,Ti)". 3) we run through all generating vectors Vi contained in GenVecRep(G,Ti) and consider the tuples (G,V1,V2,V3). 4) those tuples (G,V1,V2,V3) which fulfill the freeness condition i.e. "SmoothUnmixed(G,V1,V2,V3,T1,T2,T3)" returns true, are algebraic data of (families) of threefolds X isogenous to a product. We compute the Hodge numbers of these threefolds X using the function "HodgeDiamondUnmixed". The group, the types, the Hodge numbers and the dimension of the families are saved in the file "unmixed(chi).txt" At a certain moment within the computation there will be no further occurrences i.e. the function stops writing data in the file "unmixed(chi).txt". However, as long as the computation is running, there are still groups that need to be considered and excluded (this can take a while!). If the whole computation is finished, the function will return "Classification_accomplished". */ ClassifyUnmixed:=function(chi) F:="Unmixed" cat IntegerToString(chi) cat ".txt"; fprintf F, "Threefolds isogenous to a product: \n unmixed case, chi=%o and absolutely faithful G-action:\n\n\n\n\n", chi; count:=1; AdNum:=AdNDunmixed(chi); for D in AdNum do GOrd:=D[1][1];T1:=D[2];T2:=D[3];T3:=D[4]; for G in SmallGroups(GOrd: Warning:=false) do if ExistVectGens(G,T1) and ExistVectGens(G,T2) and ExistVectGens(G,T3) then invarset:={}; for V1 in GenVecRep(G,T1) do for V2 in GenVecRep(G,T2) do for V3 in GenVecRep(G,T3) do if SmoothUnmixed(G,V1,V2,V3,T1,T2,T3) then invar:= HodgeDiamondUnmixed(G,V1,V2,V3,T1,T2,T3); if invar notin invarset then Include(~invarset,invar); fprintf F, "%o) Group: G= %o\n",count, IdentifyGroup(G); fprintf F, "\n Types: \n"; fprintf F, "\n T1=%o \n T2=%o \n T3=%o\n", T1, T2, T3; fprintf F, "\n Hodge numbers: h30=%o, h20=%o, h10=%o, h11= %o and h12=%o\n", invar[1],invar[2], invar[3], invar[4], invar[5]; fprintf F, "\n Number of parameters: %o\n", 3*(T1[1]+T2[1]+T3[1])-12 + #T1 + #T2 + #T3; fprintf F, "\n\n\n\n\n"; count:=count+1; end if; end if; end for; end for; end for; end if; end for; end for; return "Classification_accomplished"; end function;