Skip to content

Commit a46575d

Browse files
author
Release Manager
committed
gh-36786: CM elliptic curves missing isogenies Fixes #36780. For elliptic curves over number fields, with j-invariant 0 and 1728, the function isogeny_degrees_cm was forgetting to multiply a degree bound by 3 or 2 respectively (half the number of units), resulting in some isogenies being missed. - [ x] The title is concise, informative, and self-explanatory. - [ x] The description explains in detail what this PR is about. - [ x] I have linked a relevant issue or discussion. - [ x] I have created tests covering the changes. - [ x] I have updated the documentation accordingly. URL: #36786 Reported by: John Cremona Reviewer(s): Frédéric Chapoton
2 parents 1aca3a8 + 7621f8e commit a46575d

File tree

3 files changed

+70
-37
lines changed

3 files changed

+70
-37
lines changed

src/sage/schemes/elliptic_curves/ell_number_field.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2919,6 +2919,18 @@ class number is only `3` is that the class also contains three
29192919
sage: E = EllipticCurve([a+1, 1, 1, 0, 0])
29202920
sage: C = E.isogeny_class(); len(C) # long time
29212921
4
2922+
2923+
Check that :issue:`36780` is fixed::
2924+
2925+
sage: L5.<r5> = NumberField(x^2-5)
2926+
sage: F = EllipticCurve(L5,[0,-4325477943600 *r5-4195572876000])
2927+
sage: F.isogeny_class().matrix()
2928+
[ 1 25 75 3 5 15]
2929+
[25 1 3 75 5 15]
2930+
[75 3 1 25 15 5]
2931+
[ 3 75 25 1 15 5]
2932+
[ 5 5 15 15 1 3]
2933+
[15 15 5 5 3 1]
29222934
"""
29232935
try:
29242936
return self._isoclass
@@ -3283,10 +3295,10 @@ def reducible_primes(self, algorithm='Billerey', max_l=None,
32833295
For curves without CM the list returned is exactly the finite
32843296
set of primes `\ell` for which the mod-`\ell` Galois
32853297
representation is reducible. For curves with CM this set is
3286-
infinite; we return a finite list of primes `\ell` such that
3287-
every curve isogenous to this curve can be obtained by a
3288-
finite sequence of isogenies of degree one of the primes in
3289-
the list.
3298+
infinite; we return a (not necessarily minimal) finite list
3299+
of primes `\ell` such that every curve isogenous to this curve
3300+
can be obtained by a finite sequence of isogenies of degree one
3301+
of the primes in the list.
32903302
32913303
INPUT:
32923304
@@ -3328,7 +3340,7 @@ def reducible_primes(self, algorithm='Billerey', max_l=None,
33283340
sage: rho.reducible_primes() # CM curves always return [0]
33293341
[0]
33303342
sage: E.reducible_primes()
3331-
[2]
3343+
[2, 5]
33323344
sage: E = EllipticCurve_from_j(K(0)) # CM but NOT over K
33333345
sage: rho = E.galois_representation()
33343346
sage: rho.reducible_primes() # long time

src/sage/schemes/elliptic_curves/gal_reps_number_field.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -740,37 +740,39 @@ def _exceptionals(E, L, patience=1000):
740740

741741
def _over_numberfield(E):
742742
r"""
743-
Return `E`, defined over a ``NumberField`` object.
743+
Return `E`, defined over an absolute ``NumberField``.
744744
745745
This is necessary since if `E` is defined over `\QQ`, then we
746-
cannot use Sage commands available for number fields.
746+
cannot use Sage commands available for number fields, and if the
747+
base field is relative then other problems result.
747748
748749
INPUT:
749750
750751
- ``E`` -- EllipticCurve over a number field.
751752
752753
OUTPUT:
753754
754-
- If `E` is defined over a NumberField, returns E.
755+
- If `E` is defined over an absolute number field, returns `E`.
755756
756-
- If `E` is defined over QQ, returns E defined over the NumberField QQ.
757+
- If `E` is defined over a relative number field, returns `E` defined over the absolute base field.
758+
759+
- If `E` is defined over `\QQ`, returns `E` defined over the number field `\QQ`.
757760
758761
EXAMPLES::
759762
760763
sage: E = EllipticCurve([1, 2])
761764
sage: sage.schemes.elliptic_curves.gal_reps_number_field._over_numberfield(E)
762765
Elliptic Curve defined by y^2 = x^3 + x + 2 over Number Field in a with defining polynomial x
763-
"""
764766
767+
"""
765768
K = E.base_field()
766769

767770
if K == QQ:
768-
x = QQ['x'].gen()
769-
K = NumberField(x, 'a')
770-
E = E.change_ring(K)
771-
772-
return E
773-
771+
from sage.rings.polynomial.polynomial_ring import polygen
772+
K = NumberField(polygen(QQ), 'a')
773+
else:
774+
K = K.absolute_field('a')
775+
return E.change_ring(K)
774776

