Beispiel #1
0
def nu1_mu_info(w,n):
    """ return data for ST group N(U(1)) x mu(n) (of any wt > 0); these groups are not stored in the database """
    assert w > 0 and n > 0
    n = ZZ(n)
    rec = {}
    rec['label'] = "%d.2.1.d%d"%(w,n)
    rec['weight'] = w
    rec['degree'] = 2
    rec['rational'] = boolean_name(True if n <= 2 else False)
    rec['name'] = 'U(1)[D%d]'%n if n > 1 else 'N(U(1))'
    rec['pretty'] = r'\mathrm{U}(1)[D_{%d}]'%n if n > 1 else r'N(\mathrm{U}(1))'
    rec['real_dimension'] = 1
    rec['components'] = int(2*n)
    rec['ambient'] = '\mathrm{U}(2)'
    rec['connected'] = boolean_name(rec['components'] == 1)
    rec['st0_name'] = 'U(1)'
    rec['identity_component'] = st0_pretty(rec['st0_name'])
    rec['st0_description'] = '\\left\\{\\begin{bmatrix}\\alpha&0\\\\0&\\bar\\alpha\\end{bmatrix}:\\alpha\\bar\\alpha = 1,\\ \\alpha\\in\\mathbb{C}\\right\\}'
    rec['component_group'] = 'D_{%d}'%n
    rec['abelian'] = boolean_name(n <= 2)
    rec['cyclic'] = boolean_name(n <= 1)
    rec['solvable'] = boolean_name(True)
    rec['trace_zero_density']='1/2'
    rec['gens'] = r'\left\{\begin{bmatrix} 0 & 1\\ -1 & 0\end{bmatrix}, \begin{bmatrix} 1 & 0 \\ 0 & \zeta_{%d}\end{bmatrix}\right\}'%n
    rec['numgens'] = 2
    rec['subgroups'] = comma_separated_list([st_link("%d.2.1.d%d"%(w,n/p)) for p in n.prime_factors()])
    rec['supgroups'] = comma_separated_list([st_link("%d.2.1.d%d"%(w,p*n)) for p in [2,3,5]] + ["$\ldots$"])
    rec['moments'] = [['x'] + [ '\\mathrm{E}[x^{%d}]'%m for m in range(13)]]
    nu1moments = ['1','0','1','0','3','0','10','0','35','0','126','0','462']
    rec['moments'] += [['a_1'] + [nu1moments[m] if m % n == 0  else '0' for m in range(13)]]
    rec['trace_moments'] = trace_moments(rec['moments'])
    rec['counts'] = [['a_1', [[0,n]]]]
    return rec
Beispiel #2
0
def nu1_mu_info(w,n):
    """ return data for ST group N(U(1)) x mu(n) (of any wt > 0); these groups are not stored in the database """
    assert w > 0 and n > 0
    n = ZZ(n)
    rec = {}
    rec['label'] = "%d.2.B.d%d"%(w,n)
    rec['weight'] = w
    rec['degree'] = 2
    rec['rational'] = boolean_name(True if n <= 2 else False)
    rec['name'] = 'U(1)[D%d]'%n if n > 1 else 'N(U(1))'
    rec['pretty'] = r'\mathrm{U}(1)[D_{%d}]'%n if n > 1 else r'N(\mathrm{U}(1))'
    rec['real_dimension'] = 1
    rec['components'] = int(2*n)
    rec['ambient'] = r'\mathrm{U}(2)'
    rec['connected'] = boolean_name(rec['components'] == 1)
    rec['st0_name'] = 'U(1)'
    rec['identity_component'] = st0_pretty(rec['st0_name'])
    rec['st0_description'] = r'\left\{\begin{bmatrix}\alpha&0\\0&\bar\alpha\end{bmatrix}:\alpha\bar\alpha = 1,\ \alpha\in\mathbb{C}\right\}'
    rec['symplectic_form'] = r"\begin{bmatrix}0&1\\-1&0\end{bmatrix}"
    rec['hodge_circle'] = r"u\mapsto \mathrm{diag}(u,u^{-1})"
    rec['component_group'] = 'D_{%d}'%n
    rec['abelian'] = boolean_name(n <= 2)
    rec['cyclic'] = boolean_name(n <= 1)
    rec['solvable'] = boolean_name(True)
    rec['trace_zero_density']='1/2'
    rec['gens'] = r'\left\{\begin{bmatrix} 0 & 1\\ -1 & 0\end{bmatrix}, \begin{bmatrix} 1 & 0 \\ 0 & \zeta_{%d}\end{bmatrix}\right\}'%n
    rec['numgens'] = 2
    rec['subgroups'] = comma_separated_list([st_link("%d.2.B.d%d"%(w,n/p)) for p in n.prime_factors()])
    rec['supgroups'] = comma_separated_list([st_link("%d.2.B.d%d"%(w,p*n)) for p in [2,3,5]] + [r"$\ldots$"])
    rec['moments'] = [['x'] + [ r'\mathrm{E}[x^{%d}]'%m for m in range(13)]]
    nu1moments = ['1','0','1','0','3','0','10','0','35','0','126','0','462']
    rec['moments'] += [['a_1'] + [nu1moments[m] if m % n == 0  else '0' for m in range(13)]]
    rec['trace_moments'] = trace_moments(rec['moments'])
    rec['counts'] = [['a_1', [[0,n]]]]
    return rec
Beispiel #3
0
def su2_mu_info(w,n):
    """ return data for ST group SU(2) x mu(n) (of any wt > 0); these groups are not stored in the database """
    assert w > 0 and n > 0
    n = ZZ(n)
    rec = {}
    rec['label'] = "%d.2.3.c%d"%(w,n)
    rec['weight'] = w
    rec['degree'] = 2
    rec['rational'] = boolean_name(True if n <= 2 else False)
    rec['name'] = 'SU(2)[C%d]'%n if n > 1 else 'SU(2)'
    rec['pretty'] = r'\mathrm{SU}(2)[C_{%d}]'%n if n > 1 else r'\mathrm{SU}(2)'
    rec['real_dimension'] = 3
    rec['components'] = int(n)
    rec['ambient'] = '\mathrm{U}(2)'
    rec['connected'] = boolean_name(rec['components'] == 1)
    rec['st0_name'] = 'SU(2)'
    rec['identity_component'] = st0_pretty(rec['st0_name'])
    rec['st0_description'] = r'\left\{\begin{bmatrix}\alpha&\beta\\-\bar\beta&\bar\alpha\end{bmatrix}:\alpha\bar\alpha+\beta\bar\beta = 1,\ \alpha,\beta\in\mathbb{C}\right\}'
    rec['component_group'] = 'C_{%d}'%n
    rec['abelian'] = boolean_name(True)
    rec['cyclic'] = boolean_name(True)
    rec['solvable'] = boolean_name(True)
    rec['trace_zero_density']='0'
    rec['gens'] = r'\begin{bmatrix} 1 & 0 \\ 0 & \zeta_{%d}\end{bmatrix}'%n
    rec['numgens'] = 1
    rec['subgroups'] = comma_separated_list([st_link("%d.2.3.c%d"%(w,n/p)) for p in n.prime_factors()])
    rec['supgroups'] = comma_separated_list([st_link("%d.2.3.c%d"%(w,p*n)) for p in [2,3,5]] + ["$\ldots$"])
    rec['moments'] = [['x'] + [ '\\mathrm{E}[x^{%d}]'%m for m in range(13)]]
    su2moments = ['1','0','1','0','2','0','5','0','14','0','42','0','132']
    rec['moments'] += [['a_1'] + [su2moments[m] if m % n == 0  else '0' for m in range(13)]]
    rec['trace_moments'] = trace_moments(rec['moments'])
    rec['counts'] = []
    return rec
Beispiel #4
0
def mu_info(n):
    """ return data for ST group mu(n); for n > 2 these groups are irrational and not stored in the database """
    n = ZZ(n)
    rec = {}
    rec['label'] = "0.1.%d"%n
    rec['weight'] = 0
    rec['degree'] = 1
    rec['rational'] = boolean_name(True if n <= 2 else False)
    rec['name'] = 'mu(%d)'%n
    rec['pretty'] = r'\mu(%d)'%n
    rec['real_dimension'] = 0
    rec['components'] = int(n)
    rec['ambient'] = r'\mathrm{O}(1)' if n <= 2 else r'\mathrm{U}(1)'
    rec['connected'] = boolean_name(rec['components'] == 1)
    rec['st0_name'] = 'SO(1)'
    rec['identity_component'] = st0_pretty(rec['st0_name'])
    rec['st0_description'] = r"\textsf{trivial}"
    rec['component_group'] = 'C_{%d}'%n
    rec['trace_zero_density']='0'
    rec['abelian'] = boolean_name(True)
    rec['cyclic'] = boolean_name(True)
    rec['solvable'] = boolean_name(True)
    rec['gens'] = r'\left[\zeta_{%d}\right]'%n
    rec['numgens'] = 1
    rec['subgroups'] = comma_separated_list([st_link("0.1.%d"%(n/p)) for p in n.prime_factors()])
    # only list supgroups with the same ambient (i.e.if mu(n) lies in O(1) don't list supgroups that are not)
    if n == 1:
        rec['supgroups'] = st_link("0.1.2")
    elif n > 2:
        rec['supgroups'] = comma_separated_list([st_link("0.1.%d"%(p*n)) for p in [2,3,5]] + [r"$\ldots$"])
    rec['moments'] = [['x'] + [ r'\mathrm{E}[x^{%d}]'%m for m in range(13)]]
    rec['moments'] += [['a_1'] + ['1' if m % n == 0  else '0' for m in range(13)]]
    rec['trace_moments'] = trace_moments(rec['moments'])
    rec['second_trace_moment'] = 1 if n <= 2 else 0
    rec['fourth_trace_moment'] = 1 if n <= 2 else 0
    rational_traces = [1] if n%2 else [1,-1]
    rec['counts'] = [['a_1', [[t,1] for t in rational_traces]]]
    if n > 1:
        T = [['$\\mathrm{Pr}[a_1=%s]=\\frac{1}{%s}$'%(m,n) for m in rational_traces]]
    else:
        T = [['$\\mathrm{Pr}[a_1=1]=1$']]
    rec['probabilities'] = "<table><tr>" + "<tr></tr>".join(["<td>" + "<td></td".join(r) + "</td>" for r in T]) + "</tr></table>"
    return rec
