Exemple #1
0
def group_pretty_and_nTj(n, t, useknowls=False, skip_nTj=False, cache={}):
    label = base_label(n, t)
    string = label
    if cache:
        group = cache.get(label)
    else:
        group = db.gps_transitive.lookup(label)
    group_obj = WebGaloisGroup.from_data(group)
    if useknowls and group is not None:
        ntj = '<a title = "' + label + ' [nf.galois_group.data]" knowl="nf.galois_group.data" kwargs="n=' + str(
            n) + '&t=' + str(t) + '">' + label + '</a>'
    else:
        ntj = label
    pretty = group_obj.display_short(True) if group else ''
    if pretty != '':
        # modify if we use knowls and have the gap id
        if useknowls:
            gp_label = f"{group['order']}.{group['gapid']}"
            pretty = abstract_group_display_knowl(gp_label, cache=cache)
        if skip_nTj:
            # This is used for statistics where we want to display the abstract group, but we still need to be able to get back to the nTj label for searching
            if useknowls and pretty.startswith('<a title = "Group'):
                # Use the nTj knowl
                string = '<a title = "' + label + ' [nf.galois_group.data]" knowl="nf.galois_group.data" kwargs="n=' + str(
                    n) + '&t=' + str(t) + '">' + pretty + '</a>'
            else:
                string = pretty + '<span style="display:none">%s</span>' % label
        else:
            string = pretty + ' (as ' + ntj + ')'
    else:
        string = ntj
    return string
Exemple #2
0
def render_glnQ_group(args):
    info = {}
    if 'label' in args:
        label = clean_input(args['label'])
        info = db.gps_qrep.lucky({'label': label})
        info['dispmat'] = dispmat
        info['groupname'] = '${}$'.format(group_names_pretty(info['group']))
        info['groupknowl'] = abstract_group_display_knowl(
            info['group'], info['groupname'])

        title = r'$\GL(' + str(info['dim']) + r',\Q)$ subgroup ' + label

        prop = [('Label', '%s' % label), ('Order', r'\(%s\)' % info['order']),
                ('Dimension', '%s' % info['dim'])]

        bread = get_bread([(label, )])

        #        downloads = [('Code to Magma', url_for(".hgcwa_code_download",  label=label, download_type='magma')),
        #                     ('Code to Gap', url_for(".hgcwa_code_download", label=label, download_type='gap'))]

        return render_template(
            "glnQ-show-group.html",
            title=title,
            bread=bread,
            info=info,
            properties=prop,
            #friends=friends,
            learnmore=learnmore_list(),
            #downloads=downloads,
            credit=credit_string)
Exemple #3
0
def group_display_inertia(code):
    if str(code[0]) == "t":
        return transitive_group_display_knowl(base_label(*code[1]))
    if code[1] == [1,1]:
        return "trivial"
    ans = "Intransitive group isomorphic to "+abstract_group_display_knowl(f"{code[1][0]}.{code[1][1]}")
    return ans
Exemple #4
0
 def projective_group(self):
     gapid = self._data['Proj_GAP']
     if gapid[0]:
         label = f"{gapid[0]}.{gapid[1]}"
         name = db.gps_groups.lookup(label, "tex_name")
         if name:
             return abstract_group_display_knowl(label, f"${name}$")
     ntj = self._data['Proj_nTj']
     if ntj[1]:
         return transitive_group_display_knowl(f"{ntj[0]}T{ntj[1]}")
     if gapid:
         return f'Group({gapid[0]}.{gapid[1]})'
     return 'data not computed'
Exemple #5
0
def getgroup(m1, ell):
    pind = {2: 0, 3: 1, 5: 2, 7: 3, 11: 4, 13: 5}
    if not m1[3][2]:
        return [m1[2], m1[0]]
    myA = m1[3][0]
    myB = m1[3][1]
    if not myA and not myB:  # myA = myB = []
        return [abstract_group_display_knowl("1.1", "$C_1$"), 1]
    mono = db.hgm_families.lucky({'A': myA, 'B': myB}, projection="mono")
    if mono is None:
        return ['??', 1]
    newthing = mono[pind[ell]]
    newthing = dogapthing(newthing[1])
    return [newthing[2], newthing[0]]
