Ejemplo n.º 1
0
def make_extra_data(label, number, ainvs, gens):
    """Given a curve label (and number, as some data is only stored wih
    curve number 1 in each class) and its ainvs and gens, returns a
    dict with which to update the entry.

    Extra items computed here:
    'equation': latex string of curve's equation
    'signD': sign of discriminant
    'local_data': list of dicts, one item for each bad prime
    'min_quad_twist': dict holding curve's min quadratic twist and the twisting discriminant
    'heights': list of heights of gens

    and for curve #1 in a class only:

    'aplist': list of a_p for p<100
    'anlist': list of a_n for n<=20

    """
    E = EllipticCurve(parse_ainvs(ainvs))
    data = {}
    # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]'
    data['equation'] = web_latex(E)
    data['signD'] = int(E.discriminant().sign())
    data['local_data'] = [{
        'p':
        int(ld.prime().gen()),
        'ord_cond':
        int(ld.conductor_valuation()),
        'ord_disc':
        int(ld.discriminant_valuation()),
        'ord_den_j':
        int(max(0, -(E.j_invariant().valuation(ld.prime().gen())))),
        'red':
        int(ld.bad_reduction_type()),
        'rootno':
        int(E.root_number(ld.prime().gen())),
        'kod':
        web_latex(ld.kodaira_symbol()).replace('$', ''),
        'cp':
        int(ld.tamagawa_number())
    } for ld in E.local_data()]
    Etw, Dtw = E.minimal_quadratic_twist()
    if Etw.conductor() == E.conductor():
        data['min_quad_twist'] = {'label': label, 'disc': int(1)}
    else:
        minq_ainvs = ''.join(['['] + [str(c) for c in Etw.ainvs()] + [']'])
        r = curves.find_one({
            'jinv': str(E.j_invariant()),
            'ainvs': minq_ainvs
        })
        minq_label = "" if r is None else r['label']
        data['min_quad_twist'] = {'label': minq_label, 'disc': int(Dtw)}
    from lmfdb.elliptic_curves.web_ec import parse_points
    gens = [E(g) for g in parse_points(gens)]
    data['heights'] = [float(P.height()) for P in gens]
    if number == 1:
        data['aplist'] = E.aplist(100, python_ints=True)
        data['anlist'] = E.anlist(20, python_ints=True)
    return data
