Exemplo n.º 1
0
def WebNewForm_cached(level, weight, character, label, parent=None, **kwds):
    if use_cache:
        M = WebModFormSpace_cached(level, weight, character)
        return M.hecke_orbits[label]
    else:
        F = WebNewForm(level, weight, character, label, **kwds)
        emf_logger.critical("Computed F not using cache!")
    return F
Exemplo n.º 2
0
def set_info_for_modular_form_space(level=None, weight=None, character=None, label=None, **kwds):
    r"""
      Set information about a space of modular forms.
    """
    info = dict()
    emf_logger.debug("info={0}".format(info))    
    WMFS = None
    if level <= 0:
        info['error'] = "Got wrong level: %s " % level
        return info
    try:
        WMFS = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True,character = character)
        emf_logger.debug("Created WebModFormSpace %s"%WMFS)
        if 'download' in info and 'tempfile' in info:
            save(WNF,info['tempfile'])
            info['filename'] = str(weight) + '-' + str(level) + '-' + str(character) + '-' + label + '.sobj'
            return info
    except ValueError as e:
        emf_logger.debug(e)
        emf_logger.debug(e.message)
        #if isinstance(e,IndexError):
        info['error'] = e.message
        WMFS = None
    if WMFS is None:
        info['error'] = "We are sorry. The sought space can not be found in the database. "+"<br> Detailed information: {0}".format(info.get('error',''))
        return info
    else:
        ### Somehow the Hecke orbits are sometimes not in the space...
        #if WMFS.dimension_new_cusp_forms()<>len(WMFS.hecke_orbits):
        #    ## Try to add them here... 
        #    for d in range(len(WMFS.dimension_new_cusp_forms())):
        #        F = 
        #        WMFS.hecke_orbits.append(F)
        info = {'space':WMFS}
#    info['old_decomposition'] = WMFS.oldspace_decomposition()

    ## For side-bar
    lifts = list()
    lifts.append(('Half-Integral Weight Forms', '/ModularForm/Mp2/Q'))
    lifts.append(('Siegel Modular Forms', '/ModularForm/GSp4/Q'))
    info['lifts'] = lifts
    friends = list()
    for label in WMFS.hecke_orbits:
        f = WMFS.hecke_orbits[label]
        friends.append(('Number field ' + f.base_field_label(), f.base_field_url()))
        if f.coefficient_field_label(check=True):
            friends.append(('Number field ' + f.coefficient_field_label(), f.coefficient_field_url()))
    friends.append(("Dirichlet character \(" + WMFS.character.latex_name + "\)", WMFS.character.url()))
    friends = uniq(friends)
    info['friends'] = friends
    
    return info
Exemplo n.º 3
0
def get_qexp(level, weight, character, label, prec, latex=False, **kwds):
    emf_logger.debug(
        "get_qexp for: level={0},weight={1},character={2},label={3}".format(level, weight, character, label))
    #latex = my_get(request.args, "latex", False, bool)
    emf_logger.debug(
        "get_qexp latex: {0}, prec: {1}".format(latex, prec))
    #if not arg:
    #    return flask.abort(404)
    try:
        M = WebModFormSpace_cached(level=level,weight=weight,character=character)
        WNF = M.hecke_orbits[label]
        WNF.prec = prec
        if not latex:
            c = WNF.q_expansion
        else:
            c = WNF.q_expansion_latex(prec=prec, name = 'a')
        return c
    except Exception as e:
        return "<span style='color:red;'>ERROR: %s</span>" % e.message