Beispiel #5
0
def su2_mu_info(w, n):
    """ return data for ST group SU(2) x mu(n) (of any wt > 0); these groups are not stored in the database """
    assert w > 0 and n > 0
    n = ZZ(n)
    rec = {}
    rec['label'] = "%d.2.3.c%d" % (w, n)
    rec['weight'] = w
    rec['degree'] = 2
    rec['rational'] = boolean_name(True if n <= 2 else False)
    rec['name'] = 'SU(2)[C%d]' % n if n > 1 else 'SU(2)'
    rec['pretty'] = r'\mathrm{SU}(2)[C_{%d}]' % n if n > 1 else r'\mathrm{SU}(2)'
    rec['real_dimension'] = 3
    rec['components'] = int(n)
    rec['ambient'] = r'\mathrm{U}(2)'
    rec['connected'] = boolean_name(rec['components'] == 1)
    rec['st0_name'] = 'SU(2)'
    rec['identity_component'] = st0_pretty(rec['st0_name'])
    rec['st0_description'] = r'\left\{\begin{bmatrix}\alpha&\beta\\-\bar\beta&\bar\alpha\end{bmatrix}:\alpha\bar\alpha+\beta\bar\beta = 1,\ \alpha,\beta\in\mathbb{C}\right\}'
    rec['component_group'] = 'C_{%d}' % n
    rec['abelian'] = boolean_name(True)
    rec['cyclic'] = boolean_name(True)
    rec['solvable'] = boolean_name(True)
    rec['trace_zero_density'] = '0'
    rec['gens'] = r'\begin{bmatrix} 1 & 0 \\ 0 & \zeta_{%d}\end{bmatrix}' % n
    rec['numgens'] = 1
    rec['subgroups'] = comma_separated_list(
        [st_link("%d.2.3.c%d" % (w, n / p)) for p in n.prime_factors()])
    rec['supgroups'] = comma_separated_list(
        [st_link("%d.2.3.c%d" % (w, p * n))
         for p in [2, 3, 5]] + [r"$\ldots$"])
    rec['moments'] = [['x'] + [r'\mathrm{E}[x^{%d}]' % m for m in range(13)]]
    su2moments = [
        '1', '0', '1', '0', '2', '0', '5', '0', '14', '0', '42', '0', '132'
    ]
    rec['moments'] += [
        ['a_1'] + [su2moments[m] if m % n == 0 else '0' for m in range(13)]
    ]
    rec['trace_moments'] = trace_moments(rec['moments'])
    rec['counts'] = []
    return rec
Beispiel #6
0
def mu_info(n):
    """ return data for ST group mu(n); for n > 2 these groups are irrational and not stored in the database """
    n = ZZ(n)
    rec = {}
    rec['label'] = "0.1.%d"%n
    rec['weight'] = 0
    rec['degree'] = 1
    rec['rational'] = boolean_name(True if n <= 2 else False)
    rec['name'] = 'mu(%d)'%n
    rec['pretty'] = '\mu(%d)'%n
    rec['real_dimension'] = 0
    rec['components'] = int(n)
    rec['ambient'] = '\mathrm{O}(1)' if n <= 2 else '\mathrm{U}(1)'
    rec['connected'] = boolean_name(rec['components'] == 1)
    rec['st0_name'] = '\mathrm{SO}(1)'
    rec['identity_component'] = st0_pretty(rec['st0_name'])
    rec['st0_description'] = '\\mathrm{trivial}'
    rec['component_group'] = 'C_{%d}'%n
    rec['trace_zero_density']='0'
    rec['abelian'] = boolean_name(True)
    rec['cyclic'] = boolean_name(True)
    rec['solvable'] = boolean_name(True)
    rec['gens'] = r'\left[\zeta_{%d}\right]'%n
    rec['numgens'] = 1
    rec['subgroups'] = comma_separated_list([st_link("0.1.%d"%(n/p)) for p in n.prime_factors()])
    # only list supgroups with the same ambient (i.e.if mu(n) lies in O(1) don't list supgroups that are not)
    if n == 1:
        rec['supgroups'] = st_link("0.1.2")
    elif n > 2:
        rec['supgroups'] = comma_separated_list([st_link("0.1.%d"%(p*n)) for p in [2,3,5]] + ["$\ldots$"])
    rec['moments'] = [['x'] + [ '\\mathrm{E}[x^{%d}]'%m for m in range(13)]]
    rec['moments'] += [['a_1'] + ['1' if m % n == 0  else '0' for m in range(13)]]
    rec['trace_moments'] = trace_moments(rec['moments'])
    rational_traces = [1] if n%2 else [1,-1]
    rec['counts'] = [['a_1', [[t,1] for t in rational_traces]]]
    rec['probabilities'] = [['\\mathrm{P}[a_1=%d]=\\frac{1}{%d}'%(m,n)] for m in rational_traces]
    return rec
Beispiel #7
0
def render_curve_webpage_by_label(label):
    C = lmfdb.base.getDBConnection()
    data = C.elliptic_curves.curves.find_one({'lmfdb_label': label})
    if data is None:
        return elliptic_curve_jump_error(label, {})
    info = {}
    ainvs = [int(a) for a in data['ainvs']]
    E = EllipticCurve(ainvs)
    cremona_label = data['label']
    lmfdb_label = data['lmfdb_label']
    N = ZZ(data['conductor'])
    cremona_iso_class = data['iso']  # eg '37a'
    lmfdb_iso_class = data['lmfdb_iso']  # eg '37.a'
    rank = data['rank']
    try:
        j_invariant = QQ(str(data['jinv']))
    except KeyError:
        j_invariant = E.j_invariant()
    if j_invariant == 0:
        j_inv_factored = latex(0)
    else:
        j_inv_factored = latex(j_invariant.factor())
    jinv = unicode(str(j_invariant))
    CMD = 0
    CM = "no"
    EndE = "\(\Z\)"
    if E.has_cm():
        CMD = E.cm_discriminant()
        CM = "yes (\(%s\))" % CMD
        if CMD % 4 == 0:
            d4 = ZZ(CMD) // 4
            # r = d4.squarefree_part()
            # f = (d4//r).isqrt()
            # f="" if f==1 else str(f)
            # EndE = "\(\Z[%s\sqrt{%s}]\)"%(f,r)
            EndE = "\(\Z[\sqrt{%s}]\)" % (d4)
        else:
            EndE = "\(\Z[(1+\sqrt{%s})/2]\)" % CMD

    # plot=E.plot()
    discriminant = E.discriminant()
    xintpoints_projective = [
        E.lift_x(x)
        for x in xintegral_point(data['x-coordinates_of_integral_points'])
    ]
    xintpoints = proj_to_aff(xintpoints_projective)
    if 'degree' in data:
        modular_degree = data['degree']
    else:
        try:
            modular_degree = E.modular_degree()
        except RuntimeError:
            modular_degree = 0  # invalid, will be displayed nicely

    G = E.torsion_subgroup().gens()
    E_pari = E.pari_curve(prec=200)
    from sage.libs.pari.all import PariError
    try:
        minq = E.minimal_quadratic_twist()[0]
    except PariError:  # this does occur with 164411a1
        print "PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label
        minq = E
    if E == minq:
        minq_label = lmfdb_label
    else:
        minq_ainvs = [str(c) for c in minq.ainvs()]
        minq_label = C.elliptic_curves.curves.find_one({'ainvs': minq_ainvs
                                                        })['lmfdb_label']


# We do not just do the following, as Sage's installed database
# might not have all the curves in the LMFDB database.
# minq_label = E.minimal_quadratic_twist()[0].label()

    if 'gens' in data:
        generator = parse_gens(data['gens'])
    if len(G) == 0:
        tor_struct = '\mathrm{Trivial}'
        tor_group = '\mathrm{Trivial}'
    else:
        tor_group = ' \\times '.join(['\Z/{%s}\Z' % a.order() for a in G])
    if 'torsion_structure' in data:
        info['tor_structure'] = ' \\times '.join(
            ['\Z/{%s}\Z' % int(a) for a in data['torsion_structure']])
    else:
        info['tor_structure'] = tor_group

    def trim_galois_image_code(s):
        return s[2:] if s[1].isdigit() else s[1:]

    if 'galois_images' in data:
        galois_images = data['galois_images']
        galois_images = [trim_galois_image_code(s) for s in galois_images]
        non_surjective_primes = data['non-surjective_primes']

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

    info.update(data)
    if rank >= 2:
        lder_tex = "L%s(E,1)" % ("^{(" + str(rank) + ")}")
    elif rank == 1:
        lder_tex = "L%s(E,1)" % ("'" * rank)
    else:
        assert rank == 0
        lder_tex = "L(E,1)"
    info['Gamma0optimal'] = (cremona_label[-1] == '1'
                             if cremona_iso_class != '990h' else
                             cremona_label[-1] == '3')
    info['modular_degree'] = modular_degree
    p_adic_data_exists = (C.elliptic_curves.padic_db.find({
        'lmfdb_iso':
        lmfdb_iso_class
    }).count()) > 0 and info['Gamma0optimal']

    # Local data
    local_data = []
    for p in N.prime_factors():
        local_info = E.local_data(p, algorithm="generic")
        local_data.append({
            'p':
            p,
            'tamagawa_number':
            local_info.tamagawa_number(),
            'kodaira_symbol':
            web_latex(local_info.kodaira_symbol()).replace('$', ''),
            'reduction_type':
            local_info.bad_reduction_type()
        })

    mod_form_iso = lmfdb_label_regex.match(lmfdb_iso_class).groups()[1]

    tamagawa_numbers = [
        E.local_data(p, algorithm="generic").tamagawa_number()
        for p in N.prime_factors()
    ]
    # if we use E.tamagawa_numbers() it calls E.local_data(p) which
    # crashes on some curves e.g. 164411a1
    info.update({
        'conductor':
        N,
        'disc_factor':
        latex(discriminant.factor()),
        'j_invar_factor':
        j_inv_factored,
        'label':
        lmfdb_label,
        'cremona_label':
        cremona_label,
        'iso_class':
        lmfdb_iso_class,
        'cremona_iso_class':
        cremona_iso_class,
        'equation':
        web_latex(E),
        #'f': ajax_more(E.q_eigenform, 10, 20, 50, 100, 250),
        'f':
        web_latex(E.q_eigenform(10)),
        'generators':
        ', '.join(web_latex(g) for g in generator) if 'gens' in data else ' ',
        'lder':
        lder_tex,
        'p_adic_primes': [
            p for p in sage.all.prime_range(5, 100)
            if E.is_ordinary(p) and not p.divides(N)
        ],
        'p_adic_data_exists':
        p_adic_data_exists,
        'ainvs':
        format_ainvs(data['ainvs']),
        'CM':
        CM,
        'CMD':
        CMD,
        'EndE':
        EndE,
        'tamagawa_numbers':
        r' \cdot '.join(str(sage.all.factor(c)) for c in tamagawa_numbers),
        'local_data':
        local_data,
        'cond_factor':
        latex(N.factor()),
        'galois_data':
        galois_data,
        'xintegral_points':
        ', '.join(web_latex(P) for P in xintpoints),
        'tor_gens':
        ', '.join(web_latex(eval(g))
                  for g in data['torsion_generators']) if False else ', '.join(
                      web_latex(P.element().xy()) for P in list(G))
    })
    info['friends'] = [('Isogeny class ' + lmfdb_iso_class,
                        url_for(".by_ec_label", label=lmfdb_iso_class)),
                       ('Minimal quadratic twist ' + minq_label,
                        url_for(".by_ec_label", label=minq_label)),
                       ('All twists ',
                        url_for(".rational_elliptic_curves", jinv=jinv)),
                       ('L-function',
                        url_for("l_functions.l_function_ec_page",
                                label=lmfdb_label)),
                       ('Symmetric square L-function',
                        url_for("l_functions.l_function_ec_sym_page",
                                power='2',
                                label=lmfdb_iso_class)),
                       ('Symmetric 4th power L-function',
                        url_for("l_functions.l_function_ec_sym_page",
                                power='4',
                                label=lmfdb_iso_class))]

    info['friends'].append(
        ('Modular form ' + lmfdb_iso_class.replace('.', '.2'),
         url_for("emf.render_elliptic_modular_forms",
                 level=int(N),
                 weight=2,
                 character=0,
                 label=mod_form_iso)))

    info['downloads'] = [('Download coeffients of q-expansion',
                          url_for(".download_EC_qexp",
                                  label=lmfdb_label,
                                  limit=100)),
                         ('Download all stored data',
                          url_for(".download_EC_all", label=lmfdb_label))]

    # info['learnmore'] = [('Elliptic Curves', url_for(".not_yet_implemented"))]
    # info['plot'] = image_src(plot)
    info['plot'] = url_for('.plot_ec', label=lmfdb_label)

    properties2 = [('Label', '%s' % lmfdb_label),
                   (None, '<img src="%s" width="200" height="150"/>' %
                    url_for('.plot_ec', label=lmfdb_label)),
                   ('Conductor', '\(%s\)' % N),
                   ('Discriminant', '\(%s\)' % discriminant),
                   ('j-invariant', '%s' % web_latex(j_invariant)),
                   ('CM', '%s' % CM), ('Rank', '\(%s\)' % rank),
                   ('Torsion Structure', '\(%s\)' % tor_group)]
    # properties.extend([ "prop %s = %s<br/>" % (_,_*1923) for _ in range(12) ])
    credit = 'John Cremona and Andrew Sutherland'
    if info['label'] == info['cremona_label']:
        t = "Elliptic Curve %s" % info['label']
    else:
        t = "Elliptic Curve %s (Cremona label %s)" % (info['label'],
                                                      info['cremona_label'])

    bread = [('Elliptic Curves ', url_for(".rational_elliptic_curves")),
             ('Elliptic curves %s' % lmfdb_label, ' ')]

    return render_template("curve.html",
                           properties2=properties2,
                           credit=credit,
                           bread=bread,
                           title=t,
                           info=info,
                           friends=info['friends'],
                           downloads=info['downloads'])
