Beispiel #1
0
def velu_codomain(kernel, domain=None):
    E = kernel[0].curve()
    R = []
    v = 0
    w = 0
    for P in kernel:
        g_x = 3 * P[0]**2 + E.a4()
        g_y = -2 * P[1]
        u_P = g_y**2
        if 2 * P == E(0, 1, 0):
            R.append(P)
            v_P = g_x
        else:
            if not -P in R:
                R.append(P)
                v_P = 2 * g_x
            else:
                continue

        v += v_P
        w += (u_P + P[0] * v_P)

    a = E.a4() - 5 * v
    b = E.a6() - 7 * w
    if domain != None:
        try:
            a = domain.base_field()(a)
            b = domain.base_field()(b)
            codomain = EllipticCurve(domain.base_field(), [a, b])
        except:

            codomain = EllipticCurve(E.base_field(), [a, b])
    else:
        codomain = EllipticCurve(E.base_field(), [a, b])
    return codomain
Beispiel #2
0
def isomorphism_isogeny(E, iso_E):
    field = E.base_field()
    iso_E = EllipticCurve(field, [field(iso_E.a4()), field(iso_E.a6())])
    isomorphism = E.isomorphism_to(iso_E)
    x, y = PolynomialRing(E.base_ring(), ['x', 'y']).gens()
    u, r, s, t = isomorphism.tuple()
    return u**2 * x + r, u**3 * y + s * u**2 * x + t
Beispiel #3
0
def velu(kernel, domain=None):
    E = kernel[0].curve()
    Q = PolynomialRing(E.base_field(), ['x', 'y'])
    x, y = Q.gens()
    X = x
    Y = y
    R = []
    v = 0
    w = 0

    for P in kernel:

        g_x = 3 * P[0]**2 + E.a4()
        g_y = -2 * P[1]
        u_P = g_y**2
        if 2 * P == E(0, 1, 0):
            R.append(P)
            v_P = g_x
        else:
            if not -P in R:
                R.append(P)
                v_P = 2 * g_x
            else:
                continue

        v += v_P
        w += (u_P + P[0] * v_P)
        X += (v_P / (x - P[0]) + u_P / (x - P[0])**2)
        Y -= (2 * u_P * y / (x - P[0])**3 + v_P * (y - P[1]) / (x - P[0])**2 -
              g_x * g_y / (x - P[0])**2)

    a = E.a4() - 5 * v
    b = E.a6() - 7 * w
    if domain != None:
        try:

            a = domain.base_field()(a)
            b = domain.base_field()(b)
            codomain = EllipticCurve(domain.base_field(), [a, b])
            R = PolynomialRing(E.base_field(), ['x', 'y'])
            Rf = R.fraction_field()
            X = Rf(X)
            Y = Rf(Y)
            f = standard_form((X, Y), domain)
        except:

            codomain = EllipticCurve(E.base_field(), [a, b])
            f = standard_form((X, Y), E)
    else:
        codomain = EllipticCurve(E.base_field(), [a, b])
        f = standard_form((X, Y), E)
    return codomain, f
Beispiel #4
0
def c4c6_model(c4, c6, assume_nonsingular=False):
    r"""
    Return the elliptic curve [0,0,0,-c4/48,-c6/864] with given c-invariants.

    INPUT:

    - ``c4``, ``c6`` -- elements of a number field

    - ``assume_nonsingular`` (boolean, default False) -- if True,
      check for integrality and nosingularity.

    OUTPUT:

    The elliptic curve with a-invariants [0,0,0,-c4/48,-c6/864], whose
    c-invariants are the given c4, c6.  If the supplied invariants are
    singular, returns None when ``assume_nonsingular`` is False and
    raises an ArithmeticError otherwise.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.kraus import c4c6_model
        sage: K.<a> = NumberField(x^3-10)
        sage: c4c6_model(-217728*a - 679104, 141460992*a + 409826304)
        Elliptic Curve defined by y^2 = x^3 + (4536*a+14148)*x + (-163728*a-474336) over Number Field in a with defining polynomial x^3 - 10

        sage: c4, c6 = EllipticCurve('389a1').c_invariants()
        sage: c4c6_model(c4,c6)
        Elliptic Curve defined by y^2 = x^3 - 7/3*x + 107/108 over Rational Field
    """
    if not assume_nonsingular:
        if not c4c6_nonsingular(c4,c6):
            return None
    return EllipticCurve([0,0,0,-c4/48,-c6/864])
