// Magma script that verifies the computational claims in Section 3 of // "The generalized Fermat equation with exponents 2, 3, n" // by Nuno Freitas, Bartosz Naskrecki and Michael Stoll // Some functions use later for the computations function Frey(a, b, d) // Returns the Frey curve E_{(a,b,c)}^{(d)} attached to a solution (a,b,c) of x^2 + y^3 = z^p. // Note that it depends only on a and b (adn d). return QuadraticTwist(EllipticCurve([0, 0, 0, 3*b, -2*a]), d); end function; // Find polynomial defining the p-torsion field of an elliptic curve. // In most cases, the y-coordinates of the points of order p are distinct. // Otherwisse, this is true for y-x (at least when p = 3 or 5). // Return both resulting polynomials. function defpolptorsion(E, p) // E: an elliptic curve // p: an odd prime P2 := PolynomialRing(BaseField(E), 2); pol := DivisionPolynomial(E, p); P := Parent(pol); pol := Evaluate(pol, P2.1); polE := Evaluate(DefiningEquation(E), [P2.1, P2.2, 1]); res1 := Evaluate(Resultant(pol, polE, 1), [0, P.1]); // try y-x res2 := Evaluate(Resultant(pol, Evaluate(polE, [P2.1, P2.2+P2.1]), 1), [0, P.1]); return [res1, res2]; end function; // Verify that L Q_l^nr is the inertial field of E over Q_l, // where E has potentially good reduction. // The inertial field is the smallest extension of Q_l^nr such that // E acquires good reduction. So if E has good reduction over L, // we are OK. We check in addition that the reduction of the minimal // model of E over L has full p-torsion, for given odd p /= l. // This implies by Hensel's Lemma that the same is true for E over L // and so shows that Q_l(E[p]) is contained in L. // If E does not have good reduction over L, then L Q_l^nr cannot // be the inertial field, since bad reduction persists under unramified extensions. function check_inertial_field(E, L, p, t) // L: extension of Q_l // p: odd prime different from l // t: trace of Frobenius over L that E is supposed to have // (this is needed for the proofs of Lemmas 5.2 and 5.3) l := Prime(L); assert IsOdd(p) and p ne l; EL := BaseChange(E, L); // compute reduction information and a minimal model of E over L type, Emin := LocalInformation(EL); if type[2] ne 0 then // minimal disc not a unit --> not the right field return false; end if; // find reduction of minimal model OL := Integers(L); _, red := ResidueClassField(OL); Ered := BaseChange(Emin, Bang(L, OL)*red); assert TraceOfFrobenius(Ered) eq t; // get group structure of its points and check that group contains Z/p x Z/p inv := Invariants(AbelianGroup(Ered)); assert #inv eq 2 and IsDivisibleBy(inv[1], p); return true; end function; // Specialize the above for Q_2 function check_iso_Q2(E, L) return check_inertial_field(E, L, 3, -4); end function; // Specialize the above for Q_3 function check_iso_Q3(E, L) return check_inertial_field(E, L, 5, -18); end function; // This implements a version of Lemma 7.5. // We only need the convergence statement, for which the condition c /= 0 in the lemma // is not necessary. Also, e will always be 1. function radius_of_convergence_for_root_series(rel, prseq) // rel: polynomial in two variables t, x over a number field K // prseq: sequence of pairs where pr is a prime ideal of K and e is its ramification index // (all prime ideals of the same number field and of the same residue characteristic p) // We assume that rel(x,y) = c x + O(t, x^2) with c /= 0. // We scale rel to get c = 1. Then by Lemma 7.5, there is a unique power series // phi(t) with phi(0) = 0 and rel(t, phi(t)) = 0. // The function returns: // rad: a number such that phi(t) converges whenever v_p(t) > rad. t := Parent(rel).1; x := Parent(rel).2; assert MonomialCoefficient(rel, Parent(rel)!1) eq 0; assert MonomialCoefficient(rel, x) ne 0; rel /:= MonomialCoefficient(rel, x); // make coefficient of x equal to 1 valmat := Matrix(Rationals(), [[Min(1000000, Max([Valuation(MonomialCoefficient(rel, t^m*x^n), e[1])/e[2] : e in prseq])) : n in [0..Degree(rel, x)]] : m in [0..Degree(rel, t)]]); // so valmat[1+m, 1+n] = v_p(f_{mn}) when rel(t,x) = sum_{m,n} f_{mn} t^m x^n // determine radius of convergence: // first find smallest v(r) such that the condition for m >= 1 is OK return -Min([((m-1)*valmat[1+i,1+0]+valmat[1+k,1+m])/((m-1)*i+k) : m in [1..Degree(rel, x)], i in [1..Degree(rel, t)], k in [0..Degree(rel, t)] | (m-1)*i+k gt 0]); end function; // The function check_galrep_constant below does the checking for a given family. // This works as follows. // We determine a polynomial F(t,x) over Q(t) whose roots correspond to // the points of order p on Eab(t). We then check that for each root r // of F(0,x) (this polynomial must be squarefree), there is a power series // phi_r(r) over Q(r) such that phi_r(0) = r and F(t, phi_r(t)) = 0 // and such that phi_r converges on Z_l. It is enough to do this for // one r from each Q-Galois orbit of roots if we consider all l-adic // completions of Q(r). // Specializing to any t in Z_l, the absolute Galois group of Q_l acts // on the phi_r(t) in the same way as it acts on the roots r, hence we get // the same Q_l-Galois representation on Eab(t)[p] for all t in Z_l. // More precisely, these representations are all symplectically isomorphic, // since the Weil pairing between two p-torsion points is constant along // the parameterization via t. function check_galrep_constant(Eab, l, p) // Eab: Frey curve E_(a,b,c)^(d) as in Table 1, with a or b constant // and the other one of the form c + 4*t or c + 8*t with t an indeterminate // and d fixed. // l: a prime (l = 2 or 3 in the application); work over Q_l // p: an odd prime /= l (p = 3 pr 5 in the application); work with the p-torsion F := BaseField(Eab); // the function field Q(t) PF := PolynomialRing(F); // get polynomials whose splitting field is the 3-torsion field of Eab pols := defpolptorsion(Eab, p); // specialize to t = 0 pols0 := [PolynomialRing(Rationals())![Evaluate(c, 0) : c in Coefficients(pol)] : pol in pols]; // we need one that has squarefree specialization assert exists(i){i : i in [1..#pols0] | IsSquarefree(pols0[i])}; // this assigns to i the position of a suitable polynomial pol0 := pols0[i]; // a squarefree specialization polfact := Factorization(pol0); // factor into irreducibles over Q pol := pols[i]; // the polynomial over Q(t) specializig to pol0 // Now compute the radius of convergence of the power series for r coming from each factor. for e in polfact do fact := e[1]; // the actual irreducible factor // set up the number field defined by fact and its ring of integers if Degree(fact) eq 1 then // special case K := Rationals(); r := Roots(fact)[1,1]; else K := NumberField(fact); end if; assert Evaluate(fact, r) eq 0; // just to be sure... if p eq 3 then OK := Integers(K); else // computing the maximal order can be slow when p = 5... OK := pMaximalOrder(GeneralisedEquationOrder(K), l); end if; // base-change pol to K and shift by r to satisfy assumptions of Lemma 7.5 P2K := PolynomialRing(K, 2); polK := hom P2K | hom P2K | P2K.1>, P2K.2 + r>(pol); rad := radius_of_convergence_for_root_series(polK, Decomposition(OK, l)); if rad ge 0 then // disk of convergence is too small printf "check_galrep_constant: rad = %o is not negative!\n", rad; return false; end if; end for; return true; end function; // Specialize to Q_2. function check_galrep_constant_Q2(Eab) return check_galrep_constant(Eab, 2, 3); end function; // Specialize to Q_3. function check_galrep_constant_Q3(Eab) return check_galrep_constant(Eab, 3, 5); end function; ////////////////////////////////////////////////////////////////////////////// // The following constructs the 3-torsion fields L96 and L288 of 96a1 and 288a1 over Q_2. // We will later check that the 3-torsion of 96a1/288a1 indeed splits over L96/L288. Q2 := pAdicField(2, 100); Q2nr := ext; // the unramified extension of degree 2 L96 := ext where x := PolynomialRing(Q2nr).1; L288 := ext where x := PolynomialRing(Q2nr).1; // The following constructs the 5-torsion fields L27 of 27a1 and L54 of 54a1 over Q_3. // We will later check that the 5-torsion of 27a1/54a1 indeed splits over L27/L54. Q3 := pAdicField(3, 1000); Q3nr := ext; // the unramified extension of degree 4 L27 := ext where x := PolynomialRing(Q3nr).1; L54 := ext where x := PolynomialRing(Q3nr).1; // The fields were constructed as follows. Let E be the relevant elliptic curve over Q. // First obtain a polynomial f defining the scheme of points of order 3 or 5 on E. // Then construct the splitting field of f over Q2 or Q3. This gives a totally ramified // extension of degree 8, resp. 12, over an unramified extension of Q2 or Q3. // Finally, reduce the coefficients of the defining polynomial of the ramified extension // mod 8 or mod 9 to get the polynomials used above. // That the fields are correct is checked in the code below. F := FunctionField(Rationals()); ////////////////////////////////////////////////////////////////////////////// // /* printf "\n"; printf "==================================================================\n"; printf "VERIFICATION OF THE COMPUTATIONS IN SECTION 3\n"; printf "==================================================================\n\n\n"; printf "Theorem 3.1 and following text\n"; printf "------------------------------\n\n"; // We first check that L96 is the 3-torsion field of 96a1 over Q_2 // and that L288 is the 3-torsion field of 288a1 over Q_2. printf "Checking that fields over Q_2 are correct... "; assert check_iso_Q2(EllipticCurve("96a1"), L96); assert check_iso_Q2(EllipticCurve("288a1"), L288); printf "--> OK.\n"; printf "Checking that L_{2,96} and L_{2,288} are not isomorphic... "; assert not IsIsomorphic(L96, L288); printf "--> OK.\n"; // Dito for the fields over Q_3. printf "Checking that fields over Q_3 are correct... "; assert check_iso_Q3(EllipticCurve("27a1"), L27); assert check_iso_Q3(EllipticCurve("54a1"), L54); printf "--> OK.\n"; printf "Checking that L_{3,27} and L_{3,54} are not isomorphic... "; // assert not IsIsomorphic(L27, L54); assert not check_iso_Q3(EllipticCurve("54a1"), L27); // this is faster printf "--> OK.\n\n"; // Now the text following the proof of Theorem 3.1. printf "Checking that inertial fields over Q_2 of 96a1 and 864c1 agree... "; assert check_iso_Q2(EllipticCurve("864c1"), L96); printf "--> OK.\n"; printf "Checking that inertial fields over Q_2 of 288a1, 864a1 and 864b1 agree... "; assert check_iso_Q2(EllipticCurve("864a1"), L288); assert check_iso_Q2(EllipticCurve("864b1"), L288); printf "--> OK.\n"; printf "Checking that inertial fields over Q_3 of 27a1, 864b1 and 864c1 agree... "; assert check_iso_Q3(EllipticCurve("864b1"), L27); assert check_iso_Q3(EllipticCurve("864c1"), L27); printf "--> OK.\n"; printf "Checking that inertial fields over Q_3 of 54a1 and 864a1 agree... "; assert check_iso_Q3(EllipticCurve("864a1"), L54); printf "--> OK.\n\n"; // We now proceed to verify that the Frey curves have constant mod-p Galois // representation within the residue classes given in Tables 1 and 2 // and that they have the correct inertial fields when the associated // curve from th list has maximal conductor exponent. // Note that we only need to check that the Galois representation // is constant for one value of d, since changing d twists all reps // in the family in the same way. // (We still have to check later that the reps are isomorphic among // different d's, though.) printf "Table 1\n"; printf "-------\n\n"; // We note that multiplying a by (1 + 4z)^3 and b by (1 + 4z)^2 for some z in Z_2 // induces an unramified quadratic twist over Q_2. // Since we only need the Galois representations to be isomorphic up to // unramified quadratic twist, we are free to apply such twists to the Frey curves. // So we can either multiply a by an arbitary element in 1 + 4Z_2 // or b by an arbitary element in 1 + 8Z_2. // Since at least one of a and b is odd, // we can fix a = 1 or a = -1 and vary b in its class mod 8, // or else we fix b = 1, -1, 3 or -3 and vary a in its class mod 4. // We also check the exponent of the conductor (for one curve in each family). // i_2 = 1: special case, since specialization at t = 0 is degenerate // This can be dealt with using the theory of the Tate curve; // see Proposition 5.4. // i_2 = 2, 3: we fix b and set a = 8*t, 4 + 8*t, 2 + 8*t or -2 + 8*t // (need to split in two classes mod 8 for a to get convergence). // Run through the four lines and the four values of d each. printf "Checking rows i_2 = 2, 3 of Table 1 with a and b fixed mod 8 --> "; pairs := [<1, 1>, <-3, 1>, <3, 2>, <-1, 2>]; // relevant pairs curves := [Frey(a+8*t, e[1], e[2]) : e in pairs, a in [0, 4, 2, -2]]; assert forall{E : E in curves | check_galrep_constant_Q2(E)}; curves0 := [Frey(a, e[1], e[2]) : e in pairs, a in [0, 4, 2, -2]] cat [Frey(a, e[1], -e[2]) : e in pairs, a in [0, 4, 2, -2]]; assert forall{E : E in curves0 | LocalInformation(E, 2)[3] eq 5}; printf "OK\n"; // i_2 = 4: we fix a and set b = 8*t printf "Checking row i_2 = 4 of Table 1 with a and b fixed mod 8 --> "; curves := [Frey(1, 8*t, -2), Frey(-1, 8*t, 2)]; assert forall{E : E in curves | check_galrep_constant_Q2(E)}; curves0 := [Frey(1, 0, -2), Frey(-1, 0, 2)]; assert forall{E : E in curves0 | LocalInformation(E, 2)[3] eq 0}; printf "OK\n"; // i_2 = 5, 6, 7: we fix a and set b = 2 + 8*t, -2 + 8*t, 4 + 8*t printf "Checking rows i_2 = 5, 6, 7 of Table 1 with a and b fixed mod 8 --> "; curves := [Frey(a, b + 8*t, 2) : a in [-1, 1], b in [2, -2, 4]]; assert forall{E : E in curves | check_galrep_constant_Q2(E)}; curves0 := [Frey(a, b, d) : a in [-1, 1], b in [2, -2], d in [2, -2]]; assert forall{E : E in curves0 | LocalInformation(E, 2)[3] eq 5}; curves0 := [Frey(1, 4, -2), Frey(-1, 4, 2)]; assert forall{E : E in curves0 | LocalInformation(E, 2)[3] eq 0 and TraceOfFrobenius(E, 2) in {-2,2}}; assert TraceOfFrobenius(EllipticCurve("27a1"), 2) eq 0; printf "OK\n"; printf "\n"; // Now we compare inertial fields between the various curves // with conductor exponent 5 at 2. // Note that the twists by d = 1, -3 are unramified, // so we can reduce the four possible values of d to two. printf "Checking inertial fields for row i_2 = 2 --> "; assert forall{a : a in [0,4], b in [1,-3], d in [1,-1] | check_iso_Q2(Frey(a, b, d), L288)}; assert forall{a : a in [0,4], b in [3,-1], d in [2,-2] | check_iso_Q2(Frey(a, b, d), L288)}; printf "isomorphic to L_{2,288}\n"; printf "Checking inertial fields for row i_2 = 3 --> "; assert forall{a : a in [2,-2], b in [1,-3], d in [1,-1] | check_iso_Q2(Frey(a, b, d), L96)}; assert forall{a : a in [2,-2], b in [3,-1], d in [2,-2] | check_iso_Q2(Frey(a, b, d), L96)}; printf "isomorphic to L_{2,96}\n"; printf "Checking inertial fields for row i_2 = 5 --> "; assert forall{a : a in [1,-1], b in [2], d in [2,-2] | check_iso_Q2(Frey(a, b, d), L96)}; printf "isomorphic to L_{2,96}\n"; printf "Checking inertial fields for row i_2 = 6 --> "; assert forall{a : a in [1,-1], b in [-2], d in [2,-2] | check_iso_Q2(Frey(a, b, d), L288)}; printf "isomorphic to L_{2,288}\n"; printf "\n"; printf "Table 2\n"; printf "-------\n\n"; // Now, an unramified quadratic twist corresponds to multiplying // a with u^3 and b with u^2, where u is a 3-adic unit. // So when a is not divisible by 3, we can fix a mod 9 (and change the sign), // and when b is not divisible by 3, we can fix b mod 3. // As for Table 1, we can fix one d (= 1). // We also check the exponent of the conductor (for one curve in each family). // i_3 = 1: special case, since specialization at t = 0 is degenerate // This can be dealt with using the theory of the Tate curve; // see Proposition 5.4. // i_3 = 2, 3, 4: we fix b and set a = 9*t or 3 + 9*t // Run through the four lines and the eight values of d each. printf "Checking rows i_3 = 2, 3, 4 of Table 2 with (a, b) fixed mod (9, 3):\n"; curves := [Frey(a+9*t, b, 1) : b in [1,-1], a in [0,3]]; for E in curves do assert check_galrep_constant_Q3(E); printf "."; end for; // assert forall{E : E in curves | check_galrep_constant_Q3(E)}; curves0 := [Frey(a, b, d) : b in [1,-1], a in [0], d in [1,3]]; assert forall{E : E in curves0 | LocalInformation(E, 3)[3] eq 2}; // i_3 = 2 curves0 := [Frey(a, b, d) : b in [1,-1], a in [3], d in [1,3]]; assert forall{E : E in curves0 | LocalInformation(E, 3)[3] eq 3}; // i_3 = 3, 4 printf " --> OK\n"; // i_3 = 5, 6, 7, 8: we fix a = 1, 2, 4 and set b = 3*t or b = 1 + 3*t printf "Checking rows i_3 = 5, 6, 7, 8 of Table 2 with (a, b) fixed mod (9, 3):\n"; curves := [Frey(a, b+3*t, 1) : b in [0,1], a in [1,2,4]]; for E in curves do assert check_galrep_constant_Q3(E); printf "."; end for; // assert forall{E : E in curves | check_galrep_constant_Q3(E)}; curves0 := [Frey(a, b, d) : b in [0], a in [1,2], d in [1,3]]; assert forall{E : E in curves0 | LocalInformation(E, 3)[3] eq 3}; // i_3 = 5 curves0 := [Frey(a, b, d) : b in [0], a in [4], d in [1,3]]; assert forall{E : E in curves0 | LocalInformation(E, 3)[3] eq 2}; // i_3 = 6 curves0 := [Frey(a, b, d) : b in [1], a in [1,4], d in [1,3]]; assert forall{E : E in curves0 | LocalInformation(E, 3)[3] eq 3}; // i_3 = 7 curves0 := [Frey(a, b, d) : b in [1], a in [2], d in [1,3]]; assert forall{E : E in curves0 | LocalInformation(E, 3)[3] eq 2}; // i_3 = 8 printf " --> OK\n"; printf "\n"; // Now we compare inertial fields between the various curves // with conductor exponent 3 at 3. // Note that the twists by d = 1, -1, 2, -2 are unramified, // so we can reduce the eight possible values of d to two. printf "Checking inertial fields for row i_3 = 3 --> "; assert forall{a : a in [3], b in [1,4,-2], d in [1,3] | check_iso_Q3(Frey(a, b, d), L27)}; printf "isomorphic to L_{3,27}\n"; printf "Checking inertial fields for row i_3 = 4 --> "; assert forall{a : a in [3], b in [-1,-4,2], d in [1,3] | check_iso_Q3(Frey(a, b, d), L54)}; printf "isomorphic to L_{3,54}\n"; printf "Checking inertial fields for row i_3 = 5 --> "; assert forall{a : a in [1,2], b in [0], d in [1,3] | check_iso_Q3(Frey(a, b, d), L27)}; printf "isomorphic to L_{3,27}\n"; printf "Checking inertial fields for row i_3 = 7 --> "; assert forall{a : a in [1,4], b in [1], d in [1,3] | check_iso_Q3(Frey(a, b, d), L54)}; printf "isomorphic to L_{3,54}\n"; printf "\n";