Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Merge branch 'u/chapoton/9320' in 7.3.rc0
Browse files Browse the repository at this point in the history
  • Loading branch information
Frédéric Chapoton committed Jul 29, 2016
2 parents c4f3c93 + 7a131d0 commit 60e9a78
Show file tree
Hide file tree
Showing 2 changed files with 358 additions and 7 deletions.
358 changes: 355 additions & 3 deletions src/sage/schemes/elliptic_curves/ell_number_field.py
Expand Up @@ -90,10 +90,14 @@
from .ell_generic import is_EllipticCurve
from .ell_point import EllipticCurvePoint_number_field
from .constructor import EllipticCurve
from sage.rings.all import Ring, PolynomialRing, ZZ, QQ, RealField, Integer
from sage.rings.all import PolynomialRing, ZZ, QQ, RealField, Integer
from sage.misc.all import cached_method, verbose, forall, prod, union, flatten
from sage.arith.misc import legendre_symbol, valuation, hilbert_symbol, gcd
from sage.rings.polynomial.polynomial_ring import polygen

from six import reraise as raise_


class EllipticCurve_number_field(EllipticCurve_field):
r"""
Elliptic curve over a number field.
Expand Down Expand Up @@ -2014,6 +2018,355 @@ def reduction(self,place):
Fv = OK.residue_field(place)
return self.change_ring(Fv)

@cached_method
def root_number(self, P=None):
r"""
Return the global or local root number of this elliptic curve.
This is 1 if the order of vanishing of the L-function L(E,s) at 1
is even, and -1 if it is odd.
The computations are based on [Rohr]_, [Koba]_ for primes `P|3`
and [Dokch]_ for primes `P|2`.
INPUT:
- ``P`` - prime ideal, (default:``None``) if given, return the local
root number at this ideal, otherwise return the global root
number
OUTPUT:
The global or local root number of the elliptic curve, either 1 or -1.
Over `\QQ`, the PARI C-library ``ellrootno`` implementation is used.
Otherwise, the general number field implementation is used.
EXAMPLES:
Finding some global root numbers::
sage: EllipticCurve('11a1').root_number()
1
sage: EllipticCurve('37a1').root_number()
-1
sage: EllipticCurve('389a1').root_number()
1
sage: EllipticCurve('208b1').root_number()
-1
The output is a sage integer::
sage: type(EllipticCurve('389a1').root_number())
<type 'sage.rings.integer.Integer'>
Finding local root numbers of a curve::
sage: E = EllipticCurve('100a1')
sage: E.root_number(2)
-1
sage: E.root_number(5)
1
sage: E.root_number(7)
1
The root number is cached::
sage: E.root_number(2) is E.root_number(2)
True
sage: E.root_number()
1
The root number can be calculated over number fields::
sage: K.<a> = NumberField(x^4+2)
sage: E = EllipticCurve(K, [1, a, 0, 1+a, 0])
sage: E.root_number()
1
sage: E.root_number(K.ideal(a+1))
1
sage: K.<a> = NumberField(x^2-2)
sage: E = EllipticCurve(K, [0,2,0,2*a+4,2*a+3])
sage: E.root_number()
1
REFERENCES:
.. [Rohr] D. Rohrlich "Galois theory, elliptic curves, and root numbers"
.. [Koba] S. Kobayashi "The local root number of elliptic curves with wild ramification"
.. [Dokch] T. and V. Dokchitser "Root numbers and parity ranks of elliptic curves", :arxiv:`0906.1815`
"""
# the case of base field QQ is tackled by ell_rational_field
# here is the generic implementation only

if P is None:
# contribution from places at infinity
s = self.base_field().signature()
rn = (-1) ** (s[0] + s[1])
# contribution from places where E has bad reduction
for p in self.base_ring()(self.discriminant()).support():
rn = self._root_number_local(p) * rn
return rn

return self._root_number_local(P)

def _root_number_local(E, P):
r"""
Returns the local root number of this elliptic curve at `P`.
ALGORITHM:
The computation for primes not dividing 2 or 3 is based on [Rohr]_.
INPUT:
- ``P``- a prime ideal
OUTPUT:
The local root number of the elliptic curve at the prime ideal, either
1 or -1.
EXAMPLES::
sage: K.<a> = NumberField(x^4+2)
sage: E = EllipticCurve(K, [1, a, 0, 1+a, 0])
sage: E._root_number_local(K.ideal(a+1))
1
"""
K = E.base_field()
if K is QQ and P in QQ:
P = ZZ.ideal(P)
d = E.local_data(P, algorithm='generic')
if d.has_good_reduction() or d.has_nonsplit_multiplicative_reduction():
return 1
elif d.has_split_multiplicative_reduction():
return -1
else: # additive reduction
p = P.gen() if K is QQ else P.smallest_integer()
j = E.j_invariant()
jv = j.valuation(P) if not K is QQ else valuation(j, p)
if jv < 0:
# potential multiplicative reduction
if K is QQ:
return hilbert_symbol(-1, -E.c6(), p)
return K.hilbert_symbol(-1, -E.c6(), p)
# return hilbert_symbol_magma(-1, -E.c6(), P)
else:
# potential good reduction
if p == 2: # prime | 2
return E._root_number_local_2(P)
if p == 3: # prime | 3
return E._root_number_local_3(P)

if K is QQ:
f = 1
e = 12 / gcd(12, valuation(E.discriminant(), p))
else:
f = P.residue_class_degree()
e = 12 / gcd(12, E.discriminant().valuation(P))

if f % 2 == 0 or e == 1:
eps = 1
elif e == 2 or e == 6:
eps = legendre_symbol(-1, p)
elif e == 3:
eps = legendre_symbol(-3, p)
elif e == 4:
eps = legendre_symbol(-2, p)
return eps

def _root_number_local_3(E, P):
r"""
Returns the local root number of this elliptic curve at `P`
where `P` is a prime ideal dividing 3 at which this elliptic
curve has (bad) potential good reduction.
ALGORITHM:
The computation for primes dividing 3 is based on [Koba]_.
INPUT:
- ``P`` - a prime ideal dividing 3
OUTPUT:
The local root number of the elliptic curve at the prime ideal.
EXAMPLES::
sage: K.<a> = NumberField(x^4+2)
sage: E = EllipticCurve(K, [1, a, 0, 1+a, 0])
sage: E._root_number_local(K.ideal(a+1)) # indirect doctest
1
sage: K.<r> = NumberField(x^2-x+1)
sage: E = EllipticCurve([r-1, r, 1, r-1, -1])
sage: P3 = K.ideal(2*r-1)
sage: P3.is_prime() and P3.norm() == 3
True
sage: E.has_additive_reduction(P3)
True
sage: E.root_number(P3) # indirect doctest
1
"""
def _val(a, P):
if P.base_ring() is ZZ:
return valuation(a, P.gen())
return a.valuation(P)

def quadr_residue_symbol(a):
return Kr(a).is_square() and 1 or -1

def quadr_symbol(a):
av = _val(a, P)
if av % 2 == 1:
return -1
if P.base_ring() is ZZ:
pi = P.gen()
else:
pi = P.number_field().uniformizer(P)
b = a / pi ** av
return quadr_residue_symbol(b)
# assume potential good reduction
Es = E.local_data(P, algorithm='generic').minimal_model(reduce=False)
Es = Es.short_weierstrass_model(complete_cube=False)

disc = Es.discriminant()
vD = _val(disc, P)
Kr = P.residue_field()

ks = str(Es.kodaira_symbol(P))
if ks == 'I0' or ks == 'I0*':
assert vD % 2 == 0, "error -- valuation of discriminant should be even"
return quadr_residue_symbol(-1) ** (vD / 2)
elif ks == 'III' or ks == 'III*':
return quadr_residue_symbol(-2)
else:
assert ks == 'II' or ks == 'II*' or ks == 'IV' or ks == 'IV*', "error -- unexpected kodaira symbol"
d = quadr_symbol(disc)
c = Es.a6()
cv = _val(c, P)
assert cv % 3 != 0, "error -- 3 should not divide the valuation of the constant term anymore"
K = P.number_field()
if K is QQ:
hs = hilbert_symbol(disc, c, P.gen())
else:
hs = K.hilbert_symbol(disc, c, P)
qr1 = quadr_residue_symbol(cv) ** vD
qr2 = quadr_residue_symbol(-1) ** (vD * (vD - 1) / 2)
return d * hs * qr1 * qr2

def _root_number_local_2(E, P):
r"""
Returns the local root number of this elliptic curve at `P`
where `P` is a prime ideal dividing 2 at which this elliptic
curve has (bad) potential good reduction.
ALGORITHM:
The computation for primes dividing 2 is based on [Dokch]_.
INPUT:
- ``P`` - a prime ideal dividing 2
OUTPUT:
The local root number of the elliptic curve at the prime ideal.
EXAMPLES::
sage: K.<i> = QuadraticField(-1)
sage: E = EllipticCurve([1+i, 1+i, 0, i, 0])
sage: P2 = K.ideal(1+i)
sage: P2.is_prime() and P2.norm() == 2
True
sage: E.has_additive_reduction(P2)
True
sage: E.root_number(P2) # indirect doctest
-1
"""
K = E.base_field()
rn = -1 if K is QQ else (-1) ** (P.residue_class_degree() *
P.ramification_index())

def _val(a, P):
if P.base_ring() is ZZ:
return valuation(a, P.gen())
return a.valuation(P)

def _change_ring(F, els):
L = F.absolute_field('l')
fromL, toL = L.structure()
PL = L.ideal([toL(pgen) for pgen in P.gens()])
EL = EllipticCurve(L, [toL(a) for a in E.ainvs()])
return (EL, PL, [toL(e) for e in els])

def _H(E, PO, ell=2):
H = 1
L = [(ZZ.ideal(2), 1)] if PO.base_ring() is ZZ else PO.factor()
for P, _ in L:
t = E.tamagawa_number(P)
cv = valuation(t, ell) + (0 if ell == 3 else _u_of_E(E, P))
if cv % 2:
H *= -1
return H

def _Hp(E, r, PO, ell=2):
# translate with two isogeny
E = E.change_weierstrass_model(1, r, 0, 0)
# assert E.a1() == 0 and E.a3() == 0 # really ?
E = EllipticCurve(E.base_field(), [0, -2 * E.a2(), 0,
E.a2() ** 2 - 4 * E.a4(), 0])
return _H(E, PO, ell)

def _u_of_E(E, P):
disc = E.discriminant()
Emin = E.local_data(P, algorithm='generic').minimal_model(reduce=False)
discmin = Emin.discriminant()
if E.base_field() is QQ:
return Integer(_val(disc/discmin, P) / 12)
return Integer(P.residue_class_degree() *
_val(disc/discmin, P) / 12)

disc = E.discriminant()
t = polygen(K)
# 2-division polynomial:
f = (t ** 3 + E.a2() * t ** 2 + E.a4() * t + E.a6() +
(E.a1() * t + E.a3()) ** 2 / 4)
roots = f.roots(multiplicities=False)
if len(roots) == 3: # d=1
return (rn * _H(E, P) * _Hp(E, roots[0], P) *
_Hp(E, roots[1], P) * _Hp(E, roots[2], P))

elif len(roots) == 1: # d=2
E = E.change_weierstrass_model(1, roots[0], 0, 0) # E: y^2 = ... x
# new division polynomial:
g = t ** 2 + E.a2() * t + E.a4() + (E.a1() * t) ** 2 / 4
K2 = K.extension(g, 'a2')
EL, PL, [rL] = _change_ring(K2, [K2('a2')])
return (rn * _H(E, P) * _Hp(E, 0, P) *
_Hp(EL, 0, PL) * _Hp(EL, rL, PL))

elif disc.is_square(): # d=3
K3 = K.extension(f, 'a3')
EL, PL, [rL] = _change_ring(K3, [K3('a3')])
return rn * _H(EL, PL) * _Hp(EL, rL, PL)

else: # d=6
K2 = K.extension(t ** 2 - disc, 'a2')
K3 = K.extension(f, 'a3')
K6 = K3.extension(t ** 2 - disc, 'a6')
EM, PM, [] = _change_ring(K2, [])
EL, PL, [rL] = _change_ring(K3, [K3('a3')])
EF, PF, [rF] = _change_ring(K6, [K3('a3')])
return (rn * _H(EL, PL) * _Hp(EL, rL, PL) *
_H(EF, PF) * _H(EF, PF, 3) *
_Hp(EF, rF, PF) * _H(EM, PM, 3))

def _torsion_bound(self,number_of_places = 20):
r"""
An upper bound on the order of the torsion subgroup.
Expand Down Expand Up @@ -2057,7 +2410,6 @@ def _torsion_bound(self,number_of_places = 20):
bound = ZZ(0)
k = 0
K = E.base_field()
OK = K.ring_of_integers()
disc = E.discriminant()
p = Integer(1)
# runs through primes, decomposes them into prime ideals
Expand Down Expand Up @@ -2503,7 +2855,7 @@ def gens(self, **kwds):
Uses Denis Simon's PARI/GP scripts from
http://www.math.unicaen.fr/~simon/.
"""
_ = self.simon_two_descent(**kwds)
self.simon_two_descent(**kwds)
return self._known_points

def period_lattice(self, embedding):
Expand Down

0 comments on commit 60e9a78

Please sign in to comment.