def set_info_for_modular_form_space(level=None, weight=None, character=None, label=None, **kwds):
    r"""
      Set information about a space of modular forms.
    """
    info = dict()
    emf_logger.debug("info={0}".format(info))    
    WMFS = None
    if info.has_key('error'):
        return info
    if level <= 0:
        info['error'] = "Got wrong level: %s " % level
        return info
    try:
        WMFS = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = character, update_from_db=True)
        WMFS.update_from_db() ## Need to call an extra time for some reason...
        if not WMFS.has_updated():
            stop = False
            orbit = WMFS.character.character.galois_orbit()
            while not stop:
                if len(orbit) == 0:
                    stop = True
                    continue
                c = orbit.pop()
                if c.number() == WMFS.character.number:
                    continue
                print c.number()
                WMFS_rep = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = c.number(), update_from_db=True)
                if WMFS_rep.has_updated_from_db():
                    stop = True
                    info['wmfs_rep_url'] = url_for('emf.render_elliptic_modular_forms', level=level, weight=weight, character = c.number())
                    info['wmfs_rep_number'] =  c.number()
                    
        emf_logger.debug("Created WebModFormSpace %s"%WMFS)
        if 'download' in info and 'tempfile' in info:
            save(WNF,info['tempfile'])
            info['filename'] = str(weight) + '-' + str(level) + '-' + str(character) + '-' + label + '.sobj'
            return info
    except ValueError as e:
        emf_logger.debug(e)
        emf_logger.debug(e.message)
        #if isinstance(e,IndexError):
        info['error'] = e.message
        WMFS = None
    if WMFS is None:
        info['error'] = "We are sorry. The sought space can not be found in the database. "+"<br> Detailed information: {0}".format(info.get('error',''))
        return info
    else:
        ### Somehow the Hecke orbits are sometimes not in the space...
        #if WMFS.dimension_new_cusp_forms()!=len(WMFS.hecke_orbits):
        #    ## Try to add them here... 
        #    for d in range(len(WMFS.dimension_new_cusp_forms())):
        #        F = 
        #        WMFS.hecke_orbits.append(F)
        info['space'] = WMFS
#    info['old_decomposition'] = WMFS.oldspace_decomposition()
    info['oldspace_decomposition']=''
    try: 
        emf_logger.debug("Oldspace = {0}".format(WMFS.oldspace_decomposition))
        if WMFS.oldspace_decomposition != []:
            emf_logger.debug("oldspace={0}".format(WMFS.oldspace_decomposition))
            l = []
            for t in WMFS.oldspace_decomposition:
                emf_logger.debug("t={0}".format(t))
                N,k,chi,mult,d = t
                url = url_for('emf.render_elliptic_modular_forms', level=N, weight=k, character=chi)
                if chi != 1:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}),\\chi_{{ {N} }}({chi},\\cdot))".format(k=k,N=N,chi=chi)
                else:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}))".format(k=k,N=N)
                l.append("\href{{ {url} }}{{ {sname} }}^{{\oplus {mult} }}".format(sname=sname,mult=mult,url=url))
            if l != []:            
                s = "\\oplus ".join(l)
                info['oldspace_decomposition']=' $ {0} $'.format(s)
    except Exception as e:
        emf_logger.critical("Oldspace decomposition failed. Error:{0}".format(e))
    ## For side-bar
    lifts = list()
    lifts.append(('Half-Integral Weight Forms', '/ModularForm/Mp2/Q'))
    lifts.append(('Siegel Modular Forms', '/ModularForm/GSp4/Q'))
    info['lifts'] = lifts
    friends = list()
    for label in WMFS.hecke_orbits:
        f = WMFS.hecke_orbits[label]
        # catch the url being None or set to '':
        if hasattr(f.base_ring, "lmfdb_url") and f.base_ring.lmfdb_url:
            friends.append(('Number field ' + f.base_ring.lmfdb_pretty, f.base_ring.lmfdb_url))
        if hasattr(f.coefficient_field, "lmfdb_url") and f.coefficient_field.lmfdb_url:
            friends.append(('Number field ' + f.coefficient_field.lmfdb_pretty, f.coefficient_field.lmfdb_url))
    friends.append(("Dirichlet character \(" + WMFS.character.latex_name + "\)", WMFS.character.url()))
    friends = uniq(friends)
    info['friends'] = friends
    
    return info
