/* ================================================================================================ 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 part 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. ==================================================================================================*/ /* 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".*/ 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.*/ 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 4.2 and Theorem 4.5. ================================================================================================= */ /* 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 "HodgeDiamondIndex2" determines the Hodge diamond of a threefold isogenous to a product in the index two case. Note that only the characters X1 and X2 are computed using the function "chi_phi". The character X3 is the conjugated character of X2. */ HodgeDiamondIndex2:=function(G,G0,V1,V2,T1,T2) delta:=Rep({x: x in G| x notin G0}); X1:=chi_phi(G,V1,T1); X2:=chi_phi(G0,V2,T2); ResX1:=Restriction(X1, G0); X3:=X2^(delta^(-1)); n:=#G; In:=HodgeDiamondInvarG0(G0,ResX1,X2,X3); h10:=In[3]/2; h20:=In[2]/2; h30:=In[1]/2; h11:=In[4]/2 + 1/2; h21:=In[5]/2; for g in G0 do h10:=h10 + X1(delta*g)/n; h20:=h20 - X2((delta*g)^2)/n; h30:=h30 - X1(delta*g)*X2((delta*g)^2)/n; h21:=h21 - ComplexConjugate(X1(delta*g))*X2((delta*g)^2)/n; end for; return [h30, h20, h10, h11, h21]; end function; /* The scripts "HodgeDiamondIndex3" and "HodgeDiamondIndex6" do the same as the last two scripts, but this time in the index three and index six case, respectively. */ HodgeDiamondIndex3:=function(G,G0,tau,V1,T1) X1:=chi_phi(G0,V1,T1); X2:=X1^(tau^(-1)); X3:=X1^(tau^(-2)); In:=HodgeDiamondInvarG0(G0,X1,X2,X3); n:=#G; h10:=In[3]/3; h20:=In[2]/3; h30:=In[1]/3; h11:=In[4]/3; h21:=In[5]/3; for g in G0 do h30:=h30+(X1((tau*g)^3)+ X1((tau^2*g)^3))/n; end for; return [h30, h20, h10, h11, h21]; end function; HodgeDiamondIndex6:=function(G,G0,tau,h,V1,T1) G1:=sub; X1:=chi_phi(G1,V1,T1); ResX1:=Restriction(X1, G0); ResX2:=ResX1^(tau^(-1)); ResX3:=ResX1^(tau^(-2)); n:=#G; In:=HodgeDiamondInvarG0(G0,ResX1,ResX2,ResX3); RG1:=Set(G1) diff Set(G0); h10:=In[3]/6; h20:=In[2]/6; h30:=In[1]/6; h11:=In[4]/6+1/2; h21:=In[5]/6; for g in G0 do h30:=h30+(X1((tau*g)^3)+X1((tau^2*g)^3))/n; end for; for f in RG1 do h30:=h30 - (3*X1(f)*X1(tau*(f^2)*tau^(-1)))/n; h20:=h20 - (3*X1(tau*(f^2)*tau^(-1)))/n; h10:=h10 + (3*X1(f))/n; h21:=h21 - (3*ComplexConjugate(X1(f))*X1(tau*(f^2)*tau^(-1)))/n; end for; return [h30, h20, h10, h11, h21]; 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 "SmoothIndex2" decides if the conditions i) and ii) from Proposition 2.5 a) are fulfilled. True is returned if both of them hold and otherwise false. Condition ii) is checked by the subscript "SmoothCondii". */ SmoothCondii:=function(Stabset1,Stabset2,G0,delta) test:=true; for g in G0 do if delta*g in Stabset1 and (delta*g)^2 in Stabset2 then test:=false; break g; end if; end for; return test; end function; SmoothIndex2:=function(G,G0,V1,V2,T1,T2) test:=false; delta:=Rep({x: x in G| x notin G0}); Stabset1:=StabSet(V1,T1,G); Stabset2:=StabSet(V2,T2,G0); Stabset3:={delta*x*delta^(-1): x in Stabset2}; Intersect:=Stabset1 meet Stabset2 meet Stabset3; if #Intersect eq 1 and SmoothCondii(Stabset1,Stabset2,G0,delta) then test:= true; end if; return test; end function; /* The script "SmoothIndex3i" returns true if condition i) from Proposition 2.5 b) holds and otherwise false. Note that we don't implement the second condition, since it is (under the assumption that i) holds) equivalent to the condition that the short exact sequence 1 --> G0 --> G --> A3 --> 1 is non-split. The latter is verified in the main part of the algorithm before we even start to search for generating vectors. */ SmoothIndex3i:=function(G,G0,tau,V1,T1) test:=false; stab1:=StabSet(V1,T1,G0); stab2:={tau^2*x*tau^(-2): x in stab1}; stab3:={tau*x*tau^(-1): x in stab1}; if #(stab1 meet stab2 meet stab3) eq 1 then test:=true; end if; return test; end function; /* The script "SmoothIndex6" decides if the conditions i), ii) and iii) from Proposition 2.5 c) are fulfilled. True is returned if all of them hold and otherwise false. Condition iii) is checked by the subscript "SmoothCondiii". */ SmoothCondiii:=function(stab1,G1,G0,tau) test:=true; for f in (Set(G1) diff Set(G0)) meet stab1 do if tau*(f^2)*tau^(-1) in stab1 then test:=false; break f; end if; end for; return test; end function; SmoothIndex6:=function(G,G0,tau,h,V1,T1) G1:=sub; test:=false; stab1:=StabSet(V1,T1,G1); stab2:={tau^2*x*tau^(-2): x in stab1}; stab3:={tau*x*tau^(-1): x in stab1}; Intersect:=stab1 meet stab2 meet stab3; S1:={(tau*x)^3: x in G0}; if #Intersect eq 1 and IsEmpty(S1 meet stab1) and SmoothCondiii(stab1,G1,G0,tau) then test:=true; end if; return test; end function; // ******************************************************************************************************************** // *************** Below are the main classification routines in the index two, three and six case ******************** // ******************************************************************************************************************** // **************************************** Index two ***************************************************** /* The script "AdNDindexTwo" is used to determine the set of admissible numerical data for a given input value of chi (<=-1). We briefly explain the strategy: 1) we run through the admissible group orders GOrd. i.e. all positive integers GOrd divisible by two and bounded according to Proposition 5.3. 2) for each admissible GOrd we determine the pairs [g1,g2], where gi>=2 are integers such that: * (g1-1)(g2-1)^2=-chi*GOrd * the integers GOrd and GOrd/2 are less or equal to the maximum order of the automorphism group of a curve of genus g1 and g2, respectively (i.e. Conder(GOrd,g1) and Conder(GOrd/2,g2) return true). The set, where these tuples are stored is called "Generas". In contrast to the unmixed case, we can not assume that g1 <=g2. 3) for each pair [g1,g2] in the set "Generas" we run through the admissible genera h1 and h2 of the quotients curves C1/G and C2/G0. Recall that h1 is bounded by 1-chi/(g2-1)^2 and h2 by 1-2*chi/((g1-1)*(g2-1)) (see Proposition 5.4 vi)). 4) for those combinations, where the inequality from Proposition 5.3. holds, we determine the admissible types Ti i.e. * ListOfTypes(GOrd,g1,(g2-1)^2,h1) and * ListOfTypes(GOrd/2,g2,(g1-1)*(g2-1),h2) and build the triples [GOrd,T1,T2]. Those triples, where the groups of order GOrd/2 are not contained in the database of Small Groups are stored in the file "ExcepIndexTwo(chi)". The remaining triples are returned, as the output of the function. */ AdNDindexTwo:=function(chi) F:="ExcepIndexTwo" cat IntegerToString(chi) cat ".txt"; fprintf F, "Index two case, chi=%o and absolutely faithful G-action.\n\n\n Exceptional numerical data:\n\n\n", chi; SetAdIndex2:={}; b:=Floor(168*Sqrt(-21*chi)); for G0_Ord in [1..b] do GOrd:=2*G0_Ord; Generas:={}; for d in Divisors(-chi*GOrd) do g1:=d+1; g2:=Root(-chi*GOrd/(g1-1), 2) + 1; if g2 in IntegerRing() then g2:=IntegerRing()!g2; if Conder(GOrd,g1) and Conder(G0_Ord,g2) then Include(~Generas,[g1,g2]); end if; end if; end for; for gens in Generas do g1:=gens[1]; g2:=gens[2]; maxh1:= Floor(1-chi/(g2-1)^2); maxh2:= Floor(1-2*chi/((g1-1)*(g2-1))); for h1 in [0..maxh1] do for h2 in [0..maxh2] do if GOrd^2 le (-32*chi)/(ThetaMin(h1)*ThetaMin(h2)^2) then for T1 in ListOfTypes(GOrd,g1,(g2-1)^2,h1) do for T2 in ListOfTypes(G0_Ord,g2,(g1-1)*(g2-1),h2) do D:=[[GOrd]] cat [T1,T2]; if IsInSmallGroupDatabase(G0_Ord) then Include(~SetAdIndex2,D); else fprintf F, "D=%o\n\n", D; end if; end for; end for; end if; end for; end for; end for; end for; return OrderedSeq(SetAdIndex2); end function; /* The script "NDHIndexTwo" is used to determine the set of 4-tuples of the form [GOrd,T1,T2,H], where H is a group of order GOrd/2 admitting a generating vector of type T2 and [GOrd,T1,T2] is an admissible numerical datum. (cf. Step 1 of the algorithm). The strategy is the following: 1) we run through the tuples [GOrd,T1,T2] in the output of "AdNDindexTwo", remove T1 and store the pair [GOrd,T2] in the set "Ord_T2". 2) for each pair [GOrd,T2] in the set "Ord_T2", we run through the groups H of order GOrd/2.For those H admitting a generating vector of type T2, we store the triple [GOrd,T2,H] in the set "Ord_T2_H". To test this condition, we apply the function "ExistVectGens". 3) we build all four tuples [GOrd,T1,T2,H] such that [GOrd,T1,T2] is contained in "AdNDindexTwo" and [GOrd,T2,H] in "Ord_T2_H". The set of tuples [GOrd,T1,T2,H] where the groups of order GOrd are not contained in the database of Small Groups are stored in the file "ExcepIndexTwo(chi)", the other tuples are returned as the output of the function. */ NDHIndexTwo:=function(chi) AdNum:=AdNDindexTwo(chi); F:="ExcepIndexTwo" cat IntegerToString(chi) cat ".txt"; fprintf F,"Exceptional 4-tuples: \n\n\n "; Ord_T2:={}; for D in AdNum do Include(~Ord_T2,[[D[1][1]],D[3]]); end for; Ord_T2_H:={}; for Tup in Ord_T2 do for H in SmallGroups(IntegerRing()!(Tup[1][1]/2): Warning:=false) do if ExistVectGens(H,Tup[2]) then ID:=IdentifyGroup(H); Include(~Ord_T2_H, Tup cat [[ID[1],ID[2]]]); end if; end for; end for; NumandH:=[]; for D in AdNum do for Tup in Ord_T2_H do if D[1][1] eq Tup[1][1] and D[3] eq Tup[2] then DNew:=D cat [Tup[3]]; if IsInSmallGroupDatabase(D[1][1]) then Append(~NumandH,DNew); else fprintf F, "%o\n\n", DNew; end if; end if; end for; end for; return NumandH; end function; /* The script "ClassifyIndexTwo" is used to perform Step 2 of the algorithm in Section 5. It determines for a given negative integer "chi" (the input value) all threefolds isogenous to a product of mixed type with "chi(O_X)=chi" in the index two case. The strategy is the following: 1) we determine the list "PossOrders", which contains all integers GOrd belonging to some four tuple [GOrd,T1,T2,H] in "NDHIndexTwo(chi)". 2) for each GOrd in "PossOrders" and for each group G of order GOrd, we build the set "PG0" of normal subgroups G0 of order GOrd/2. 3) for each normal subgroup G0 in PG0 and for each four tuple [GOrd,T1,T2,H] in "NDHIndexTwo(chi)", such that H is isomorphic to G0, we determine a set of representatives of generating vectors Vi of type Ti calling the functions "GenVecRep(G,T1)" and "GenVecRep(G0,T2)". 4) we run through all V1 contained in GenVecRep(G,T1) and V2 contained in GenVecRep(G0,T2) and consider the tuples (G,G0,V1,V2). 5) those tuples (G,G0,V1,V2) that fulfill the freeness conditions of Proposition 2.5 a), i.e. "SmoothIndex2(G,G0,V1,V2,T1,T2)" 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 "HodgeDiamondIndex2". The group G, the types T1 and T2, the Hodge numbers and the dimension of the families (cf. Remark 3.6) are stored in the file "IndexTwo(chi).txt". */ ClassifyIndexTwo:=function(chi); F:="IndexTwo" cat IntegerToString(chi) cat ".txt"; fprintf F, "Threefolds isogenous to a product of mixed type: \n index two case, chi=%o and absolutely faithful G-action:\n\n\n\n\n", chi; count:=1; Num_H:=NDHIndexTwo(chi); Set:={}; for D in Num_H do Include(~Set,D[1][1]); end for; PossOrders:=OrderedSeq(Set); for GOrd in PossOrders do G0_Ord:=IntegerRing()!(GOrd/2); for G in SmallGroups(GOrd: Warning:=false) do NG0:=NormalSubgroups(G);invarset:={}; PG0:={NG0[i]`subgroup : i in [1..#NG0]| NG0[i]`order eq G0_Ord}; for G0 in PG0 do IdG0:=IdentifyGroup(G0); for D in Num_H do n:=D[1][1]; T1:=D[2]; T2:=D[3]; identi:=D[4]; if n eq GOrd and [IdG0[1],IdG0[2]] eq identi then for V1 in GenVecRep(G,T1) do for V2 in GenVecRep(G0,T2) do if SmoothIndex2(G,G0,V1,V2,T1,T2)then invar:=HodgeDiamondIndex2(G,G0,V1,V2,T1,T2) cat T1 cat T2 cat [IdG0[1],IdG0[2]]; if invar notin invarset then Include(~invarset,invar); fprintf F, " %o) Groups: G= %o, G0:=%o\n",count, IdentifyGroup(G), IdG0; fprintf F, "\n Types: \n"; fprintf F, "\n T1=%o \n T2=%o\n", T1, T2; 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])-8 + #T1 + #T2; fprintf F, "\n\n\n\n\n"; count:=count+1; end if; end if; end for; end for; end if; end for; end for; end for; end for; return "Classification_accomplished"; end function; // **************************************** Index three ***************************************************** /*The script "AdNDindexThree" is used to determine the set of admissible numerical data for a given input value of chi (<=-1) (see the algorithm in Chapter 3). We briefly explain the strategy: 1) we determine the maximum value "GOrdMax" of GOrd according to Propsition 5.3. and the maximum value "g1max" of g1 in terms of "GOrdMax" using Remark 5.5. 2) we run through all admissible values of g1 in the range 2 <= g1 <=g1max, determine the corresponding group order GOrd:= -chi*(g1-1)^3 and check the following conditions: * GOrd is divisible by 9 and * GOrd/3 are less or equal to the maximum order of the automorphism group of a curve of genus g1 (i.e. Conder(GOrd/3,g1) returns true). The pairs [GOrd,g1] which fulfill these conditions are stored in the list "ListPairs". 3) for each pair [GOrd,g1] in "ListPairs" we run through the admissible genera h1 of the quotient curve C1/G0. The genus h1 is bounded by 1-3*chi/(g1-1)^2 according to Proposition 5.4 vi). 4) for those combinations, where the inequality from Proposition 5.3 holds, we determine the admissible types T1 i.e. ListOfTypes(GOrd/3,g1,(g1-1)^2,h1) and form all possible pairs [GOrd,T1]. Those pairs where the groups of order GOrd/3 are not contained in the database of Small Groups are stored in the file "ExcepIndexThree(chi)". The remaining tuples are returned as the output of the function. */ AdNDindexThree:=function(chi) F:="ExcepIndexThree" cat IntegerToString(chi) cat ".txt"; fprintf F, "Index three case, chi=%o and absolutely faithful G-action.\n\n\n Exceptional numerical data:\n\n\n", chi; GOrdMax:=Floor(1512*Sqrt(-7*chi)); g1max:=Floor(Root(-chi*GOrdMax, 3)+1); ListAdIndex3:=[]; ListPairs:=[]; for g1 in [2..g1max] do GOrd:=-(g1-1)^3/chi; if GOrd/9 in IntegerRing() and Conder(GOrd/3,g1) then GOrd:=IntegerRing()!GOrd; Append(~ListPairs,[GOrd,g1]); end if; end for; for Pair in ListPairs do GOrd:=Pair[1]; G0_Ord:=IntegerRing()!(GOrd/3); g1:=Pair[2]; h1max:= Floor(1-3*chi/(g1-1)^2); for h1 in [0..h1max] do if GOrd^2 le -216*chi/(ThetaMin(h1)^3) then for T1 in ListOfTypes(G0_Ord,g1,(g1-1)^2,h1) do D:=[[GOrd],T1]; if IsInSmallGroupDatabase(G0_Ord) then Append(~ListAdIndex3,D); else fprintf F, "D=%o\n\n", D; end if; end for; end if; end for; end for; return ListAdIndex3; end function; /* The script "NDHIndexThree" is used to determine the set of triples of the form [GOrd,T1,H], where [GOrd,T1] is an admissible numerical datum and H is a candidate for G0 i.e. * H is of order GOrd/3 and * H admits three generating vectors U, V and W of type T1 with trivial intersection of the corresponding stabilizer sets. The triples [GOrd,T1,H], where the groups of order GOrd are not contained in the database of Small Groups are stored in the file "ExcepIndexThree(chi)". The remaining triples are returned as the output of the function. */ NDHIndexThree:=function(chi) AdNum:=AdNDindexThree(chi); F:="ExcepIndexThree" cat IntegerToString(chi) cat ".txt"; fprintf F,"Exceptional triples: \n\n\n "; Ord_T1_H:=[]; for Tup in AdNum do GOrd:=Tup[1][1]; T1:=Tup[2]; for H in SmallGroups(IntegerRing()!(GOrd/3): Warning:=false) do GV:=GenVecRep(H,T1); for U in GV do for V in GV do for W in GV do if #(StabSet(U,T1,H) meet StabSet(V,T1,H) meet StabSet(W,T1,H)) eq 1 then ID:=IdentifyGroup(H); DNew:=Tup cat [[ID[1],ID[2]]]; if IsInSmallGroupDatabase(GOrd) then Append(~Ord_T1_H,DNew); else fprintf F, "%o\n\n", DNew; end if; break U; end if; end for; end for; end for; end for; end for; return Ord_T1_H; end function; /* The function "NonSplitIndex3" returns "true" if the short exact sequence 1 --> G0 --> G --> A3 --> 1 is non-split (or equivalently no element in G\G0 is of order three). This condition is equivalent to the freeness condition of Proposition 2.5 b) ii) under the assumption that Proposition 2.5 b) i) holds, see Corollary 2.7 b). */ NonSplitIndex3:=function(G,G0) test:=true; L:=Set(G) diff Set(G0); if not IsEmpty(ElsOfOrd(L,3)) then test:=false; end if; return test; end function; /* The script "ClassifyIndexThree" is used to perform Step 2 of the algorithm. It determines for a given negative integer "chi" (the input value) all threefolds isogenous to a product of mixed type with "chi(O_X)=chi" in the index three case. The strategy is the following: 1) we determine the list "PossOrders", which contains all integers GOrd belonging to some triple [GOrd,T1,H] in "NDHIndexThree(chi)". 2) for each GOrd in "PossOrders" and for each group G of order GOrd, we build the set "PG0" of normal subgroups G0 of Order GOrd/3 such that the short exact sequence 1 --> G0 --> G --> A3 --> 1 is non-split. 3) we run through the groups G0 in PG0, choose an element "tau" outside of G0 and run through the triples [GOrd,T1,H] in "NDHIndexThree(chi)". For those triples, where H is isomorphic to G0 we determine a set of representatives of generating vectors V1 of type T1 calling the function "GenVecRep(G,T1)". 4) we run through all V1 contained in GenVecRep(G,T1) and consider the tuples (G,G0,tau,V1). 5) those tuples (G,G0,tau,V1) which fulfill the freeness condition of Proposition 2.5 b) i), i.e. "SmoothIndex3i(G,G0,tau,V1,T1)" returns true, are algebraic data of (families) of threefolds X isogenous to a product. We compute the Hodge numbers of these threefolds X with the help of the function "HodgeDiamondIndex3". The groups G and G0, the type T1, the Hodge numbers and the dimension of the families (cf. Remark 3.6) are stored in the file "IndexThree(chi).txt". */ ClassifyIndexThree:=function(chi) F:="IndexThree" cat IntegerToString(chi) cat ".txt"; fprintf F, "Threefolds isogenous to a product of mixed type: \n index three case, chi=%o and absolutely faithful G-action:\n\n\n\n\n", chi; count:=1; Num_H:=NDHIndexThree(chi); Set:={}; for Tup in Num_H do Include(~Set,Tup[1][1]); end for; PossOrders:=OrderedSeq(Set); for GOrd in PossOrders do G0_Ord:=IntegerRing()!(GOrd/3); for G in SmallGroups(GOrd: Warning:=false) do invarset:={}; NG0:=NormalSubgroups(G); PG0:={NG0[i]`subgroup : i in [1..#NG0]| NG0[i]`order eq G0_Ord and NonSplitIndex3(G,NG0[i]`subgroup)}; for G0 in PG0 do IdG0:=IdentifyGroup(G0); tau:=Rep({x: x in G| x notin G0}); for D in Num_H do n:=D[1][1]; T1:=D[2]; identi:=D[3]; if n eq GOrd and [IdG0[1],IdG0[2]] eq identi then for V1 in GenVecRep(G0,T1) do if SmoothIndex3i(G,G0,tau,V1,T1) then invar:=HodgeDiamondIndex3(G,G0,tau,V1,T1) cat T1 cat [IdG0[1],IdG0[2]]; if invar notin invarset then Include(~invarset,invar); fprintf F, "%o) Groups: G= %o, G0= %o\n", count, IdentifyGroup(G), IdG0; fprintf F, "\n Type: T1=%o \n", T1; 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] -4 + #T1; fprintf F, "\n\n\n\n\n"; count:=count+1; end if; end if; end for; end if; end for; end for; end for; end for; return "Classification_accomplished"; end function; // **************************************** Index six ***************************************************** /* The script "AdNDindexSix" is used to determine the set of admissible numerical data for a given input value of chi (<=-1) (see the algorithm in Chapter 3). The computation is the same as in the index three case, except that the group order GOrd is divisible by 18 and not just by 9. */ AdNDindexSix:=function(chi) F:="ExcepIndexSix" cat IntegerToString(chi) cat ".txt"; fprintf F, "Index six case, chi=%o and absolutely faithful G-action.\n\n\n Exceptional numerical data:\n\n\n", chi; GOrdMax:=Floor(1512*Sqrt(-7*chi)); g1max:=Floor(Root(-chi*GOrdMax, 3)+1); ListAdIndex6:=[]; ListPairs:=[]; for g1 in [2..g1max] do GOrd:=-(g1-1)^3/chi; if GOrd/18 in IntegerRing() and Conder(GOrd/3,g1) then GOrd:=IntegerRing()!GOrd; Append(~ListPairs,[GOrd,g1]); end if; end for; for Pair in ListPairs do GOrd:=Pair[1]; G1_Ord:=IntegerRing()!(GOrd/3); g1:=Pair[2]; h1max:= Floor(1-3*chi/(g1-1)^2); for h1 in [0..h1max] do if GOrd^2 le -216*chi/(ThetaMin(h1)^3) then for T1 in ListOfTypes(G1_Ord,g1,(g1-1)^2,h1) do D:=[[GOrd],T1]; if IsInSmallGroupDatabase(G1_Ord) then Append(~ListAdIndex6,D); else fprintf F, "D=%o\n\n", D; end if; end for; end if; end for; end for; return ListAdIndex6; end function; /* The script "NDHIndexSix" is used to determine the set of triples of the form [GOrd,T1,H], where [GOrd,T1] is an admissible numerical datum and H is a candidate for G1 i.e. H is of order GOrd/3 and admits a generating vector of type "T1". The triples [GOrd,T1,H], where the groups of order GOrd are not contained in the database of Small Groups are stored in the file "ExcepIndexSix(chi)". The remaining triples are returned as the output of the function. */ NDHIndexSix:=function(chi) AdNum:=AdNDindexSix(chi); F:="ExcepIndexSix" cat IntegerToString(chi) cat ".txt"; fprintf F,"Exceptional triples: \n\n\n "; Ord_T1_H:=[]; for Tup in AdNum do GOrd:=Tup[1][1]; T1:=Tup[2]; for H in SmallGroups(IntegerRing()!(GOrd/3): Warning:=false) do if ExistVectGens(H,T1) then ID:=IdentifyGroup(H); DNew:=Tup cat [[ID[1],ID[2]]]; if IsInSmallGroupDatabase(GOrd) then Append(~Ord_T1_H,DNew); else fprintf F, "%o\n\n", DNew; end if; end if; end for; end for; return Ord_T1_H; end function; /* The function "NonSplitIndexSix" returns true if the sequence 1 --> G0 --> G --> S3 --> 1 is non-split. This is a necessary condition for the freeness of the G-action according to Corollary 2.7 a). */ NonSplitIndexSix:=function(G,G0) test:=true; L:=Set(G) diff Set(G0); for a in ElsOfOrd(L,2) do for b in ElsOfOrd(L,3) do if a*b*a eq b^(-1) then test:=false; break a; end if; end for; end for; return test; end function; /* Let G be a finite group and G0 be a normal subgroup of index six such that G/G0 is isomorphic to S3. The function "Elemets_tau_h" returns elements tau and h in G\G0 such that tau^2 is not contained in G0 and h^2 is contained in G0. Note that these elements give rise to an isomorphism G/G0 --> S3. */ Elemets_tau_h:=function(G,G0) L:=Set(G) diff Set(G0); for g in L do if g^2 notin G0 then tau:=g; break g; end if; end for; for u in L do if u^2 in G0 then h:=u;end if; end for; return tau, h; end function; /* The script "ClassifyIndexSix" is used to perform Step 2 of the algorithm. It determines for a given negative integer "chi" (the input value) all threefolds isogenous to a product of mixed type with "chi(O_X)=chi" in the index six case. The strategy is the following: 1) we determine the list "PossOrders", which contains all integers GOrd belonging to some triple [GOrd,T1,H] in "NDHIndexSix(chi)". 2) for each GOrd in "PossOrders" and for each group G of order GOrd we build the set "PG0" of normal subgroups G0 of Order GOrd/3 such that G/G0 is isomporphic to S3 and the short exact sequence 1 --> G0 --> G --> S3 --> 1 is non-split. 3) we run through the groups G0 in PG0, determine for each G0 elements tau and h in G\G0 as explained above and define the subgroup G1cand to be the subgroup generated by all elements of G0 and the element h. 4) next we run through the triples [GOrd,T1,H] in "NDHIndexSix(chi)". For those triples, where H is isomorphic to G1cand we determine a set of representatives of generating vectors V1 calling the function "GenVecRep(G1cand,T1)". 5) we run through all V1 contained in "GenVecRep(G1cand,T1) and consider the tuples (G,G0,tau,h,V1). 6) those tuples (G,G0,tau,V1) fulfilling the freeness conditions of Proposition 2.5 c) are algebraic data of (families) of threefolds X isogenous to a product. We compute the Hodge numbers of these threefolds X using the function "HodgeDiamondIndex6". The groups G and G0, the type T1, the Hodge numbers and the dimension of the families are saved in the file "IndexSix(chi).txt". */ ClassifyIndexSix:=function(chi); F:="IndexSix" cat IntegerToString(chi) cat ".txt"; fprintf F, "Threefolds isogenous to a product of mixed type:\n index six case, chi=%o and absolutely faithful G-action:\n\n\n\n\n", chi; count:=1; Num_H:=NDHIndexSix(chi); SetOrd:={}; for D in Num_H do Include(~SetOrd,D[1][1]); end for; PossOrders:=OrderedSeq(SetOrd); for GOrd in PossOrders do for G in SmallGroups(GOrd: Warning:=false) do N:=NormalSubgroups(G); PossG0:={N[i]`subgroup : i in [1..#N]| IsIsomorphic(G/N[i]`subgroup,Sym(3)) and NonSplitIndexSix(G,N[i]`subgroup)}; for G0 in PossG0 do IdG0:=IdentifyGroup(G0); tau,h :=Elemets_tau_h(G,G0); G1cand:=sub; for D in Num_H do T1:=D[2]; ide:=; invarset:={}; if eq IdentifyGroup(G1cand) then for V1 in GenVecRep(G1cand,T1) do if SmoothIndex6(G,G0,tau,h,V1,T1) then invar:=HodgeDiamondIndex6(G,G0,tau,h,V1,T1) cat [IdG0[1],IdG0[2]]; if invar notin invarset then Include(~invarset,invar); fprintf F, "%o) Groups: G= %o, G0=%o \n", count, IdentifyGroup(G), [IdG0[1],IdG0[2]]; fprintf F, "\n Type: (the first entry is gi') \n"; fprintf F, "\n T1=%o;\n", T1; 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\n\n\n\n"; fprintf F, "\n number of parameters: %o;\n", 3*T1[1] - 4 + #T1; fprintf F, "\n\n\n\n\n"; count:=count+1; end if; end if; end for; end if; end for; end for; end for; end for; return "Classification_accomplished"; end function;