Exemple #6
0
def dogapthing(m1):
    mnew = str(m1[2])
    mnew = mnew.replace(' ', '')
    if GAP_ID_RE.match(mnew):
        mnew = mnew[1:-1]
        two = mnew.split(',')
        two = [int(j) for j in two]
        try:
            m1[2] = abstract_group_display_knowl(f"{two[0]}.{two[1]}")
        except TypeError:
            m1[2] = f'Group({two[0]}.{two[1]})'
    else:
        # Fix multiple backslashes
        m1[2] = re.sub(r'\\+', r'\\', m1[2])
        m1[2] = '$%s$' % m1[2]
    return m1
Exemple #7
0
 def structure_group_knowl(self):
     inv = self.H.invariants()
     label = ".".join(str(v) for v in inv)
     parts = defaultdict(list)
     if label:
         for piece in label.split("."):
             if "_" in piece:
                 base, exp = map(ZZ, piece.split("_"))
             else:
                 base = ZZ(piece)
                 exp = 1
             for p, e in base.factor():
                 parts[p].extend([p ** e] * exp)
     for v in parts.values():
         v.sort()
     primary = sum((parts[p] for p in sorted(parts)), [])
     dblabel = db.gps_groups.lucky({"abelian": True, "primary_abelian_invariants": primary}, "label")
     if dblabel is None:
         abgp_url = url_for('abstract.by_abelian_label', label=label)
         return f'<a href= %s >{self.structure}</a>' % abgp_url
     return abstract_group_display_knowl(dblabel, f"{self.structure}")
Exemple #8
0
def render_field_webpage(args):
    data = None
    info = {}
    if 'label' in args:
        label = clean_input(args['label'])
        data = db.lf_fields.lookup(label)
        if data is None:
            if re.match(r'^\d+\.\d+\.\d+\.\d+$', label):
                flash_error("Field %s was not found in the database.", label)
            else:
                flash_error("%s is not a valid label for a $p$-adic field.",
                            label)
            return redirect(url_for(".index"))
        title = '$p$-adic field ' + prettyname(data)
        titletag = 'p-adic field ' + prettyname(data)
        polynomial = coeff_to_poly(data['coeffs'])
        p = data['p']
        Qp = r'\Q_{%d}' % p
        e = data['e']
        f = data['f']
        cc = data['c']
        gt = int(data['galois_label'].split('T')[1])
        gn = data['n']
        the_gal = WebGaloisGroup.from_nt(gn, gt)
        isgal = ' Galois' if the_gal.order() == gn else ' not Galois'
        abelian = ' and abelian' if the_gal.is_abelian() else ''
        galphrase = 'This field is' + isgal + abelian + r' over $\Q_{%d}.$' % p
        autstring = r'\Gal' if the_gal.order() == gn else r'\Aut'
        prop2 = [
            ('Label', label),
            ('Base', r'\(%s\)' % Qp),
            ('Degree', r'\(%s\)' % data['n']),
            ('e', r'\(%s\)' % e),
            ('f', r'\(%s\)' % f),
            ('c', r'\(%s\)' % cc),
            ('Galois group', group_pretty_and_nTj(gn, gt)),
        ]
        # Look up the unram poly so we can link to it
        unramlabel = db.lf_fields.lucky({'p': p, 'n': f, 'c': 0}, projection=0)
        if unramlabel is None:
            logger.fatal("Cannot find unramified field!")
            unramfriend = ''
        else:
            unramfriend = url_for_label(unramlabel)
            unramdata = db.lf_fields.lookup(unramlabel)

        Px = PolynomialRing(QQ, 'x')
        Pt = PolynomialRing(QQ, 't')
        Ptx = PolynomialRing(Pt, 'x')
        if data['f'] == 1:
            unramp = r'$%s$' % Qp
            eisenp = Ptx(str(data['eisen']).replace('y', 'x'))
            eisenp = raw_typeset(eisenp, web_latex(eisenp))

        else:
            unramp = data['unram'].replace('t', 'x')
            unramp = raw_typeset(unramp, web_latex(Px(str(unramp))))
            unramp = prettyname(
                unramdata
            ) + ' $\\cong ' + Qp + '(t)$ where $t$ is a root of ' + unramp
            eisenp = Ptx(str(data['eisen']).replace('y', 'x'))
            eisenp = raw_typeset(str(eisenp),
                                 web_latex(eisenp),
                                 extra=r'$\ \in' + Qp + '(t)[x]$')

        rflabel = db.lf_fields.lucky(
            {
                'p': p,
                'n': {
                    '$in': [1, 2]
                },
                'rf': data['rf']
            }, projection=0)
        if rflabel is None:
            logger.fatal("Cannot find discriminant root field!")
            rffriend = ''
        else:
            rffriend = url_for_label(rflabel)
        gsm = data['gsm']
        if gsm == [0]:
            gsm = 'Not computed'
        elif gsm == [-1]:
            gsm = 'Does not exist'
        else:
            gsm = lf_formatfield(','.join(str(b) for b in gsm))

        if 'wild_gap' in data:
            wild_inertia = abstract_group_display_knowl(
                f"{data['wild_gap'][0]}.{data['wild_gap'][1]}")
        else:
            wild_inertia = 'data not computed'

        info.update({
            'polynomial':
            raw_typeset(polynomial),
            'n':
            data['n'],
            'p':
            p,
            'c':
            data['c'],
            'e':
            data['e'],
            'f':
            data['f'],
            't':
            data['t'],
            'u':
            data['u'],
            'rf':
            lf_display_knowl(rflabel, name=printquad(data['rf'], p)),
            'base':
            lf_display_knowl(str(p) + '.1.0.1', name='$%s$' % Qp),
            'hw':
            data['hw'],
            'slopes':
            show_slopes(data['slopes']),
            'gal':
            group_pretty_and_nTj(gn, gt, True),
            'gt':
            gt,
            'inertia':
            group_display_inertia(data['inertia']),
            'wild_inertia':
            wild_inertia,
            'unram':
            unramp,
            'eisen':
            eisenp,
            'gms':
            data['gms'],
            'gsm':
            gsm,
            'galphrase':
            galphrase,
            'autstring':
            autstring,
            'subfields':
            format_subfields(data['subfields'], p),
            'aut':
            data['aut'],
        })
        friends = [('Galois group', "/GaloisGroup/%dT%d" % (gn, gt))]
        if unramfriend != '':
            friends.append(('Unramified subfield', unramfriend))
        if rffriend != '':
            friends.append(('Discriminant root field', rffriend))
        if db.nf_fields.exists({'local_algs': {'$contains': label}}):
            friends.append(
                ('Number fields with this completion',
                 url_for('number_fields.number_field_render_webpage') +
                 "?completions={}".format(label)))

        bread = get_bread([(label, ' ')])
        return render_template(
            "lf-show-field.html",
            title=title,
            titletag=titletag,
            bread=bread,
            info=info,
            properties=prop2,
            friends=friends,
            learnmore=learnmore_list(),
            KNOWL_ID="lf.%s" % label,
        )