Exemplo n.º 5
0
def set_info_for_modular_form_space(level=None, weight=None, character=None, label=None, **kwds):
    r"""
      Set information about a space of modular forms.
    """
    info = dict()
    emf_logger.debug("info={0}".format(info))    
    WMFS = None
    if info.has_key('error'):
        return info
    if level <= 0:
        info['error'] = "Got wrong level: %s " % level
        return info
    try:
        WMFS = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = character, update_from_db=True)
        emf_logger.debug("Created WebModFormSpace %s"%WMFS)
        if not WMFS.has_updated():
            #get the representative we have in the db for this space (Galois conjugate)
            #note that this does not use the web_object infrastructure at all right now
            #which should be changed for sure!
            dimension_table_name = WebModFormSpace._dimension_table_name
            db_dim = getDBConnection()['modularforms2'][dimension_table_name]
            rep = db_dim.find_one({'level': level, 'weight': weight, 'character_orbit': {'$in': [character]}})
            if not rep is None and not rep['cchi'] == character: # don't link back to myself!
                info['wmfs_rep_url'] = url_for('emf.render_elliptic_modular_forms', level=level, weight=weight, character=rep['cchi'])
                info['wmfs_rep_number'] =  rep['cchi']
        # FIXME: the variable WNF is not defined above, so the code below cannot work (I don't think it is ever used)
        # if 'download' in info and 'tempfile' in info:
        #     save(WNF,info['tempfile'])
        #     info['filename'] = str(weight) + '-' + str(level) + '-' + str(character) + '-' + label + '.sobj'
        #     return info
    except ValueError as e:
        emf_logger.debug(e)
        emf_logger.debug(e.message)
        #if isinstance(e,IndexError):
        info['error'] = e.message
        WMFS = None
    if WMFS is None:
        info['error'] = "We are sorry. The sought space can not be found in the database. "+"<br> Detailed information: {0}".format(info.get('error',''))
        return info
    else:
        ### Somehow the Hecke orbits are sometimes not in the space...
        #if WMFS.dimension_new_cusp_forms()!=len(WMFS.hecke_orbits):
        #    ## Try to add them here... 
        #    for d in range(len(WMFS.dimension_new_cusp_forms())):
        #        F = 
        #        WMFS.hecke_orbits.append(F)
        info['space'] = WMFS
        info['max_height'] = default_max_height
#    info['old_decomposition'] = WMFS.oldspace_decomposition()
    info['oldspace_decomposition']=''
    try: 
        emf_logger.debug("Oldspace = {0}".format(WMFS.oldspace_decomposition))
        if WMFS.oldspace_decomposition != []:
            emf_logger.debug("oldspace={0}".format(WMFS.oldspace_decomposition))
            l = []
            for t in WMFS.oldspace_decomposition:
                emf_logger.debug("t={0}".format(t))
                N,k,chi,mult,d = t
                url = url_for('emf.render_elliptic_modular_forms', level=N, weight=k, character=chi)
                if chi != 1:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}),\\chi_{{ {N} }}({chi},\\cdot))".format(k=k,N=N,chi=chi)
                else:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}))".format(k=k,N=N)
                l.append("\href{{ {url} }}{{ {sname} }}^{{\oplus {mult} }}".format(sname=sname,mult=mult,url=url))
            if l != []:            
                s = "\\oplus ".join(l)
                info['oldspace_decomposition']=' $ {0} $'.format(s)
    except Exception as e:
        emf_logger.critical("Oldspace decomposition failed. Error:{0}".format(e))
    ## For side-bar
    lifts = list()
    lifts.append(('Half-Integral Weight Forms', '/ModularForm/Mp2/Q'))
    lifts.append(('Siegel Modular Forms', '/ModularForm/GSp4/Q'))
    info['lifts'] = lifts
    friends = list()
    for label in WMFS.hecke_orbits:
        f = WMFS.hecke_orbits[label]
        # catch the url being None or set to '':
        if hasattr(f.base_ring, "lmfdb_url") and f.base_ring.lmfdb_url:
            friends.append(('Number field ' + f.base_ring.lmfdb_pretty, f.base_ring.lmfdb_url))
        if hasattr(f.coefficient_field, "lmfdb_url") and f.coefficient_field.lmfdb_url:
            friends.append(('Number field ' + f.coefficient_field.lmfdb_pretty, f.coefficient_field.lmfdb_url))
    friends.append(("Dirichlet character \(" + WMFS.character.latex_name + "\)", WMFS.character.url()))
    friends = uniq(friends)
    info['friends'] = friends
    info['code'] = WMFS.code
    
    return info