Ejemplo n.º 2
0
def download_qexp():
    ainvs = request.args.get('ainvs')
    E = EllipticCurve([int(a) for a in ainvs.split(',')])
    response = make_response('\n'.join(
        str(an) for an in E.anlist(int(request.args.get('limit', 100)),
                                   python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 3
0
def download_EC_qexp(label, limit):
    N, iso, number = split_lmfdb_label(label)
    if number:
        ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_label')
    else:
        ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_iso')
    E = EllipticCurve(ainvs)
    response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 4
0
def download_EC_qexp(label, limit):
    N, iso, number = split_lmfdb_label(label)
    if number:
        ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_label')
    else:
        ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_iso')
    E = EllipticCurve(ainvs)
    response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 5
0
def download_EC_qexp(label, limit):
    CDB = db_ec()
    N, iso, number = split_lmfdb_label(label)
    if number:
        data = CDB.find_one({'lmfdb_label': label})
    else:
        data = CDB.find_one({'lmfdb_iso': label})
    E = EllipticCurve(parse_ainvs(data['ainvs']))
    response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 6
0
def download_EC_qexp(label, limit):
    CDB = db_ec()
    N, iso, number = split_lmfdb_label(label)
    if number:
        data = CDB.find_one({'lmfdb_label': label})
    else:
        data = CDB.find_one({'lmfdb_iso': label})
    E = EllipticCurve(parse_ainvs(data['ainvs']))
    response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 7
0
def download_EC_qexp(label, limit):
    logger.debug(label)
    CDB = lmfdb.base.getDBConnection().elliptic_curves.curves
    N, iso, number = lmfdb_label_regex.match(label).groups()
    if number:
        data = CDB.find_one({"lmfdb_label": label})
    else:
        data = CDB.find_one({"lmfdb_iso": label})
    ainvs = data["ainvs"]
    logger.debug(ainvs)
    E = EllipticCurve([int(a) for a in ainvs])
    response = make_response(",".join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers["Content-type"] = "text/plain"
    return response
Ejemplo n.º 8
0
def download_EC_qexp(label, limit):
    ec_logger.debug(label)
    CDB = lmfdb.base.getDBConnection().elliptic_curves.curves
    N, iso, number = split_lmfdb_label(label)
    if number:
        data = CDB.find_one({'lmfdb_label': label})
    else:
        data = CDB.find_one({'lmfdb_iso': label})
    ainvs = data['ainvs']
    ec_logger.debug(ainvs)
    E = EllipticCurve([int(a) for a in ainvs])
    response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 9
0
def download_EC_qexp(label, limit):
    ec_logger.debug(label)
    CDB = lmfdb.base.getDBConnection().elliptic_curves.curves
    N, iso, number = split_lmfdb_label(label)
    if number:
        data = CDB.find_one({'lmfdb_label': label})
    else:
        data = CDB.find_one({'lmfdb_iso': label})
    ainvs = data['ainvs']
    ec_logger.debug(ainvs)
    E = EllipticCurve([int(a) for a in ainvs])
    response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 10
0
def make_extra_data(label, number, ainvs, gens):
    """
    C is a database elliptic curve entry.  Returns a dict with which to update the entry.

    Data fields needed in C already: 'ainvs', 'lmfdb_label', 'gens', 'number'
    """
    E = EllipticCurve([int(a) for a in ainvs])
    data = {}
    # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]'
    data['xainvs'] = ''.join(['[', ','.join(ainvs), ']'])
    data['equation'] = web_latex(E)
    data['signD'] = int(E.discriminant().sign())
    data['local_data'] = [{
        'p':
        int(ld.prime().gen()),
        'ord_cond':
        int(ld.conductor_valuation()),
        'ord_disc':
        int(ld.discriminant_valuation()),
        'ord_den_j':
        int(max(0, -(E.j_invariant().valuation(ld.prime().gen())))),
        'red':
        int(ld.bad_reduction_type()),
        'rootno':
        int(E.root_number(ld.prime().gen())),
        'kod':
        web_latex(ld.kodaira_symbol()).replace('$', ''),
        'cp':
        int(ld.tamagawa_number())
    } for ld in E.local_data()]
    Etw, Dtw = E.minimal_quadratic_twist()
    if Etw.conductor() == E.conductor():
        data['min_quad_twist'] = {'label': label, 'disc': int(1)}
    else:
        # Later this should be changed to look for xainvs but now all curves have ainvs
        minq_ainvs = [str(c) for c in Etw.ainvs()]
        r = curves.find_one({
            'jinv': str(E.j_invariant()),
            'ainvs': minq_ainvs
        })
        minq_label = "" if r is None else r['label']
        data['min_quad_twist'] = {'label': minq_label, 'disc': int(Dtw)}
    from lmfdb.elliptic_curves.web_ec import parse_points
    gens = [E(g) for g in parse_points(gens)]
    data['heights'] = [float(P.height()) for P in gens]
    if number == 1:
        data['aplist'] = E.aplist(100, python_ints=True)
        data['anlist'] = E.anlist(20, python_ints=True)
    return data
Ejemplo n.º 11
0
def _test_an_dict_over_Q(ainvs, B=100):
    """
    Test that the an_dict function works and gives the correct answer
    for an elliptic curve defined over QQ, by computing using the
    generic code in this file, and comparing with the output of Sage's
    anlist function for rational elliptic curves.
    """
    from sage.all import polygen, QQ, NumberField, EllipticCurve
    x = polygen(QQ,'x')
    F = NumberField(x - 1,'a'); a = F.gen()
    E = EllipticCurve(F, ainvs)
    EQ = EllipticCurve(QQ, ainvs)
    v = EQ.anlist(B)
    an = an_dict(E, B)
    for i, j in an.iteritems():
        assert j == v[i[0]]
Ejemplo n.º 12
0
def make_extra_data(label,number,ainvs,gens):
    """Given a curve label (and number, as some data is only stored wih
    curve number 1 in each class) and its ainvs and gens, returns a
    dict with which to update the entry.

    Extra items computed here:
    'equation': latex string of curve's equation
    'signD': sign of discriminant
    'local_data': list of dicts, one item for each bad prime
    'min_quad_twist': dict holding curve's min quadratic twist and the twisting discriminant
    'heights': list of heights of gens

    and for curve #1 in a class only:

    'aplist': list of a_p for p<100
    'anlist': list of a_n for n<=20

    """
    E = EllipticCurve(parse_ainvs(ainvs))
    data = {}
    # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]'
    data['equation'] = web_latex(E)
    data['signD'] = int(E.discriminant().sign())
    data['local_data'] = [{'p': int(ld.prime().gen()),
                           'ord_cond':int(ld.conductor_valuation()),
                           'ord_disc':int(ld.discriminant_valuation()),
                           'ord_den_j':int(max(0,-(E.j_invariant().valuation(ld.prime().gen())))),
                           'red':int(ld.bad_reduction_type()),
                           'rootno':int(E.root_number(ld.prime().gen())),
                           'kod':web_latex(ld.kodaira_symbol()).replace('$',''),
                           'cp':int(ld.tamagawa_number())}
                          for ld in E.local_data()]
    Etw, Dtw = E.minimal_quadratic_twist()
    if Etw.conductor()==E.conductor():
        data['min_quad_twist'] = {'label':label, 'disc':int(1)}
    else:
        minq_ainvs = ''.join(['['] + [str(c) for c in Etw.ainvs()] + [']'])
        r = curves.find_one({'jinv':str(E.j_invariant()), 'ainvs':minq_ainvs})
        minq_label = "" if r is None else r['label']
        data['min_quad_twist'] = {'label':minq_label, 'disc':int(Dtw)}
    from lmfdb.elliptic_curves.web_ec import parse_points
    gens = [E(g) for g in parse_points(gens)]
    data['heights'] = [float(P.height()) for P in gens]
    if number==1:
        data['aplist'] = E.aplist(100,python_ints=True)
        data['anlist'] = E.anlist(20,python_ints=True)
    return data
Ejemplo n.º 13
0
def download_EC_qexp(label, limit):
    try:
        N, iso, number = split_lmfdb_label(label)
    except (ValueError,AttributeError):
        return elliptic_curve_jump_error(label, {})
    if number:
        ainvs = db.ec_curvedata.lookup(label, 'ainvs', 'lmfdb_label')
    else:
        ainvs = db.ec_curvedata.lookup(label, 'ainvs', 'lmfdb_iso')
    if ainvs is None:
        return elliptic_curve_jump_error(label, {})        
    if limit > 100000:
        return redirect(url_for('.download_EC_qexp',label=label,limit=10000), 301)
    E = EllipticCurve(ainvs)
    response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 14
0
def make_extra_data(label,number,ainvs,gens):
    """
    C is a database elliptic curve entry.  Returns a dict with which to update the entry.

    Data fields needed in C already: 'ainvs', 'lmfdb_label', 'gens', 'number'
    """
    E = EllipticCurve([int(a) for a in ainvs])
    data = {}
    # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]'
    data['xainvs'] = ''.join(['[',','.join(ainvs),']'])
    data['equation'] = web_latex(E)
    data['signD'] = int(E.discriminant().sign())
    data['local_data'] = [{'p': int(ld.prime().gen()),
                           'ord_cond':int(ld.conductor_valuation()),
                           'ord_disc':int(ld.discriminant_valuation()),
                           'ord_den_j':int(max(0,-(E.j_invariant().valuation(ld.prime().gen())))),
                           'red':int(ld.bad_reduction_type()),
                           'rootno':int(E.root_number(ld.prime().gen())),
                           'kod':web_latex(ld.kodaira_symbol()).replace('$',''),
                           'cp':int(ld.tamagawa_number())}
                          for ld in E.local_data()]
    Etw, Dtw = E.minimal_quadratic_twist()
    if Etw.conductor()==E.conductor():
        data['min_quad_twist'] = {'label':label, 'disc':int(1)}
    else:
        # Later this should be changed to look for xainvs but now all curves have ainvs
        minq_ainvs = [str(c) for c in Etw.ainvs()]
        r = curves.find_one({'jinv':str(E.j_invariant()), 'ainvs':minq_ainvs})
        minq_label = "" if r is None else r['label']
        data['min_quad_twist'] = {'label':minq_label, 'disc':int(Dtw)}
    from lmfdb.elliptic_curves.web_ec import parse_points
    gens = [E(g) for g in parse_points(gens)]
    data['heights'] = [float(P.height()) for P in gens]
    if number==1:
        data['aplist'] = E.aplist(100,python_ints=True)
        data['anlist'] = E.anlist(20,python_ints=True)
    return data
Ejemplo n.º 15
0
class WebEC(object):
    """
    Class for an elliptic curve over Q
    """
    def __init__(self, dbdata):
        """
        Arguments:

            - dbdata: the data from the database
        """
        logger.debug("Constructing an instance of WebEC")
        self.__dict__.update(dbdata)
        # Next lines because the hyphens make trouble
        self.xintcoords = split_list(
            dbdata['x-coordinates_of_integral_points'])
        self.non_surjective_primes = dbdata['non-surjective_primes']
        # Next lines because the python identifiers cannot start with 2
        self.twoadic_index = dbdata['2adic_index']
        self.twoadic_log_level = dbdata['2adic_log_level']
        self.twoadic_gens = dbdata['2adic_gens']
        self.twoadic_label = dbdata['2adic_label']
        # All other fields are handled here
        self.make_curve()

    @staticmethod
    def by_label(label):
        """
        Searches for a specific elliptic curve in the curves
        collection by its label, which can be either in LMFDB or
        Cremona format.
        """
        try:
            N, iso, number = split_lmfdb_label(label)
            data = db_ec().find_one({"lmfdb_label": label})
        except AttributeError:
            try:
                N, iso, number = split_cremona_label(label)
                data = db_ec().find_one({"label": label})
            except AttributeError:
                return "Invalid label"  # caller must catch this and raise an error

        if data:
            return WebEC(data)
        return "Curve not found"  # caller must catch this and raise an error

    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

        # Old version: required constructing the actual elliptic curve
        # E, and computing some further data about it.

        # New version (May 2016): extra data fields now in the
        # database so we do not have to construct the curve or do any
        # computation with it on the fly.  As a failsafe the old way
        # is still included.

        data = self.data = {}
        try:
            data['ainvs'] = [int(c) for c in self.xainvs[1:-1].split(',')]
        except AttributeError:
            data['ainvs'] = [int(ai) for ai in self.ainvs]
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:  # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])
        mw = self.mw = {}
        mw['rank'] = self.rank
        mw['int_points'] = ''
        if self.xintcoords:
            a1, a2, a3, a4, a6 = [ZZ(a) for a in data['ainvs']]

            def lift_x(x):
                f = ((x + a2) * x + a4) * x + a6
                b = (a1 * x + a3)
                d = (b * b + 4 * f).sqrt()
                return (x, (-b + d) / 2)

            mw['int_points'] = ', '.join(
                web_latex(lift_x(x)) for x in self.xintcoords)

        mw['generators'] = ''
        mw['heights'] = []
        if self.gens:
            mw['generators'] = [
                web_latex(tuple(P)) for P in parse_points(self.gens)
            ]

        mw['tor_order'] = self.torsion
        tor_struct = [int(c) for c in self.torsion_structure]
        if mw['tor_order'] == 1:
            mw['tor_struct'] = '\mathrm{Trivial}'
            mw['tor_gens'] = ''
        else:
            mw['tor_struct'] = ' \\times '.join(
                ['\Z/{%s}\Z' % n for n in tor_struct])
            mw['tor_gens'] = ', '.join(
                web_latex(tuple(P))
                for P in parse_points(self.torsion_generators))

        # try to get all the data we need from the database entry (now in self)
        try:
            data['equation'] = self.equation
            local_data = self.local_data
            D = self.signD * prod(
                [ld['p']**ld['ord_disc'] for ld in local_data])
            data['disc'] = D
            Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond'])
                                  for ld in local_data])
            Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc'])
                                  for ld in local_data],
                                 unit=ZZ(self.signD))

            data['minq_D'] = minqD = self.min_quad_twist['disc']
            minq_label = self.min_quad_twist['label']
            data['minq_label'] = db_ec().find_one(
                {'label': minq_label}, ['lmfdb_label'])['lmfdb_label']
            data['minq_info'] = '(itself)' if minqD == 1 else '(by %s)' % minqD
            try:
                data['degree'] = self.degree
            except AttributeError:
                data['degree'] = 0  # invalid, but will be displayed nicely
            mw['heights'] = self.heights
            if self.number == 1:
                data['an'] = self.anlist
                data['ap'] = self.aplist
            else:
                r = db_ec().find_one({
                    'lmfdb_iso': self.lmfdb_iso,
                    'number': 1
                }, ['anlist', 'aplist'])
                data['an'] = r['anlist']
                data['ap'] = r['aplist']

        # otherwise fall back to computing it from the curve
        except AttributeError:
            print("Falling back to constructing E")
            self.E = EllipticCurve(data['ainvs'])
            data['equation'] = web_latex(self.E)
            data['disc'] = D = self.E.discriminant()
            Nfac = N.factor()
            Dfac = D.factor()
            bad_primes = [p for p, e in Nfac]
            try:
                data['degree'] = self.degree
            except AttributeError:
                try:
                    data['degree'] = self.E.modular_degree()
                except RuntimeError:
                    data['degree'] = 0  # invalid, but will be displayed nicely
            minq, minqD = self.E.minimal_quadratic_twist()
            data['minq_D'] = minqD
            if minqD == 1:
                data['minq_label'] = self.lmfdb_label
                data['minq_info'] = '(itself)'
            else:
                # This relies on the minimal twist being in the
                # database, which is true when the database only
                # contains the Cremona database.  It would be a good
                # idea if, when the database is extended, we ensured
                # that for any curve included, all twists of smaller
                # conductor are also included.
                minq_ainvs = [str(c) for c in minq.ainvs()]
                data['minq_label'] = db_ec().find_one(
                    {
                        'jinv': str(self.E.j_invariant()),
                        'ainvs': minq_ainvs
                    }, ['lmfdb_label'])['lmfdb_label']
                data['minq_info'] = '(by %s)' % minqD

            if self.gens:
                self.generators = [self.E(g) for g in parse_points(self.gens)]
                mw['heights'] = [P.height() for P in self.generators]

            data['an'] = self.E.anlist(20, python_ints=True)
            data['ap'] = self.E.aplist(100, python_ints=True)
            self.local_data = local_data = []
            for p in bad_primes:
                ld = self.E.local_data(p, algorithm="generic")
                local_data_p = {}
                local_data_p['p'] = p
                local_data_p['cp'] = ld.tamagawa_number()
                local_data_p['kod'] = web_latex(ld.kodaira_symbol()).replace(
                    '$', '')
                local_data_p['red'] = ld.bad_reduction_type()
                rootno = -ld.bad_reduction_type()
                if rootno == 0:
                    rootno = self.E.root_number(p)
                local_data_p['rootno'] = rootno
                local_data_p['ord_cond'] = ld.conductor_valuation()
                local_data_p['ord_disc'] = ld.discriminant_valuation()
                local_data_p['ord_den_j'] = max(
                    0, -self.E.j_invariant().valuation(p))
                local_data.append(local_data_p)

        # If we got the data from the database, the root numbers may
        # not have been stored there, so we have to compute them.  If
        # there are additive primes this means constructing the curve.
        for ld in self.local_data:
            if not 'rootno' in ld:
                rootno = -ld['red']
                if rootno == 0:
                    try:
                        E = self.E
                    except AttributeError:
                        self.E = E = EllipticCurve(data['ainvs'])
                    rootno = E.root_number(ld['p'])
                ld['rootno'] = rootno

        minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label'])

        data['disc_factor'] = latex(Dfac)
        data['cond_factor'] = latex(Nfac)
        data['disc_latex'] = web_latex(D)
        data['cond_latex'] = web_latex(N)

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['CM'] = "yes (\(D=%s\))" % data['CMD']
            if data['CMD'] % 4 == 0:
                d4 = ZZ(data['CMD']) // 4
                data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4
            else:
                data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD']
            data['ST'] = st_link_by_name(1, 2, 'N(U(1))')
        else:
            data['ST'] = st_link_by_name(1, 2, 'SU(2)')

        data['p_adic_primes'] = [
            p for i, p in enumerate(prime_range(5, 100))
            if (N * data['ap'][i]) % p != 0
        ]

        try:
            data['galois_images'] = [
                trim_galois_image_code(s) for s in self.galois_images
            ]
            data['non_surjective_primes'] = self.non_surjective_primes
        except AttributeError:
            #print "No Galois image data"
            data['galois_images'] = []
            data['non_surjective_primes'] = []

        data['galois_data'] = [{
            'p': p,
            'image': im
        } for p, im in zip(data['non_surjective_primes'],
                           data['galois_images'])]

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        self.class_url = url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)
        self.ncurves = db_ec().count({'lmfdb_iso': self.lmfdb_iso})
        isodegs = [str(d) for d in self.isogeny_degrees if d > 1]
        if len(isodegs) < 3:
            data['isogeny_degrees'] = " and ".join(isodegs)
        else:
            data['isogeny_degrees'] = " and ".join(
                [", ".join(isodegs[:-1]), isodegs[-1]])

        if self.twoadic_gens:
            from sage.matrix.all import Matrix
            data['twoadic_gen_matrices'] = ','.join(
                [latex(Matrix(2, 2, M)) for M in self.twoadic_gens])
            data[
                'twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"

        # Leading term of L-function & BSD data
        bsd = self.bsd = {}
        r = self.rank
        if r >= 2:
            bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r, r)
        elif r:
            bsd['lder_name'] = "L'(E,1)"
        else:
            bsd['lder_name'] = "L(E,1)"

        bsd['reg'] = self.regulator
        bsd['omega'] = self.real_period
        bsd['sha'] = int(0.1 + self.sha_an)
        bsd['lder'] = self.special_value

        # Optimality (the optimal curve in the class is the curve
        # whose Cremona label ends in '1' except for '990h' which was
        # labelled wrongly long ago)

        if self.iso == '990h':
            data['Gamma0optimal'] = bool(self.number == 3)
        else:
            data['Gamma0optimal'] = bool(self.number == 1)

        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = (padic_db().find({
                'lmfdb_iso':
                self.lmfdb_iso
            }).count()) > 0

        tamagawa_numbers = [ZZ(ld['cp']) for ld in local_data]
        cp_fac = [cp.factor() for cp in tamagawa_numbers]
        cp_fac = [
            latex(cp) if len(cp) < 2 else '(' + latex(cp) + ')'
            for cp in cp_fac
        ]
        bsd['tamagawa_factors'] = r'\cdot'.join(cp_fac)
        bsd['tamagawa_product'] = prod(tamagawa_numbers)

        data['newform'] = web_latex(
            PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))
        data['newform_label'] = self.newform_label = newform_label(
            cond, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms",
                                    level=cond,
                                    weight=2,
                                    character=1,
                                    label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)
        self._code = None

        self.class_url = url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)
        self.friends = [('Isogeny class ' + self.lmfdb_iso, self.class_url),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_triple_label",
                                 conductor=minq_N,
                                 iso_label=minq_iso,
                                 number=minq_number)),
                        ('All twists ',
                         url_for(".rational_elliptic_curves", jinv=self.jinv)),
                        ('L-function',
                         url_for("l_functions.l_function_ec_page",
                                 label=self.lmfdb_label))]
        if not self.cm:
            if N <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          label=self.lmfdb_iso))]
            if N <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          label=self.lmfdb_iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.downloads = [('Download coefficients of q-expansion',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_label,
                                   limit=1000)),
                          ('Download all stored data',
                           url_for(".download_EC_all",
                                   label=self.lmfdb_label)),
                          ('Download Magma code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='magma')),
                          ('Download Sage code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='sage')),
                          ('Download GP code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='gp'))]

        try:
            self.plot = encode_plot(self.E.plot())
        except AttributeError:
            self.plot = encode_plot(EllipticCurve(data['ainvs']).plot())

        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [('Label', self.lmfdb_label), (None, self.plot_link),
                           ('Conductor', '\(%s\)' % data['conductor']),
                           ('Discriminant', '\(%s\)' % data['disc']),
                           ('j-invariant', '%s' % data['j_inv_latex']),
                           ('CM', '%s' % data['CM']),
                           ('Rank', '\(%s\)' % mw['rank']),
                           ('Torsion Structure', '\(%s\)' % mw['tor_struct'])]

        self.title = "Elliptic Curve %s (Cremona label %s)" % (
            self.lmfdb_label, self.label)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]

    def code(self):
        if self._code == None:
            self.make_code_snippets()
        return self._code

    def make_code_snippets(self):
        # read in code.yaml from current directory:

        _curdir = os.path.dirname(os.path.abspath(__file__))
        self._code = yaml.load(open(os.path.join(_curdir, "code.yaml")))

        # Fill in placeholders for this specific curve:

        for lang in ['sage', 'pari', 'magma']:
            self._code['curve'][lang] = self._code['curve'][lang] % (
                self.data['ainvs'], self.label)
        return
        for k in self._code:
            if k != 'prompt':
                for lang in self._code[k]:
                    self._code[k][lang] = self._code[k][lang].split("\n")
                    # remove final empty line
                    if len(self._code[k][lang][-1]) == 0:
                        self._code[k][lang] = self._code[k][lang][:-1]
Ejemplo n.º 16
0
def download_qexp():
    ainvs = request.args.get('ainvs')
    E = EllipticCurve([int(a) for a in ainvs.split(',')])
    response = make_response('\n'.join(str(an) for an in E.anlist(int(request.args.get('limit', 100)), python_ints=True)))
    response.headers['Content-type'] = 'text/plain'
    return response
Ejemplo n.º 17
0
def read_line_old(line):
    r""" Parses one line from input file.  Returns the hash and a dict
    containing fields with keys as above.  This original version
    expects 6 fields on each line, separated by a colon:

    0. hash
    1. label
    2. root number
    3. (not used)
    4. zeros
    5. plot data

    """
    fields = line.split(":")
    assert len(fields)==6
    label = fields[1] # use this isogeny class label to get info about the curve
    E = curves.find_one({'iso': label})

    data = constant_data()
    instances = {}

    # Set the fields in the Instances collection:

    cond = data['conductor'] = int(E['conductor'])
    iso = E['lmfdb_iso'].split('.')[1]
    instances['url'] = 'EllipticCurve/Q/%s/%s' % (cond,iso)
    instances['Lhash'] = Lhash = fields[0]
    instances['type'] = 'ECQ'

    # Set the fields in the Lfunctions collection:

    data['Lhash'] = Lhash
    data['root_number'] = int(fields[2])
    data['order_of_vanishing'] = int(E['rank'])
    data['central_character'] = '%s.1' % cond
    data['st_group'] = 'N(U(1))' if E['cm'] else 'SU(2)'
    data['leading_term'] = float(E['special_value'])

    # Zeros

    zeros = fields[4][1:-1].split(",")
    # omit negative ones and 0, using only string tests:
    data['positive_zeros'] = [y for y in zeros if y!='0' and y[0]!='-']
    data['z1'] = data['positive_zeros'][0]
    data['z2'] = data['positive_zeros'][1]
    data['z3'] = data['positive_zeros'][2]

    # plot data

    plot_xy = [[float(v) for v in vv.split(",")] for vv in fields[5][2:-3].split("],[")]
    # constant difference in x-coordinate sequence:
    data['plot_delta'] = plot_xy[1][0]-plot_xy[0][0]
    # list of y coordinates for x>0:
    data['plot_values'] = [y for x,y in plot_xy if x>=0]

    # Euler factors: we need the ap which are currently not in the
    # database so we call Sage.  It might be a good idea to store in
    # the ec database (1) all ap for p<100; (2) all ap for bad p.
    Esage = EllipticCurve([ZZ(a) for a in E['ainvs']])
    data['bad_lfactors'] = make_bad_lfactors(Esage)
    data['euler_factors'] = make_euler_factors(Esage)

    # Dirichlet coefficients

    an = Esage.anlist(10)
    for n in range(2,11):
        data['A%s' % n] = str(an[n])
        data['a%s' % n] = [an[n]/sqrt(float(n)),0]

    return Lhash, data, instances
Ejemplo n.º 18
0
def allgens(line):
    r""" Parses one line from an allgens file.  Returns the label and
    a dict containing fields with keys 'conductor', 'iso', 'number',
    'ainvs', 'jinv', 'cm', 'rank', 'gens', 'torsion_order', 'torsion_structure',
    'torsion_generators', all values being strings or ints, and more.

    Input line fields:

    conductor iso number ainvs rank torsion_structure gens torsion_gens

    Sample input line:

    20202 i 2 [1,0,0,-298389,54947169] 1 [2,4] [-570:6603:1] [-622:311:1] [834:19239:1]
    """
    global lmfdb_label_to_label
    global label_to_lmfdb_label

    data = split(line)
    iso = data[0] + data[1]
    label = iso + data[2]
    try:
        lmfdb_label = label_to_lmfdb_label[label]
    except AttributeError:
        print("Label {} not found in label_to_lmfdb_label dict!".format(label))
        lmfdb_label = ""

    global nallgens
    nallgens += 1
    if nallgens % 100 == 0:
        print("processing allgens for {} (#{})".format(label, nallgens))
    rank = int(data[4])
    t = data[5]
    tor_struct = [] if t == '[]' else t[1:-1].split(",")
    torsion = int(prod([int(ti) for ti in tor_struct], 1))
    ainvs = parse_ainvs(data[3])
    E = EllipticCurve(ainvs)
    jinv = text_type(E.j_invariant())
    if E.has_cm():
        cm = int(E.cm_discriminant())
    else:
        cm = int(0)
    N = E.conductor()
    bad_p = N.prime_factors()  # will be sorted
    num_bad_p = len(bad_p)

    local_data = [{
        'p':
        int(ld.prime().gen()),
        'ord_cond':
        int(ld.conductor_valuation()),
        'ord_disc':
        int(ld.discriminant_valuation()),
        'ord_den_j':
        int(max(0, -(E.j_invariant().valuation(ld.prime().gen())))),
        'red':
        int(ld.bad_reduction_type()),
        'rootno':
        int(E.root_number(ld.prime().gen())),
        'kod':
        web_latex(ld.kodaira_symbol()).replace('$', ''),
        'cp':
        int(ld.tamagawa_number())
    } for ld in E.local_data()]
    semistable = all([ld['ord_cond'] == 1 for ld in local_data])

    gens = [
        gen.replace("[", "(").replace("]", ")") for gen in data[6:6 + rank]
    ]
    tor_gens = ["%s" % parse_tgens(tgens[1:-1]) for tgens in data[6 + rank:]]

    from lmfdb.elliptic_curves.web_ec import parse_points
    heights = [float(E(P).height()) for P in parse_points(gens)]

    Etw, Dtw = E.minimal_quadratic_twist()
    if Etw.conductor() == N:
        min_quad_twist = {
            'label': label,
            'lmfdb_label': lmfdb_label,
            'disc': int(1)
        }
    else:
        minq_ainvs = Etw.ainvs()
        r = curves.lucky({
            'jinv': str(E.j_invariant()),
            'ainvs': minq_ainvs
        },
                         projection=['label', 'lmfdb_label'])
        min_quad_twist = {
            'label': r['label'],
            'lmfdb_label': r['lmfdb_label'],
            'disc': int(Dtw)
        }

    trace_hash = TraceHashClass(iso, E)

    return label, {
        'conductor': int(data[0]),
        'iso': iso,
        'number': int(data[2]),
        'ainvs': ainvs,
        'jinv': jinv,
        'cm': cm,
        'rank': rank,
        'gens': gens,
        'torsion': torsion,
        'torsion_structure': tor_struct,
        'torsion_generators': tor_gens,
        'trace_hash': trace_hash,
        'equation': web_latex(E),
        'bad_primes': bad_p,
        'num_bad_primes': num_bad_p,
        'local_data': local_data,
        'semistable': semistable,
        'signD': int(E.discriminant().sign()),
        'heights': heights,
        'aplist': E.aplist(100, python_ints=True),
        'anlist': E.anlist(20, python_ints=True),
        'min_quad_twist': min_quad_twist,
    }
Ejemplo n.º 19
0
class WebEC(object):
    """
    Class for an elliptic curve over Q
    """
    def __init__(self, dbdata):
        """
        Arguments:

            - dbdata: the data from the database
        """
        logger.debug("Constructing an instance of ECisog_class")
        self.__dict__.update(dbdata)
        # Next lines because the hyphens make trouble
        self.xintcoords = split_list(dbdata['x-coordinates_of_integral_points'])
        self.non_surjective_primes = dbdata['non-surjective_primes']
        # Next lines because the python identifiers cannot start with 2
        self.twoadic_index = dbdata['2adic_index']
        self.twoadic_log_level = dbdata['2adic_log_level']
        self.twoadic_gens = dbdata['2adic_gens']
        self.twoadic_label = dbdata['2adic_label']
        # All other fields are handled here
        self.make_curve()

    @staticmethod
    def by_label(label):
        """
        Searches for a specific elliptic curve in the curves
        collection by its label, which can be either in LMFDB or
        Cremona format.
        """
        try:
            N, iso, number = split_lmfdb_label(label)
            data = db_ec().find_one({"lmfdb_label" : label})
        except AttributeError:
            try:
                N, iso, number = split_cremona_label(label)
                data = db_ec().find_one({"label" : label})
            except AttributeError:
                return "Invalid label" # caller must catch this and raise an error

        if data:
            return WebEC(data)
        return "Curve not found" # caller must catch this and raise an error

    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

        # Old version: required constructing the actual elliptic curve
        # E, and computing some further data about it.

        # New version (May 2016): extra data fields now in the
        # database so we do not have to construct the curve or do any
        # computation with it on the fly.  As a failsafe the old way
        # is still included.

        data = self.data = {}
        try:
            data['ainvs'] = [int(c) for c in self.xainvs[1:-1].split(',')]
        except AttributeError:
            data['ainvs'] = [int(ai) for ai in self.ainvs]
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']: # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])
        mw = self.mw = {}
        mw['rank'] = self.rank
        mw['int_points'] = ''
        if self.xintcoords:
            a1, a2, a3, a4, a6 = [ZZ(a) for a in data['ainvs']]
            def lift_x(x):
                f = ((x + a2) * x + a4) * x + a6
                b = (a1*x + a3)
                d = (b*b + 4*f).sqrt()
                return (x, (-b+d)/2)
            mw['int_points'] = ', '.join(web_latex(lift_x(x)) for x in self.xintcoords)

        mw['generators'] = ''
        mw['heights'] = []
        if self.gens:
            mw['generators'] = [web_latex(tuple(P)) for P in parse_points(self.gens)]

        mw['tor_order'] = self.torsion
        tor_struct = [int(c) for c in self.torsion_structure]
        if mw['tor_order'] == 1:
            mw['tor_struct'] = '\mathrm{Trivial}'
            mw['tor_gens'] = ''
        else:
            mw['tor_struct'] = ' \\times '.join(['\Z/{%s}\Z' % n for n in tor_struct])
            mw['tor_gens'] = ', '.join(web_latex(tuple(P)) for P in parse_points(self.torsion_generators))

        # try to get all the data we need from the database entry (now in self)
        try:
            data['equation'] = self.equation
            local_data = self.local_data
            badprimes = [ZZ(ld['p']) for ld in local_data]
            D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data])
            data['disc'] = D
            Nfac = Factorization([(ZZ(ld['p']),ld['ord_cond']) for ld in local_data])
            Dfac = Factorization([(ZZ(ld['p']),ld['ord_disc']) for ld in local_data], unit=ZZ(self.signD))

            data['minq_D'] = minqD = self.min_quad_twist['disc']
            minq_label = self.min_quad_twist['label']
            data['minq_label'] = db_ec().find_one({'label':minq_label}, ['lmfdb_label'])['lmfdb_label']
            data['minq_info'] = '(itself)' if minqD==1 else '(by %s)' % minqD
            try:
                data['degree'] = self.degree
            except AttributeError:
                data['degree']  =0 # invalid, but will be displayed nicely
            mw['heights'] = self.heights
            if self.number == 1:
                data['an'] = self.anlist
                data['ap'] = self.aplist
            else:
                r = db_ec().find_one({'lmfdb_iso':self.lmfdb_iso, 'number':1}, ['anlist','aplist'])
                data['an'] = r['anlist']
                data['ap'] = r['aplist']

        # otherwise fall back to computing it from the curve
        except AttributeError:
            print("Falling back to constructing E")
            self.E = EllipticCurve(data['ainvs'])
            data['equation'] = web_latex(self.E)
            data['disc'] = D = self.E.discriminant()
            Nfac = N.factor()
            Dfac = D.factor()
            bad_primes = [p for p,e in Nfac]
            try:
                data['degree'] = self.degree
            except AttributeError:
                try:
                    data['degree'] = self.E.modular_degree()
                except RuntimeError:
                    data['degree'] = 0  # invalid, but will be displayed nicely
            minq, minqD = self.E.minimal_quadratic_twist()
            data['minq_D'] = minqD
            if minqD == 1:
                data['minq_label'] = self.lmfdb_label
                data['minq_info'] = '(itself)'
            else:
                # This relies on the minimal twist being in the
                # database, which is true when the database only
                # contains the Cremona database.  It would be a good
                # idea if, when the database is extended, we ensured
                # that for any curve included, all twists of smaller
                # conductor are also included.
                minq_ainvs = [str(c) for c in minq.ainvs()]
                data['minq_label'] = db_ec().find_one({'jinv':str(self.E.j_invariant()),
                                                       'ainvs': minq_ainvs},['lmfdb_label'])['lmfdb_label']
                data['minq_info'] = '(by %s)' % minqD

            if self.gens:
                self.generators = [self.E(g) for g in parse_points(self.gens)]
                mw['heights'] = [P.height() for P in self.generators]

            data['an'] = self.E.anlist(20,python_ints=True)
            data['ap'] = self.E.aplist(100,python_ints=True)
            self.local_data = local_data = []
            for p in bad_primes:
                ld = self.E.local_data(p, algorithm="generic")
                local_data_p = {}
                local_data_p['p'] = p
                local_data_p['cp'] = ld.tamagawa_number()
                local_data_p['kod'] = web_latex(ld.kodaira_symbol()).replace('$', '')
                local_data_p['red'] = ld.bad_reduction_type()
                local_data_p['ord_cond'] = ld.conductor_valuation()
                local_data_p['ord_disc'] = ld.discriminant_valuation()
                local_data_p['ord_den_j'] = max(0,-self.E.j_invariant().valuation(p))
                local_data.append(local_data_p)

        jfac = Factorization([(ZZ(ld['p']),ld['ord_den_j']) for ld in local_data])

        minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label'])

        data['disc_factor'] = latex(Dfac)
        data['cond_factor'] =latex(Nfac)
        data['disc_latex'] = web_latex(D)
        data['cond_latex'] = web_latex(N)

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['CM'] = "yes (\(D=%s\))" % data['CMD']
            if data['CMD']%4==0:
                d4 = ZZ(data['CMD'])//4
                data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4
            else:
                data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD']
            data['ST'] = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.N(U(1))'),'N(\\mathrm{U}(1))')
        else:
            data['ST'] = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.SU(2)'),'\\mathrm{SU}(2)')

        data['p_adic_primes'] = [p for i,p in enumerate(sage.all.prime_range(5, 100))
                                 if (N*data['ap'][i]) %p !=0]

        try:
            data['galois_images'] = [trim_galois_image_code(s) for s in self.galois_images]
            data['non_surjective_primes'] = self.non_surjective_primes
        except AttributeError:
            #print "No Galois image data"
            data['galois_images'] = []
            data['non_surjective_primes'] = []

        data['galois_data'] = [{'p': p,'image': im }
                               for p,im in zip(data['non_surjective_primes'],
                                               data['galois_images'])]

        if self.twoadic_gens:
            from sage.matrix.all import Matrix
            data['twoadic_gen_matrices'] = ','.join([latex(Matrix(2,2,M)) for M in self.twoadic_gens])
            data['twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"

        # Leading term of L-function & BSD data
        bsd = self.bsd = {}
        r = self.rank
        if r >= 2:
            bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r,r)
        elif r:
            bsd['lder_name'] = "L'(E,1)"
        else:
            bsd['lder_name'] = "L(E,1)"

        bsd['reg'] = self.regulator
        bsd['omega'] = self.real_period
        bsd['sha'] = int(0.1+self.sha_an)
        bsd['lder'] = self.special_value

        # Optimality (the optimal curve in the class is the curve
        # whose Cremona label ends in '1' except for '990h' which was
        # labelled wrongly long ago)

        if self.iso == '990h':
            data['Gamma0optimal'] = bool(self.number == 3)
        else:
            data['Gamma0optimal'] = bool(self.number == 1)


        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = (padic_db().find({'lmfdb_iso': self.lmfdb_iso}).count()) > 0

        tamagawa_numbers = [ZZ(ld['cp']) for ld in local_data]
        cp_fac = [cp.factor() for cp in tamagawa_numbers]
        cp_fac = [latex(cp) if len(cp)<2 else '('+latex(cp)+')' for cp in cp_fac]
        bsd['tamagawa_factors'] = r'\cdot'.join(cp_fac)
        bsd['tamagawa_product'] = sage.misc.all.prod(tamagawa_numbers)

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        data['newform'] =  web_latex(PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))
        data['newform_label'] = self.newform_label = newform_label(cond,2,1,iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=cond, weight=2, character=1, label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)
        self._code = None

        self.friends = [
            ('Isogeny class ' + self.lmfdb_iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)),
            ('Minimal quadratic twist %s %s' % (data['minq_info'], data['minq_label']), url_for(".by_triple_label", conductor=minq_N, iso_label=minq_iso, number=minq_number)),
            ('All twists ', url_for(".rational_elliptic_curves", jinv=self.jinv)),
            ('L-function', url_for("l_functions.l_function_ec_page", label=self.lmfdb_label))]
        if not self.cm:
            if N<=300:
                self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso))]
            if N<=50:
                self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', label=self.lmfdb_iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label, self.newform_link)]

        self.downloads = [('Download coefficients of q-expansion', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=1000)),
                          ('Download all stored data', url_for(".download_EC_all", label=self.lmfdb_label)),
                          ('Download Magma code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='magma')),
                          ('Download Sage code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='sage')),
                          ('Download GP code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='gp'))
        ]

        try:
            self.plot = encode_plot(self.E.plot())
        except AttributeError:
            self.plot = encode_plot(EllipticCurve(data['ainvs']).plot())

        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [('Label', self.lmfdb_label),
                           (None, self.plot_link),
                           ('Conductor', '\(%s\)' % data['conductor']),
                           ('Discriminant', '\(%s\)' % data['disc']),
                           ('j-invariant', '%s' % data['j_inv_latex']),
                           ('CM', '%s' % data['CM']),
                           ('Rank', '\(%s\)' % mw['rank']),
                           ('Torsion Structure', '\(%s\)' % mw['tor_struct'])
                           ]

        self.title = "Elliptic Curve %s (Cremona label %s)" % (self.lmfdb_label, self.label)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                           ('$\Q$', url_for(".rational_elliptic_curves")),
                           ('%s' % N, url_for(".by_conductor", conductor=N)),
                           ('%s' % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)),
                           ('%s' % num,' ')]

    def code(self):
        if self._code == None:
            self.make_code_snippets()
        return self._code

    def make_code_snippets(self):
        # read in code.yaml from current directory:

        _curdir = os.path.dirname(os.path.abspath(__file__))
        self._code =  yaml.load(open(os.path.join(_curdir, "code.yaml")))

        # Fill in placeholders for this specific curve:

        for lang in ['sage', 'pari', 'magma']:
            self._code['curve'][lang] = self._code['curve'][lang] % (self.data['ainvs'],self.label)
        return
        for k in self._code:
            if k != 'prompt':
                for lang in self._code[k]:
                    self._code[k][lang] = self._code[k][lang].split("\n")
                    # remove final empty line
                    if len(self._code[k][lang][-1])==0:
                        self._code[k][lang] = self._code[k][lang][:-1]