Exemple #9
0
def render_group_webpage(args):
    data = {}
    if 'label' in args:
        label = clean_input(args['label'])
        label = label.replace('t', 'T')
        data = db.gps_transitive.lookup(label)
        if data is None:
            if re.match(r'^\d+T\d+$', label):
                flash_error("Group %s was not found in the database.", label)
            else:
                flash_error("%s is not a valid label for a Galois group.",
                            label)
            return redirect(url_for(".index"))
        title = 'Galois group: ' + label
        wgg = WebGaloisGroup.from_nt(data['n'], data['t'])
        data['wgg'] = wgg
        n = data['n']
        t = data['t']
        data['yesno'] = yesno
        order = data['order']
        data['orderfac'] = latex(ZZ(order).factor())
        orderfac = latex(ZZ(order).factor())
        data['ordermsg'] = "$%s=%s$" % (order, latex(orderfac))
        if order == 1:
            data['ordermsg'] = "$1$"
        if ZZ(order).is_prime():
            data['ordermsg'] = "$%s$ (is prime)" % order
        pgroup = len(ZZ(order).prime_factors()) < 2
        if wgg.num_conjclasses() < 50:
            data['cclasses'] = wgg.conjclasses()
        if ZZ(order) < ZZ(10000000) and wgg.num_conjclasses() < 21:
            data['chartable'] = chartable(n, t)
        data['gens'] = wgg.generator_string()
        if n == 1 and t == 1:
            data['gens'] = 'None needed'
        data['num_cc'] = comma(wgg.num_conjclasses())
        data['parity'] = "$%s$" % data['parity']
        data['subinfo'] = subfield_display(n, data['subfields'])
        data['resolve'] = resolve_display(data['quotients'])
        if data['gapid'] == 0:
            data['gapid'] = "not available"
        else:
            gp_label = f"{data['order']}.{data['gapid']}"
            data['gapid'] = abstract_group_display_knowl(gp_label, gp_label)
        data['otherreps'] = wgg.otherrep_list()
        ae = data['arith_equiv']
        if ae > 0:
            if ae > 1:
                data[
                    'arith_equiv'] = r'A number field with this Galois group has %d <a knowl="nf.arithmetically_equivalent", title="arithmetically equivalent">arithmetically equivalent</a> fields.' % ae
            else:
                data[
                    'arith_equiv'] = r'A number field with this Galois group has exactly one <a knowl="nf.arithmetically_equivalent", title="arithmetically equivalent">arithmetically equivalent</a> field.'
        elif ae > -1:
            data[
                'arith_equiv'] = r'A number field with this Galois group has no <a knowl="nf.arithmetically_equivalent", title="arithmetically equivalent">arithmetically equivalent</a> fields.'
        else:
            data[
                'arith_equiv'] = r'Data on whether or not a number field with this Galois group has <a knowl="nf.arithmetically_equivalent", title="arithmetically equivalent">arithmetically equivalent</a> fields has not been computed.'
        intreps = list(db.gps_gmodules.search({'n': n, 't': t}))
        if intreps:
            data['int_rep_classes'] = [str(z[0]) for z in intreps[0]['gens']]
            for onerep in intreps:
                onerep['gens'] = [
                    list_to_latex_matrix(z[1]) for z in onerep['gens']
                ]
            data['int_reps'] = intreps
            data['int_reps_complete'] = int_reps_are_complete(intreps)
            dcq = data['moddecompuniq']
            if dcq[0] == 0:
                data['decompunique'] = 0
            else:
                data['decompunique'] = dcq[0]
                data['isoms'] = [[mult2mult(z[0]),
                                  mult2mult(z[1])] for z in dcq[1]]
                data['isoms'] = [[
                    modules2string(n, t, z[0]),
                    modules2string(n, t, z[1])
                ] for z in data['isoms']]
                #print dcq[1]
                #print data['isoms']

        friends = []
        if db.nf_fields.exists({'degree': n, 'galt': t}):
            friends.append(
                ('Number fields with this Galois group',
                 url_for('number_fields.number_field_render_webpage') +
                 "?galois_group=%dT%d" % (n, t)))
        if db.lf_fields.exists({'n': n, 'galT': t}):
            friends.append(
                ('$p$-adic fields with this Galois group',
                 url_for('local_fields.index') + "?gal=%dT%d" % (n, t)))
        prop2 = [
            ('Label', label),
            ('Degree', prop_int_pretty(data['n'])),
            ('Order', prop_int_pretty(order)),
            ('Cyclic', yesno(data['cyc'])),
            ('Abelian', yesno(data['ab'])),
            ('Solvable', yesno(data['solv'])),
            ('Primitive', yesno(data['prim'])),
            ('$p$-group', yesno(pgroup)),
        ]
        pretty = group_display_short(n, t, emptyifnotpretty=True)
        if len(pretty) > 0:
            prop2.extend([('Group:', pretty)])
            data['pretty_name'] = pretty
        data['name'] = re.sub(r'_(\d+)', r'_{\1}', data['name'])
        data['name'] = re.sub(r'\^(\d+)', r'^{\1}', data['name'])
        data['nilpotency'] = '$%s$' % data['nilpotency']
        if data['nilpotency'] == '$-1$':
            data['nilpotency'] += ' (not nilpotent)'

        bread = get_bread([(label, ' ')])
        return render_template("gg-show-group.html",
                               title=title,
                               bread=bread,
                               info=data,
                               properties=prop2,
                               friends=friends,
                               KNOWL_ID="gg.%s" % label,
                               learnmore=learnmore_list())