Beispiel #5
0
def elkies_mod_poly(E, j2, l):
    j = E.j_invariant()
    Phi = ClassicalModularPolynomialDatabase()[l]
    x = PolynomialRing(E.base_field(), 'x').gen()
    f = Phi(j2, x)
    F1 = f.derivative()(j)
    g = Phi(j, x)
    F2 = g.derivative()(j2)
    try:
        lam = E.a6() / E.a4() * F1 / F2 * j * (-18) / l
        aa = -lam**2 / (j2 * (j2 - 1728) * l**4 * 48)
        bb = -lam**3 / (j2**2 * (j2 - 1728) * l**6 * 864)
        return EllipticCurve(E.base_field(), [aa, bb])
    except:
        return None
Beispiel #6
0
def c4c6_model(c4, c6, assume_nonsingular=False):
    r"""
    Return the elliptic curve [0,0,0,-c4/48,-c6/864] with given c-invariants.

    INPUT:

    - ``c4``, ``c6`` -- elements of a number field

    - ``assume_nonsingular`` (boolean, default False) -- if True,
      check for integrality and nosingularity.

    OUTPUT:

    The elliptic curve with a-invariants [0,0,0,-c4/48,-c6/864], whose
    c-invariants are the given c4, c6.  If the supplied invariants are
    singular, returns None when ``assume_nonsingular`` is False and
    raises an ArithmeticError otherwise.
    """
    if not assume_nonsingular:
        if not check_c4c6_nonsingular(c4, c6):
            return None
    return EllipticCurve([0, 0, 0, -c4 / 48, -c6 / 864])