Beispiel #8
0
def render_field_webpage(args):
    data = None
    if 'label' in args:
        label = str(args['label'])
        import base
        C = base.getDBConnection()
        data = C.numberfields.fields.find_one({'label': label})
    if data is None:
        return "No such field: " + label + " in the database"
    info = {}

    try:
        info['count'] = args['count']
    except KeyError:
        info['count'] = 10
    K = coeff_to_nf(data['coefficients'])
    D = data['discriminant']
    h = data['class_number']
    data['galois_group'] = str(data['galois_group'][3])
    data['class_group_invs'] = data['class_group']
    if data['class_group_invs'] == []:
        data['class_group_invs'] = 'Trivial'
    data['class_group'] = str(AbelianGroup(data['class_group']))
    sig = data['signature']
    D = ZZ(data['discriminant'])
    ram_primes = D.prime_factors()
    npr = len(ram_primes)
    ram_primes = str(ram_primes)[1:-1]
    Gorder, Gsign, Gab = GG_data(data['galois_group'])
    if Gab:
        Gab = 'abelian'
    else:
        Gab = 'non-abelian'
    unit_rank = sig[0] + sig[1] - 1
    if unit_rank == 0:
        reg = 1
    else:
        reg = K.regulator()
    UK = K.unit_group()

    info.update(data)
    info.update({
        'label':
        field_pretty(label),
        'polynomial':
        web_latex(K.defining_polynomial()),
        'ram_primes':
        ram_primes,
        'integral_basis':
        web_latex(K.integral_basis()),
        'regulator':
        web_latex(reg),
        'unit_rank':
        unit_rank,
        'root_of_unity':
        web_latex(UK.torsion_generator()),
        'fund_units':
        ',&nbsp; '.join([web_latex(u) for u in UK.fundamental_units()]),
        'Gorder':
        Gorder,
        'Gsign':
        Gsign,
        'Gab':
        Gab
    })
    info['downloads_visible'] = True
    info['downloads'] = [('worksheet', '/')]
    #    info['friends'] = [('L-function', '/')]
    info['friends'] = [('L-function', "/L/NumberField/%s" % label)]
    info['learnmore'] = [
        ('Number Field labels', url_for("render_labels_page")),
        ('Galois group labels', url_for("render_groups_page")),
        ('Discriminant ranges', url_for("render_discriminants_page"))
    ]
    bread = [('Number Fields', url_for("number_field_render_webpage")),
             ('%s' % info['label'], ' ')]
    t = "Number Field %s" % info['label']

    properties = ['<br>']
    properties.extend('<table>')
    properties.extend(
        '<tr><td align=left><b>Degree:</b><td align=left> %s</td>' %
        data['degree'])
    properties.extend(
        '<tr><td align=left><b>Signature:</b><td align=left>%s</td>' %
        data['signature'])
    properties.extend(
        '<tr><td align=left><b>Discriminant:</b><td align=left>%s</td>' %
        data['discriminant'])
    if npr == 1:
        properties.extend(
            '<tr><td align=left><b>Ramified prime:</b><td align=left>%s</td>' %
            ram_primes)
    else:
        if npr == 0:
            properties.extend(
                '<tr><td align=left><b>Ramified primes:</b><td align=left>%s</td>'
                % "None")
        else:
            properties.extend(
                '<tr><td align=left><b>Ramified primes:</b><td align=left>%s</td>'
                % ram_primes)
    properties.extend(
        '<tr><td align=left><b>Class number:</b><td align=left>%s</td>' %
        data['class_number'])
    properties.extend(
        '<tr><td align=left><b>Class group:</b><td align=left>%s</td>' %
        data['class_group_invs'])
    properties.extend(
        '<tr><td align=left><b>Galois group:</b><td align=left>%s</td>' %
        data['galois_group'])
    properties.extend('</table>')
    del info['_id']
    return render_template("number_field/number_field.html",
                           properties=properties,
                           credit=NF_credit,
                           title=t,
                           bread=bread,
                           friends=info.pop('friends'),
                           info=info)
Beispiel #9
0
class GaloisRepresentation(Lfunction):
    def __init__(self, thingy):
        """
        Class representing a L-function coming from a Galois representation.
        Typically, dirichlet characters, artin reps, elliptic curves,...
        can give rise to such a class.

        It can be used for tensor two such together (mul below) and a
        L-function class can be extracted from it.
        """

        # this is an important global variable.
        # it is the maximum of the imag parts of values s at
        # which we will compute L(s,.)
        self.max_imaginary_part = "40"

        if isinstance(
                thingy, sage.schemes.elliptic_curves.ell_rational_field.
                EllipticCurve_rational_field):
            self.init_elliptic_curve(thingy)

        elif isinstance(thingy, lmfdb.WebCharacter.WebDirichletCharacter):
            self.init_dir_char(thingy)

        elif isinstance(
                thingy,
                lmfdb.artin_representations.math_classes.ArtinRepresentation):
            self.init_artin_rep(thingy)

        elif (isinstance(thingy, list) and len(thingy) == 2 and isinstance(
                thingy[0],
                lmfdb.classical_modular_forms.web_newform.WebNewform)
              and isinstance(thingy[1], sage.rings.integer.Integer)):
            self.init_elliptic_modular_form(thingy[0], thingy[1])

        elif (isinstance(thingy, list) and len(thingy) == 2
              and isinstance(thingy[0], GaloisRepresentation)
              and isinstance(thingy[1], GaloisRepresentation)):
            self.init_tensor_product(thingy[0], thingy[1])

        else:
            raise ValueError(
                "GaloisRepresentations are currently not implemented for that type (%s) of objects"
                % type(thingy))

        # set a few common variables
        self.level = self.conductor
        self.degree = self.dim
        self.poles = []
        self.residues = []
        self.algebraic = True
        self.weight = self.motivic_weight + 1

