Testing whether elliptic curves over number fields are -curves#
AUTHORS:
John Cremona (February 2021)
The code here implements the algorithm of Cremona and Najman presented in [CrNa2020].
- sage.schemes.elliptic_curves.Qcurves.Step4Test(E, B, oldB=0, verbose=False)[source]#
Apply local Q-curve test to E at all primes up to B.
INPUT:
(elliptic curve): an elliptic curve defined over a number field (integer): upper bound on primes to testoldB
(integer, default 0): lower bound on primes to testverbose
(boolean, defaultFalse
): verbosity flag
OUTPUT:
Either (
False
, ), if the local test at proves that is not a -curve, or (True
, ) if all local tests at primes betweenoldB
andB
fail to prove that is not a -curve.ALGORITHM (see [CrNa2020] for details):
This local test at
only applies if has good reduction at all of the primes lying above in the base field of . It tests whether (1) is either ordinary at all , or supersingular at all; (2) if ordinary at all, it tests that the squarefree part of is the same for all .EXAMPLES:
A non-
-curve over a quartic field (with LMFDB label ‘4.4.8112.1-12.1-a1’) fails this test at :sage: from sage.schemes.elliptic_curves.Qcurves import Step4Test sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field sage: E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field ....: K([-621,778,138,-178]), K([9509,2046,-24728,10380])]) sage: Step4Test(E, 100, verbose=True) # needs sage.rings.number_field No: inconsistency at the 2 ordinary primes dividing 13 - Frobenius discriminants mod squares: [-3, -1] (False, 13)
from sage.schemes.elliptic_curves.Qcurves import Step4Test R.<x> = PolynomialRing(QQ) K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field K([-621,778,138,-178]), K([9509,2046,-24728,10380])]) Step4Test(E, 100, verbose=True) # needs sage.rings.number_field
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.Qcurves import Step4Test >>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1) >>> K = NumberField(R([Integer(3), Integer(0), -Integer(5), Integer(0), Integer(1)]), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field >>> E = EllipticCurve([K([-Integer(3),-Integer(4),Integer(1),Integer(1)]), K([Integer(4),-Integer(1),-Integer(1),Integer(0)]), K([-Integer(2),Integer(0),Integer(1),Integer(0)]), # needs sage.rings.number_field ... K([-Integer(621),Integer(778),Integer(138),-Integer(178)]), K([Integer(9509),Integer(2046),-Integer(24728),Integer(10380)])]) >>> Step4Test(E, Integer(100), verbose=True) # needs sage.rings.number_field No: inconsistency at the 2 ordinary primes dividing 13 - Frobenius discriminants mod squares: [-3, -1] (False, 13)
A
-curve over a sextic field (with LMFDB label ‘6.6.1259712.1-64.1-a6’) passes this test for all :sage: from sage.schemes.elliptic_curves.Qcurves import Step4Test sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(R([-3, 0, 9, 0, -6, 0, 1])) # needs sage.rings.number_field sage: E = EllipticCurve([K([1,-3,0,1,0,0]), K([5,-3,-6,1,1,0]), # needs sage.rings.number_field ....: K([1,-3,0,1,0,0]), K([-139,-129,331,277,-76,-63]), ....: K([2466,1898,-5916,-4582,1361,1055])]) sage: Step4Test(E, 100, verbose=True) # needs sage.rings.number_field (True, 0)
from sage.schemes.elliptic_curves.Qcurves import Step4Test R.<x> = PolynomialRing(QQ) K.<a> = NumberField(R([-3, 0, 9, 0, -6, 0, 1])) # needs sage.rings.number_field E = EllipticCurve([K([1,-3,0,1,0,0]), K([5,-3,-6,1,1,0]), # needs sage.rings.number_field K([1,-3,0,1,0,0]), K([-139,-129,331,277,-76,-63]), K([2466,1898,-5916,-4582,1361,1055])]) Step4Test(E, 100, verbose=True) # needs sage.rings.number_field
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.Qcurves import Step4Test >>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1) >>> K = NumberField(R([-Integer(3), Integer(0), Integer(9), Integer(0), -Integer(6), Integer(0), Integer(1)]), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field >>> E = EllipticCurve([K([Integer(1),-Integer(3),Integer(0),Integer(1),Integer(0),Integer(0)]), K([Integer(5),-Integer(3),-Integer(6),Integer(1),Integer(1),Integer(0)]), # needs sage.rings.number_field ... K([Integer(1),-Integer(3),Integer(0),Integer(1),Integer(0),Integer(0)]), K([-Integer(139),-Integer(129),Integer(331),Integer(277),-Integer(76),-Integer(63)]), ... K([Integer(2466),Integer(1898),-Integer(5916),-Integer(4582),Integer(1361),Integer(1055)])]) >>> Step4Test(E, Integer(100), verbose=True) # needs sage.rings.number_field (True, 0)
- sage.schemes.elliptic_curves.Qcurves.conjugacy_test(jlist, verbose=False)[source]#
Test whether a list of algebraic numbers contains a complete conjugacy class of 2-power degree.
INPUT:
jlist
(list): a list of algebraic numbers in the same fieldverbose
(boolean, defaultFalse
): verbosity flag
OUTPUT:
A possibly empty list of irreducible polynomials over
of 2-power degree all of whose roots are in the list.EXAMPLES:
sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.Qcurves import conjugacy_test sage: conjugacy_test([3]) [x - 3] sage: K.<a> = QuadraticField(2) sage: conjugacy_test([K(3), a]) [x - 3] sage: conjugacy_test([K(3), 3 + a]) [x - 3] sage: conjugacy_test([3 + a]) [] sage: conjugacy_test([3 + a, 3 - a]) [x^2 - 6*x + 7] sage: x = polygen(QQ) sage: f = x^3 - 3 sage: K.<a> = f.splitting_field() sage: js = f.roots(K, multiplicities=False) sage: conjugacy_test(js) [] sage: f = x^4 - 3 sage: K.<a> = NumberField(f) sage: js = f.roots(K, multiplicities=False) sage: conjugacy_test(js) [] sage: K.<a> = f.splitting_field() sage: js = f.roots(K, multiplicities=False) sage: conjugacy_test(js) [x^4 - 3]
# needs sage.rings.number_field from sage.schemes.elliptic_curves.Qcurves import conjugacy_test conjugacy_test([3]) K.<a> = QuadraticField(2) conjugacy_test([K(3), a]) conjugacy_test([K(3), 3 + a]) conjugacy_test([3 + a]) conjugacy_test([3 + a, 3 - a]) x = polygen(QQ) f = x^3 - 3 K.<a> = f.splitting_field() js = f.roots(K, multiplicities=False) conjugacy_test(js) f = x^4 - 3 K.<a> = NumberField(f) js = f.roots(K, multiplicities=False) conjugacy_test(js) K.<a> = f.splitting_field() js = f.roots(K, multiplicities=False) conjugacy_test(js)
>>> from sage.all import * >>> # needs sage.rings.number_field >>> from sage.schemes.elliptic_curves.Qcurves import conjugacy_test >>> conjugacy_test([Integer(3)]) [x - 3] >>> K = QuadraticField(Integer(2), names=('a',)); (a,) = K._first_ngens(1) >>> conjugacy_test([K(Integer(3)), a]) [x - 3] >>> conjugacy_test([K(Integer(3)), Integer(3) + a]) [x - 3] >>> conjugacy_test([Integer(3) + a]) [] >>> conjugacy_test([Integer(3) + a, Integer(3) - a]) [x^2 - 6*x + 7] >>> x = polygen(QQ) >>> f = x**Integer(3) - Integer(3) >>> K = f.splitting_field(names=('a',)); (a,) = K._first_ngens(1) >>> js = f.roots(K, multiplicities=False) >>> conjugacy_test(js) [] >>> f = x**Integer(4) - Integer(3) >>> K = NumberField(f, names=('a',)); (a,) = K._first_ngens(1) >>> js = f.roots(K, multiplicities=False) >>> conjugacy_test(js) [] >>> K = f.splitting_field(names=('a',)); (a,) = K._first_ngens(1) >>> js = f.roots(K, multiplicities=False) >>> conjugacy_test(js) [x^4 - 3]
- sage.schemes.elliptic_curves.Qcurves.is_Q_curve(E, maxp=100, certificate=False, verbose=False)[source]#
Return whether
E
is a -curve, with optional certificate.INPUT:
E
(elliptic curve) – an elliptic curve over a number field.maxp
(int, default 100): bound on primes used for checking necessary local conditions. The result will not depend on this, but using a larger value may returnFalse
faster.certificate
(bool, defaultFalse
): ifTrue
then a second value is returned giving a certificate for the -curve property.
OUTPUT:
If
certificate
isFalse
: eitherTrue
(if is a -curve), orFalse
.If
certificate
isTrue
: a tuple consisting of a boolean flag as before and a certificate, defined as follows:when the flag is
True
, so is a -curve:either {‘CM’:
} where is a negative discriminant, when has potential CM with discriminant ;otherwise {‘CM’:
, ‘core_poly’: , ‘rho’: , ‘r’: , ‘N’: }, when is a non-CM -curve, where the core polynomial is an irreducible monic polynomial over of degree , all of whose roots are -invariants of curves isogenous to , the core level is a square-free integer with prime factors which is the LCM of the degrees of the isogenies between these conjugates. For example, if there exists a curve isogenous to with , then the certificate is {‘CM’:0, ‘r’:0, ‘rho’:0, ‘core_poly’: x-j, ‘N’:1}.
when the flag is
False
, so is not a -curve, the certificate is a prime such that the reductions of at the primes dividing are inconsistent with the property of being a -curve. See the ALGORITHM section for details.
ALGORITHM:
See [CrNa2020] for details.
1. If
has rational -invariant, or has CM, then returnTrue
.2. Replace
by a curve defined over . Let be the conductor norm.3. For all primes
check that the valuations of at all are either all negative or all non-negative; if not, returnFalse
.4. For
, , check that either is ordinary mod for all , or is supersingular mod for all ; if neither, returnFalse
. If all are ordinary, check that the integers have the same square-free part; if not, returnFalse
.5. Compute the
-isogeny class of using the “heuristic” option (which is faster, but not guaranteed to be complete). Check whether the set of -invariants of curves in the class of -power degree contains a complete Galois orbit. If so, returnTrue
.6. Otherwise repeat step 4 for more primes, and if still undecided, repeat Step 5 without the “heuristic” option, to get the complete
-isogeny class (which will probably be no bigger than before). Now returnTrue
if the set of -invariants of curves in the class contains a complete Galois orbit, otherwise returnFalse
.EXAMPLES:
A non-CM curve over
and a CM curve over are both trivially -curves:sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve sage: E = EllipticCurve([1,2,3,4,5]) sage: flag, cert = is_Q_curve(E, certificate=True) sage: flag True sage: cert {'CM': 0, 'N': 1, 'core_poly': x, 'r': 0, 'rho': 0} sage: E = EllipticCurve(j=8000) sage: flag, cert = is_Q_curve(E, certificate=True) sage: flag True sage: cert {'CM': -8}
from sage.schemes.elliptic_curves.Qcurves import is_Q_curve E = EllipticCurve([1,2,3,4,5]) flag, cert = is_Q_curve(E, certificate=True) flag cert E = EllipticCurve(j=8000) flag, cert = is_Q_curve(E, certificate=True) flag cert
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.Qcurves import is_Q_curve >>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)]) >>> flag, cert = is_Q_curve(E, certificate=True) >>> flag True >>> cert {'CM': 0, 'N': 1, 'core_poly': x, 'r': 0, 'rho': 0} >>> E = EllipticCurve(j=Integer(8000)) >>> flag, cert = is_Q_curve(E, certificate=True) >>> flag True >>> cert {'CM': -8}
A non-
-curve over a quartic field. The local data at bad primes above is inconsistent:sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field sage: E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field ....: K([-621,778,138,-178]), K([9509,2046,-24728,10380])]) sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + (a^3+a^2-4*a-3)*x*y + (a^2-2)*y = x^3 + (-a^2-a+4)*x^2 + (-178*a^3+138*a^2+778*a-621)*x + (10380*a^3-24728*a^2+2046*a+9509) over Number Field in a with defining polynomial x^4 - 5*x^2 + 3 is a Q-curve No: inconsistency at the 2 primes dividing 3 - potentially multiplicative: [True, False] (False, 3)
from sage.schemes.elliptic_curves.Qcurves import is_Q_curve R.<x> = PolynomialRing(QQ) K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field K([-621,778,138,-178]), K([9509,2046,-24728,10380])]) is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.Qcurves import is_Q_curve >>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1) >>> K = NumberField(R([Integer(3), Integer(0), -Integer(5), Integer(0), Integer(1)]), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field >>> E = EllipticCurve([K([-Integer(3),-Integer(4),Integer(1),Integer(1)]), K([Integer(4),-Integer(1),-Integer(1),Integer(0)]), K([-Integer(2),Integer(0),Integer(1),Integer(0)]), # needs sage.rings.number_field ... K([-Integer(621),Integer(778),Integer(138),-Integer(178)]), K([Integer(9509),Integer(2046),-Integer(24728),Integer(10380)])]) >>> is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + (a^3+a^2-4*a-3)*x*y + (a^2-2)*y = x^3 + (-a^2-a+4)*x^2 + (-178*a^3+138*a^2+778*a-621)*x + (10380*a^3-24728*a^2+2046*a+9509) over Number Field in a with defining polynomial x^4 - 5*x^2 + 3 is a Q-curve No: inconsistency at the 2 primes dividing 3 - potentially multiplicative: [True, False] (False, 3)
A non-
-curve over a quadratic field. The local data at bad primes is consistent, but the local test at good primes above is not:sage: K.<a> = NumberField(R([-10, 0, 1])) # needs sage.rings.number_field sage: E = EllipticCurve([K([0,1]), K([-1,-1]), K([0,0]), # needs sage.rings.number_field ....: K([-236,40]), K([-1840,464])]) sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + a*x*y = x^3 + (-a-1)*x^2 + (40*a-236)*x + (464*a-1840) over Number Field in a with defining polynomial x^2 - 10 is a Q-curve Applying local tests at good primes above p<=100 No: inconsistency at the 2 ordinary primes dividing 13 - Frobenius discriminants mod squares: [-1, -3] No: local test at p=13 failed (False, 13)
K.<a> = NumberField(R([-10, 0, 1])) # needs sage.rings.number_field E = EllipticCurve([K([0,1]), K([-1,-1]), K([0,0]), # needs sage.rings.number_field K([-236,40]), K([-1840,464])]) is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field
>>> from sage.all import * >>> K = NumberField(R([-Integer(10), Integer(0), Integer(1)]), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field >>> E = EllipticCurve([K([Integer(0),Integer(1)]), K([-Integer(1),-Integer(1)]), K([Integer(0),Integer(0)]), # needs sage.rings.number_field ... K([-Integer(236),Integer(40)]), K([-Integer(1840),Integer(464)])]) >>> is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + a*x*y = x^3 + (-a-1)*x^2 + (40*a-236)*x + (464*a-1840) over Number Field in a with defining polynomial x^2 - 10 is a Q-curve Applying local tests at good primes above p<=100 No: inconsistency at the 2 ordinary primes dividing 13 - Frobenius discriminants mod squares: [-1, -3] No: local test at p=13 failed (False, 13)
A quadratic
-curve with CM discriminant ( -invariant not in ):sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(R([-1, -1, 1])) # needs sage.rings.number_field sage: E = EllipticCurve([K([1,0]), K([-1,0]), K([0,1]), K([0,-2]), K([0,1])]) # needs sage.rings.number_field sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + x*y + a*y = x^3 + (-1)*x^2 + (-2*a)*x + a over Number Field in a with defining polynomial x^2 - x - 1 is a Q-curve Yes: E is CM (discriminant -15) (True, {'CM': -15})
from sage.schemes.elliptic_curves.Qcurves import is_Q_curve R.<x> = PolynomialRing(QQ) K.<a> = NumberField(R([-1, -1, 1])) # needs sage.rings.number_field E = EllipticCurve([K([1,0]), K([-1,0]), K([0,1]), K([0,-2]), K([0,1])]) # needs sage.rings.number_field is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.Qcurves import is_Q_curve >>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1) >>> K = NumberField(R([-Integer(1), -Integer(1), Integer(1)]), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field >>> E = EllipticCurve([K([Integer(1),Integer(0)]), K([-Integer(1),Integer(0)]), K([Integer(0),Integer(1)]), K([Integer(0),-Integer(2)]), K([Integer(0),Integer(1)])]) # needs sage.rings.number_field >>> is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + x*y + a*y = x^3 + (-1)*x^2 + (-2*a)*x + a over Number Field in a with defining polynomial x^2 - x - 1 is a Q-curve Yes: E is CM (discriminant -15) (True, {'CM': -15})
An example over
. The -invariant is in , so computations will be done over that field, and in fact there is an isogenous curve with rational , so we have a so-called rational -curve:sage: # needs sage.rings.number_field sage: K.<a> = NumberField(R([1, 0, -4, 0, 1])) sage: E = EllipticCurve([K([-2,-4,1,1]), K([0,1,0,0]), K([0,1,0,0]), ....: K([-4780,9170,1265,-2463]), ....: K([163923,-316598,-43876,84852])]) sage: flag, cert = is_Q_curve(E, certificate=True) sage: flag True sage: cert {'CM': 0, 'N': 1, 'core_degs': [1], 'core_poly': x - 85184/3, 'r': 0, 'rho': 0}
# needs sage.rings.number_field K.<a> = NumberField(R([1, 0, -4, 0, 1])) E = EllipticCurve([K([-2,-4,1,1]), K([0,1,0,0]), K([0,1,0,0]), K([-4780,9170,1265,-2463]), K([163923,-316598,-43876,84852])]) flag, cert = is_Q_curve(E, certificate=True) flag cert
>>> from sage.all import * >>> # needs sage.rings.number_field >>> K = NumberField(R([Integer(1), Integer(0), -Integer(4), Integer(0), Integer(1)]), names=('a',)); (a,) = K._first_ngens(1) >>> E = EllipticCurve([K([-Integer(2),-Integer(4),Integer(1),Integer(1)]), K([Integer(0),Integer(1),Integer(0),Integer(0)]), K([Integer(0),Integer(1),Integer(0),Integer(0)]), ... K([-Integer(4780),Integer(9170),Integer(1265),-Integer(2463)]), ... K([Integer(163923),-Integer(316598),-Integer(43876),Integer(84852)])]) >>> flag, cert = is_Q_curve(E, certificate=True) >>> flag True >>> cert {'CM': 0, 'N': 1, 'core_degs': [1], 'core_poly': x - 85184/3, 'r': 0, 'rho': 0}
Over the same field, a so-called strict
-curve which is not isogenous to one with rational , but whose core field is quadratic. In fact the isogeny class over consists of curves, four with conjugate quartic -invariants and with quadratic conjugate -invariants in (but which are not base-changes from the quadratic subfield):sage: # needs sage.rings.number_field sage: E = EllipticCurve([K([0,-3,0,1]), K([1,4,0,-1]), K([0,0,0,0]), ....: K([-2,-16,0,4]), K([-19,-32,4,8])]) sage: flag, cert = is_Q_curve(E, certificate=True) sage: flag True sage: cert {'CM': 0, 'N': 2, 'core_degs': [1, 2], 'core_poly': x^2 - 840064*x + 1593413632, 'r': 1, 'rho': 1}
# needs sage.rings.number_field E = EllipticCurve([K([0,-3,0,1]), K([1,4,0,-1]), K([0,0,0,0]), K([-2,-16,0,4]), K([-19,-32,4,8])]) flag, cert = is_Q_curve(E, certificate=True) flag cert
>>> from sage.all import * >>> # needs sage.rings.number_field >>> E = EllipticCurve([K([Integer(0),-Integer(3),Integer(0),Integer(1)]), K([Integer(1),Integer(4),Integer(0),-Integer(1)]), K([Integer(0),Integer(0),Integer(0),Integer(0)]), ... K([-Integer(2),-Integer(16),Integer(0),Integer(4)]), K([-Integer(19),-Integer(32),Integer(4),Integer(8)])]) >>> flag, cert = is_Q_curve(E, certificate=True) >>> flag True >>> cert {'CM': 0, 'N': 2, 'core_degs': [1, 2], 'core_poly': x^2 - 840064*x + 1593413632, 'r': 1, 'rho': 1}