Exemplo n.º 6
0
def set_info_for_modular_form_space(level=None, weight=None, character=None, label=None, **kwds):
    r"""
      Set information about a space of modular forms.
    """
    info = dict()
    emf_logger.debug("info={0}".format(info))    
    WMFS = None
    if info.has_key('error'):
        return info
    if level <= 0:
        info['error'] = "Got wrong level: %s " % level
        return info
    try:
        WMFS = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = character, update_from_db=True)
        emf_logger.debug("Created WebModFormSpace %s"%WMFS)
        if not WMFS.has_updated():
            #get the representative we have in the db for this space (Galois conjugate)
            #note that this does not use the web_object infrastructure at all right now
            #which should be changed for sure!
            dimension_table_name = WebModFormSpace._dimension_table_name
            db_dim = getDBConnection()['modularforms2'][dimension_table_name]
            rep = db_dim.find_one({'level': level, 'weight': weight, 'character_orbit': {'$in': [character]}})
            if not rep is None and not rep['cchi'] == character: # don't link back to myself!
                info['wmfs_rep_url'] = url_for('emf.render_elliptic_modular_forms', level=level, weight=weight, character=rep['cchi'])
                info['wmfs_rep_number'] =  rep['cchi']
        # FIXME: the variable WNF is not defined above, so the code below cannot work (I don't think it is ever used)
        # if 'download' in info and 'tempfile' in info:
        #     save(WNF,info['tempfile'])
        #     info['filename'] = str(weight) + '-' + str(level) + '-' + str(character) + '-' + label + '.sobj'
        #     return info
    except ValueError as e:
        emf_logger.debug(e)
        emf_logger.debug(e.message)
        #if isinstance(e,IndexError):
        info['error'] = e.message
        WMFS = None
    if WMFS is None:
        info['error'] = "We are sorry. The sought space can not be found in the database. "+"<br> Detailed information: {0}".format(info.get('error',''))
        return info
    else:
        ### Somehow the Hecke orbits are sometimes not in the space...
        #if WMFS.dimension_new_cusp_forms()!=len(WMFS.hecke_orbits):
        #    ## Try to add them here... 
        #    for d in range(len(WMFS.dimension_new_cusp_forms())):
        #        F = 
        #        WMFS.hecke_orbits.append(F)
        info['space'] = WMFS
        info['max_height'] = default_max_height
#    info['old_decomposition'] = WMFS.oldspace_decomposition()
    info['oldspace_decomposition']=''
    try: 
        emf_logger.debug("Oldspace = {0}".format(WMFS.oldspace_decomposition))
        if WMFS.oldspace_decomposition != []:
            emf_logger.debug("oldspace={0}".format(WMFS.oldspace_decomposition))
            l = []
            for t in WMFS.oldspace_decomposition:
                emf_logger.debug("t={0}".format(t))
                N,k,chi,mult,d = t
                url = url_for('emf.render_elliptic_modular_forms', level=N, weight=k, character=chi)
                if chi != 1:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}),\\chi_{{ {N} }}({chi},\\cdot))".format(k=k,N=N,chi=chi)
                else:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}))".format(k=k,N=N)
                l.append("\href{{ {url} }}{{ {sname} }}^{{\oplus {mult} }}".format(sname=sname,mult=mult,url=url))
            if l != []:            
                s = "\\oplus ".join(l)
                info['oldspace_decomposition']=' $ {0} $'.format(s)
    except Exception as e:
        emf_logger.critical("Oldspace decomposition failed. Error:{0}".format(e))
    ## For side-bar
    lifts = list()
    lifts.append(('Half-Integral Weight Forms', '/ModularForm/Mp2/Q'))
    lifts.append(('Siegel Modular Forms', '/ModularForm/GSp4/Q'))
    info['lifts'] = lifts
    friends = list()
    for label in WMFS.hecke_orbits:
        f = WMFS.hecke_orbits[label]
        # catch the url being None or set to '':
        if hasattr(f.base_ring, "lmfdb_url") and f.base_ring.lmfdb_url:
            friends.append(('Number field ' + f.base_ring.lmfdb_pretty, f.base_ring.lmfdb_url))
        if hasattr(f.coefficient_field, "lmfdb_url") and f.coefficient_field.lmfdb_url:
            friends.append(('Number field ' + f.coefficient_field.lmfdb_pretty, f.coefficient_field.lmfdb_url))
    friends.append(("Dirichlet character \(" + WMFS.character.latex_name + "\)", WMFS.character.url()))
    friends = uniq(friends)
    info['friends'] = friends
    info['code'] = WMFS.code
    
    return info