Beispiel #7
0
def is_cm_j_invariant(j, method='new'):
    """
    Return whether or not this is a CM `j`-invariant.

    INPUT:

    - ``j`` -- an element of a number field `K`

    OUTPUT:

    A pair (bool, (d,f)) which is either (False, None) if `j` is not a
    CM j-invariant or (True, (d,f)) if `j` is the `j`-invariant of the
    imaginary quadratic order of discriminant `D=df^2` where `d` is
    the associated fundamental discriminant and `f` the index.

    .. note::

       The current implementation makes use of the classification of
       all orders of class number up to 100, and hence will raise an
       error if `j` is an algebraic integer of degree greater than
       this.  It would be possible to implement a more general
       version, using the fact that `d` must be supported on the
       primes dividing the discriminant of the minimal polynomial of
       `j`.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: is_cm_j_invariant(0)
        (True, (-3, 1))
        sage: is_cm_j_invariant(8000)
        (True, (-8, 1))

        sage: K.<a> = QuadraticField(5)
        sage: is_cm_j_invariant(282880*a + 632000)
        (True, (-20, 1))
        sage: K.<a> = NumberField(x^3 - 2)
        sage: is_cm_j_invariant(31710790944000*a^2 + 39953093016000*a + 50337742902000)
        (True, (-3, 6))

    TESTS::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: all([is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)])
        True

    """
    # First we check that j is an algebraic number:

    from sage.rings.all import NumberFieldElement, NumberField
    if not isinstance(j, NumberFieldElement) and not j in QQ:
        raise NotImplementedError(
            "is_cm_j_invariant() is only implemented for number field elements"
        )

    # for j in ZZ we have a lookup-table:

    if j in ZZ:
        j = ZZ(j)
        table = dict([(jj, (d, f))
                      for d, f, jj in cm_j_invariants_and_orders(QQ)])
        if j in table:
            return True, table[j]
        return False, None

    # Otherwise if j is in Q then it is not integral so is not CM:

    if j in QQ:
        return False, None

    # Now j has degree at least 2.  If it is not integral so is not CM:

    if not j.is_integral():
        return False, None

    # Next we find its minimal polynomial and degree h, and if h is
    # less than the degree of j.parent() we recreate j as an element
    # of Q(j):

    jpol = PolynomialRing(QQ, 'x')([-j, 1
                                    ]) if j in QQ else j.absolute_minpoly()
    h = jpol.degree()

    # This will be used as a fall-back if we cannot determine the
    # result using local data.  For this to be necessary there would
    # have to be very few primes of degree 1 and norm under 1000,
    # since we only need to find one prime of degree 1, good
    # reduction for which a_P is nonzero.
    if method == 'old':
        if h > 100:
            raise NotImplementedError(
                "CM data only available for class numbers up to 100")
        for d, f in cm_orders(h):
            if jpol == hilbert_class_polynomial(d * f**2):
                return True, (d, f)
        return False, None

    # replace j by a clone whose parent is Q(j), if necessary:

    K = j.parent()
    if h < K.absolute_degree():
        K = NumberField(jpol, 'j')
        j = K.gen()

    # Construct an elliptic curve with j-invariant j, with
    # integral model:

    from sage.schemes.elliptic_curves.all import EllipticCurve
    E = EllipticCurve(j=j).integral_model()
    D = E.discriminant()
    prime_bound = 1000  # test primes of degree 1 up to this norm
    max_primes = 20  # test at most this many primes
    num_prime = 0
    cmd = 0
    cmf = 0

    # Test primes of good reduction.  If E has CM then for half the
    # primes P we will have a_P=0, and for all other prime P the CM
    # field is Q(sqrt(a_P^2-4N(P))).  Hence if these fields are
    # different for two primes then E does not have CM.  If they are
    # all equal for the primes tested, then we have a candidate CM
    # field.  Moreover the discriminant of the endomorphism ring
    # divides all the values a_P^2-4N(P), since that is the
    # discriminant of the order containing the Frobenius at P.  So we
    # end up with a finite number (usually one) of candidate
    # discriminants to test.  Each is tested by checking that its class
    # number is h, and if so then that j is a root of its Hilbert
    # class polynomial.  In practice non CM curves will be eliminated
    # by the local test at a small number of primes (probably just 2).

    for P in K.primes_of_degree_one_iter(prime_bound):
        if num_prime > max_primes:
            if cmd:  # we have a candidate CM field already
                break
            else:  # we need to try more primes
                max_primes *= 2
        if D.valuation(P) > 0:  # skip bad primes
            continue
        aP = E.reduction(P).trace_of_frobenius()
        if aP == 0:  # skip supersingular primes
            continue
        num_prime += 1
        DP = aP**2 - 4 * P.norm()
        dP = DP.squarefree_part()
        fP = ZZ(DP // dP).isqrt()
        if cmd == 0:  # first one, so store d and f
            cmd = dP
            cmf = fP
        elif cmd != dP:  # inconsistent with previous
            return False, None
        else:  # consistent d, so update f
            cmf = cmf.gcd(fP)

    if cmd == 0:  # no conclusion, we found no degree 1 primes, revert to old method
        return is_cm_j_invariant(j, method='old')

    # it looks like cm by disc cmd * f**2 where f divides cmf

    if cmd % 4 != 1:
        cmd = cmd * 4
        cmf = cmf // 2

    # Now we must check if h(cmd*f**2)==h for f|cmf; if so we check
    # whether j is a root of the associated Hilbert class polynomial.
    for f in cmf.divisors():  # only positive divisors
        d = cmd * f**2
        if h != d.class_number():
            continue
        pol = hilbert_class_polynomial(d)
        if pol(j) == 0:
            return True, (cmd, f)
    return False, None
Beispiel #8
0
    def make_E(self):
        coeffs = self.ainvs  # list of 5 lists of d strings
        self.ainvs = [self.field.parse_NFelt(x) for x in coeffs]
        self.latex_ainvs = web_latex(self.ainvs)
        from sage.schemes.elliptic_curves.all import EllipticCurve
        self.E = E = EllipticCurve(self.ainvs)
        self.equn = web_latex(E)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = E.conductor()
        self.cond = web_latex(N)
        self.cond_norm = web_latex(N.norm())
        if N.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
        else:
            self.fact_cond = web_latex_ideal_fact(N.factor())
        self.fact_cond_norm = web_latex(N.norm().factor())

        D = self.field.K().ideal(E.discriminant())
        self.disc = web_latex(D)
        self.disc_norm = web_latex(D.norm())
        if D.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
        else:
            self.fact_disc = web_latex_ideal_fact(D.factor())
        self.fact_disc_norm = web_latex(D.norm().factor())

        # Minimal model?
        #
        # All curves in the database should be given
        # by models which are globally minimal if possible, else
        # minimal at all but one prime.  But we do not rely on this
        # here, and the display should be correct if either (1) there
        # exists a global minimal model but this model is not; or (2)
        # this model is non-minimal at more than one prime.
        #
        self.non_min_primes = non_minimal_primes(E)
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = True
        if not self.is_minimal:
            self.non_min_prime = ','.join(
                [web_latex(P) for P in self.non_min_primes])
            self.has_minimal_model = has_global_minimal_model(E)

        if not self.is_minimal:
            Dmin = minimal_discriminant_ideal(E)
            self.mindisc = web_latex(Dmin)
            self.mindisc_norm = web_latex(Dmin.norm())
            if Dmin.norm(
            ) == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
            else:
                self.fact_mindisc = web_latex_ideal_fact(Dmin.factor())
            self.fact_mindisc_norm = web_latex(Dmin.norm().factor())

        j = E.j_invariant()
        if j:
            d = j.denominator()
            n = d * j  # numerator exists for quadratic fields only!
            g = GCD(list(n))
            n1 = n / g
            self.j = web_latex(n1)
            if d != 1:
                if n1 > 1:
                    #self.j = "("+self.j+")\(/\)"+web_latex(d)
                    self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
                else:
                    self.j = web_latex(d)
                if g > 1:
                    if n1 > 1:
                        self.j = web_latex(g) + self.j
                    else:
                        self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        if j.is_zero():
            self.fact_j = web_latex(j)
        else:
            try:
                self.fact_j = web_latex(j.factor())
            except (ArithmeticError,
                    ValueError):  # if not all prime ideal factors principal
                pass

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(
                self.torsion_structure)
        torsion_gens = [
            E([self.field.parse_NFelt(x) for x in P])
            for P in self.torsion_gens
        ]
        self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens])

        # Rank etc
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "not recorded"
#       if rank in self:
#            self.r = web_latex(self.rank)