## Various ways to construct such a class

    def init_elliptic_curve(self, E):
        """
        Returns the Galois rep of an elliptic curve over Q
        """

        self.original_object = [E]
        self.object_type = "ellipticcurve"
        self.dim = 2
        self.motivic_weight = 1
        self.conductor = E.conductor()
        self.bad_semistable_primes = [
            fa[0] for fa in self.conductor.factor() if fa[1] == 1
        ]
        self.bad_pot_good = [
            p for p in self.conductor.prime_factors()
            if E.j_invariant().valuation(p) > 0
        ]
        self.sign = E.root_number()
        self.mu_fe = []
        self.nu_fe = [ZZ(1) / ZZ(2)]
        self.gammaV = [0, 1]
        self.langlands = True
        self.selfdual = True
        self.primitive = True
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.coefficient_type = 2
        self.coefficient_period = 0
        self.besancon_bound = 50000
        self.ld.gp().quit()

        def eu(p):
            """
            Local Euler factor passed as a function
            whose input is a prime and
            whose output is a polynomial
            such that evaluated at p^-s,
            we get the inverse of the local factor
            of the L-function
            """
            R = PolynomialRing(QQ, "T")
            T = R.gens()[0]
            N = self.conductor
            if N % p != 0:  # good reduction
                return 1 - E.ap(p) * T + p * T**2
            elif N % (p**2) != 0:  # multiplicative reduction
                return 1 - E.ap(p) * T
            else:
                return R(1)

        self.local_euler_factor = eu

    def init_dir_char(self, chi):
        """
        Initiate with a Web Dirichlet character.
        """
        self.original_object = [chi]
        chi = chi.chi.primitive_character()
        self.object_type = "dirichletcharacter"
        self.dim = 1
        self.motivic_weight = 0
        self.conductor = ZZ(chi.conductor())
        self.bad_semistable_primes = []
        self.bad_pot_good = self.conductor.prime_factors()
        if chi.is_odd():
            aa = 1
            bb = I
        else:
            aa = 0
            bb = 1
        self.sign = chi.gauss_sum_numerical() / (bb *
                                                 float(sqrt(chi.modulus())))
        # this has now type python complex. later we need a gp complex
        self.sign = ComplexField()(self.sign)
        self.mu_fe = [aa]
        self.nu_fe = []
        self.gammaV = [aa]
        self.langlands = True
        self.selfdual = (chi.multiplicative_order() <= 2)
        # rather than all(  abs(chi(m).imag) < 0.0001 for m in range(chi.modulus() ) )
        self.primitive = True
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.dirichlet_coefficients = [
            chi(m) for m in range(self.numcoeff + 1)
        ]
        if self.selfdual:
            self.coefficient_type = 2
        else:
            self.coefficient_type = 3
        self.coefficient_period = chi.modulus()
        self.besancon_bound = 10000

        def eu(p):
            """
            local euler factor
            """
            if self.selfdual:
                K = QQ
            else:
                K = ComplexField()
            R = PolynomialRing(K, "T")
            T = R.gens()[0]
            if self.conductor % p != 0:
                return 1 - ComplexField()(chi(p)) * T
            else:
                return R(1)

        self.local_euler_factor = eu
        self.ld.gp().quit()

    def init_artin_rep(self, rho):
        """
        Initiate with an Artin representation
 
        """
        self.original_object = [rho]
        self.object_type = "Artin representation"
        self.dim = rho.dimension()
        self.motivic_weight = 0
        self.conductor = ZZ(rho.conductor())
        self.bad_semistable_primes = []
        self.bad_pot_good = self.conductor.prime_factors()
        self.sign = rho.root_number()
        self.mu_fe = rho.mu_fe()
        self.nu_fe = rho.nu_fe()
        self.gammaV = [
            0 for i in range(
                rho.number_of_eigenvalues_plus_one_complex_conjugation())
        ]
        for i in range(
                rho.number_of_eigenvalues_minus_one_complex_conjugation()):
            self.gammaV.append(1)
        self.langlands = rho.langlands()
        self.selfdual = rho.selfdual()
        self.primitive = rho.primitive()
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.coefficient_type = 0
        self.coefficient_period = 0
        self.besancon_bound = 3000

        def eu(p):
            """
            local euler factor
            """
            f = rho.local_factor(p)
            co = [ZZ(round(x)) for x in f.coefficients(sparse=False)]
            R = PolynomialRing(QQ, "T")
            T = R.gens()[0]
            return sum(co[n] * T**n for n in range(len(co)))

        self.local_euler_factor = eu
        self.ld.gp().quit()

    def init_elliptic_modular_form(self, F, number):
        """
        Initiate with an Elliptic Modular Form.
        """
        self.number = number
        self.original_object = [[F, number]]
        self.object_type = "Elliptic Modular newform"
        self.dim = 2
        self.weight = ZZ(F.weight)
        self.motivic_weight = ZZ(F.weight) - 1
        self.conductor = ZZ(F.level)
        self.bad_semistable_primes = [
            fa[0] for fa in self.conductor.factor() if fa[1] == 1
        ]
        # should be including primes of bad red that are pot good
        # however I don't know how to recognise them
        self.bad_pot_good = []
        self.langlands = True
        self.mu_fe = []
        self.nu_fe = [ZZ(F.weight - 1) / ZZ(2)]
        self.primitive = True
        self.selfdual = True
        self.coefficient_type = 2
        self.coefficient_period = 0
        self.sign = (-1)**(self.weight / 2.)
        if self.conductor != 1:
            for p, ev in F.atkin_lehner_eigenvals:
                self.sign *= ev**(self.conductor.valuation(p))
        self.gammaV = [0, 1]
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.besancon_bound = 300

        def eu(p):
            """
            Local euler factor
            """
            # There was no function q_expansion_embeddings before the transition to postgres
            # so I'm not sure what this is supposed to do.
            ans = F.q_expansion_embeddings(p + 1)
            K = ComplexField()
            R = PolynomialRing(K, "T")
            T = R.gens()[0]
            N = self.conductor
            if N % p != 0:  # good reduction
                return 1 - ans[p - 1][self.number] * T + T**2
            elif N % (p**2) != 0:  # semistable reduction
                return 1 - ans[p - 1][self.number] * T
            else:
                return R(1)

        self.local_euler_factor = eu
        self.ld.gp().quit()

    def init_tensor_product(self, V, W):
        """
        We are given two Galois representations and we
        will return their tensor product.
        """
        self.original_object = V.original_object + W.original_object
        self.object_type = "tensorproduct"
        self.V1 = V
        self.V2 = W
        self.dim = V.dim * W.dim
        self.motivic_weight = V.motivic_weight + W.motivic_weight
        self.langlands = False  # status 2014 :)
        self.besancon_bound = min(V.besancon_bound, W.besancon_bound)

        bad2 = ZZ(W.conductor).prime_factors()
        bad_primes = [x for x in ZZ(V.conductor).prime_factors() if x in bad2]
        for p in bad_primes:
            if (p not in V.bad_semistable_primes
                    and p not in W.bad_semistable_primes):
                # this condition above only applies to the current type of objects
                # for general reps we would have to test the lines below
                # to be certain that the formulae are correct.
                #if ((p not in V.bad_semistable_primes or p not in W.bad_pot_good) and
                #(p not in W.bad_semistable_primes or p not in V.bad_pot_good) and
                #(p not in V.bad_semistable_primes or p not in W.bad_semistable_primes)):
                raise NotImplementedError(
                    "Currently tensor products of Galois representations are only implemented under some conditions.",
                    "The behaviour at %d is too wild (both factors must be semistable)."
                    % p)

        # check for the possibily of getting poles
        if V.weight == W.weight and V.conductor == W.conductor:
            Vans = V.algebraic_coefficients(50)
            Wans = W.algebraic_coefficients(50)
            CC = ComplexField()
            if ((Vans[2] in ZZ and Wans[2] in ZZ
                 and all(Vans[n] == Wans[n] for n in range(1, 50)))
                    or all(CC(Vans[n]) == CC(Wans[n]) for n in range(1, 50))):
                raise NotImplementedError(
                    "It seems you are asking to tensor a " +
                    "Galois representation with its dual " +
                    "which results in the L-function having " +
                    "a pole. This is not implemented here.")

        scommon = [
            x for x in V.bad_semistable_primes if x in W.bad_semistable_primes
        ]

        N = W.conductor**V.dim
        N *= V.conductor**W.dim
        for p in bad_primes:
            n1_tame = V.dim - V.local_euler_factor(p).degree()
            n2_tame = W.dim - W.local_euler_factor(p).degree()
            nn = n1_tame * n2_tame
            N = N // p**nn
            if p in scommon:  # both are degree 1 in this case
                N = N // p
        self.conductor = N

        h1 = selberg_to_hodge(V.motivic_weight, V.mu_fe, V.nu_fe)
        h2 = selberg_to_hodge(W.motivic_weight, W.mu_fe, W.nu_fe)
        h = tensor_hodge(h1, h2)
        w, m, n = hodge_to_selberg(h)
        self.mu_fe = m
        self.nu_fe = n
        _, self.gammaV = gamma_factors(h)

        # this is used in getting the Dirichlet coefficients.
        self.bad_primes_info = []
        for p in bad_primes:
            # we have to check if this works in all bad cases !
            f1 = V.local_euler_factor(p)
            f2 = W.local_euler_factor(p)
            # might be dodgy if f1 or f2 is an approx to the Euler factor
            if p in scommon:
                E = tensor_local_factors(f1, f2, V.dim * W.dim)
                T = f1.parent().gens()[0]  # right answer is E(T)*E(pT)
                self.bad_primes_info.append(
                    [p, E * E(p * T), 1 - T]
                )  #bad_primes_info.append() with 1-T as the second argument is equivalent to taking the first argument as the results (it does a convolution, as in the next line)
            else:
                self.bad_primes_info.append([p, f1, f2])

        CC = ComplexField()
        I = CC.gens()[0]
        self.sign = I**root_number_at_oo(h)
        self.sign /= I**(root_number_at_oo(h1) * V.dim)
        self.sign /= I**(root_number_at_oo(h2) * W.dim)
        self.sign *= V.sign**W.dim
        self.sign *= W.sign**V.dim
        for p in bad_primes:
            if p not in V.bad_semistable_primes or p not in V.bad_semistable_primes:
                f1 = V.local_euler_factor(p)
                f2 = W.local_euler_factor(p)
                det1 = f1.leading_coefficient() * (-1)**f1.degree()
                det2 = f2.leading_coefficient() * (-1)**f2.degree()
                n1_tame = V.dim - f1.degree()
                n2_tame = W.dim - f2.degree()
                n1_wild = ZZ(V.conductor).valuation(p) - n1_tame
                n2_wild = ZZ(W.conductor).valuation(p) - n2_tame
                # additionally, we would need to correct this by
                # replacing det1 by chi1(p) if p is semistable for V
                # however for all the possible input this currently does
                # not affect the sign
                if p in V.bad_semistable_primes:
                    chi1p = 1  # here
                else:
                    chi1p = det1
                if p in W.bad_semistable_primes:
                    chi2p = 1  # here
                else:
                    chi2p = det2

                corr = chi1p**n2_wild
                corr *= det1**n2_tame
                corr *= chi2p**n1_wild
                corr *= det2**n1_tame
                corr *= (-1)**(n1_tame * n2_tame)

                self.sign *= corr / corr.abs()

        #self.primitive = False
        self.set_dokchitser_Lfunction()
        # maybe we should change this to take as many coefficients as implemented
        # in other Lfunctions
        self.set_number_of_coefficients()

        someans = self.algebraic_coefficients(50)  # why not.
        if all(x in ZZ for x in someans):
            self.selfdual = True
        else:
            CC = ComplexField()
            self.selfdual = all(CC(an).imag().abs() < 0.0001 for an in someans)

        self.coefficient_type = max(V.coefficient_type, W.coefficient_type)
        self.coefficient_period = ZZ(V.coefficient_period).lcm(
            W.coefficient_period)
        self.ld.gp().quit()