Exemplo n.º 7
0
def set_info_for_modular_form_space(level=None, weight=None, character=None, label=None, **kwds):
    r"""
      Set information about a space of modular forms.
    """
    info = dict()
    emf_logger.debug("info={0}".format(info))    
    WMFS = None
    if info.has_key('error'):
        return info
    if level <= 0:
        info['error'] = "Got wrong level: %s " % level
        return info
    try:
        WMFS = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = character, update_from_db=True)
        if not WMFS.has_updated():
            WMFS.update_from_db() ## Need to call an extra time for some reason...
        if not WMFS.has_updated():
            stop = False
            orbit = WMFS.character.character.galois_orbit()
            while not stop:
                if len(orbit) == 0:
                    stop = True
                    continue
                c = orbit.pop()
                if c.number() == WMFS.character.number:
                    continue
                print c.number()
                WMFS_rep = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = c.number(), update_from_db=True)
                if WMFS_rep.has_updated_from_db():
                    stop = True
                    info['wmfs_rep_url'] = url_for('emf.render_elliptic_modular_forms', level=level, weight=weight, character = c.number())
                    info['wmfs_rep_number'] =  c.number()
                    
        emf_logger.debug("Created WebModFormSpace %s"%WMFS)
        if 'download' in info and 'tempfile' in info:
            save(WNF,info['tempfile'])
            info['filename'] = str(weight) + '-' + str(level) + '-' + str(character) + '-' + label + '.sobj'
            return info
    except ValueError as e:
        emf_logger.debug(e)
        emf_logger.debug(e.message)
        #if isinstance(e,IndexError):
        info['error'] = e.message
        WMFS = None
    if WMFS is None:
        info['error'] = "We are sorry. The sought space can not be found in the database. "+"<br> Detailed information: {0}".format(info.get('error',''))
        return info
    else:
        ### Somehow the Hecke orbits are sometimes not in the space...
        #if WMFS.dimension_new_cusp_forms()!=len(WMFS.hecke_orbits):
        #    ## Try to add them here... 
        #    for d in range(len(WMFS.dimension_new_cusp_forms())):
        #        F = 
        #        WMFS.hecke_orbits.append(F)
        info['space'] = WMFS
        info['max_height'] = default_max_height
#    info['old_decomposition'] = WMFS.oldspace_decomposition()
    info['oldspace_decomposition']=''
    try: 
        emf_logger.debug("Oldspace = {0}".format(WMFS.oldspace_decomposition))
        if WMFS.oldspace_decomposition != []:
            emf_logger.debug("oldspace={0}".format(WMFS.oldspace_decomposition))
            l = []
            for t in WMFS.oldspace_decomposition:
                emf_logger.debug("t={0}".format(t))
                N,k,chi,mult,d = t
                url = url_for('emf.render_elliptic_modular_forms', level=N, weight=k, character=chi)
                if chi != 1:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}),\\chi_{{ {N} }}({chi},\\cdot))".format(k=k,N=N,chi=chi)
                else:
                    sname = "S^{{ new }}_{{ {k} }}(\\Gamma_0({N}))".format(k=k,N=N)
                l.append("\href{{ {url} }}{{ {sname} }}^{{\oplus {mult} }}".format(sname=sname,mult=mult,url=url))
            if l != []:            
                s = "\\oplus ".join(l)
                info['oldspace_decomposition']=' $ {0} $'.format(s)
    except Exception as e:
        emf_logger.critical("Oldspace decomposition failed. Error:{0}".format(e))
    ## For side-bar
    lifts = list()
    lifts.append(('Half-Integral Weight Forms', '/ModularForm/Mp2/Q'))
    lifts.append(('Siegel Modular Forms', '/ModularForm/GSp4/Q'))
    info['lifts'] = lifts
    friends = list()
    for label in WMFS.hecke_orbits:
        f = WMFS.hecke_orbits[label]
        # catch the url being None or set to '':
        if hasattr(f.base_ring, "lmfdb_url") and f.base_ring.lmfdb_url:
            friends.append(('Number field ' + f.base_ring.lmfdb_pretty, f.base_ring.lmfdb_url))
        if hasattr(f.coefficient_field, "lmfdb_url") and f.coefficient_field.lmfdb_url:
            friends.append(('Number field ' + f.coefficient_field.lmfdb_pretty, f.coefficient_field.lmfdb_url))
    friends.append(("Dirichlet character \(" + WMFS.character.latex_name + "\)", WMFS.character.url()))
    friends = uniq(friends)
    info['friends'] = friends
    
    return info
