Repository: LMFDB/lmfdb

Issue:
Genus 2 curve missing HMF friend
The genus 2 curve L-function

http://www.lmfdb.org/L/Genus2Curve/Q/3125/a/

and the HMF L-function

http://www.lmfdb.org/L/ModularForm/GL2/TotallyReal/2.2.5.1/holomorphic/2.2.5.1-125.1-a/0/0/ 

are the same, but the genus 2 curve and the HMF do not know they are friends.

We should fix this and search for any other missing HMF or BMF friends of genus 2 curves.



Discussion:
As we discussed at IAS, I think the time to be systematic is when we're finishing up our many author paper.  If I were to do this, I would go over each row of the giant table and make sure all matches are there--but it will be more efficient if we do this while writing, especially if any mathematical issues come up.  

It would be more reliable if there was a source-independent way (e.g., hash) on the L-functions in the database--or perhaps equivalently the relevant CMFs, HMFs, and BMFs--and these friends were generated automatically.  Then the humans could check the computations and hopefully we agree.  

I'm not sure this is worth holding up v1.1: the links to CMFs seem to be there, we never promised that all friends will be there, and there's no way we will forget to do this.  
I agree this is not worth holding up v1.1, but I believe we already have enough data to completely automate this (which I agree is absolutely necessary).  I'll take a stab at this today.  I don't think it will be hard to generate a list of potential friends that is provably complete, and I think this will be a short list (tens not hundreds).
There is a related and perhaps more pressing issue.  The genus 2 curve

http://www.lmfdb.org/Genus2Curve/Q/12500/a/12500/1

knows its HMF friend, and the L-function lists both the genus 2 curve and the HMF as related objects

http://www.lmfdb.org/L/Genus2Curve/Q/12500/a/

because both are listed in lfunc_instances.  But If you click the HMF link on the L-function page, and then click the L-function link on the HMF page, you return to a different version of the same L-function

http://www.lmfdb.org/L/ModularForm/GL2/TotallyReal/2.2.5.1/holomorphic/2.2.5.1-500.1-a/0/0/

which no longer knows that it is the L-function of a genus 2 curve.  So you can navigate  genus 2 curve -> L-function -> HMF -> L-function but then cannot get back to the genus 2 curve you started with, and along the way you see the same L-function presented in two different ways (one has no arithmetic normalization or Euler factors available, and the Z-plots are scaled differently).  This is surely not the "Langlands experience" we are looking for :)

There is an easy fix: the L-function display code should check its instances table when given an HMF URL, just as it does for genus 2 curves and CMFS,  and only compute the L-function on the fly when it doesn't find a record.  I will submit a PR that does this and also has the HMF display code check lfunc_instances for genus 2 friends (which is how genus 2 curves find their HMF friends, there is nothing in the genus 2 tables that makes this happen, and I can copy the code to do this from the genus 2 code).

Once this has been done, addressing the initial problem mentioned in this issue is simply a matter of adding more HMF records to the lfunc_instances table, which we can do as and when we wish.

The problem with 
- http://www.lmfdb.org/L/Genus2Curve/Q/3125/a/ and
- http://www.lmfdb.org/L/ModularForm/GL2/TotallyReal/2.2.5.1/holomorphic/2.2.5.1-125.1-a/0/0/
Is that the L-fun for the G2C is served from the DB, while the HMF is computed on the fly.
To make them show in both sides we would need to add the corresponding instance for the HMF for both **embeddings**, as the G2C matches either L-function of an embedding, but not the orbit. However, before doing this we should perhaps discuss labels for HMF embedded forms, so they match CMFs.

I will address the other issues in an upcoming PR


Resolving patch:
diff --git a/lmfdb/genus2_curves/web_g2c.py b/lmfdb/genus2_curves/web_g2c.py
--- a/lmfdb/genus2_curves/web_g2c.py
+++ b/lmfdb/genus2_curves/web_g2c.py
@@ -3,7 +3,8 @@
 from ast import literal_eval
 from lmfdb import db
 from lmfdb.utils import web_latex, encode_plot, list_to_factored_poly_otherorder
-from lmfdb.ecnf.main import split_full_label
+from lmfdb.ecnf.main import split_full_label as split_ecnf_label
+from lmfdb.ecnf.WebEllipticCurve import convert_IQF_label
 from lmfdb.elliptic_curves.web_ec import split_lmfdb_label
 from lmfdb.number_fields.number_field import field_pretty
 from lmfdb.number_fields.web_number_field import nf_display_knowl
@@ -39,12 +40,9 @@ def url_for_ec(label):
     if not '-' in label:
         return url_for('ec.by_ec_label', label = label)
     else:
-        (nf, conductor_label, class_label, number) = split_full_label(label)
-        url = url_for('ecnf.show_ecnf', nf = nf, conductor_label = conductor_label, class_label = class_label, number = number)
-        # fixup conductor norm labels for the form "[a,b,c]" that have been converted to urls to ensure friend matching works
-        url.replace("%5B","[")
-        url.replace("%2C",".")
-        url.replace("%5D","]")
+        (nf, cond, isog, num) = split_ecnf_label(label)
+        cond = convert_IQF_label(nf,cond)
+        url = url_for('ecnf.show_ecnf', nf = nf, conductor_label = cond, class_label = isog, number = num)
         return url
 
 def url_for_ec_class(ec_label):
@@ -52,8 +50,9 @@ def url_for_ec_class(ec_label):
         (cond, iso, num) = split_lmfdb_label(ec_label)
         return url_for('ec.by_double_iso_label', conductor=cond, iso_label=iso)
     else:
-        (nf, cond, iso, num) = split_full_label(ec_label)
-        return url_for('ecnf.show_ecnf_isoclass', nf=nf, conductor_label=cond, class_label=iso)
+        (nf, cond, isog, num) = split_ecnf_label(ec_label)
+        cond = convert_IQF_label(nf,cond)
+        return url_for('ecnf.show_ecnf_isoclass', nf=nf, conductor_label=cond, class_label=isog)
 
 def ec_label_class(ec_label):
     x = ec_label
@@ -228,8 +227,8 @@ def st0_group_name(name):
 
 def gl2_statement_base(factorsRR, base):
     if factorsRR in [ ['RR', 'RR'], ['CC'] ]:
-        return "of \(\GL_2\)-type over " + base
-    return "not of \(\GL_2\)-type over " + base
+        return "Of \(\GL_2\)-type over " + base
+    return "Not of \(\GL_2\)-type over " + base
 
 def gl2_simple_statement(factorsQQ, factorsRR):
     if factorsRR in [ ['RR', 'RR'], ['CC'] ]:
@@ -418,11 +417,18 @@ def lfunction_friend_from_url(url):
         label = parts[2] + "." + parts[3]
         return ("EC isogeny class " + label, "/" + url)
     if parts[0] == "EllipticCurve":
-        label = parts[1] + "-" + parts[2] + "-" + parts[3]
+        cond = convert_IQF_label(parts[1],parts[2])
+        label = parts[1] + "-" + cond + "-" + parts[3]
         return ("EC isogeny class " + label, "/" + url)
     if parts[0] == "ModularForm" and parts[1] == "GL2" and parts[2] == "TotallyReal" and parts[4] == "holomorphic":
         label = parts[5]
         return ("Hilbert MF " + label, "/" + url)
+    if parts[0] == "ModularForm" and parts[1] == "GL2" and parts[2] == "ImaginaryQuadratic":
+        label = '.'.join(parts[4:6])
+        return ("Bianchi MF " + label, "/" + url)
+    if parts[0] == "ModularForm" and parts[1] == "GL2" and parts[2] == "Q" and parts[3] == "holomorphic":
+        label = '.'.join(parts[4:8])
+        return ("Modular form " + label, "/" + url)
     return (url, "/" + url)
 
 # add new friend to list of friends, but only if really new (don't add an elliptic curve and its isogeny class)
@@ -664,6 +670,14 @@ def make_object(self, curve, endo, tama, ratpts, is_curve):
                     add_friend (friends, lfunction_friend_from_url(url))
             else:
                 add_friend (friends, lfunction_friend_from_url(friend_url))
+        # Hack to deal with the fact that currently the same L-function can appear more than once in db.lfunc_lfunctions and we want to friend instances of all of them
+        for Lhash in db.lfunc_lfunctions.search({"trace_hash":data["Lhash"]},"Lhash"):
+            for friend_url in db.lfunc_instances.search({'Lhash':Lhash}, 'url'):
+                if '|' in friend_url:
+                    for url in friend_url.split('|'):
+                        add_friend (friends, lfunction_friend_from_url(url))
+                else:
+                    add_friend (friends, lfunction_friend_from_url(friend_url))           
         for cmf_friend in db.mf_newforms.search({'trace_hash':data['Lhash']},["label","dim","level"]):
             # be selective, only cmfs of the right dimension and conductor get to be our friends
             if cmf_friend["dim"] == 2 and cmf_friend["level"]**2 == data['cond']:


Test patch:
diff --git a/lmfdb/genus2_curves/test_genus2_curves.py b/lmfdb/genus2_curves/test_genus2_curves.py
--- a/lmfdb/genus2_curves/test_genus2_curves.py
+++ b/lmfdb/genus2_curves/test_genus2_curves.py
@@ -169,3 +169,37 @@ def test_endo_search(self):
                 ('M_2(CM)', '2916.b.11664.1')]:
             L = self.tc.get('/Genus2Curve/Q/?geom_end_alg={}'.format(endo))
             assert text in L.data
+
+    def test_related_objects(self):
+        for url, friends in [
+                ('/Genus2Curve/Q/20736/i/373248/1',
+                    ('L-function',
+                        'Isogeny class 20736.i',
+                        'Elliptic curve 576.f3',
+                        'Elliptic curve 36.a4',
+                        'EC isogeny class 2.0.8.1-324.3-a',
+                        'Bianchi MF 324.3.a',
+                        'Hilbert MF 2.2.24.1-36.1-a',
+                        'EC isogeny class 2.2.24.1-36.1-a',
+                        'Twists',)
+                    ),
+                ('/Genus2Curve/Q/20736/i/',
+                    ('L-function',
+                        'EC isogeny class 576.f',
+                        'EC isogeny class 36.a',
+                        'EC isogeny class 2.0.8.1-324.3-a',
+                        'Bianchi MF 324.3.a',
+                        'Hilbert MF 2.2.24.1-36.1-a',
+                        'EC isogeny class 2.2.24.1-36.1-a',)
+                    ),
+                ('/Genus2Curve/Q/576/a/',
+                    ('L-function',
+                        'EC isogeny class 2.2.8.1-9.1-a',
+                        'Modular form 24.2.d.a',
+                        'Hilbert MF 2.2.8.1-9.1-a',)
+                    )
+                ]:
+            data = self.tc.get(url).data
+            for friend in friends:
+                assert friend in data
+