## These are used when creating the classes with the above

    def set_dokchitser_Lfunction(self):
        """
        The L-function calling Dokchitser's code
        """
        if hasattr(self, "sign"):
            # print type(self.sign)
            # type complex would yield an error here.
            self.ld = Dokchitser(conductor=self.conductor,
                                 gammaV=self.gammaV,
                                 weight=self.motivic_weight,
                                 eps=self.sign,
                                 poles=[],
                                 residues=[])
        else:
            # find the sign from the functional equation
            # this should be implemented later:
            # one can pass a variable 'x' to the function
            # checking the functional equation
            # and it will return a linear polynomial in x
            # such that the root must be the sign
            raise NotImplementedError

    def set_number_of_coefficients(self):
        """
        Determines the number of coefficients needed using Dokchitser's
        Note is the number we SHOULD compute. However we will cap this to
        a smaller size later.
        """
        if not hasattr(self, "ld"):
            self.set_dokchitser_Lfunction()
        # note the following line only sets all the variables in the
        # gp session of Dokchitser
        self.ld._gp_eval("MaxImaginaryPart = %s" % self.max_imaginary_part)
        self.numcoeff = self.ld.num_coeffs()
        # to be on the safe side, we make sure to have a min of terms
        if self.numcoeff < 50:
            self.numcoeff = 50

## produce coefficients

    def algebraic_coefficients(self, number_of_terms):
        """
        Computes the list [a1,a2,... of coefficients up
        to a bound. Note that [0] is a1.
        This is in the alg. normalisation, i.e. s <-> w+1-s
        """

        if self.object_type == "ellipticcurve":
            return self.original_object[0].anlist(number_of_terms)[1:]
        elif self.object_type == "dirichletcharacter":
            chi = self.original_object[0].chi.primitive_character()
            return [chi(m) for m in range(1, number_of_terms)]
        elif self.object_type == "Artin representation":
            rho = self.original_object[0]
            return rho.coefficients_list(upperbound=number_of_terms)
        elif self.object_type == "Elliptic Modular newform":
            F = self.original_object[0][0]
            i = self.original_object[0][1]
            embeddings = F.q_expansion_embeddings(number_of_terms)[1:]
            return [x[i] for x in embeddings]
        elif self.object_type == "tensorproduct":
            V = self.V1
            W = self.V2
            L1 = V.algebraic_coefficients(number_of_terms)
            L2 = W.algebraic_coefficients(number_of_terms)
            return tensor_get_an(L1, L2, V.dim, W.dim, self.bad_primes_info)
        else:
            raise ValueError("You asked for a type that we don't have")

    def renormalise_coefficients(self):
        """
        This turns a list of algebraically normalised coefficients
        as above into a list of automorphically normalised,
        i.e. s <-> 1-s
        """
        # this also turns them into floats and complex.
        for n in range(len(self.dirichlet_coefficients)):
            self.dirichlet_coefficients[n] /= sqrt(
                float(n + 1)**self.motivic_weight)

## The tensor product

    def __mul__(self, other):
        """
        The tensor product of two galois representations
        is represented here by *
        """
        return GaloisRepresentation([self, other])

## various direct accessible functions

    def root_number(self):
        """
        Root number
        """
        return self.sign

    def dimension(self):
        """
        Dimension = Degree
        """
        return self.dim

    def cond(self):
        """
        Conductor
        """
        return self.conductor

## Now to the L-function itself

    def lfunction(self):
        """
        This method replaces the class LFunction in lmfdb.lfunctions.Lfunction
        to generate the page for this sort of class.

        After asking for this method the object should have all
        methods and attributes as one of the subclasses of Lfunction in
        lmfdb.lfunctions.Lfunction.
        """
        self.compute_kappa_lambda_Q_from_mu_nu()

        # when tensoring a modular form with a dim > 1 rep, we run
        # into having to compute a lot of coefficients and this will
        # take a lot of time. We cut it down and print a warning
        number_of_terms = min(self.numcoeff, self.besancon_bound)
        self.dirichlet_coefficients = self.algebraic_coefficients(
            number_of_terms + 1)
        self.renormalise_coefficients()

        self.texname = "L(s,\\rho)"
        self.texnamecompleteds = "\\Lambda(s,\\rho)"
        self.texnamecompleted1ms = "\\Lambda(1-s, \\widehat{\\rho})"
        self.title = "$L(s,\\rho)$, where $\\rho$ is a Galois representation"

        self.credit = 'Workshop in Besancon, 2014'

        from lmfdb.lfunctions.Lfunction import generateSageLfunction
        generateSageLfunction(self)

    def Ltype(self):
        return "galoisrepresentation"
Beispiel #10
0
class GaloisRepresentation( Lfunction):

    def __init__(self, thingy):
        """
        Class representing a L-function coming from a Galois representation.
        Typically, dirichlet characters, artin reps, elliptic curves,...
        can give rise to such a class.

        It can be used for tensor two such together (mul below) and a
        L-function class can be extracted from it.
        """

        # this is an important global variable.
        # it is the maximum of the imag parts of values s at
        # which we will compute L(s,.)
        self.max_imaginary_part = "40"

        if isinstance(thingy, sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field):
            self.init_elliptic_curve(thingy)

        elif isinstance(thingy, lmfdb.WebCharacter.WebDirichletCharacter):
            self.init_dir_char(thingy)

        elif isinstance(thingy, lmfdb.artin_representations.math_classes.ArtinRepresentation):
            self.init_artin_rep(thingy)

        elif (isinstance(thingy, list) and
              len(thingy) == 2 and
              isinstance(thingy[0],lmfdb.modular_forms.elliptic_modular_forms.backend.web_newforms.WebNewForm) and
              isinstance(thingy[1],sage.rings.integer.Integer) ):
            self.init_elliptic_modular_form(thingy[0],thingy[1])

        elif (isinstance(thingy, list) and
              len(thingy) == 2 and
              isinstance(thingy[0], GaloisRepresentation) and
              isinstance(thingy[1], GaloisRepresentation) ):
            self.init_tensor_product(thingy[0], thingy[1])

        else:
            raise ValueError("GaloisRepresentations are currently not implemented for that type (%s) of objects"%type(thingy))

        # set a few common variables
        self.level = self.conductor
        self.degree = self.dim
        self.poles = []
        self.residues = []
        self.algebraic = True
        self.weight = self.motivic_weight + 1

