// Magma example // Compute the algebraic Brauer-Manin obstruction on the K3 surface // X : X0^4 + X1^4 = 6 X2^4 + 12 X3^4 // // Define a few useful objects Q := Rationals(); Z := Integers(); // // Define 3-dimensional projective space over Q P3 := ProjectiveSpace(Q,3); // And the variety X X := Scheme(P3, X0^4 + X1^4 - 6*X2^4 - 12*X3^4); X; // // Before we do anything else, we should check to see that X has points // in each Q_v. It is clear that there are real points. For the other // places, general arguments tell us that we only need to check at 5 // and at the primes dividing the coefficients. IsLocallySolvable(X,2); IsLocallySolvable(X,3); IsLocallySolvable(X,5); // // Good. To compute the Brauer-Manin obstruction, the first thing we // need to do is construct the Picard group and the Galois action on it. // We know that the Picard group of this surface is generated by the 48 // straight lines that it contains, and it is easy to see that they are // all defined over the field K formed by adjoining to Q a square root // of -1, a fourth root of 2 and a fourth root of 3. // // Define the polynomial ring Q[t] _ := PolynomialRing(Q); // Define the number field generated by three elements // i satisfying i^2 = -1 // r2 satisfying r2^4 = 2 // r3 satisfying r3^4 = 3 K := NumberField([t^2+1, t^4-2, t^4-3] : Abs := true); K; // and let e be a primitive eighth root of unity in this field. e := (1+i)/(r2^2); // // We now want to know the Galois group Gal(K/Q). We could ask Magma // to compute it, but that would take a very long time. As it's an // easy extension (a Kummer extension of Q[i]), we already know three // generators for the Galois group. tau := hom< K->K | [-i, r2, r3] >; sigma2 := hom< K->K | [i, i*r2, r3] >; sigma3 := hom< K->K | [i, r2, i*r3] >; // // Now we can ask Magma to compose these and see what group they // generate. We get an abstract group Gal together with a map // Gal -> Aut(K/Q) giving the action. Gal, GalKAction := GenericGroup([tau, sigma2, sigma3]); Gal; #Gal; // Good. It has order 32. // // We want to define the 48 lines on X, but they are only defined over K. // So we create P3 over K, and base change X into it. P3K := ProjectiveSpace(K,3); XK := BaseChange(X, P3K); // // Now we define the 48 lines on X; their equations are // { X0 = e^m a1 X1, X2 = e^n (a3/a2) X3 : m,n in [1,3,5,7] } // { X0 = e^m a2 X2, X3 = e^n (a1/a3) X1 : m,n in [1,3,5,7] } // { X0 = e^m a3 X3, X1 = e^n (a2/a1) X2 : m,n in [1,3,5,7] }. // where a1, a2, a3 are chosen fourth roots of 1, -6 and -12 respectively. a1 := 1; a2 := e*r2*r3; a3 := e*r2^2*r3; // lines1 := [ Scheme(P3K, [X0K - (e^m*a1) * X1K, X2K - (e^n*a3/a2) * X3K] ) : m,n in [1,3,5,7] ]; lines2 := [ Scheme(P3K, [X0K - (e^m*a2) * X2K, X3K - (e^n*a1/a3) * X1K] ) : m,n in [1,3,5,7] ]; lines3 := [ Scheme(P3K, [X0K - (e^m*a3) * X3K, X1K - (e^n*a2/a1) * X2K] ) : m,n in [1,3,5,7] ]; // // Put them all together in one big list lines := lines1 cat lines2 cat lines3; #lines; // // Check that they do all indeed lie in X [ l subset XK : l in lines ]; // and that they are all lines [ Degree(l) : l in lines ]; // // Next we want to know that Galois action on the lines - that is, a // subgroup of S48 isomorphic to the Galois group and its permutation // action on the lines. // // First we need to be able to let elements of the Galois group act on // the lines. At the moment they can only act on elements of K. // // Firstly, define a function which computes the image of a polynomial // over K under an automorphism of K. We just extract the coefficients // of the polynomial, find their images under the action, and put // everything back together into a polynomial. If we're careful, it can // also work for polynomials defined over subfields of K. AutPolyAction := function(P, a) k := BaseRing(Parent(P)); m := Monomials(P); c := Coefficients(P); return &+[ k!(c[i] @ a) * m[i] : i in [1..#c] ]; end function; // // Given that, we can define a function which computes the image of a // scheme defined over K under an automorphism of K. We list the defining // polynomials of the scheme Y, act on them using the previous function // and use the resulting polynomials to define a new scheme. AutSchemeAction := function(Y, a) A := AmbientSpace(Y); return Scheme(A, [ AutPolyAction(P, a) : P in DefiningPolynomials(Y) ] ); end function; // // Now, given an automorphism of K/Q, we can find how it permutes // the lines. LAction := func< a | [ Index(lines, AutSchemeAction(l, a)) : l in lines ] >; // // For example, here is what sigma2 does: LAction(sigma2); // // We create the subgroup of S48 generated by the permutations // corresponding to our three generators of the Galois group. G := PermutationGroup<48 | [ LAction(tau), LAction(sigma2), LAction(sigma3) ] >; G; #G; // // There is an isomorphism from G to Gal phi := hom< G -> Gal | Gal.1, Gal.2, Gal.3 >; // // And for convenience we give a name to the composite homomorphism // from G to Aut(K). GKAction := phi * GalKAction; // // From on we will do all our group theory in G, rather than Gal - it is // much faster to work in a permutation group than in a group defined by // generators and relations, and more algorithms are available. // // Now we would like to compute the intersection numbers of all the lines. // Since they are lines, it's very easy. If two distinct lines meet, they // have intersection number 1; if they don't meet, they have intersection // number 0. We can write this as // l1 . l2 = dim(l1 meet l2) + 1 // since Magma thinks an empty scheme has dimension -1. // This takes a little while - computing with schemes is sometimes slow. Int := Matrix([ [ Dimension(l1 meet l2) + 1 : l1 in lines ] : l2 in lines ]); // The self-intersection of each line is -2, as we can tell from the // adjunction formula. We put -2's down the diagonal of the matrix. for i in [1..48] do Int[i,i] := -2; end for; // // This intersection form should be preserved by the action of G on // the free Z-module generated by the 48 lines. Let's check. [ P * Int * Transpose(P) eq Int where P is PermutationMatrix(Z, g) : g in Generators(G) ]; // // We'll write Lambda for the free Z-module generated by the 48 lines. // We can create a separate object to represent the corresponding // G-module, which is Lambda together with the permutation action of G. LambdaMod := PermutationModule(G, Z); // Give a name to the homomorphism G -> GL(Z,48) rhoL := Representation(LambdaMod); // // The Picard group of X is generated by the 48 lines, and divisors are // linearly equivalent if and only if they are numerically equivalent. // The sums of lines numerically equivalent to zero are those lying in // the kernel of the intersection matrix. // // So we want to create the quotient G-module of Lambda by the kernel // of Int. But there's no function to do that. First we create the // quotient of the underlying Z-module, together with the quotient map // taking a sum of lines to its class in Pic X. Lambda := VectorSpace(LambdaMod); // poorly-named function Pic, class := quo< Lambda | Kernel(Int) >; // // To compute the G-action on the quotient, we need a matrix representing // the quotient map... ClassMatrix := Matrix( [ class(Lambda.i) : i in [1..48] ] ); // // ... and a section (in this case a *right* inverse) of it. ClassSection := Solution(ClassMatrix, IdentityMatrix(Z, 20)); // // Using these, we can work out the action on Pic of each generator of G. // So we can construct the G-module corresponding to Pic. PicMod := GModule(G, [ ClassSection * M * ClassMatrix : M in ActionGenerators(LambdaMod) ] ); // // We now have done everything we need to compute H^1(Gal(K/Q), Pic X_K). // In Magma, we first create a cohomology module... CM := CohomologyModule(G, PicMod); // ... and then compute the cohomology group. H1 := CohomologyGroup(CM, 1); #H1; // // This has order 2. The one non-trivial element corresponds to a // non-trivial algebra in Br_1 X / Br Q. // // We hope that our element is split by a cyclic extension of Q. // To check, we list all the subgroups H of G such that G/H is cyclic. // For each one, we will compute the cohomology group H^1(H, Pic X_K) // and the restriction map to it. If the restriction of our element // is zero, then it is split by the fixed field of H. // // First list the proper normal subgroups of G, and check whether // the quotient is cyclic. CycSubs := [ H`subgroup : H in Subgroups(G : Al := "Normal") | H`order lt 32 and IsCyclic( quo< G | H`subgroup> ) ]; #CycSubs; [ Index(G,H) : H in CycSubs ]; // // We'll make a list of those subgroups which do give a splitting field. Split := []; // Now, for each subgroup... for H in CycSubs do // Create a new cohomology module for the restriction to H CMH := Restriction(CM, H); // Compute the cohomology group H1H := CohomologyGroup(CMH, 1); // Form the restriction map H^1(G, Pic X_K) -> H^1(H, Pic X_K). res := hom