Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CM elliptic curves missing isogenies #36786

Merged
merged 5 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
#36780: CM elliptic curves missing isogenies
  • Loading branch information
JohnCremona committed Nov 27, 2023
commit 2fd3b343875e248d2eaf32b1272e7fddb41f257b
24 changes: 18 additions & 6 deletions src/sage/schemes/elliptic_curves/ell_number_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -2919,6 +2919,18 @@ class number is only `3` is that the class also contains three
sage: E = EllipticCurve([a+1, 1, 1, 0, 0])
sage: C = E.isogeny_class(); len(C) # long time
4

Check that :issue:`36780` is fixed::

sage: L5.<r5> = NumberField(x^2-5)
sage: F = EllipticCurve(L5,[0,-4325477943600 *r5-4195572876000])
sage: F.isogeny_class().matrix()
[ 1 25 75 3 5 15]
[25 1 3 75 5 15]
[75 3 1 25 15 5]
[ 3 75 25 1 15 5]
[ 5 5 15 15 1 3]
[15 15 5 5 3 1]
"""
try:
return self._isoclass
Expand Down Expand Up @@ -3283,10 +3295,10 @@ def reducible_primes(self, algorithm='Billerey', max_l=None,
For curves without CM the list returned is exactly the finite
set of primes `\ell` for which the mod-`\ell` Galois
representation is reducible. For curves with CM this set is
infinite; we return a finite list of primes `\ell` such that
every curve isogenous to this curve can be obtained by a
finite sequence of isogenies of degree one of the primes in
the list.
infinite; we return a (not necessarily minimal) finite list
of primes `\ell` such that every curve isogenous to this curve
can be obtained by a finite sequence of isogenies of degree one
of the primes in the list.

INPUT:

Expand Down Expand Up @@ -3328,13 +3340,13 @@ def reducible_primes(self, algorithm='Billerey', max_l=None,
sage: rho.reducible_primes() # CM curves always return [0]
[0]
sage: E.reducible_primes()
[2]
[2, 3, 5]
sage: E = EllipticCurve_from_j(K(0)) # CM but NOT over K
sage: rho = E.galois_representation()
sage: rho.reducible_primes() # long time
[2, 3]
sage: E.reducible_primes()
[2, 3]
[2, 3, 5, 7, 11, 13]
sage: E = EllipticCurve_from_j(K(2268945/128)).global_minimal_model() # c.f. [Sut2012]
sage: rho = E.galois_representation()
sage: rho.isogeny_bound() # ..but there is no 7-isogeny, long time
Expand Down
24 changes: 13 additions & 11 deletions src/sage/schemes/elliptic_curves/gal_reps_number_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,37 +740,39 @@ def _exceptionals(E, L, patience=1000):

def _over_numberfield(E):
r"""
Return `E`, defined over a ``NumberField`` object.
Return `E`, defined over an absolute ``NumberField``.

This is necessary since if `E` is defined over `\QQ`, then we
cannot use Sage commands available for number fields.
cannot use Sage commands available for number fields, and if the
base field is relative then other problems result.

INPUT:

- ``E`` -- EllipticCurve over a number field.

OUTPUT:

- If `E` is defined over a NumberField, returns E.
- If `E` is defined over an absolute number field, returns `E`.

- If `E` is defined over QQ, returns E defined over the NumberField QQ.
- If `E` is defined over a relative number field, returns `E` defined over the absolute base field.

- If `E` is defined over `\QQ`, returns `E` defined over the number field `\QQ`.

EXAMPLES::

sage: E = EllipticCurve([1, 2])
sage: sage.schemes.elliptic_curves.gal_reps_number_field._over_numberfield(E)
Elliptic Curve defined by y^2 = x^3 + x + 2 over Number Field in a with defining polynomial x
"""

"""
K = E.base_field()

if K == QQ:
x = QQ['x'].gen()
K = NumberField(x, 'a')
E = E.change_ring(K)

return E

from sage.rings.polynomial.polynomial_ring import polygen
K = NumberField(polygen(QQ), 'a')
else:
K = K.absolute_field('a')
return E.change_ring(K)

def deg_one_primes_iter(K, principal_only=False):
r"""
Expand Down
61 changes: 40 additions & 21 deletions src/sage/schemes/elliptic_curves/isogeny_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,8 @@ def isogeny_degrees_cm(E, verbose=False):

A finite list of primes `\ell` such that every curve isogenous to
this curve can be obtained by a finite sequence of isogenies of
degree one of the primes in the list.
degree one of the primes in the list. This list is not
necessarily minimal.

ALGORITHM:

Expand Down Expand Up @@ -1188,8 +1189,20 @@ def isogeny_degrees_cm(E, verbose=False):
downward split primes: {2, 3}
downward inert primes: {5}
primes generating the class group: [2]
Complete set of primes: {2, 3, 5}
[2, 3, 5]
Set of primes before filtering: {2, 3, 5}
List of primes after filtering: [2, 3]
[2, 3]

TESTS:

Check that :issue:`36780` is fixed::

sage: L5.<r5> = NumberField(x^2-5)
sage: E = EllipticCurve(L5,[0,-4325477943600 *r5-4195572876000])
sage: from sage.schemes.elliptic_curves.isogeny_class import isogeny_degrees_cm
sage: isogeny_degrees_cm(E)
[3, 5]

"""
if not E.has_cm():
raise ValueError("possible_isogeny_degrees_cm(E) requires E to be an elliptic curve with CM")
Expand All @@ -1205,6 +1218,11 @@ def isogeny_degrees_cm(E, verbose=False):
n = E.base_field().absolute_degree()
if not E.has_rational_cm():
n *= 2
# For discriminants with extra units there's an extra factor in the class number formula:
if d==-4:
n *= 2
if d==-3:
n *= 3
divs = n.divisors()

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

# Compute the ramified primes
# (a) ramified primes

ram_l = d.odd_part().prime_factors()

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

else:

# Find the "upward" primes (index divided by l):
# "Upward" primes (index divided by l):

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

# Find the "downward" primes (index multiplied by l, class
# number multiplied by l-kronecker_symbol(d,l)):

# (a) ramified primes; the suborder has class number l*h, so l
# must divide n/2h:
# "Downward" ramified primes; index multiplied by l, class
# number multiplied by l, so l must divide n/2h:

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

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

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

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

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

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

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

if verbose:
print("Complete set of primes: %s" % L)

return sorted(L)
print("Set of primes before filtering: %s" % L)

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

def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None,
num_l=None, exact=True, verbose=False):
Expand Down Expand Up @@ -1434,8 +1452,9 @@ def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None,
downward split primes: {2, 3}
downward inert primes: {5}
primes generating the class group: [2]
Complete set of primes: {2, 3, 5}
[2, 3, 5]
Set of primes before filtering: {2, 3, 5}
List of primes after filtering: [2, 3]
[2, 3]
"""
if E.has_cm():
return isogeny_degrees_cm(E, verbose)
Expand Down