## Various ways to construct such a class

    def init_elliptic_curve(self, E):
        """
        Returns the Galois rep of an elliptic curve over Q
        """

        self.original_object = [E]
        self.object_type = "ellipticcurve"
        self.dim = 2
        self.motivic_weight = 1
        self.conductor = E.conductor()
        self.bad_semistable_primes = [ fa[0] for fa in self.conductor.factor() if fa[1]==1 ]
        self.bad_pot_good = [p for p in self.conductor.prime_factors() if E.j_invariant().valuation(p) > 0 ]
        self.sign = E.root_number()
        self.mu_fe = []
        self.nu_fe = [ZZ(1)/ZZ(2)]
        self.gammaV = [0, 1]
        self.langlands = True
        self.selfdual = True
        self.primitive = True
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.coefficient_type = 2
        self.coefficient_period = 0
        self.besancon_bound = 50000
        self.ld.gp().quit()

        def eu(p):
            """
            Local Euler factor passed as a function
            whose input is a prime and
            whose output is a polynomial
            such that evaluated at p^-s,
            we get the inverse of the local factor
            of the L-function
            """
            R = PolynomialRing(QQ, "T")
            T = R.gens()[0]
            N = self.conductor
            if N % p != 0 : # good reduction
                return 1 - E.ap(p) * T + p * T**2
            elif N % (p**2) != 0: # multiplicative reduction
                return 1 - E.ap(p) * T
            else:
                return R(1)

        self.local_euler_factor = eu

    def init_dir_char(self, chi):
        """
        Initiate with a Web Dirichlet character.
        """
        self.original_object = [chi]
        chi = chi.chi.primitive_character()
        self.object_type = "dirichletcharacter"
        self.dim = 1
        self.motivic_weight = 0
        self.conductor = ZZ(chi.conductor())
        self.bad_semistable_primes = []
        self.bad_pot_good = self.conductor.prime_factors()
        if chi.is_odd():
            aa = 1
            bb = I
        else:
            aa = 0
            bb = 1
        self.sign = chi.gauss_sum_numerical() / (bb * float(sqrt(chi.modulus())) )
        # this has now type python complex. later we need a gp complex
        self.sign = ComplexField()(self.sign)
        self.mu_fe = [aa]
        self.nu_fe = []
        self.gammaV = [aa]
        self.langlands = True
        self.selfdual = (chi.multiplicative_order() <= 2)
        # rather than all(  abs(chi(m).imag) < 0.0001 for m in range(chi.modulus() ) )
        self.primitive = True
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.dirichlet_coefficients = [ chi(m) for m in range(self.numcoeff + 1) ]
        if self.selfdual:
            self.coefficient_type = 2
        else:
            self.coefficient_type = 3
        self.coefficient_period = chi.modulus()
        self.besancon_bound = 10000

        def eu(p):
            """
            local euler factor
            """
            if self.selfdual:
                K = QQ
            else:
                K = ComplexField()
            R = PolynomialRing(K, "T")
            T = R.gens()[0]
            if self.conductor % p != 0:
                return  1 - ComplexField()(chi(p)) * T
            else:
                return R(1)

        self.local_euler_factor = eu
        self.ld.gp().quit()


    def init_artin_rep(self, rho):
        """
        Initiate with an Artin representation
 
        """
        self.original_object = [rho]
        self.object_type = "Artin representation"
        self.dim = rho.dimension()
        self.motivic_weight = 0
        self.conductor = ZZ(rho.conductor())
        self.bad_semistable_primes = []
        self.bad_pot_good = self.conductor.prime_factors()
        self.sign = rho.root_number()
        self.mu_fe = rho.mu_fe()
        self.nu_fe = rho.nu_fe()
        self.gammaV = [0 for i in range(rho.number_of_eigenvalues_plus_one_complex_conjugation())]
        for i in range(rho.number_of_eigenvalues_minus_one_complex_conjugation() ):
            self.gammaV.append(1)
        self.langlands = rho.langlands()
        self.selfdual = rho.selfdual()
        self.primitive = rho.primitive()
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.coefficient_type = 0
        self.coefficient_period = 0
        self.besancon_bound = 3000

        def eu(p):
            """
            local euler factor
            """
            f = rho.local_factor(p)
            co = [ZZ(round(x)) for x in f.coefficients(sparse=False)]
            R = PolynomialRing(QQ, "T")
            T = R.gens()[0]
            return sum( co[n] * T**n for n in range(len(co)))

        self.local_euler_factor = eu
        self.ld.gp().quit()

    def init_elliptic_modular_form(self, F, number):
        """
        Initiate with an Elliptic Modular Form.
        """
        self.number = number
        self.original_object = [[F,number]]
        self.object_type = "Elliptic Modular newform"
        self.dim = 2
        self.weight = ZZ(F.weight())
        self.motivic_weight = ZZ(F.weight()) - 1
        self.conductor = ZZ(F.level())
        self.bad_semistable_primes = [fa[0] for fa in self.conductor.factor() if fa[1]==1 ]
        # should be including primes of bad red that are pot good
        # however I don't know how to recognise them
        self.bad_pot_good = []
        self.langlands = True
        self.mu_fe = []
        self.nu_fe = [ZZ(F.weight()-1)/ZZ(2)]
        self.primitive = True
        self.selfdual = True
        self.coefficient_type = 2
        self.coefficient_period = 0
        self.sign = (-1) ** (self.weight / 2.)
        if self.conductor != 1:
            AL = F.atkin_lehner_eigenvalues()
            self.sign = AL[self.conductor] * self.sign
        self.gammaV = [0,1]
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.besancon_bound = 300

        def eu(p):
            """
            Local euler factor
            """
            ans = F.q_expansion_embeddings(p + 1)
            K = ComplexField()
            R = PolynomialRing(K, "T")
            T = R.gens()[0]
            N = self.conductor
            if N % p != 0 : # good reduction
                return 1 - ans[p-1][self.number] * T + T**2
            elif N % (p**2) != 0: # semistable reduction
                return 1 - ans[p-1][self.number] * T
            else:
                return R(1)

        self.local_euler_factor = eu
        self.ld.gp().quit()


    def init_tensor_product(self, V, W):
        """
        We are given two Galois representations and we
        will return their tensor product.
        """
        self.original_object = V.original_object + W.original_object
        self.object_type = "tensorproduct"
        self.V1 = V
        self.V2 = W
        self.dim = V.dim * W.dim
        self.motivic_weight = V.motivic_weight + W.motivic_weight
        self.langlands = False # status 2014 :)
        self.besancon_bound = min(V.besancon_bound, W.besancon_bound)

        bad2 = ZZ(W.conductor).prime_factors()
        bad_primes = [x for x in ZZ(V.conductor).prime_factors() if x in bad2]
        for p in bad_primes:
            if ( p not in V.bad_semistable_primes and p not in W.bad_semistable_primes) :
                # this condition above only applies to the current type of objects
                # for general reps we would have to test the lines below
                # to be certain that the formulae are correct.
                #if ((p not in V.bad_semistable_primes or p not in W.bad_pot_good) and
                    #(p not in W.bad_semistable_primes or p not in V.bad_pot_good) and
                    #(p not in V.bad_semistable_primes or p not in W.bad_semistable_primes)):
                raise NotImplementedError("Currently tensor products of Galois representations are only implemented under some conditions.",
                                          "The behaviour at %d is too wild (both factors must be semistable)." % p)

        # check for the possibily of getting poles
        if V.weight == W.weight and V.conductor == W.conductor :
            Vans = V.algebraic_coefficients(50)
            Wans = W.algebraic_coefficients(50)
            CC = ComplexField()
            if ((Vans[2] in ZZ and Wans[2] in ZZ and
                all(Vans[n] == Wans[n] for n in range(1,50) ) ) or
                all( CC(Vans[n]) == CC(Wans[n]) for n in range(1,50) ) ):
                    raise NotImplementedError("It seems you are asking to tensor a "+
                                              "Galois representation with its dual " +
                                              "which results in the L-function having "+
                                              "a pole. This is not implemented here.")

        scommon = [x for x in V.bad_semistable_primes if x in W.bad_semistable_primes]

        N = W.conductor ** V.dim
        N *= V.conductor ** W.dim
        for p in bad_primes:
            n1_tame = V.dim - V.local_euler_factor(p).degree()
            n2_tame = W.dim - W.local_euler_factor(p).degree()
            nn = n1_tame * n2_tame
            N = N // p ** nn
            if p in scommon: # both are degree 1 in this case
                N = N // p
        self.conductor = N

        h1 = selberg_to_hodge(V.motivic_weight,V.mu_fe,V.nu_fe)
        h2 = selberg_to_hodge(W.motivic_weight,W.mu_fe,W.nu_fe)
        h = tensor_hodge(h1, h2)
        w,m,n = hodge_to_selberg(h)
        self.mu_fe = m
        self.nu_fe = n
        _, self.gammaV = gamma_factors(h)

        # this is used in getting the Dirichlet coefficients.
        self.bad_primes_info = []
        for p in bad_primes:
            # we have to check if this works in all bad cases !
            f1 = V.local_euler_factor(p)
            f2 = W.local_euler_factor(p)
            # might be dodgy if f1 or f2 is an approx to the Euler factor
            if p in scommon:
                E = tensor_local_factors(f1,f2,V.dim*W.dim)
                T = f1.parent().gens()[0] # right answer is E(T)*E(pT)
                self.bad_primes_info.append([p,E*E(p*T),1-T]) #bad_primes_info.append() with 1-T as the second argument is equivalent to taking the first argument as the results (it does a convolution, as in the next line)
            else:
                self.bad_primes_info.append([p,f1,f2])

        CC = ComplexField()
        I = CC.gens()[0]
        self.sign = I ** root_number_at_oo(h)
        self.sign /= I ** (root_number_at_oo(h1) * V.dim)
        self.sign /= I ** (root_number_at_oo(h2) * W.dim)
        self.sign *= V.sign ** W.dim
        self.sign *= W.sign ** V.dim
        for p in bad_primes:
            if p not in V.bad_semistable_primes or p not in V.bad_semistable_primes:
                f1 = V.local_euler_factor(p)
                f2 = W.local_euler_factor(p)
                det1 = f1.leading_coefficient() * (-1) ** f1.degree()
                det2 = f2.leading_coefficient() * (-1) ** f2.degree()
                n1_tame = V.dim - f1.degree()
                n2_tame = W.dim - f2.degree()
                n1_wild = ZZ(V.conductor).valuation(p) - n1_tame
                n2_wild = ZZ(W.conductor).valuation(p) - n2_tame
                # additionally, we would need to correct this by
                # replacing det1 by chi1(p) if p is semistable for V
                # however for all the possible input this currently does
                # not affect the sign
                if p in V.bad_semistable_primes:
                    chi1p = 1 # here
                else:
                    chi1p = det1
                if p in W.bad_semistable_primes:
                    chi2p = 1 # here
                else:
                    chi2p = det2

                corr = chi1p ** n2_wild
                corr *= det1 ** n2_tame
                corr *= chi2p ** n1_wild
                corr *= det2 ** n1_tame
                corr *= (-1) ** (n1_tame * n2_tame)

                self.sign *= corr/corr.abs()

        #self.primitive = False
        self.set_dokchitser_Lfunction()
        # maybe we should change this to take as many coefficients as implemented
        # in other Lfunctions
        self.set_number_of_coefficients()

        someans = self.algebraic_coefficients(50) # why not.
        if all( x in ZZ for x in someans):
            self.selfdual = True
        else:
            CC = ComplexField()
            self.selfdual = all( CC(an).imag().abs() < 0.0001 for an in someans)

        self.coefficient_type = max(V.coefficient_type, W.coefficient_type)
        self.coefficient_period = ZZ(V.coefficient_period).lcm(W.coefficient_period)
        self.ld.gp().quit()


## These are used when creating the classes with the above

    def set_dokchitser_Lfunction(self):
        """
        The L-function calling Dokchitser's code
        """
        if hasattr(self, "sign"):
            # print type(self.sign)
            # type complex would yield an error here.
            self.ld = Dokchitser(conductor = self.conductor,
                                gammaV = self.gammaV,
                                weight = self.motivic_weight,
                                eps = self.sign,
                                poles = [],
                                residues = [])
        else:
            # find the sign from the functional equation
            # this should be implemented later:
            # one can pass a variable 'x' to the function
            # checking the functional equation
            # and it will return a linear polynomial in x
            # such that the root must be the sign
            raise NotImplementedError


    def set_number_of_coefficients(self):
        """
        Determines the number of coefficients needed using Dokchitser's
        Note is the number we SHOULD compute. However we will cap this to
        a smaller size later.
        """
        if not hasattr(self, "ld"):
            self.set_dokchitser_Lfunction()
        # note the following line only sets all the variables in the
        # gp session of Dokchitser
        self.ld._gp_eval("MaxImaginaryPart = %s"%self.max_imaginary_part)
        self.numcoeff = self.ld.num_coeffs()
        # to be on the safe side, we make sure to have a min of terms
        if self.numcoeff < 50:
            self.numcoeff = 50

## produce coefficients

    def algebraic_coefficients(self, number_of_terms):
        """
        Computes the list [a1,a2,... of coefficients up
        to a bound. Note that [0] is a1.
        This is in the alg. normalisation, i.e. s <-> w+1-s
        """

        if self.object_type == "ellipticcurve":
            return self.original_object[0].anlist(number_of_terms)[1:]
        elif self.object_type == "dirichletcharacter":
            chi = self.original_object[0].chi.primitive_character()
            return [ chi(m) for m in range(1, number_of_terms) ]
        elif self.object_type == "Artin representation":
            rho = self.original_object[0]
            return rho.coefficients_list(upperbound=number_of_terms)
        elif self.object_type == "Elliptic Modular newform":
            F = self.original_object[0][0]
            i = self.original_object[0][1]
            embeddings = F.q_expansion_embeddings(number_of_terms)[1:]
            return [x[i] for x in embeddings]
        elif self.object_type == "tensorproduct":
            V = self.V1
            W = self.V2
            L1 = V.algebraic_coefficients(number_of_terms)
            L2 = W.algebraic_coefficients(number_of_terms)
            return tensor_get_an(L1, L2, V.dim, W.dim, self.bad_primes_info)
        else:
            raise ValueError("You asked for a type that we don't have")


    def renormalise_coefficients(self):
        """
        This turns a list of algebraically normalised coefficients
        as above into a list of automorphically normalised,
        i.e. s <-> 1-s
        """
        # this also turns them into floats and complex.
        for n in range(len(self.dirichlet_coefficients)):
            self.dirichlet_coefficients[n] /= sqrt(float(n+1)**self.motivic_weight)


## The tensor product

    def __mul__(self, other):
        """
        The tensor product of two galois representations
        is represented here by *
        """
        return GaloisRepresentation([self,other])

## various direct accessible functions


    def root_number(self):
        """
        Root number
        """
        return self.sign


    def dimension(self):
        """
        Dimension = Degree
        """
        return self.dim

    def cond(self):
        """
        Conductor
        """
        return self.conductor