# Local data
        self.local_data = []
        for p in N.prime_factors():
            self.local_info = E.local_data(p, algorithm="generic")
            self.local_data.append({
                'p':
                web_latex(p),
                'norm':
                web_latex(p.norm().factor()),
                'tamagawa_number':
                self.local_info.tamagawa_number(),
                'kodaira_symbol':
                web_latex(self.local_info.kodaira_symbol()).replace('$', ''),
                'reduction_type':
                self.local_info.bad_reduction_type(),
                'ord_den_j':
                max(0,
                    E.j_invariant().valuation(p)),
                'ord_mindisc':
                self.local_info.discriminant_valuation()
            })

        # URLs of self and related objects:
        self.urls = {}
        self.urls['curve'] = url_for(".show_ecnf",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label,
                                     number=self.number)
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=self.conductor_label)
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        if self.field.is_real_quadratic():
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)

        if self.field.is_imag_quadratic():
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label,
                          self.urls['class'])]
        if self.field.is_real_quadratic():
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]
        if self.field.is_imag_quadratic():
            self.friends += [
                ('Bianchi Modular Form %s not yet available' % self.bmf_label,
                 '')
            ]

        self.properties = [('Base field', self.field.field_pretty()),
                           ('Label', self.label)]

        # Plot
        n1 = len(E.base_field().embeddings(RR))
        if (n1):
            self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [('Conductor', self.cond),
                            ('Conductor norm', self.cond_norm),
                            ('j-invariant', self.j), ('CM', self.cm_bool)]

        if self.base_change:
            self.properties += [
                ('base-change',
                 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))
            ]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Q-curve', self.qc)]

        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', self.rk),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0,
                              url_for("ec.by_ec_label", label=E0))]