Exemplo n.º 8
0
def set_info_for_modular_form_space(level=None, weight=None, character=None, label=None, **kwds):
    r"""
      Set information about a space of modular forms.
    """
    info = dict()
    emf_logger.debug("info={0}".format(info))    
    WMFS = None
    if info.has_key('error'):
        return info
    if level <= 0:
        info['error'] = "Got wrong level: %s " % level
        return info
    try:
        WMFS = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = character, update_from_db=True)
        if not WMFS.has_updated():
            stop = False
            orbit = WMFS.character.character.galois_orbit()
            while not stop:
                if len(orbit) == 0:
                    stop = True
                    continue
                c = orbit.pop()
                if c.number() == WMFS.character.number:
                    continue
                print c.number()
                WMFS_rep = WebModFormSpace_cached(level = level, weight = weight, cuspidal=True, character = c.number(), update_from_db=True)
                if WMFS_rep.has_updated_from_db():
                    stop = True
                    info['wmfs_rep_url'] = url_for('emf.render_elliptic_modular_forms', level=level, weight=weight, character = c.number())
                    info['wmfs_rep_number'] =  c.number()
                    
        emf_logger.debug("Created WebModFormSpace %s"%WMFS)
        if 'download' in info and 'tempfile' in info:
            save(WNF,info['tempfile'])
            info['filename'] = str(weight) + '-' + str(level) + '-' + str(character) + '-' + label + '.sobj'
            return info
    except ValueError as e:
        emf_logger.debug(e)
        emf_logger.debug(e.message)
        #if isinstance(e,IndexError):
        info['error'] = e.message
        WMFS = None
    if WMFS is None:
        info['error'] = "We are sorry. The sought space can not be found in the database. "+"<br> Detailed information: {0}".format(info.get('error',''))
        return info
    else:
        ### Somehow the Hecke orbits are sometimes not in the space...
        #if WMFS.dimension_new_cusp_forms()!=len(WMFS.hecke_orbits):
        #    ## Try to add them here... 
        #    for d in range(len(WMFS.dimension_new_cusp_forms())):
        #        F = 
        #        WMFS.hecke_orbits.append(F)
        info['space'] = WMFS
#    info['old_decomposition'] = WMFS.oldspace_decomposition()

    ## For side-bar
    lifts = list()
    lifts.append(('Half-Integral Weight Forms', '/ModularForm/Mp2/Q'))
    lifts.append(('Siegel Modular Forms', '/ModularForm/GSp4/Q'))
    info['lifts'] = lifts
    friends = list()
    for label in WMFS.hecke_orbits:
        f = WMFS.hecke_orbits[label]
        # catch the url being None or set to '':
        if hasattr(f.base_ring, "lmfdb_url") and f.base_ring.lmfdb_url:
            friends.append(('Number field ' + f.base_ring.lmfdb_pretty, f.base_ring.lmfdb_url))
        if hasattr(f.coefficient_field, "lmfdb_url") and f.coefficient_field.lmfdb_url:
            friends.append(('Number field ' + f.coefficient_field.lmfdb_pretty, f.coefficient_field.lmfdb_url))
    friends.append(("Dirichlet character \(" + WMFS.character.latex_name + "\)", WMFS.character.url()))
    friends = uniq(friends)
    info['friends'] = friends
    
    return info