## Now to the L-function itself

    def lfunction(self):
        """
        This method replaces the class LFunction in lmfdb.lfunctions.Lfunction
        to generate the page for this sort of class.

        After asking for this method the object should have all
        methods and attributes as one of the subclasses of Lfunction in
        lmfdb.lfunctions.Lfunction.
        """
        self.compute_kappa_lambda_Q_from_mu_nu()

        # when tensoring a modular form with a dim > 1 rep, we run
        # into having to compute a lot of coefficients and this will
        # take a lot of time. We cut it down and print a warning
        number_of_terms = min(self.numcoeff, self.besancon_bound)
        self.dirichlet_coefficients = self.algebraic_coefficients(number_of_terms+1)
        self.renormalise_coefficients()

        self.texname = "L(s,\\rho)"
        self.texnamecompleteds = "\\Lambda(s,\\rho)"
        self.texnamecompleted1ms = "\\Lambda(1-s, \\widehat{\\rho})" 
        self.title = "$L(s,\\rho)$, where $\\rho$ is a Galois representation"

        self.credit = 'Workshop in Besancon, 2014'

        from lmfdb.lfunctions.Lfunction import generateSageLfunction
        generateSageLfunction(self)

    def Ltype(self):
        return "galoisrepresentation"

    # does not have keys in the previous sense really.
    def Lkey(self):
        return {"galoisrepresentation":self.title}
Beispiel #11
0
def render_curve_webpage_by_label(label):
    C = lmfdb.base.getDBConnection()
    data = C.elliptic_curves.curves.find_one({'lmfdb_label': label})
    if data is None:
        return elliptic_curve_jump_error(label, {})
    info = {}
    ainvs = [int(a) for a in data['ainvs']]
    E = EllipticCurve(ainvs)
    cremona_label = data['label']
    lmfdb_label = data['lmfdb_label']
    N = ZZ(data['conductor'])
    cremona_iso_class = data['iso']  # eg '37a'
    lmfdb_iso_class = data['lmfdb_iso']  # eg '37.a'
    rank = data['rank']
    try:
        j_invariant = QQ(str(data['jinv']))
    except KeyError:
        j_invariant = E.j_invariant()
    if j_invariant == 0:
        j_inv_factored = latex(0)
    else:
        j_inv_factored = latex(j_invariant.factor())
    jinv = unicode(str(j_invariant))
    CMD = 0
    CM = "no"
    EndE = "\(\Z\)"
    if E.has_cm():
        CMD = E.cm_discriminant()
        CM = "yes (\(%s\))"%CMD
        if CMD%4==0:
            d4 = ZZ(CMD)//4
            # r = d4.squarefree_part()
            # f = (d4//r).isqrt()
            # f="" if f==1 else str(f)
            # EndE = "\(\Z[%s\sqrt{%s}]\)"%(f,r)
            EndE = "\(\Z[\sqrt{%s}]\)"%(d4)
        else:            
            EndE = "\(\Z[(1+\sqrt{%s})/2]\)"%CMD

    # plot=E.plot()
    discriminant = E.discriminant()
    xintpoints_projective = [E.lift_x(x) for x in xintegral_point(data['x-coordinates_of_integral_points'])]
    xintpoints = proj_to_aff(xintpoints_projective)
    if 'degree' in data:
        modular_degree = data['degree']
    else:
        try:
            modular_degree = E.modular_degree()
        except RuntimeError:
            modular_degree = 0  # invalid, will be displayed nicely

    G = E.torsion_subgroup().gens()
    minq = E.minimal_quadratic_twist()[0]
    if E == minq:
        minq_label = lmfdb_label
    else:
        minq_ainvs = [str(c) for c in minq.ainvs()]
        minq_label = C.elliptic_curves.curves.find_one({'ainvs': minq_ainvs})['lmfdb_label']