Beispiel #9
0
    def make_E(self):
        coeffs = self.ainvs  # list of 5 lists of d strings
        self.ainvs = [self.field.parse_NFelt(x) for x in coeffs]
        self.latex_ainvs = web_latex(self.ainvs)
        from sage.schemes.elliptic_curves.all import EllipticCurve
        self.E = E = EllipticCurve(self.ainvs)
        self.equn = web_latex(E)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = E.conductor()
        self.cond = web_latex(N)
        self.cond_norm = web_latex(N.norm())
        if N.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
        else:
            self.fact_cond = web_latex_ideal_fact(N.factor())
        self.fact_cond_norm = web_latex(N.norm().factor())

        D = self.field.K().ideal(E.discriminant())
        self.disc = web_latex(D)
        self.disc_norm = web_latex(D.norm())
        if D.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
        else:
            self.fact_disc = web_latex_ideal_fact(D.factor())
        self.fact_disc_norm = web_latex(D.norm().factor())

        # Minimal model?
        #
        # All curves in the database should be given
        # by models which are globally minimal if possible, else
        # minimal at all but one prime.  But we do not rely on this
        # here, and the display should be correct if either (1) there
        # exists a global minimal model but this model is not; or (2)
        # this model is non-minimal at more than one prime.
        #
        self.non_min_primes = non_minimal_primes(E)
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = True
        if not self.is_minimal:
            self.non_min_prime = ','.join(
                [web_latex(P) for P in self.non_min_primes])
            self.has_minimal_model = has_global_minimal_model(E)

        if not self.is_minimal:
            Dmin = minimal_discriminant_ideal(E)
            self.mindisc = web_latex(Dmin)
            self.mindisc_norm = web_latex(Dmin.norm())
            if Dmin.norm(
            ) == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
            else:
                self.fact_mindisc = web_latex_ideal_fact(Dmin.factor())
            self.fact_mindisc_norm = web_latex(Dmin.norm().factor())

        j = E.j_invariant()
        if j:
            d = j.denominator()
            n = d * j  # numerator exists for quadratic fields only!
            g = GCD(list(n))
            n1 = n / g
            self.j = web_latex(n1)
            if d != 1:
                if n1 > 1:
                    # self.j = "("+self.j+")\(/\)"+web_latex(d)
                    self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
                else:
                    self.j = web_latex(d)
                if g > 1:
                    if n1 > 1:
                        self.j = web_latex(g) + self.j
                    else:
                        self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        # See issue 1258: some j factorizations work bu take too long (e.g. EllipticCurve/6.6.371293.1/1.1/a/1)
        # If these are really wanted, they could be precomputed and stored in the db
        if j.is_zero():
            self.fact_j = web_latex(j)
        else:
            if self.field.K().degree(
            ) < 3:  #j.numerator_ideal().norm()<1000000000000:
                try:
                    self.fact_j = web_latex(j.factor())
                except (ArithmeticError, ValueError
                        ):  # if not all prime ideal factors principal
                    pass

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm
            # The line below will need to change once we have curves over non-quadratic fields
            # that contain the Hilbert class field of an imaginary quadratic field
            if self.signature == [0, 1] and ZZ(
                    -self.abs_disc * self.cm).is_square():
                self.ST = '<a href="%s">$%s$</a>' % (url_for(
                    'st.by_label', label='1.2.U(1)'), '\\mathrm{U}(1)')
            else:
                self.ST = '<a href="%s">$%s$</a>' % (url_for(
                    'st.by_label', label='1.2.N(U(1))'), 'N(\\mathrm{U}(1))')
        else:
            self.ST = '<a href="%s">$%s$</a>' % (url_for(
                'st.by_label', label='1.2.SU(2)'), '\\mathrm{SU}(2)')

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(
                self.torsion_structure)
        torsion_gens = [
            E([self.field.parse_NFelt(x) for x in P])
            for P in self.torsion_gens
        ]
        self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens])

        # Rank or bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.rank_bounds)
        except AttributeError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not available"

        # Generators
        try:
            gens = [
                E([self.field.parse_NFelt(x) for x in P]) for P in self.gens
            ]
            self.gens = ", ".join([web_latex(P) for P in gens])
            if self.rk == "?":
                self.reg = "not available"
            else:
                if gens:
                    self.reg = E.regulator_of_points(gens)
                else:
                    self.reg = 1  # otherwise we only get 1.00000...

        except AttributeError:
            self.gens = "not available"
            self.reg = "not available"
            try:
                if self.rank == 0:
                    self.reg = 1
            except AttributeError:
                pass

        # Local data
        self.local_data = []
        for p in N.prime_factors():
            self.local_info = E.local_data(p, algorithm="generic")
            self.local_data.append({
                'p':
                web_latex(p),
                'norm':
                web_latex(p.norm().factor()),
                'tamagawa_number':
                self.local_info.tamagawa_number(),
                'kodaira_symbol':
                web_latex(self.local_info.kodaira_symbol()).replace('$', ''),
                'reduction_type':
                self.local_info.bad_reduction_type(),
                'ord_den_j':
                max(0, -E.j_invariant().valuation(p)),
                'ord_mindisc':
                self.local_info.discriminant_valuation(),
                'ord_cond':
                self.local_info.conductor_valuation()
            })

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label),
                                         class_label=self.iso_label,
                                         number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=quote(
                                         self.conductor_label),
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        sig = self.signature
        real_quadratic = sig == [2, 0]
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]

        if totally_real:
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page",
                                             field=self.field_label,
                                             label=self.hmf_label,
                                             character='0',
                                             number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label,
                          self.urls['class'])]
        self.friends += [('Twists',
                          url_for('ecnf.index',
                                  field_label=self.field_label,
                                  jinv=self.jinv))]
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]
            self.friends += [('L-function', self.urls['Lfunction'])]
        if imag_quadratic:
            self.friends += [
                ('Bianchi Modular Form %s not available' % self.bmf_label, '')
            ]

        self.properties = [('Base field', self.field.field_pretty()),
                           ('Label', self.label)]

        # Plot
        if E.base_field().signature()[0]:
            self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)
        ]

        if self.base_change:
            self.properties += [
                ('base-change',
                 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))
            ]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0,
                              url_for("ec.by_ec_label", label=E0))]

        self._code = None  # will be set if needed by get_code()
