Exemplo n.º 1
0
    def _tate(self, proof=None):
        r"""
        Tate's algorithm for an elliptic curve over a number field.

        Computes both local reduction data at a prime ideal and a
        local minimal model.

        The model is not required to be integral on input.  If `P` is
        principal, uses a generator as uniformizer, so it will not
        affect integrality or minimality at other primes.  If `P` is not
        principal, the minimal model returned will preserve
        integrality at other primes, but not minimality.

        .. note:: 

           Called only by ``EllipticCurveLocalData.__init__()``.

        OUTPUT:

        (tuple) ``(Emin, p, val_disc, fp, KS, cp)`` where:

        - ``Emin`` (EllipticCurve) is a model (integral and) minimal at P
        - ``p`` (int) is the residue characteristic
        - ``val_disc`` (int) is the valuation of the local minimal discriminant
        - ``fp`` (int) is the valuation of the conductor
        - ``KS`` (string) is the Kodaira symbol
        - ``cp`` (int) is the Tamagawa number


        EXAMPLES (this raised a type error in sage prior to 4.4.4, see ticket #7930) ::

            sage: E = EllipticCurve('99d1')
                          
            sage: R.<X> = QQ[]
            sage: K.<t> = NumberField(X^3 + X^2 - 2*X - 1)
            sage: L.<s> = NumberField(X^3 + X^2 - 36*X - 4)

            sage: EK = E.base_extend(K)
            sage: toK = EK.torsion_order()
            sage: da = EK.local_data()  # indirect doctest

            sage: EL = E.base_extend(L)
            sage: da = EL.local_data()  # indirect doctest

        EXAMPLES:

        The following example shows that the bug at #9324 is fixed::

            sage: K.<a> = NumberField(x^2-x+6)
            sage: E = EllipticCurve([0,0,0,-53160*a-43995,-5067640*a+19402006])
            sage: E.conductor() # indirect doctest
            Fractional ideal (18, 6*a)

        The following example shows that the bug at #9417 is fixed::

            sage: K.<a> = NumberField(x^2+18*x+1)
            sage: E = EllipticCurve(K, [0, -36, 0, 320, 0])
            sage: E.tamagawa_number(K.ideal(2))
            4

        """
        E = self._curve
        P = self._prime
        K = E.base_ring()
        OK = K.maximal_order()
        t = verbose("Running Tate's algorithm with P = %s" % P, level=1)
        F = OK.residue_field(P)
        p = F.characteristic()

        # In case P is not principal we mostly use a uniformiser which
        # is globally integral (with positive valuation at some other
        # primes); for this to work, it is essential that we can
        # reduce (mod P) elements of K which are not integral (but are
        # P-integral).  However, if the model is non-minimal and we
        # end up dividing a_i by pi^i then at that point we use a
        # uniformiser pi which has non-positive valuation at all other
        # primes, so that we can divide by it without losing
        # integrality at other primes.

        principal_flag = P.is_principal()
        if principal_flag:
            pi = P.gens_reduced()[0]
            verbose("P is principal, generator pi = %s" % pi, t, 1)
        else:
            pi = K.uniformizer(P, 'positive')
            verbose("P is not principal, uniformizer pi = %s" % pi, t, 1)
        pi2 = pi * pi
        pi3 = pi * pi2
        pi4 = pi * pi3
        pi_neg = None
        prime = pi if K is QQ else P

        pval = lambda x: x.valuation(prime)
        pdiv = lambda x: x.is_zero() or pval(x) > 0
        # Since ResidueField is cached in a way that
        # does not care much about embeddings of number
        # fields, it can happen that F.p.ring() is different
        # from K. This is a problem: If F.p.ring() has no
        # embedding but K has, then there is no coercion
        # from F.p.ring().maximal_order() to K. But it is
        # no problem to do an explicit conversion in that
        # case (Simon King, trac ticket #8800).

        from sage.categories.pushout import pushout, CoercionException
        try:
            if hasattr(F.p.ring(), 'maximal_order'):  # it is not ZZ
                _tmp_ = pushout(F.p.ring().maximal_order(), K)
            pinv = lambda x: F.lift(~F(x))
            proot = lambda x, e: F.lift(
                F(x).nth_root(e, extend=False, all=True)[0])
            preduce = lambda x: F.lift(F(x))
        except CoercionException:  # the pushout does not exist, we need conversion
            pinv = lambda x: K(F.lift(~F(x)))
            proot = lambda x, e: K(
                F.lift(F(x).nth_root(e, extend=False, all=True)[0]))
            preduce = lambda x: K(F.lift(F(x)))

        def _pquadroots(a, b, c):
            r"""
            Local function returning True iff `ax^2 + bx + c` has roots modulo `P`
            """
            (a, b, c) = (F(a), F(b), F(c))
            if a == 0:
                return (b != 0) or (c == 0)
            elif p == 2:
                return len(PolynomialRing(F, "x")([c, b, a]).roots()) > 0
            else:
                return (b**2 - 4 * a * c).is_square()

        def _pcubicroots(b, c, d):
            r"""
            Local function returning the number of roots of `x^3 +
            b*x^2 + c*x + d` modulo `P`, counting multiplicities
            """

            return sum([
                rr[1] for rr in PolynomialRing(F, 'x')
                ([F(d), F(c), F(b), F(1)]).roots()
            ], 0)

        if p == 2:
            halfmodp = OK(Integer(0))
        else:
            halfmodp = pinv(Integer(2))

        A = E.a_invariants()
        A = [0, A[0], A[1], A[2], A[3], 0, A[4]]
        indices = [1, 2, 3, 4, 6]
        if min([pval(a) for a in A if a != 0]) < 0:
            verbose(
                "Non-integral model at P: valuations are %s; making integral" %
                ([pval(a) for a in A if a != 0]), t, 1)
            e = 0
            for i in range(7):
                if A[i] != 0:
                    e = max(e, (-pval(A[i]) / i).ceil())
            pie = pi**e
            for i in range(7):
                if A[i] != 0:
                    A[i] *= pie**i
            verbose(
                "P-integral model is %s, with valuations %s" %
                ([A[i] for i in indices], [pval(A[i]) for i in indices]), t, 1)

        split = None  # only relevant for multiplicative reduction

        (a1, a2, a3, a4, a6) = (A[1], A[2], A[3], A[4], A[6])
        while True:
            C = EllipticCurve([a1, a2, a3, a4, a6])
            (b2, b4, b6, b8) = C.b_invariants()
            (c4, c6) = C.c_invariants()
            delta = C.discriminant()
            val_disc = pval(delta)

            if val_disc == 0:
                ## Good reduction already
                cp = 1
                fp = 0
                KS = KodairaSymbol("I0")
                break  #return

            # Otherwise, we change coordinates so that p | a3, a4, a6
            if p == 2:
                if pdiv(b2):
                    r = proot(a4, 2)
                    t = proot(((r + a2) * r + a4) * r + a6, 2)
                else:
                    temp = pinv(a1)
                    r = temp * a3
                    t = temp * (a4 + r * r)
            elif p == 3:
                if pdiv(b2):
                    r = proot(-b6, 3)
                else:
                    r = -pinv(b2) * b4
                t = a1 * r + a3
            else:
                if pdiv(c4):
                    r = -pinv(12) * b2
                else:
                    r = -pinv(12 * c4) * (c6 + b2 * c4)
                t = -halfmodp * (a1 * r + a3)
            r = preduce(r)
            t = preduce(t)
            verbose("Before first transform C = %s" % C)
            verbose("[a1,a2,a3,a4,a6] = %s" % ([a1, a2, a3, a4, a6]))
            C = C.rst_transform(r, 0, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            if min([pval(a) for a in (a1, a2, a3, a4, a6) if a != 0]) < 0:
                raise RuntimeError, "Non-integral model after first transform!"
            verbose(
                "After first transform %s\n, [a1,a2,a3,a4,a6] = %s\n, valuations = %s"
                % ([r, 0, t], [a1, a2, a3, a4, a6],
                   [pval(a1), pval(a2),
                    pval(a3), pval(a4),
                    pval(a6)]), t, 2)
            if pval(a3) == 0:
                raise RuntimeError, "p does not divide a3 after first transform!"
            if pval(a4) == 0:
                raise RuntimeError, "p does not divide a4 after first transform!"
            if pval(a6) == 0:
                raise RuntimeError, "p does not divide a6 after first transform!"

            # Now we test for Types In, II, III, IV
            # NB the c invariants never change.

            if not pdiv(c4):
                # Multiplicative reduction: Type In (n = val_disc)
                split = False
                if _pquadroots(1, a1, -a2):
                    cp = val_disc
                    split = True
                elif Integer(2).divides(val_disc):
                    cp = 2
                else:
                    cp = 1
                KS = KodairaSymbol("I%s" % val_disc)
                fp = 1
                break  #return

            # Additive reduction

            if pval(a6) < 2:
                ## Type II
                KS = KodairaSymbol("II")
                fp = val_disc
                cp = 1
                break  #return
            if pval(b8) < 3:
                ## Type III
                KS = KodairaSymbol("III")
                fp = val_disc - 1
                cp = 2
                break  #return
            if pval(b6) < 3:
                ## Type IV
                cp = 1
                a3t = preduce(a3 / pi)
                a6t = preduce(a6 / pi2)
                if _pquadroots(1, a3t, -a6t): cp = 3
                KS = KodairaSymbol("IV")
                fp = val_disc - 2
                break  #return

            # If our curve is none of these types, we change coords so that
            # p | a1, a2;  p^2 | a3, a4;  p^3 | a6
            if p == 2:
                s = proot(a2, 2)  # so s^2=a2 (mod pi)
                t = pi * proot(a6 / pi2, 2)  # so t^2=a6 (mod pi^3)
            elif p == 3:
                s = a1  # so a1'=2s+a1=3a1=0 (mod pi)
                t = a3  # so a3'=2t+a3=3a3=0 (mod pi^2)
            else:
                s = -a1 * halfmodp  # so a1'=2s+a1=0 (mod pi)
                t = -a3 * halfmodp  # so a3'=2t+a3=0 (mod pi^2)
            C = C.rst_transform(0, s, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            verbose(
                "After second transform %s\n[a1, a2, a3, a4, a6] = %s\nValuations: %s"
                % ([0, s, t], [a1, a2, a3, a4, a6],
                   [pval(a1), pval(a2),
                    pval(a3), pval(a4),
                    pval(a6)]), t, 2)
            if pval(a1) == 0:
                raise RuntimeError, "p does not divide a1 after second transform!"
            if pval(a2) == 0:
                raise RuntimeError, "p does not divide a2 after second transform!"
            if pval(a3) < 2:
                raise RuntimeError, "p^2 does not divide a3 after second transform!"
            if pval(a4) < 2:
                raise RuntimeError, "p^2 does not divide a4 after second transform!"
            if pval(a6) < 3:
                raise RuntimeError, "p^3 does not divide a6 after second transform!"
            if min(pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)) < 0:
                raise RuntimeError, "Non-integral model after second transform!"

            # Analyze roots of the cubic T^3 + bT^2 + cT + d = 0 mod P, where
            # b = a2/p, c = a4/p^2, d = a6/p^3
            b = preduce(a2 / pi)
            c = preduce(a4 / pi2)
            d = preduce(a6 / pi3)
            bb = b * b
            cc = c * c
            bc = b * c
            w = 27 * d * d - bb * cc + 4 * b * bb * d - 18 * bc * d + 4 * c * cc
            x = 3 * c - bb
            if pdiv(w):
                if pdiv(x):
                    sw = 3
                else:
                    sw = 2
            else:
                sw = 1
            verbose(
                "Analyzing roots of cubic T^3 + %s*T^2 + %s*T + %s, case %s" %
                (b, c, d, sw), t, 1)
            if sw == 1:
                ## Three distinct roots - Type I*0
                verbose("Distinct roots", t, 1)
                KS = KodairaSymbol("I0*")
                cp = 1 + _pcubicroots(b, c, d)
                fp = val_disc - 4
                break  #return
            elif sw == 2:
                ## One double root - Type I*m for some m
                verbose("One double root", t, 1)
                ## Change coords so that the double root is T = 0 mod p
                if p == 2:
                    r = proot(c, 2)
                elif p == 3:
                    r = c * pinv(b)
                else:
                    r = (bc - 9 * d) * pinv(2 * x)
                r = pi * preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # The rest of this branch is just to compute cp, fp, KS.
                # We use pi to keep transforms integral.
                ix = 3
                iy = 3
                mx = pi2
                my = mx
                while True:
                    a2t = preduce(a2 / pi)
                    a3t = preduce(a3 / my)
                    a4t = preduce(a4 / (pi * mx))
                    a6t = preduce(a6 / (mx * my))
                    if pdiv(a3t * a3t + 4 * a6t):
                        if p == 2:
                            t = my * proot(a6t, 2)
                        else:
                            t = my * preduce(-a3t * halfmodp)
                        C = C.rst_transform(0, 0, t)
                        (a1, a2, a3, a4, a6) = C.a_invariants()
                        (b2, b4, b6, b8) = C.b_invariants()
                        my *= pi
                        iy += 1
                        a2t = preduce(a2 / pi)
                        a3t = preduce(a3 / my)
                        a4t = preduce(a4 / (pi * mx))
                        a6t = preduce(a6 / (mx * my))
                        if pdiv(a4t * a4t - 4 * a6t * a2t):
                            if p == 2:
                                r = mx * proot(a6t * pinv(a2t), 2)
                            else:
                                r = mx * preduce(-a4t * pinv(2 * a2t))
                            C = C.rst_transform(r, 0, 0)
                            (a1, a2, a3, a4, a6) = C.a_invariants()
                            (b2, b4, b6, b8) = C.b_invariants()
                            mx *= pi
                            ix += 1  # and stay in loop
                        else:
                            if _pquadroots(a2t, a4t, a6t):
                                cp = 4
                            else:
                                cp = 2
                            break  # exit loop
                    else:
                        if _pquadroots(1, a3t, -a6t):
                            cp = 4
                        else:
                            cp = 2
                        break
                KS = KodairaSymbol("I%s*" % (ix + iy - 5))
                fp = val_disc - ix - iy + 1
                break  #return
            else:  # sw == 3
                ## The cubic has a triple root
                verbose("Triple root", t, 1)
                ## First we change coordinates so that T = 0 mod p
                if p == 2:
                    r = b
                elif p == 3:
                    r = proot(-d, 3)
                else:
                    r = -b * pinv(3)
                r = pi * preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                verbose(
                    "After third transform %s\n[a1,a2,a3,a4,a6] = %s\nValuations: %s"
                    % ([r, 0, 0], [a1, a2, a3, a4, a6],
                       [pval(ai) for ai in [a1, a2, a3, a4, a6]]), t, 2)
                if min(pval(ai) for ai in [a1, a2, a3, a4, a6]) < 0:
                    raise RuntimeError, "Non-integral model after third transform!"
                if pval(a2) < 2 or pval(a4) < 3 or pval(a6) < 4:
                    raise RuntimeError, "Cubic after transform does not have a triple root at 0"
                a3t = preduce(a3 / pi2)
                a6t = preduce(a6 / pi4)
                # We test for Type IV*
                if not pdiv(a3t * a3t + 4 * a6t):
                    cp = 3 if _pquadroots(1, a3t, -a6t) else 1
                    KS = KodairaSymbol("IV*")
                    fp = val_disc - 6
                    break  #return
                # Now change coordinates so that p^3|a3, p^5|a6
                if p == 2:
                    t = -pi2 * proot(a6t, 2)
                else:
                    t = pi2 * preduce(-a3t * halfmodp)
                C = C.rst_transform(0, 0, t)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # We test for types III* and II*
                if pval(a4) < 4:
                    ## Type III*
                    KS = KodairaSymbol("III*")
                    fp = val_disc - 7
                    cp = 2
                    break  #return
                if pval(a6) < 6:
                    ## Type II*
                    KS = KodairaSymbol("II*")
                    fp = val_disc - 8
                    cp = 1
                    break  #return
                if pi_neg is None:
                    if principal_flag:
                        pi_neg = pi
                    else:
                        pi_neg = K.uniformizer(P, 'negative')
                    pi_neg2 = pi_neg * pi_neg
                    pi_neg3 = pi_neg * pi_neg2
                    pi_neg4 = pi_neg * pi_neg3
                    pi_neg6 = pi_neg4 * pi_neg2
                a1 /= pi_neg
                a2 /= pi_neg2
                a3 /= pi_neg3
                a4 /= pi_neg4
                a6 /= pi_neg6
                verbose(
                    "Non-minimal equation, dividing out...\nNew model is %s" %
                    ([a1, a2, a3, a4, a6]), t, 1)
        return (C, p, val_disc, fp, KS, cp, split)
Exemplo n.º 2
0
    def __init__(self, E, P, proof=None, algorithm="pari"):
        r"""
        Initializes the reduction data for the elliptic curve `E` at the prime `P`.

        INPUT:

        - ``E`` -- an elliptic curve defined over a number field, or `\QQ`.

        - ``P`` -- a prime ideal of the field, or a prime integer if the field is `\QQ`.

        - ``proof`` (bool)-- if True, only use provably correct
          methods (default controlled by global proof module).  Note
          that the proof module is number_field, not elliptic_curves,
          since the functions that actually need the flag are in
          number fields.  

        - ``algorithm`` (string, default: "pari") -- Ignored unless the
          base field is `\QQ`.  If "pari", use the PARI C-library
          ``ellglobalred`` implementation of Tate's algorithm over
          `\QQ`. If "generic", use the general number field
          implementation.

        .. note::

           This function is not normally called directly by users, who
           may access the data via methods of the EllipticCurve
           classes.

        EXAMPLES::

            sage: from sage.schemes.elliptic_curves.ell_local_data import EllipticCurveLocalData
            sage: E = EllipticCurve('14a1')
            sage: EllipticCurveLocalData(E,2)
            Local data at Principal ideal (2) of Integer Ring:
            Reduction type: bad non-split multiplicative
            Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
            Minimal discriminant valuation: 6
            Conductor exponent: 1
            Kodaira Symbol: I6
            Tamagawa Number: 2

        ::    

            sage: EllipticCurveLocalData(E,2,algorithm="generic")
            Local data at Principal ideal (2) of Integer Ring:
            Reduction type: bad non-split multiplicative
            Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
            Minimal discriminant valuation: 6
            Conductor exponent: 1
            Kodaira Symbol: I6
            Tamagawa Number: 2

        ::    

            sage: EllipticCurveLocalData(E,2,algorithm="pari")
            Local data at Principal ideal (2) of Integer Ring:
            Reduction type: bad non-split multiplicative
            Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
            Minimal discriminant valuation: 6
            Conductor exponent: 1
            Kodaira Symbol: I6
            Tamagawa Number: 2

        ::    

            sage: EllipticCurveLocalData(E,2,algorithm="unknown")
            Traceback (most recent call last):
            ...
            ValueError: algorithm must be one of 'pari', 'generic'

        ::    

            sage: EllipticCurveLocalData(E,3)
            Local data at Principal ideal (3) of Integer Ring:
            Reduction type: good
            Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
            Minimal discriminant valuation: 0
            Conductor exponent: 0
            Kodaira Symbol: I0
            Tamagawa Number: 1

        ::    

            sage: EllipticCurveLocalData(E,7)            
            Local data at Principal ideal (7) of Integer Ring:
            Reduction type: bad split multiplicative
            Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
            Minimal discriminant valuation: 3
            Conductor exponent: 1
            Kodaira Symbol: I3
            Tamagawa Number: 3
        """
        self._curve = E
        K = E.base_field()
        p = check_prime(K, P)  # error handling done in that function
        if algorithm != "pari" and algorithm != "generic":
            raise ValueError, "algorithm must be one of 'pari', 'generic'"

        self._reduction_type = None
        if K is QQ:
            self._prime = ZZ.ideal(p)
        else:
            self._prime = p

        if algorithm == "pari" and K is QQ:
            Eint = E.integral_model()
            data = Eint.pari_curve().elllocalred(p)
            self._fp = data[0].python()
            self._KS = KodairaSymbol(data[1].python())
            self._cp = data[3].python()
            # We use a global minimal model since we can:
            self._Emin_reduced = Eint.minimal_model()
            self._val_disc = self._Emin_reduced.discriminant().valuation(p)
            if self._fp > 0:
                self._reduction_type = Eint.ap(p)  # = 0,-1 or +1
        else:
            self._Emin, ch, self._val_disc, self._fp, self._KS, self._cp, self._split = self._tate(
                proof)
            if self._fp > 0:
                if self._Emin.c4().valuation(p) > 0:
                    self._reduction_type = 0
                elif self._split:
                    self._reduction_type = +1
                else:
                    self._reduction_type = -1