# We do not just do the following, as Sage's installed database
# might not have all the curves in the LMFDB database.
# minq_label = E.minimal_quadratic_twist()[0].label()

    if 'gens' in data:
        generator = parse_gens(data['gens'])
    if len(G) == 0:
        tor_struct = '\mathrm{Trivial}'
        tor_group = '\mathrm{Trivial}'
    else:
        tor_group = ' \\times '.join(['\Z/{%s}\Z' % a.order() for a in G])
    if 'torsion_structure' in data:
        info['tor_structure'] = ' \\times '.join(['\Z/{%s}\Z' % int(a) for a in data['torsion_structure']])
    else:
        info['tor_structure'] = tor_group

    info.update(data)
    if rank >= 2:
        lder_tex = "L%s(E,1)" % ("^{(" + str(rank) + ")}")
    elif rank == 1:
        lder_tex = "L%s(E,1)" % ("'" * rank)
    else:
        assert rank == 0
        lder_tex = "L(E,1)"
    info['Gamma0optimal'] = (
        cremona_label[-1] == '1' if cremona_iso_class != '990h' else cremona_label[-1] == '3')
    info['modular_degree'] = modular_degree
    p_adic_data_exists = (C.elliptic_curves.padic_db.find(
        {'lmfdb_iso': lmfdb_iso_class}).count()) > 0 and info['Gamma0optimal']

    # Local data
    local_data = []
    for p in N.prime_factors():
        local_info = E.local_data(p)
        local_data.append({'p': p,
                           'tamagawa_number': local_info.tamagawa_number(),
                           'kodaira_symbol': web_latex(local_info.kodaira_symbol()).replace('$', ''),
                           'reduction_type': local_info.bad_reduction_type()
                           })

    mod_form_iso = lmfdb_label_regex.match(lmfdb_iso_class).groups()[1]

    info.update({
        'conductor': N,
        'disc_factor': latex(discriminant.factor()),
        'j_invar_factor': j_inv_factored,
        'label': lmfdb_label,
        'cremona_label': cremona_label,
        'iso_class': lmfdb_iso_class,
        'cremona_iso_class': cremona_iso_class,
        'equation': web_latex(E),
        #'f': ajax_more(E.q_eigenform, 10, 20, 50, 100, 250),
        'f': web_latex(E.q_eigenform(10)),
        'generators': ', '.join(web_latex(g) for g in generator) if 'gens' in data else ' ',
        'lder': lder_tex,
        'p_adic_primes': [p for p in sage.all.prime_range(5, 100) if E.is_ordinary(p) and not p.divides(N)],
        'p_adic_data_exists': p_adic_data_exists,
        'ainvs': format_ainvs(data['ainvs']),
        'CM': CM,
        'CMD': CMD,
        'EndE': EndE,
        'tamagawa_numbers': r' \cdot '.join(str(sage.all.factor(c)) for c in E.tamagawa_numbers()),
        'local_data': local_data,
        'cond_factor': latex(N.factor()),
        'xintegral_points': ', '.join(web_latex(P) for P in xintpoints),
        'tor_gens': ', '.join(web_latex(eval(g)) for g in data['torsion_generators']) if False else ', '.join(web_latex(P.element().xy()) for P in list(G))
    })
    info['friends'] = [
        ('Isogeny class ' + lmfdb_iso_class, "/EllipticCurve/Q/%s" % lmfdb_iso_class),
        ('Minimal quadratic twist ' + minq_label, "/EllipticCurve/Q/%s" % minq_label),
        ('All twists ', url_for("rational_elliptic_curves", jinv=jinv)),
        ('L-function', url_for("l_functions.l_function_ec_page", label=lmfdb_label)),
        ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2',
                                                label=lmfdb_iso_class)),
        ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4',
                                                   label=lmfdb_iso_class))]

    info['friends'].append(('Modular form ' + lmfdb_iso_class.replace('.', '.2'), url_for(
        "emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=mod_form_iso)))

    info['downloads'] = [('Download coeffients of q-expansion', url_for("download_EC_qexp", label=lmfdb_label, limit=100)),
                         ('Download all stored data', url_for("download_EC_all", label=lmfdb_label))]

    # info['learnmore'] = [('Elliptic Curves', url_for("not_yet_implemented"))]
    # info['plot'] = image_src(plot)
    info['plot'] = url_for('plot_ec', label=lmfdb_label)

    properties2 = [('Label', '%s' % lmfdb_label),
                   (None, '<img src="%s" width="200" height="150"/>' % url_for(
                       'plot_ec', label=lmfdb_label)),
                   ('Conductor', '\(%s\)' % N),
                   ('Discriminant', '\(%s\)' % discriminant),
                   ('j-invariant', '%s' % web_latex(j_invariant)),
                   ('CM', '%s' % CM),
                   ('Rank', '\(%s\)' % rank),
                   ('Torsion Structure', '\(%s\)' % tor_group)
                   ]
    # properties.extend([ "prop %s = %s<br/>" % (_,_*1923) for _ in range(12) ])
    credit = 'John Cremona'
    if info['label'] == info['cremona_label']:
        t = "Elliptic Curve %s" % info['label']
    else:
        t = "Elliptic Curve %s (Cremona label %s)" % (info['label'], info['cremona_label'])

    bread = [('Elliptic Curves ', url_for("rational_elliptic_curves")), ('Elliptic curves %s' %
             lmfdb_label, ' ')]

    return render_template("elliptic_curve/elliptic_curve.html",
                           properties2=properties2, credit=credit, bread=bread, title=t, info=info, friends=info['friends'], downloads=info['downloads'])
Beispiel #12
0
def render_field_webpage(args):
    data = None
    if 'label' in args:
        label = str(args['label'])
        import base
        C = base.getDBConnection()
        data = C.numberfields.fields.find_one({'label': label})
    if data is None:
        return "No such field: " + label + " in the database"  
    info = {}

    try:
        info['count'] = args['count']
    except KeyError:
        info['count'] = 10
    K = coeff_to_nf(data['coefficients'])
    D = data['discriminant']
    h = data['class_number']
    data['galois_group'] = str(data['galois_group'][3])
    data['class_group_invs'] = data['class_group']
    if data['class_group_invs']==[]:
        data['class_group_invs']='Trivial'
    data['class_group'] = str(AbelianGroup(data['class_group']))
    sig = data['signature']
    D = ZZ(data['discriminant'])
    ram_primes = D.prime_factors()
    npr = len(ram_primes)
    ram_primes = str(ram_primes)[1:-1]
    Gorder,Gsign,Gab = GG_data(data['galois_group'])
    if Gab:
        Gab='abelian'
    else:
        Gab='non-abelian'
    unit_rank = sig[0]+sig[1]-1
    if unit_rank==0:
        reg = 1
    else:
        reg = K.regulator()
    UK = K.unit_group()
    
    info.update(data)
    info.update({
        'label': field_pretty(label),
        'polynomial': web_latex(K.defining_polynomial()),
        'ram_primes': ram_primes,
        'integral_basis': web_latex(K.integral_basis()),
        'regulator': web_latex(reg),
        'unit_rank': unit_rank,
        'root_of_unity': web_latex(UK.torsion_generator()),
        'fund_units': ',&nbsp; '.join([web_latex(u) for u in UK.fundamental_units()]),
        'Gorder': Gorder, 'Gsign': Gsign, 'Gab': Gab
        })
    info['downloads_visible'] = True
    info['downloads'] = [('worksheet', '/')]
#    info['friends'] = [('L-function', '/')]
    info['friends'] = [('L-function', "/L/NumberField/%s" % label)]
    info['learnmore'] = [('Number Field labels', url_for("render_labels_page")), ('Galois group labels',url_for("render_groups_page")), ('Discriminant ranges',url_for("render_discriminants_page"))]
    bread = [('Number Fields', url_for("number_field_render_webpage")),('%s'%info['label'],' ')]
    t = "Number Field %s" % info['label']

    properties = ['<br>']
    properties.extend('<table>')
    properties.extend('<tr><td align=left><b>Degree:</b><td align=left> %s</td>'%data['degree'])
    properties.extend('<tr><td align=left><b>Signature:</b><td align=left>%s</td>'%data['signature'])
    properties.extend('<tr><td align=left><b>Discriminant:</b><td align=left>%s</td>'%data['discriminant'])
    if npr==1:
        properties.extend('<tr><td align=left><b>Ramified prime:</b><td align=left>%s</td>'%ram_primes)
    else:
        if npr==0:
            properties.extend('<tr><td align=left><b>Ramified primes:</b><td align=left>%s</td>'%"None")
        else:
            properties.extend('<tr><td align=left><b>Ramified primes:</b><td align=left>%s</td>'%ram_primes)
    properties.extend('<tr><td align=left><b>Class number:</b><td align=left>%s</td>'%data['class_number'])
    properties.extend('<tr><td align=left><b>Class group:</b><td align=left>%s</td>'%data['class_group_invs'])
    properties.extend('<tr><td align=left><b>Galois group:</b><td align=left>%s</td>'%data['galois_group'])
    properties.extend('</table>')
    del info['_id']
    return render_template("number_field/number_field.html", properties=properties, credit=NF_credit, title = t, bread=bread, friends=info.pop('friends'), info=info )
Beispiel #13
0
def render_curve_webpage_by_label(label):
    C = lmfdb.base.getDBConnection()
    data = C.elliptic_curves.curves.find_one({"lmfdb_label": label})
    if data is None:
        return elliptic_curve_jump_error(label, {})
    info = {}
    ainvs = [int(a) for a in data["ainvs"]]
    E = EllipticCurve(ainvs)
    cremona_label = data["label"]
    lmfdb_label = data["lmfdb_label"]
    N = ZZ(data["conductor"])
    cremona_iso_class = data["iso"]  # eg '37a'
    lmfdb_iso_class = data["lmfdb_iso"]  # eg '37.a'
    rank = data["rank"]
    try:
        j_invariant = QQ(str(data["jinv"]))
    except KeyError:
        j_invariant = E.j_invariant()
    if j_invariant == 0:
        j_inv_factored = latex(0)
    else:
        j_inv_factored = latex(j_invariant.factor())
    jinv = unicode(str(j_invariant))
    CMD = 0
    CM = "no"
    EndE = "\(\Z\)"
    if E.has_cm():
        CMD = E.cm_discriminant()
        CM = "yes (\(%s\))" % CMD
        if CMD % 4 == 0:
            d4 = ZZ(CMD) // 4
            # r = d4.squarefree_part()
            # f = (d4//r).isqrt()
            # f="" if f==1 else str(f)
            # EndE = "\(\Z[%s\sqrt{%s}]\)"%(f,r)
            EndE = "\(\Z[\sqrt{%s}]\)" % (d4)
        else:
            EndE = "\(\Z[(1+\sqrt{%s})/2]\)" % CMD

    # plot=E.plot()
    discriminant = E.discriminant()
    xintpoints_projective = [E.lift_x(x) for x in xintegral_point(data["x-coordinates_of_integral_points"])]
    xintpoints = proj_to_aff(xintpoints_projective)
    if "degree" in data:
        modular_degree = data["degree"]
    else:
        try:
            modular_degree = E.modular_degree()
        except RuntimeError:
            modular_degree = 0  # invalid, will be displayed nicely

    G = E.torsion_subgroup().gens()
    E_pari = E.pari_curve(prec=200)
    from sage.libs.pari.all import PariError

    try:
        minq = E.minimal_quadratic_twist()[0]
    except PariError:  # this does occur with 164411a1
        print "PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label
        minq = E
    if E == minq:
        minq_label = lmfdb_label
    else:
        minq_ainvs = [str(c) for c in minq.ainvs()]
        minq_label = C.elliptic_curves.curves.find_one({"ainvs": minq_ainvs})["lmfdb_label"]
    # We do not just do the following, as Sage's installed database
    # might not have all the curves in the LMFDB database.
    # minq_label = E.minimal_quadratic_twist()[0].label()

    if "gens" in data:
        generator = parse_gens(data["gens"])
    if len(G) == 0:
        tor_struct = "\mathrm{Trivial}"
        tor_group = "\mathrm{Trivial}"
    else:
        tor_group = " \\times ".join(["\Z/{%s}\Z" % a.order() for a in G])
    if "torsion_structure" in data:
        info["tor_structure"] = " \\times ".join(["\Z/{%s}\Z" % int(a) for a in data["torsion_structure"]])
    else:
        info["tor_structure"] = tor_group

    info.update(data)
    if rank >= 2:
        lder_tex = "L%s(E,1)" % ("^{(" + str(rank) + ")}")
    elif rank == 1:
        lder_tex = "L%s(E,1)" % ("'" * rank)
    else:
        assert rank == 0
        lder_tex = "L(E,1)"
    info["Gamma0optimal"] = cremona_label[-1] == "1" if cremona_iso_class != "990h" else cremona_label[-1] == "3"
    info["modular_degree"] = modular_degree
    p_adic_data_exists = (C.elliptic_curves.padic_db.find({"lmfdb_iso": lmfdb_iso_class}).count()) > 0 and info[
        "Gamma0optimal"
    ]

    # Local data
    local_data = []
    for p in N.prime_factors():
        local_info = E.local_data(p, algorithm="generic")
        local_data.append(
            {
                "p": p,
                "tamagawa_number": local_info.tamagawa_number(),
                "kodaira_symbol": web_latex(local_info.kodaira_symbol()).replace("$", ""),
                "reduction_type": local_info.bad_reduction_type(),
            }
        )

    mod_form_iso = lmfdb_label_regex.match(lmfdb_iso_class).groups()[1]

    tamagawa_numbers = [E.local_data(p, algorithm="generic").tamagawa_number() for p in N.prime_factors()]
    # if we use E.tamagawa_numbers() it calls E.local_data(p) which
    # crashes on some curves e.g. 164411a1
    info.update(
        {
            "conductor": N,
            "disc_factor": latex(discriminant.factor()),
            "j_invar_factor": j_inv_factored,
            "label": lmfdb_label,
            "cremona_label": cremona_label,
            "iso_class": lmfdb_iso_class,
            "cremona_iso_class": cremona_iso_class,
            "equation": web_latex(E),
            #'f': ajax_more(E.q_eigenform, 10, 20, 50, 100, 250),
            "f": web_latex(E.q_eigenform(10)),
            "generators": ", ".join(web_latex(g) for g in generator) if "gens" in data else " ",
            "lder": lder_tex,
            "p_adic_primes": [p for p in sage.all.prime_range(5, 100) if E.is_ordinary(p) and not p.divides(N)],
            "p_adic_data_exists": p_adic_data_exists,
            "ainvs": format_ainvs(data["ainvs"]),
            "CM": CM,
            "CMD": CMD,
            "EndE": EndE,
            "tamagawa_numbers": r" \cdot ".join(str(sage.all.factor(c)) for c in tamagawa_numbers),
            "local_data": local_data,
            "cond_factor": latex(N.factor()),
            "xintegral_points": ", ".join(web_latex(P) for P in xintpoints),
            "tor_gens": ", ".join(web_latex(eval(g)) for g in data["torsion_generators"])
            if False
            else ", ".join(web_latex(P.element().xy()) for P in list(G)),
        }
    )
    info["friends"] = [
        ("Isogeny class " + lmfdb_iso_class, "/EllipticCurve/Q/%s" % lmfdb_iso_class),
        ("Minimal quadratic twist " + minq_label, "/EllipticCurve/Q/%s" % minq_label),
        ("All twists ", url_for("rational_elliptic_curves", jinv=jinv)),
        ("L-function", url_for("l_functions.l_function_ec_page", label=lmfdb_label)),
        (
            "Symmetric square L-function",
            url_for("l_functions.l_function_ec_sym_page", power="2", label=lmfdb_iso_class),
        ),
        (
            "Symmetric 4th power L-function",
            url_for("l_functions.l_function_ec_sym_page", power="4", label=lmfdb_iso_class),
        ),
    ]

    info["friends"].append(
        (
            "Modular form " + lmfdb_iso_class.replace(".", ".2"),
            url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=mod_form_iso),
        )
    )

    info["downloads"] = [
        ("Download coeffients of q-expansion", url_for("download_EC_qexp", label=lmfdb_label, limit=100)),
        ("Download all stored data", url_for("download_EC_all", label=lmfdb_label)),
    ]

    # info['learnmore'] = [('Elliptic Curves', url_for("not_yet_implemented"))]
    # info['plot'] = image_src(plot)
    info["plot"] = url_for("plot_ec", label=lmfdb_label)

    properties2 = [
        ("Label", "%s" % lmfdb_label),
        (None, '<img src="%s" width="200" height="150"/>' % url_for("plot_ec", label=lmfdb_label)),
        ("Conductor", "\(%s\)" % N),
        ("Discriminant", "\(%s\)" % discriminant),
        ("j-invariant", "%s" % web_latex(j_invariant)),
        ("CM", "%s" % CM),
        ("Rank", "\(%s\)" % rank),
        ("Torsion Structure", "\(%s\)" % tor_group),
    ]
    # properties.extend([ "prop %s = %s<br/>" % (_,_*1923) for _ in range(12) ])
    credit = "John Cremona"
    if info["label"] == info["cremona_label"]:
        t = "Elliptic Curve %s" % info["label"]
    else:
        t = "Elliptic Curve %s (Cremona label %s)" % (info["label"], info["cremona_label"])

    bread = [("Elliptic Curves ", url_for("rational_elliptic_curves")), ("Elliptic curves %s" % lmfdb_label, " ")]

    return render_template(
        "elliptic_curve/elliptic_curve.html",
        properties2=properties2,
        credit=credit,
        bread=bread,
        title=t,
        info=info,
        friends=info["friends"],
        downloads=info["downloads"],
    )