Beispiel #10
0
def is_cm_j_invariant(j, method='new'):
    """
    Return whether or not this is a CM `j`-invariant.

    INPUT:

    - ``j`` -- an element of a number field `K`

    OUTPUT:

    A pair (bool, (d,f)) which is either (False, None) if `j` is not a
    CM j-invariant or (True, (d,f)) if `j` is the `j`-invariant of the
    imaginary quadratic order of discriminant `D=df^2` where `d` is
    the associated fundamental discriminant and `f` the index.

    .. note::

       The current implementation makes use of the classification of
       all orders of class number up to 100, and hence will raise an
       error if `j` is an algebraic integer of degree greater than
       this.  It would be possible to implement a more general
       version, using the fact that `d` must be supported on the
       primes dividing the discriminant of the minimal polynomial of
       `j`.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: is_cm_j_invariant(0)
        (True, (-3, 1))
        sage: is_cm_j_invariant(8000)
        (True, (-8, 1))

        sage: K.<a> = QuadraticField(5)
        sage: is_cm_j_invariant(282880*a + 632000)
        (True, (-20, 1))
        sage: K.<a> = NumberField(x^3 - 2)
        sage: is_cm_j_invariant(31710790944000*a^2 + 39953093016000*a + 50337742902000)
        (True, (-3, 6))

    TESTS::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: all([is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)])
        True

    """
    # First we check that j is an algebraic number:

    from sage.rings.all import NumberFieldElement, NumberField
    if not isinstance(j, NumberFieldElement) and not j in QQ:
        raise NotImplementedError("is_cm_j_invariant() is only implemented for number field elements")

    # for j in ZZ we have a lookup-table:

    if j in ZZ:
        j = ZZ(j)
        table = dict([(jj,(d,f)) for d,f,jj in cm_j_invariants_and_orders(QQ)])
        if j in table:
            return True, table[j]
        return False, None

    # Otherwise if j is in Q then it is not integral so is not CM:

    if j in QQ:
        return False, None

    # Now j has degree at least 2.  If it is not integral so is not CM:

    if not j.is_integral():
        return False, None

    # Next we find its minimal polynomial and degree h, and if h is
    # less than the degree of j.parent() we recreate j as an element
    # of Q(j):

    jpol = PolynomialRing(QQ,'x')([-j,1]) if j in QQ else j.absolute_minpoly()
    h = jpol.degree()

    # This will be used as a fall-back if we cannot determine the
    # result using local data.  For this to be necessary there would
    # have to be very few primes of degree 1 and norm under 1000,
    # since we only need to find one prime of degree 1, good
    # reduction for which a_P is nonzero.
    if method=='old':
        if h>100:
            raise NotImplementedError("CM data only available for class numbers up to 100")
        for d,f in cm_orders(h):
            if jpol == hilbert_class_polynomial(d*f**2):
                return True, (d,f)
        return False, None

    # replace j by a clone whose parent is Q(j), if necessary:

    K = j.parent()
    if h < K.absolute_degree():
        K = NumberField(jpol, 'j')
        j = K.gen()

    # Construct an elliptic curve with j-invariant j, with
    # integral model:

    from sage.schemes.elliptic_curves.all import EllipticCurve
    E = EllipticCurve(j=j).integral_model()
    D = E.discriminant()
    prime_bound = 1000 # test primes of degree 1 up to this norm
    max_primes =    20 # test at most this many primes
    num_prime = 0
    cmd = 0
    cmf = 0

    # Test primes of good reduction.  If E has CM then for half the
    # primes P we will have a_P=0, and for all other prime P the CM
    # field is Q(sqrt(a_P^2-4N(P))).  Hence if these fields are
    # different for two primes then E does not have CM.  If they are
    # all equal for the primes tested, then we have a candidate CM
    # field.  Moreover the discriminant of the endomorphism ring
    # divides all the values a_P^2-4N(P), since that is the
    # discriminant of the order containing the Frobenius at P.  So we
    # end up with a finite number (usually one) of candidate
    # discriminats to test.  Each is tested by checking that its class
    # number is h, and if so then that j is a root of its Hilbert
    # class polynomial.  In practice non CM curves will be eliminated
    # by the local test at a small number of primes (probably just 2).

    for P in K.primes_of_degree_one_iter(prime_bound):
        if num_prime > max_primes:
            if cmd: # we have a candidate CM field already
                break
            else:   # we need to try more primes
                max_primes *=2
        if D.valuation(P)>0: # skip bad primes
            continue
        aP = E.reduction(P).trace_of_frobenius()
        if aP == 0: # skip supersingular primes
            continue
        num_prime += 1
        DP = aP**2 - 4*P.norm()
        dP = DP.squarefree_part()
        fP = ZZ(DP//dP).isqrt()
        if cmd==0:      # first one, so store d and f
            cmd = dP
            cmf = fP
        elif cmd != dP: # inconsistent with previous
            return False, None
        else:           # consistent d, so update f
            cmf = cmf.gcd(fP)

    if cmd==0: # no conclusion, we found no degree 1 primes, revert to old method
        return is_cm_j_invariant(j, method='old')

    # it looks like cm by disc cmd * f**2 where f divides cmf

    if cmd%4!=1:
        cmd = cmd*4
        cmf = cmf//2

    # Now we must check if h(cmd*f**2)==h for f|cmf; if so we check
    # whether j is a root of the associated Hilbert class polynomial.
    for f in cmf.divisors(): # only positive divisors
        d = cmd*f**2
        if h != d.class_number():
            continue
        pol = hilbert_class_polynomial(d)
        if pol(j)==0:
            return True, (cmd,f)
    return False, None
Beispiel #11
0
    def add_reductions(self, q):
        r"""Add reduction data at primes above q if not already there.

        INPUT:

        - ``q`` -- a prime number not dividing the defining polynomial
          of self.__field.

        OUTPUT:

        Returns nothing, but updates self._reductions dictionary for
        key ``q`` to a dict whose keys are the roots of the defining
        polynomial mod ``q`` and values tuples (``nq``, ``Eq``) where
        ``Eq`` is an elliptic curve over `GF(q)` and ``nq`` its
        cardinality.  If ``q`` divides the conductor norm or order
        discriminant nothing is added.

        EXAMPLES:

        Over `\QQ`::

            sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator
            sage: E = EllipticCurve('11a1')
            sage: saturator = EllipticCurveSaturator(E)
            sage: saturator._reductions
            {}
            sage: saturator.add_reductions(19)
            sage: saturator._reductions
            {19: {0: (20,
            Elliptic Curve defined by y^2 + y = x^3 + 18*x^2 + 9*x + 18 over Finite Field of size 19)}}

        Over a number field::

            sage: x = polygen(QQ);  K.<a> = NumberField(x^2 + 2)
            sage: E = EllipticCurve(K, [0,1,0,a,a])
            sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator
            sage: saturator = EllipticCurveSaturator(E)
            sage: for q in primes(20):
            ....:     saturator.add_reductions(q)
            ....:
            sage: saturator._reductions
            {2: {},
            3: {},
            5: {},
            7: {},
            11: {3: (16,
            Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 3 over Finite Field of size 11),
            8: (8,
            Elliptic Curve defined by y^2 = x^3 + x^2 + 8*x + 8 over Finite Field of size 11)},
            13: {},
            17: {7: (20,
            Elliptic Curve defined by y^2 = x^3 + x^2 + 7*x + 7 over Finite Field of size 17),
            10: (18,
            Elliptic Curve defined by y^2 = x^3 + x^2 + 10*x + 10 over Finite Field of size 17)},
            19: {6: (16,
            Elliptic Curve defined by y^2 = x^3 + x^2 + 6*x + 6 over Finite Field of size 19),
            13: (12,
            Elliptic Curve defined by y^2 = x^3 + x^2 + 13*x + 13 over Finite Field of size 19)}}
        """
        if q in self._reductions:
            return
        self._reductions[q] = redmodq = dict()
        if q.divides(self._N) or q.divides(self._D):
            return
        from sage.schemes.elliptic_curves.all import EllipticCurve
        for amodq in sorted(self._Kpol.roots(GF(q), multiplicities=False)):
            Eq = EllipticCurve(
                [reduce_mod_q(ai, amodq) for ai in self._curve.ainvs()])
            nq = Eq.cardinality()
            redmodq[amodq] = (nq, Eq)
Beispiel #12
0
def frobenius_image_curve(E, r):
    p = E.base_field().characteristic()
    return EllipticCurve(E.base_field(), [E.a4()**(p**r), E.a6()**(p**r)])
Beispiel #13
0
def extend_field(E, r):
    q = E.base_field().order()
    field = GF(q**r)
    a = field(E.a4())
    b = field(E.a6())
    return EllipticCurve(field, [a, b])
Beispiel #14
0
def r_frobenius_morphism(E, r):
    x, y = PolynomialRing(E.base_ring(), ['x', 'y']).gens()
    p = E.base_field().characteristic()
    a = E.a4()**(p**r)
    b = E.a6()**(p**r)
    return (x**(p**r), y**(p**r)), EllipticCurve(E.base_field(), [a, b])