Exemple #10
0
    def make_object(self, curve, endo, tama, ratpts, clus, is_curve):
        from lmfdb.genus2_curves.main import url_for_curve_label

        # all information about the curve, its Jacobian, isogeny class, and endomorphisms goes in the data dictionary
        # most of the data from the database gets polished/formatted before we put it in the data dictionary
        data = self.data = {}

        data['label'] = curve['label'] if is_curve else curve['class']
        data['slabel'] = data['label'].split('.')

        # set attributes common to curves and isogeny classes here
        data['Lhash'] = str(curve['Lhash'])
        data['cond'] = ZZ(curve['cond'])
        data['cond_factor_latex'] = web_latex_factored_integer(data['cond'])
        data['analytic_rank'] = ZZ(curve['analytic_rank'])
        data['mw_rank'] = ZZ(0) if curve.get('mw_rank') is None else ZZ(curve['mw_rank']) # 0 will be marked as a lower bound
        data['mw_rank_proved'] = curve['mw_rank_proved']
        data['analytic_rank_proved'] = curve['analytic_rank_proved']
        data['hasse_weil_proved'] = curve['hasse_weil_proved']
        data['st_group'] = curve['st_group']
        data['st_group_link'] = st_link_by_name(1,4,data['st_group'])
        data['st0_group_name'] = st0_group_name(curve['real_geom_end_alg'])
        data['is_gl2_type'] = curve['is_gl2_type']
        data['root_number'] = ZZ(curve['root_number'])
        data['lfunc_url'] = url_for("l_functions.l_function_genus2_page", cond=data['slabel'][0], x=data['slabel'][1])
        data['bad_lfactors'] = literal_eval(curve['bad_lfactors'])
        data['bad_lfactors_pretty'] = [ (c[0], list_to_factored_poly_otherorder(c[1])) for c in data['bad_lfactors']]
        if is_curve:
            # invariants specific to curve
            data['class'] = curve['class']
            data['abs_disc'] = ZZ(curve['abs_disc'])
            data['disc'] = curve['disc_sign'] * data['abs_disc']
            data['min_eqn'] = literal_eval(curve['eqn'])
            data['min_eqn_display'] = min_eqns_pretty(data['min_eqn'])
            data['disc_factor_latex'] = web_latex_factored_integer(data['disc'])
            data['igusa_clebsch'] = [ZZ(a) for a in literal_eval(curve['igusa_clebsch_inv'])]
            data['igusa'] = [ZZ(a) for a in literal_eval(curve['igusa_inv'])]
            data['g2'] = [QQ(a) for a in literal_eval(curve['g2_inv'])]
            data['igusa_clebsch_factor_latex'] = [web_latex_factored_integer(i) for i in data['igusa_clebsch']]
            data['igusa_factor_latex'] = [ web_latex_factored_integer(j) for j in data['igusa'] ]
            data['aut_grp'] = abstract_group_display_knowl(curve['aut_grp_label'], f"${curve['aut_grp_tex']}$")
            data['geom_aut_grp'] = abstract_group_display_knowl(curve['geom_aut_grp_label'], f"${curve['geom_aut_grp_tex']}$")
            data['num_rat_wpts'] = ZZ(curve['num_rat_wpts'])
            data['has_square_sha'] = "square" if curve['has_square_sha'] else "twice a square"
            P = curve['non_solvable_places']
            if len(P):
                sz = "except over "
                sz += ", ".join([QpName(p) for p in P])
                last = " and"
                if len(P) > 2:
                    last = ", and"
                sz = last.join(sz.rsplit(",",1))
            else:
                sz = "everywhere"
            data['non_solvable_places'] = sz
            data['two_selmer_rank'] = ZZ(curve['two_selmer_rank'])
            data['torsion_order'] = curve['torsion_order']

            data['end_ring_base'] = endo['ring_base']
            data['end_ring_geom'] = endo['ring_geom']
            data['real_period'] = decimal_pretty(str(curve['real_period']))
            data['regulator'] = decimal_pretty(str(curve['regulator'])) if curve['regulator'] > -0.5 else 'unknown'
            if data['mw_rank'] == 0 and data['mw_rank_proved']:
                data['regulator'] = '1' # display an exact 1 when we know this

            data['tamagawa_product'] = ZZ(curve['tamagawa_product']) if curve.get('tamagawa_product') else 0
            data['analytic_sha'] = ZZ(curve['analytic_sha']) if curve.get('analytic_sha') else 0
            data['leading_coeff'] = decimal_pretty(str(curve['leading_coeff'])) if curve['leading_coeff'] else 'unknown'

            data['rat_pts'] = ratpts['rat_pts']
            data['rat_pts_v'] =  ratpts['rat_pts_v']
            data['rat_pts_table'] = ratpts_table(ratpts['rat_pts'],ratpts['rat_pts_v'])
            data['rat_pts_simple_table'] = ratpts_simpletable(ratpts['rat_pts'],ratpts['rat_pts_v'],data['min_eqn'])

            data['mw_gens_v'] = ratpts['mw_gens_v']
            lower = len([n for n in ratpts['mw_invs'] if n == 0])
            upper = data['analytic_rank']
            invs = ratpts['mw_invs'] if data['mw_gens_v'] or lower >= upper else [0 for n in range(upper-lower)] + ratpts['mw_invs']
            if len(invs) == 0:
                data['mw_group'] = 'trivial'
            else:
                data['mw_group'] = r'\(' + r' \times '.join([ (r'\Z' if n == 0 else r'\Z/{%s}\Z' % n) for n in invs]) + r'\)'
            if lower >= upper:
                data['mw_gens_table'] = mw_gens_table (ratpts['mw_invs'], ratpts['mw_gens'], ratpts['mw_heights'], ratpts['rat_pts'])
                data['mw_gens_simple_table'] = mw_gens_simple_table (ratpts['mw_invs'], ratpts['mw_gens'], ratpts['mw_heights'], ratpts['rat_pts'], data['min_eqn'])

            if curve['two_torsion_field'][0]:
                data['two_torsion_field_knowl'] = nf_display_knowl (curve['two_torsion_field'][0], field_pretty(curve['two_torsion_field'][0]))
            else:
                t = curve['two_torsion_field']
                data['two_torsion_field_knowl'] = r"splitting field of \(%s\) with Galois group %s" % (intlist_to_poly(t[1]),transitive_group_display_knowl(f"{t[2][0]}T{t[2][1]}"))

            tamalist = [[item['p'],item['tamagawa_number']] for item in tama]
            data['local_table'] = local_table (data['cond'],data['abs_disc'],tamalist,data['bad_lfactors_pretty'],clus)

        else:
            # invariants specific to isogeny class
            curves_data = list(db.g2c_curves.search({"class" : curve['class']}, ['label','eqn']))
            if not curves_data:
                raise KeyError("No curves found in database for isogeny class %s of genus 2 curve %s." %(curve['class'],curve['label']))
            data['curves'] = [ {"label" : c['label'], "equation_formatted" : min_eqn_pretty(literal_eval(c['eqn'])), "url": url_for_curve_label(c['label'])} for c in curves_data ]
            lfunc_data = db.lfunc_lfunctions.lucky({'Lhash':str(curve['Lhash'])})
            if not lfunc_data:
                raise KeyError("No Lfunction found in database for isogeny class of genus 2 curve %s." %curve['label'])
            if lfunc_data and lfunc_data.get('euler_factors'):
                data['good_lfactors'] = [[nth_prime(n+1),lfunc_data['euler_factors'][n]] for n in range(len(lfunc_data['euler_factors'])) if nth_prime(n+1) < 30 and (data['cond'] % nth_prime(n+1))]
                data['good_lfactors_pretty'] = [ (c[0], list_to_factored_poly_otherorder(c[1])) for c in data['good_lfactors']]

        # Endomorphism data over QQ:
        data['gl2_statement_base'] = gl2_statement_base(endo['factorsRR_base'], r'\(\Q\)')
        data['factorsQQ_base'] = endo['factorsQQ_base']
        data['factorsRR_base'] = endo['factorsRR_base']
        data['end_statement_base'] = (r"Endomorphism %s over \(\Q\):<br>" %("ring" if is_curve else "algebra") +
            end_statement(data['factorsQQ_base'], endo['factorsRR_base'], ring=data['end_ring_base'] if is_curve else None))

        # Field over which all endomorphisms are defined
        data['end_field_label'] = endo['fod_label']
        data['end_field_poly'] = intlist_to_poly(endo['fod_coeffs'])
        data['end_field_statement'] = end_field_statement(data['end_field_label'], data['end_field_poly'])

        # Endomorphism data over QQbar:
        data['factorsQQ_geom'] = endo['factorsQQ_geom']
        data['factorsRR_geom'] = endo['factorsRR_geom']
        if data['end_field_label'] != '1.1.1.1':
            data['gl2_statement_geom'] = gl2_statement_base(data['factorsRR_geom'], r'\(\overline{\Q}\)')
            data['end_statement_geom'] = (r"Endomorphism %s over \(\overline{\Q}\):" %("ring" if is_curve else "algebra") +
                end_statement(data['factorsQQ_geom'], data['factorsRR_geom'], field=r'\overline{\Q}', ring=data['end_ring_geom'] if is_curve else None))
        data['real_geom_end_alg_name'] = real_geom_end_alg_name(curve['real_geom_end_alg'])
        data['geom_end_alg_name'] = geom_end_alg_name(curve['geom_end_alg'])
        data['end_alg_name'] = end_alg_name(curve['end_alg'])

        # Endomorphism data over intermediate fields not already treated (only for curves, not necessarily isogeny invariant):
        if is_curve:
            data['end_lattice'] = (endo['lattice'])[1:-1]
            if data['end_lattice']:
                data['end_lattice_statement'] = end_lattice_statement(data['end_lattice'])

        # Field over which the Jacobian decomposes (base field if Jacobian is geometrically simple)
        data['is_simple_geom'] = endo['is_simple_geom']
        data['split_field_label'] = endo['spl_fod_label']
        data['split_field_poly'] = intlist_to_poly(endo['spl_fod_coeffs'])
        data['split_field_statement'] = split_field_statement(data['is_simple_geom'], data['split_field_label'], data['split_field_poly'])

        # Elliptic curve factors for non-simple Jacobians
        if not data['is_simple_geom']:
            data['split_coeffs'] = endo['spl_facs_coeffs']
            if 'spl_facs_labels' in endo and len(endo['spl_facs_labels']) == len(endo['spl_facs_coeffs']):
                data['split_labels'] = endo['spl_facs_labels']
            data['split_condnorms'] = endo['spl_facs_condnorms']
            data['split_statement'] = split_statement(data['split_coeffs'], data.get('split_labels'), data['split_condnorms'])

        # Properties
        self.properties = properties = [('Label', data['label'])]
        if is_curve:
            plot_from_db = db.g2c_plots.lucky({"label": curve['label']})
            if (plot_from_db is None):
                self.plot = encode_plot(eqn_list_to_curve_plot(data['min_eqn'], ratpts['rat_pts'] if ratpts else []))
            else:
                self.plot = plot_from_db['plot']
            plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(self.plot)

            properties += [
                (None, plot_link),
                ('Conductor', prop_int_pretty(data['cond'])),
                ('Discriminant', prop_int_pretty(data['disc'])),
                ]
            if data['mw_rank_proved']:
                properties += [('Mordell-Weil group', data['mw_group'])]
        else:
            properties += [('Conductor', prop_int_pretty(data['cond']))]
        properties += [
            ('Sato-Tate group', data['st_group_link']),
            (r'\(\End(J_{\overline{\Q}}) \otimes \R\)', r'\(%s\)' % data['real_geom_end_alg_name']),
            (r'\(\End(J_{\overline{\Q}}) \otimes \Q\)', r'\(%s\)' % data['geom_end_alg_name']),
            (r'\(\End(J) \otimes \Q\)', r'\(%s\)' % data['end_alg_name']),
            (r'\(\overline{\Q}\)-simple', bool_pretty(data['is_simple_geom'])),
            (r'\(\mathrm{GL}_2\)-type', bool_pretty(data['is_gl2_type'])),
            ]

        # Friends
        self.friends = friends = []
        if is_curve:
            friends.append(('Genus 2 curve %s.%s' % (data['slabel'][0], data['slabel'][1]), url_for(".by_url_isogeny_class_label", cond=data['slabel'][0], alpha=data['slabel'][1])))

        # first deal with ECs and MFs
        ecs = []
        mfs = []
        if 'split_labels' in data:
            for friend_label in data['split_labels']:
                if is_curve:
                    ecs.append(("Elliptic curve " + friend_label, url_for_ec(friend_label)))
                else:
                    ecs.append(("Elliptic curve " + ec_label_class(friend_label), url_for_ec_class(friend_label)))
                try:
                    cond, iso = ec_label_class(friend_label).split(".")
                    newform_label = ".".join([cond, str(2), 'a', iso])
                    mfs.append(("Modular form " + newform_label, url_for("cmf.by_url_newform_label", level=cond, weight=2, char_orbit_label='a', hecke_orbit=iso)))
                except ValueError:
                    # means the friend isn't an elliptic curve over Q; adding Hilbert/Bianchi modular forms
                    # is dealt with via the L-functions instances below
                    pass

        ecs.sort(key=lambda x: key_for_numerically_sort(x[0]))
        mfs.sort(key=lambda x: key_for_numerically_sort(x[0]))

        # then again EC from lfun
        instances = []
        for elt in db.lfunc_instances.search({'Lhash':data['Lhash'], 'type' : 'ECQP'}, 'url'):
            instances.extend(elt.split('|'))

        # and then the other isogeny friends
        instances.extend([
            elt['url'] for elt in
            get_instances_by_Lhash_and_trace_hash(data["Lhash"],
                                                  4,
                                                  int(data["Lhash"])
                                                  )
            ])

        exclude = {elt[1].rstrip('/').lstrip('/') for elt in self.friends
                   if elt[1]}
        exclude.add(data['lfunc_url'].lstrip('/L/').rstrip('/'))
        for elt in ecs + mfs + names_and_urls(instances, exclude=exclude):
            # because of the splitting we must use G2C specific code
            add_friend(friends, elt)
        if is_curve:
            friends.append(('Twists', url_for(".index_Q",
                                              g20=str(data['g2'][0]),
                                              g21=str(data['g2'][1]),
                                              g22=str(data['g2'][2]))))

        friends.append(('L-function', data['lfunc_url']))

        # Breadcrumbs
        self.bread = bread = [
             ('Genus 2 curves', url_for(".index")),
             (r'$\Q$', url_for(".index_Q")),
             ('%s' % data['slabel'][0], url_for(".by_conductor", cond=data['slabel'][0])),
             ('%s' % data['slabel'][1], url_for(".by_url_isogeny_class_label", cond=data['slabel'][0], alpha=data['slabel'][1]))
             ]
        if is_curve:
            bread += [
                ('%s' % data['slabel'][2], url_for(".by_url_isogeny_class_discriminant", cond=data['slabel'][0], alpha=data['slabel'][1], disc=data['slabel'][2])),
                ('%s' % data['slabel'][3], url_for(".by_url_curve_label", cond=data['slabel'][0], alpha=data['slabel'][1], disc=data['slabel'][2], num=data['slabel'][3]))
                ]

        # Title
        self.title = "Genus 2 " + ("curve " if is_curve else "isogeny class ") + data['label']

        # Code snippets (only for curves)
        if not is_curve:
            return
        self.code = code = {}
        code['show'] = {'sage':'','magma':''} # use default show names
        f,h = fh = data['min_eqn']
        g = simplify_hyperelliptic(fh)
        code['curve'] = {'sage':'R.<x> = PolynomialRing(QQ); C = HyperellipticCurve(R(%s), R(%s));'%(f,h),
                         'magma':'R<x> := PolynomialRing(Rationals()); C := HyperellipticCurve(R!%s, R!%s);'%(f,h) }
        code['simple_curve'] = {'sage':'X = HyperellipticCurve(R(%s))'%(g), 'magma':'X,pi:= SimplifiedModel(C);' }
        if data['abs_disc'] % 4096 == 0:
            ind2 = [a[0] for a in data['bad_lfactors']].index(2)
            bad2 = data['bad_lfactors'][ind2][1]
            magma_cond_option = ': ExcFactors:=[*<2,Valuation('+str(data['cond'])+',2),R!'+str(bad2)+'>*]'
        else:
            magma_cond_option = ''
        code['cond'] = {'magma': 'Conductor(LSeries(C%s)); Factorization($1);'% magma_cond_option}
        code['disc'] = {'magma':'Discriminant(C); Factorization(Integers()!$1);'}
        code['geom_inv'] = {'sage':'C.igusa_clebsch_invariants(); [factor(a) for a in _]',
                            'magma':'IgusaClebschInvariants(C); IgusaInvariants(C); G2Invariants(C);'}
        code['aut'] = {'magma':'AutomorphismGroup(C); IdentifyGroup($1);'}
        code['autQbar'] = {'magma':'AutomorphismGroup(ChangeRing(C,AlgebraicClosure(Rationals()))); IdentifyGroup($1);'}
        code['num_rat_wpts'] = {'magma':'#Roots(HyperellipticPolynomials(SimplifiedModel(C)));'}
        if ratpts:
            code['rat_pts'] = {'magma': '[' + ','.join(["C![%s,%s,%s]"%(p[0],p[1],p[2]) for p in ratpts['rat_pts']]) + ']; // minimal model'}
            code['rat_pts_simp'] = {'magma': '[' + ','.join(["C![%s,%s,%s]"%(p[0],p[1],p[2]) for p in [simplify_hyperelliptic_point(data['min_eqn'], pt) for pt in ratpts['rat_pts']]]) + ']; // simplified model'}
        code['mw_group'] = {'magma':'MordellWeilGroupGenus2(Jacobian(C));'}
        code['two_selmer'] = {'magma':'TwoSelmerGroup(Jacobian(C)); NumberOfGenerators($1);'}
        code['has_square_sha'] = {'magma':'HasSquareSha(Jacobian(C));'}
        code['locally_solvable'] = {'magma':'f,h:=HyperellipticPolynomials(C); g:=4*f+h^2; HasPointsEverywhereLocally(g,2) and (#Roots(ChangeRing(g,RealField())) gt 0 or LeadingCoefficient(g) gt 0);'}
        code['torsion_subgroup'] = {'magma':'TorsionSubgroup(Jacobian(SimplifiedModel(C))); AbelianInvariants($1);'}