775777
def deg_one_primes_iter(K, principal_only=False):
776778
r"""

src/sage/schemes/elliptic_curves/isogeny_class.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,8 @@ def isogeny_degrees_cm(E, verbose=False):
11351135
11361136
A finite list of primes `\ell` such that every curve isogenous to
11371137
this curve can be obtained by a finite sequence of isogenies of
1138-
degree one of the primes in the list.
1138+
degree one of the primes in the list. This list is not
1139+
necessarily minimal.
11391140
11401141
ALGORITHM:
11411142
@@ -1188,8 +1189,20 @@ def isogeny_degrees_cm(E, verbose=False):
11881189
downward split primes: {2, 3}
11891190
downward inert primes: {5}
11901191
primes generating the class group: [2]
1191-
Complete set of primes: {2, 3, 5}
1192-
[2, 3, 5]
1192+
Set of primes before filtering: {2, 3, 5}
1193+
List of primes after filtering: [2, 3]
1194+
[2, 3]
1195+
1196+
TESTS:
1197+
1198+
Check that :issue:`36780` is fixed::
1199+
1200+
sage: L5.<r5> = NumberField(x^2-5)
1201+
sage: E = EllipticCurve(L5,[0,-4325477943600 *r5-4195572876000])
1202+
sage: from sage.schemes.elliptic_curves.isogeny_class import isogeny_degrees_cm
1203+
sage: isogeny_degrees_cm(E)
1204+
[3, 5]
1205+
11931206
"""
11941207
if not E.has_cm():
11951208
raise ValueError("possible_isogeny_degrees_cm(E) requires E to be an elliptic curve with CM")
@@ -1205,6 +1218,11 @@ def isogeny_degrees_cm(E, verbose=False):
12051218
n = E.base_field().absolute_degree()
12061219
if not E.has_rational_cm():
12071220
n *= 2
1221+
# For discriminants with extra units there's an extra factor in the class number formula:
1222+
if d == -4:
1223+
n *= 2
1224+
if d == -3:
1225+
n *= 3
12081226
divs = n.divisors()
12091227

12101228
data = pari(d).quadclassunit()
@@ -1232,7 +1250,7 @@ def isogeny_degrees_cm(E, verbose=False):
12321250
# of the order O of discriminant d. The latter case can only
12331251
# happen when l^2 divides d.
12341252

1235-
# Compute the ramified primes
1253+
# (a) ramified primes
12361254

12371255
ram_l = d.odd_part().prime_factors()
12381256

@@ -1247,25 +1265,22 @@ def isogeny_degrees_cm(E, verbose=False):
12471265

12481266
else:
12491267

1250-
# Find the "upward" primes (index divided by l):
1268+
# "Upward" primes (index divided by l):
12511269

12521270
L1 = Set([l for l in ram_l if d.valuation(l) > 1])
12531271
L += L1
12541272
if verbose:
12551273
print("upward primes: %s" % L1)
12561274

1257-
# Find the "downward" primes (index multiplied by l, class
1258-
# number multiplied by l-kronecker_symbol(d,l)):
1259-
1260-
# (a) ramified primes; the suborder has class number l*h, so l
1261-
# must divide n/2h:
1275+
# "Downward" ramified primes; index multiplied by l, class
1276+
# number multiplied by l, so l must divide n/2h:
12621277

12631278
L1 = Set([l for l in ram_l if l.divides(n_over_2h)])
12641279
L += L1
12651280
if verbose:
12661281
print("downward ramified primes: %s" % L1)
12671282

1268-
# (b) split primes; the suborder has class number (l-1)*h, so
1283+
# (b) Downward split primes; the suborder has class number (l-1)*h, so
12691284
# l-1 must divide n/2h:
12701285

12711286
L1 = Set([lm1+1 for lm1 in divs
@@ -1274,7 +1289,7 @@ def isogeny_degrees_cm(E, verbose=False):
12741289
if verbose:
12751290
print("downward split primes: %s" % L1)
12761291

1277-
# (c) inert primes; the suborder has class number (l+1)*h, so
1292+
# (c) Downward inert primes; the suborder has class number (l+1)*h, so
12781293
# l+1 must divide n/2h:
12791294

12801295
L1 = Set([lp1-1 for lp1 in divs
@@ -1283,10 +1298,9 @@ def isogeny_degrees_cm(E, verbose=False):
12831298
if verbose:
12841299
print("downward inert primes: %s" % L1)
12851300

1286-
# Now find primes represented by each form of discriminant d.
1287-
# In the rational CM case, we use all forms associated to
1288-
# generators of the class group, otherwise only forms of order
1289-
# 2:
1301+
# Horizontal primes (rational CM only): same order, degrees are
1302+
# all integers represented by some binary quadratic form of
1303+
# discriminant d, so we find a prime represented by each form.
12901304

12911305
if E.has_rational_cm():
12921306
from sage.quadratic_forms.binary_qf import BinaryQF
@@ -1300,10 +1314,14 @@ def isogeny_degrees_cm(E, verbose=False):
13001314
# Return sorted list
13011315

13021316
if verbose:
1303-
print("Complete set of primes: %s" % L)
1304-
1305-
return sorted(L)
1317+
print("Set of primes before filtering: %s" % L)
13061318

1319+
# This filter will quickly eliminate most false entries in the set
1320+
from .gal_reps_number_field import Frobenius_filter
1321+
L = Frobenius_filter(E, sorted(L))
1322+
if verbose:
1323+
print("List of primes after filtering: %s" % L)
1324+
return L
13071325

13081326
def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None,
13091327
num_l=None, exact=True, verbose=False):
@@ -1434,8 +1452,9 @@ def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None,
14341452
downward split primes: {2, 3}
14351453
downward inert primes: {5}
14361454
primes generating the class group: [2]
1437-
Complete set of primes: {2, 3, 5}
1438-
[2, 3, 5]
1455+
Set of primes before filtering: {2, 3, 5}
1456+
List of primes after filtering: [2, 3]
1457+
[2, 3]
14391458
"""
14401459
if E.has_cm():
14411460
return isogeny_degrees_cm(E, verbose)

0 commit comments

Comments
 (0)