Exemple #1
0
 def newton_plot(self):
     S = [QQ(s) for s in self.slopes]
     C = Counter(S)
     pts = [(0,0)]
     x = y = 0
     for s in sorted(C):
         c = C[s]
         x += c
         y += c*s
         pts.append((x,y))
     L = Graphics()
     L += line([(0,0),(0,y+0.2)],color="grey")
     for i in range(1,y+1):
         L += line([(0,i),(0.06,i)],color="grey")
     for i in range(1,C[0]):
         L += line([(i,0),(i,0.06)],color="grey")
     for i in range(len(pts)-1):
         P = pts[i]
         Q = pts[i+1]
         for x in range(P[0],Q[0]+1):
             L += line([(x,P[1]),(x,P[1] + (x-P[0])*(Q[1]-P[1])/(Q[0]-P[0]))],color="grey")
         for y in range(P[1],Q[1]):
             L += line([(P[0] + (y-P[1])*(Q[0]-P[0])/(Q[1]-P[1]),y),(Q[0],y)],color="grey")
     L += line(pts, thickness = 2)
     L.axes(False)
     L.set_aspect_ratio(1)
     return encode_plot(L, pad=0, pad_inches=0, bbox_inches='tight')
Exemple #2
0
 def newton_plot(self):
     S = [QQ(s) for s in self.polygon_slopes]
     C = Counter(S)
     pts = [(0, 0)]
     x = y = 0
     for s in sorted(C):
         c = C[s]
         x += c
         y += c * s
         pts.append((x, y))
     L = Graphics()
     L += line([(0, 0), (0, y + 0.2)], color="grey")
     for i in range(1, y + 1):
         L += line([(0, i), (0.06, i)], color="grey")
     for i in range(1, C[0]):
         L += line([(i, 0), (i, 0.06)], color="grey")
     for i in range(len(pts) - 1):
         P = pts[i]
         Q = pts[i + 1]
         for x in range(P[0], Q[0] + 1):
             L += line(
                 [(x, P[1]),
                  (x, P[1] + (x - P[0]) * (Q[1] - P[1]) / (Q[0] - P[0]))],
                 color="grey",
             )
         for y in range(P[1], Q[1]):
             L += line(
                 [(P[0] + (y - P[1]) * (Q[0] - P[0]) / (Q[1] - P[1]), y),
                  (Q[0], y)],
                 color="grey",
             )
     L += line(pts, thickness=2)
     L.axes(False)
     L.set_aspect_ratio(1)
     return encode_plot(L, pad=0, pad_inches=0, bbox_inches="tight")
Exemple #3
0
def mu_portrait(n):
    """ returns an encoded scatter plot of the nth roots of unity in the complex plane """
    if n <= 120:
        plot =  list_plot([(cos(2*pi*m/n),sin(2*pi*m/n)) for m in range(n)],pointsize=30+60/n, axes=False)
    else:
        plot = circle((0,0),1,thickness=3)
    plot.xmin(-1); plot.xmax(1); plot.ymin(-1); plot.ymax(1)
    plot.set_aspect_ratio(4.0/3.0)
    return encode_plot(plot)
Exemple #4
0
def mu_portrait(n):
    """ returns an encoded scatter plot of the nth roots of unity in the complex plane """
    if n <= 120:
        plot =  list_plot([(cos(2*pi*m/n),sin(2*pi*m/n)) for m in range(n)],pointsize=30+60/n, axes=False)
    else:
        plot = circle((0,0),1,thickness=3)
    plot.xmin(-1); plot.xmax(1); plot.ymin(-1); plot.ymax(1)
    plot.set_aspect_ratio(4.0/3.0)
    return encode_plot(plot)
Exemple #5
0
def nu1_mu_portrait(n):
    """ returns an encoded scatter plot of the nth roots of unity in the complex plane """
    if n == 1:
        return db.gps_sato_tate.lookup('1.2.1.2.1a').get('trace_histogram')
    if n <= 120:
        plot =  sum([line2d([(-2*cos(2*pi*m/n),-2*sin(2*pi*m/n)),(2*cos(2*pi*m/n),2*sin(2*pi*m/n))],thickness=3) for m in range(n)]) + circle((0,0),0.1,rgbcolor=(0,0,0),fill=True)
    else:
        plot = circle((0,0),2,fill=True)
    plot.xmin(-2); plot.xmax(2); plot.ymin(-2); plot.ymax(2)
    plot.set_aspect_ratio(4.0/3.0)
    plot.axes(False)
    return encode_plot(plot)
Exemple #6
0
def nu1_mu_portrait(n):
    """ returns an encoded scatter plot of the nth roots of unity in the complex plane """
    if n == 1:
        return db.gps_st.lookup('1.2.B.2.1a').get('trace_histogram')
    if n <= 120:
        plot =  sum([line2d([(-2*cos(2*pi*m/n),-2*sin(2*pi*m/n)),(2*cos(2*pi*m/n),2*sin(2*pi*m/n))],thickness=3) for m in range(n)]) + circle((0,0),0.1,rgbcolor=(0,0,0),fill=True)
    else:
        plot = circle((0,0),2,fill=True)
    plot.xmin(-2); plot.xmax(2); plot.ymin(-2); plot.ymax(2)
    plot.set_aspect_ratio(4.0/3.0)
    plot.axes(False)
    return encode_plot(plot)
Exemple #7
0
def su2_mu_portrait(n):
    """ returns an encoded line plot of SU(2) x mu(n) in the complex plane """
    if n == 1:
        return db.gps_st.lookup('1.2.A.1.1a').get('trace_histogram')
    if n <= 120:
        plot =  sum([line2d([(-2*cos(2*pi*m/n),-2*sin(2*pi*m/n)),(2*cos(2*pi*m/n),2*sin(2*pi*m/n))],thickness=3) for m in range(n)])
    else:
        plot = circle((0,0),2,fill=True)
    plot.xmin(-2); plot.xmax(2); plot.ymin(-2); plot.ymax(2)
    plot.set_aspect_ratio(4.0/3.0)
    plot.axes(False)
    return encode_plot(plot)
Exemple #8
0
def su2_mu_portrait(n):
    """ returns an encoded line plot of SU(2) x mu(n) in the complex plane """
    if n == 1:
        return db.gps_sato_tate.lookup('1.2.3.1.1a').get('trace_histogram')
    if n <= 120:
        plot =  sum([line2d([(-2*cos(2*pi*m/n),-2*sin(2*pi*m/n)),(2*cos(2*pi*m/n),2*sin(2*pi*m/n))],thickness=3) for m in range(n)])
    else:
        plot = circle((0,0),2,fill=True)
    plot.xmin(-2); plot.xmax(2); plot.ymin(-2); plot.ymax(2)
    plot.set_aspect_ratio(4.0/3.0)
    plot.axes(False)
    return encode_plot(plot)
Exemple #9
0
    def make_class(self):
        self.ECNF = ECNF.by_label(self.label)

        # Create a list of the curves in the class from the database
        self.db_curves = [ECNF(c) for c in db_ec().find(
            {'field_label' : self.field_label, 'conductor_label' :
             self.conductor_label, 'iso_label' : self.iso_label}).sort('number')]
        size = len(self.db_curves)

        # Extract the isogeny degree matrix from the database if possible, else create it
        if hasattr(self,'isogeny_matrix'):
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        else:
            self.isogeny_matrix = make_iso_matrix(self.db_curves)

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        self.curves = [[c.short_label, c.urls['curve'], c.latex_ainvs] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf = self.field_label, conductor_label=self.conductor_label, class_label = self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf = self.field_label, conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.ECNF.field_label)
        self.field = self.ECNF.field
        if self.field.is_real_quadratic():
            self.hmf_label = "-".join([self.field.label,self.conductor_label,self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field.label, label=self.hmf_label)

        if self.field.is_imag_quadratic():
            self.bmf_label = "-".join([self.field.label,self.conductor_label,self.iso_label])


        self.friends = []
        if self.field.is_real_quadratic():
            self.friends += [('Hilbert Modular Form '+self.hmf_label, self.urls['hmf'])]
        if self.field.is_imag_quadratic():
            self.friends += [('Bianchi Modular Form %s not yet available' % self.bmf_label, '')]

        self.properties = [('Label', self.ECNF.label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.ECNF.cond)
                           ]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.ECNF.field_label, self.urls['field']),
                      (self.ECNF.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.ECNF.short_label, self.urls['class'])]
Exemple #10
0
    def plot(self, typ="circle"):
        assert typ in ['circle', 'linear', 'constant']
        if typ == 'circle':
            G = circle_image(self.A, self.B)
        elif typ == 'linear':
            G = piecewise_linear_image(self.A, self.B)
        else:
            G = piecewise_constant_image(self.A, self.B)

        return encode_plot(G.plot(),
                           pad=0,
                           pad_inches=0,
                           bbox_inches='tight',
                           remove_axes=True)
Exemple #11
0
 def circle_plot(self):
     pts = []
     pi = RR.pi()
     for angle in self.angles:
         angle = RR(angle)*pi
         c = angle.cos()
         s = angle.sin()
         if abs(s) < 0.00000001:
             pts.append((c,s))
         else:
             pts.extend([(c,s),(c,-s)])
     P = points(pts,size=100) + circle((0,0),1,color='black')
     P.axes(False)
     P.set_aspect_ratio(1)
     return encode_plot(P)
Exemple #12
0
 def circle_plot(self):
     pts = []
     pi = RR.pi()
     for angle in self.angles:
         angle = RR(angle) * pi
         c = angle.cos()
         s = angle.sin()
         if abs(s) < 0.00000001:
             pts.append((c, s))
         else:
             pts.extend([(c, s), (c, -s)])
     P = points(pts, size=100) + circle((0, 0), 1, color='black')
     P.axes(False)
     P.set_aspect_ratio(1)
     return encode_plot(P)
Exemple #13
0
 def circle_plot(self):
     pts = []
     pi = RR.pi()
     for angle in self.angles:
         angle = RR(angle) * pi
         c = angle.cos()
         s = angle.sin()
         if abs(s) < 0.00000001:
             pts.append((c, s))
         else:
             pts.extend([(c, s), (c, -s)])
     P = circle((0, 0), 1, color="black", thickness=2.5)
     P[0].set_zorder(-1)
     P += points(pts, size=300, rgbcolor="darkblue")
     P.axes(False)
     P.set_aspect_ratio(1)
     return encode_plot(P, pad=0, pad_inches=None, transparent=True, axes_pad=0.04)
Exemple #14
0
    def make_class(self):

        # Create a list of the curves in the class from the database
        self.db_curves = list(db.ec_nfcurves.search(
            {'field_label': self.field_label,
             'conductor_norm': self.conductor_norm,
             'conductor_label': self.conductor_label,
             'iso_nlabel': self.iso_nlabel}))

        # Rank or bounds
        try:
            self.rk = web_latex(self.db_curves[0]['rank'])
        except KeyError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds'])
        except KeyError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not recorded"


        # Extract the isogeny degree matrix from the database
        if not hasattr(self, 'isogeny_matrix'):
            # this would happen if the class is initiated with a curve
            # which is not #1 in its class:
            self.isogeny_matrix = self.db_curves[0].isogeny_matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.one_deg = ZZ(self.class_deg).is_prime()

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(Matrix(self.isogeny_matrix))

        self.field = FIELD(self.field_label)
        self.field_name = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label, self.field_name)
        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[c['short_label'], curve_url(c), web_ainvs(self.field_label,c['ainvs'])] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=self.conductor_label, class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0,1]
        if totally_real:
            self.hmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field_label, label=self.hmf_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if sig[0] <= 2 and db.lfunc_instances.exists({'url': origin_url}):
                self.urls['Lfunction'] = lfun_url
            elif self.abs_disc ** 2 * self.conductor_norm < 40000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0')

        if imag_quadratic:
            self.bmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage', field_label=self.field_label, level_label=self.conductor_label, label_suffix=self.iso_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if db.lfunc_instances.exists({'url':origin_url}):
                self.urls['Lfunction'] = lfun_url

        # most of this code is repeated in WebEllipticCurve.py
        # and should be refactored
        self.friends = []
        if totally_real and 'Lfunction' not in self.urls:
            self.friends += [('Hilbert modular form ' + self.hmf_label, self.urls['hmf'])]

        if imag_quadratic:
            if "CM" in self.label:
                self.friends += [('Bianchi modular form is not cuspidal', '')]
            elif 'Lfunction' not in self.urls:
                if db.bmf_forms.label_exists(self.bmf_label):
                    self.friends += [('Bianchi modular form %s' % self.bmf_label, self.bmf_url)]
                else:
                    self.friends += [('(Bianchi modular form %s)' % self.bmf_label, '')]

        if 'Lfunction' in self.urls:
            Lfun = get_lfunction_by_url(self.urls['Lfunction'].lstrip('/L').rstrip('/'), projection=['degree', 'trace_hash', 'Lhash'])
            instances = get_instances_by_Lhash_and_trace_hash(
                    Lfun['Lhash'],
                    Lfun['degree'],
                    Lfun.get('trace_hash'))
            exclude={elt[1].rstrip('/').lstrip('/') for elt in self.friends
                     if elt[1]}
            exclude.add(lfun_url.lstrip('/L/').rstrip('/'))
            self.friends += names_and_urls(instances, exclude=exclude)
            self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]


        self.properties = [('Base field', self.field_name),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)
                       ]
        if self.rk != '?':
            self.properties += [('Rank', '%s' % self.rk)]
        else:
            if self.rk_bnds == 'not recorded':
                self.properties += [('Rank', '%s' % self.rk_bnds)]
            else:
                self.properties += [('Rank bounds', '%s' % self.rk_bnds)]

        self.bread = [('Elliptic curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label, self.urls['class'])]
Exemple #15
0
    def make_E(self):
        K = self.field.K()

        # a-invariants
        self.ainvs = parse_ainvs(K,self.ainvs)
        self.latex_ainvs = web_latex(self.ainvs)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = ideal_from_string(K,self.conductor_ideal)
        self.cond = web_latex(N)
        self.cond_norm = web_latex(self.conductor_norm)
        local_data = self.local_data

        # NB badprimes is a list of primes which divide the
        # discriminant of this model.  At most one of these might
        # actually be a prime of good reduction, if the curve has no
        # global minimal model.
        badprimes = [ideal_from_string(K,ld['p']) for ld in local_data]
        badnorms = [ZZ(ld['normp']) for ld in local_data]
        mindisc_ords = [ld['ord_disc'] for ld in local_data]

        # Assumption: the curve models stored in the database are
        # either global minimal models or minimal at all but one
        # prime, so the list here has length 0 or 1:

        self.non_min_primes = [ideal_from_string(K,P) for P in self.non_min_p]
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = self.is_minimal
        disc_ords = [ld['ord_disc'] for ld in local_data]
        if not self.is_minimal:
            Pmin = self.non_min_primes[0]
            P_index = badprimes.index(Pmin)
            self.non_min_prime = web_latex(Pmin)
            disc_ords[P_index] += 12

        if self.conductor_norm == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
            self.fact_cond_norm = self.cond
        else:
            Nfac = Factorization([(P,ld['ord_cond']) for P,ld in zip(badprimes,local_data)])
            self.fact_cond = web_latex_ideal_fact(Nfac)
            Nnormfac = Factorization([(q,ld['ord_cond']) for q,ld in zip(badnorms,local_data)])
            self.fact_cond_norm = web_latex(Nnormfac)

        # D is the discriminant ideal of the model
        D = prod([P**e for P,e in zip(badprimes,disc_ords)], K.ideal(1))
        self.disc = web_latex(D)
        Dnorm = D.norm()
        self.disc_norm = web_latex(Dnorm)
        if Dnorm == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
            self.fact_disc_norm = self.disc
        else:
            Dfac = Factorization([(P,e) for P,e in zip(badprimes,disc_ords)])
            self.fact_disc = web_latex_ideal_fact(Dfac)
            Dnormfac = Factorization([(q,e) for q,e in zip(badnorms,disc_ords)])
            self.fact_disc_norm = web_latex(Dnormfac)


        if not self.is_minimal:
            Dmin = ideal_from_string(K,self.minD)
            self.mindisc = web_latex(Dmin)
            Dmin_norm = Dmin.norm()
            self.mindisc_norm = web_latex(Dmin_norm)
            if Dmin_norm == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
                self.fact_mindisc_norm = self.mindisc
            else:
                Dminfac = Factorization([(P,e) for P,edd in zip(badprimes,mindisc_ords)])
                self.fact_mindisc = web_latex_ideal_fact(Dminfac)
                Dminnormfac = Factorization([(q,e) for q,e in zip(badnorms,mindisc_ords)])
                self.fact_mindisc_norm = web_latex(Dminnormfac)

        j = self.field.parse_NFelt(self.jinv)
        # if j:
        #     d = j.denominator()
        #     n = d * j  # numerator exists for quadratic fields only!
        #     g = GCD(list(n))
        #     n1 = n / g
        #     self.j = web_latex(n1)
        #     if d != 1:
        #         if n1 > 1:
        #         # self.j = "("+self.j+")\(/\)"+web_latex(d)
        #             self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
        #         else:
        #             self.j = web_latex(d)
        #         if g > 1:
        #             if n1 > 1:
        #                 self.j = web_latex(g) + self.j
        #             else:
        #                 self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        # See issue 1258: some j factorizations work but take too long
        # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1).  Note that we do
        # store the factorization of the denominator of j and display
        # that, which is the most interesting part.

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm
            # The line below will need to change once we have curves over non-quadratic fields
            # that contain the Hilbert class field of an imaginary quadratic field
            if self.signature == [0,1] and ZZ(-self.abs_disc*self.cm).is_square():
                self.ST = st_link_by_name(1,2,'U(1)')
            else:
                self.ST = st_link_by_name(1,2,'N(U(1))')
        else:
            self.ST = st_link_by_name(1,2,'SU(2)')

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure)

        torsion_gens = [parse_point(K,P) for P in self.torsion_gens]
        self.torsion_gens = ",".join([web_point(P) for P in torsion_gens])

        # Rank or bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.rank_bounds)
        except AttributeError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not available"

        # Generators
        try:
            gens = [parse_point(K,P) for P in self.gens]
            self.gens = ", ".join([web_point(P) for P in gens])
            if self.rk == "?":
                self.reg = "not available"
            else:
                if gens:
                    try:
                        self.reg = self.reg
                    except AttributeError:
                        self.reg = "not available"
                    pass # self.reg already set
                else:
                    self.reg = 1  # otherwise we only get 1.00000...

        except AttributeError:
            self.gens = "not available"
            self.reg = "not available"
            try:
                if self.rank == 0:
                    self.reg = 1
            except AttributeError:
                pass

        # Local data
        for P,ld in zip(badprimes,local_data):
            ld['p'] = web_latex(P)
            ld['norm'] = P.norm()
            ld['kod'] = web_latex(ld['kod']).replace('$', '')

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0,1]

        if totally_real:
            self.hmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field.label, label=self.hmf_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0')

        if imag_quadratic:
            self.bmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])]
        self.friends += [('Twists', url_for('ecnf.index', field=self.field_label, jinv=rename_j(j)))]
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])]
            self.friends += [('L-function', self.urls['Lfunction'])]
        if imag_quadratic:
            self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')]

        self.properties = [
            ('Base field', self.field.field_pretty()),
            ('Label', self.label)]

        # Plot
        if K.signature()[0]:
            self.plot = encode_plot(EC_nf_plot(K,self.ainvs, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden (can be very large)
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)]

        if self.base_change:
            self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))]

        self._code = None # will be set if needed by get_code()
Exemple #16
0
    def make_E(self):
        #print("Creating ECNF object for {}".format(self.label))
        #sys.stdout.flush()
        K = self.field.K()

        # a-invariants
        self.ainvs = parse_ainvs(K,self.ainvs)
        self.latex_ainvs = web_latex(self.ainvs)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        if self.conductor_norm==1:
            N = K.ideal(1)
        else:
            N = ideal_from_string(K,self.conductor_ideal)
        # The following can trigger expensive computations!
        #self.cond = web_latex(N)
        self.cond = pretty_ideal(N)
        self.cond_norm = web_latex(self.conductor_norm)
        local_data = self.local_data

        # NB badprimes is a list of primes which divide the
        # discriminant of this model.  At most one of these might
        # actually be a prime of good reduction, if the curve has no
        # global minimal model.
        badprimes = [ideal_from_string(K,ld['p']) for ld in local_data]
        badnorms = [ZZ(ld['normp']) for ld in local_data]
        mindisc_ords = [ld['ord_disc'] for ld in local_data]

        # Assumption: the curve models stored in the database are
        # either global minimal models or minimal at all but one
        # prime, so the list here has length 0 or 1:

        self.non_min_primes = [ideal_from_string(K,P) for P in self.non_min_p]
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = self.is_minimal
        disc_ords = [ld['ord_disc'] for ld in local_data]
        if not self.is_minimal:
            Pmin = self.non_min_primes[0]
            P_index = badprimes.index(Pmin)
            self.non_min_prime = pretty_ideal(Pmin)
            disc_ords[P_index] += 12

        if self.conductor_norm == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
            self.fact_cond_norm = '1'
        else:
            Nfac = Factorization([(P,ld['ord_cond']) for P,ld in zip(badprimes,local_data)])
            self.fact_cond = web_latex_ideal_fact(Nfac)
            Nnormfac = Factorization([(q,ld['ord_cond']) for q,ld in zip(badnorms,local_data)])
            self.fact_cond_norm = web_latex(Nnormfac)

        # D is the discriminant ideal of the model
        D = prod([P**e for P,e in zip(badprimes,disc_ords)], K.ideal(1))
        self.disc = pretty_ideal(D)
        Dnorm = D.norm()
        self.disc_norm = web_latex(Dnorm)
        if Dnorm == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
            self.fact_disc_norm = '1'
        else:
            Dfac = Factorization([(P,e) for P,e in zip(badprimes,disc_ords)])
            self.fact_disc = web_latex_ideal_fact(Dfac)
            Dnormfac = Factorization([(q,e) for q,e in zip(badnorms,disc_ords)])
            self.fact_disc_norm = web_latex(Dnormfac)

        if not self.is_minimal:
            Dmin = ideal_from_string(K,self.minD)
            self.mindisc = pretty_ideal(Dmin)
            Dmin_norm = Dmin.norm()
            self.mindisc_norm = web_latex(Dmin_norm)
            if Dmin_norm == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
                self.fact_mindisc_norm = self.mindisc
            else:
                Dminfac = Factorization([(P,e) for P,edd in zip(badprimes,mindisc_ords)])
                self.fact_mindisc = web_latex_ideal_fact(Dminfac)
                Dminnormfac = Factorization([(q,e) for q,e in zip(badnorms,mindisc_ords)])
                self.fact_mindisc_norm = web_latex(Dminnormfac)

        j = self.field.parse_NFelt(self.jinv)
        # if j:
        #     d = j.denominator()
        #     n = d * j  # numerator exists for quadratic fields only!
        #     g = GCD(list(n))
        #     n1 = n / g
        #     self.j = web_latex(n1)
        #     if d != 1:
        #         if n1 > 1:
        #         # self.j = "("+self.j+")\(/\)"+web_latex(d)
        #             self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
        #         else:
        #             self.j = web_latex(d)
        #         if g > 1:
        #             if n1 > 1:
        #                 self.j = web_latex(g) + self.j
        #             else:
        #                 self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        # See issue 1258: some j factorizations work but take too long
        # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1).  Note that we do
        # store the factorization of the denominator of j and display
        # that, which is the most interesting part.

        # Images of Galois representations

        if not hasattr(self,'galois_images'):
            #print "No Galois image data"
            self.galois_images = "?"
            self.non_surjective_primes = "?"
            self.galois_data = []
        else:
            self.galois_data = [{'p': p,'image': im }
                                for p,im in zip(self.non_surjective_primes,
                                                self.galois_images)]

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.rational_cm = K(self.cm).is_square()
            self.cm_sqf = ZZ(self.cm).squarefree_part()
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Galois images in CM case:
        if self.cm and self.galois_images != '?':
            self.cm_ramp = [p for p in ZZ(self.cm).support() if not p in self.non_surjective_primes]
            self.cm_nramp = len(self.cm_ramp)
            if self.cm_nramp==1:
                self.cm_ramp = self.cm_ramp[0]
            else:
                self.cm_ramp = ", ".join([str(p) for p in self.cm_ramp])

        # Sato-Tate:
        # The lines below will need to change once we have curves over non-quadratic fields
        # that contain the Hilbert class field of an imaginary quadratic field
        if self.cm:
            if self.signature == [0,1] and ZZ(-self.abs_disc*self.cm).is_square():
                self.ST = st_link_by_name(1,2,'U(1)')
            else:
                self.ST = st_link_by_name(1,2,'N(U(1))')
        else:
            self.ST = st_link_by_name(1,2,'SU(2)')

        # Q-curve / Base change
        self.qc = self.q_curve
        if self.qc == "?":
            self.qc = "not determined"
        elif self.qc == True:
            self.qc = "yes"
        elif self.qc == False:
            self.qc = "no"
        else: # just in case
            self.qc = "not determined"

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure)

        torsion_gens = [parse_point(K,P) for P in self.torsion_gens]
        self.torsion_gens = ",".join([web_point(P) for P in torsion_gens])

        # Rank or bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.rank_bounds)
        except AttributeError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not available"

        # Generators
        try:
            gens = [parse_point(K,P) for P in self.gens]
            self.gens = ", ".join([web_point(P) for P in gens])
            if self.rk == "?":
                self.reg = "not available"
            else:
                if gens:
                    try:
                        self.reg = self.reg
                    except AttributeError:
                        self.reg = "not available"
                    pass # self.reg already set
                else:
                    self.reg = 1  # otherwise we only get 1.00000...

        except AttributeError:
            self.gens = "not available"
            self.reg = "not available"
            try:
                if self.rank == 0:
                    self.reg = 1
            except AttributeError:
                pass

        # Local data
        for P,ld in zip(badprimes,local_data):
            ld['p'] = web_latex(P)
            ld['norm'] = P.norm()
            ld['kod'] = ld['kod'].replace('\\\\', '\\')
            ld['kod'] = web_latex(ld['kod']).replace('$', '')

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        # Isogeny information

        self.one_deg = ZZ(self.class_deg).is_prime()
        isodegs = [str(d) for d in self.isogeny_degrees if d>1]
        if len(isodegs)<3:
            self.isogeny_degrees = " and ".join(isodegs)
        else:
            self.isogeny_degrees = " and ".join([", ".join(isodegs[:-1]),isodegs[-1]])


        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0,1]

        if totally_real:
            self.hmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field.label, label=self.hmf_label)
            if sig[0] <= 2:
                self.urls['Lfunction'] = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label)
            elif self.abs_disc ** 2 * self.conductor_norm < 70000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0')

        if imag_quadratic:
            self.bmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage', field_label=self.field_label, level_label=self.conductor_label, label_suffix=self.iso_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label)

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])]
        self.friends += [('Twists', url_for('ecnf.index', field=self.field_label, jinv=rename_j(j)))]
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])]

        if imag_quadratic:
            if "CM" in self.label:
                self.friends += [('Bianchi Modular Form is not cuspidal', '')]
            else:
                if db.bmf_forms.label_exists(self.bmf_label):
                    self.friends += [('Bianchi Modular Form %s' % self.bmf_label, self.bmf_url)]
                else:
                    self.friends += [('(Bianchi Modular Form %s)' % self.bmf_label, '')]

        if 'Lfunction' in self.urls:
            self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]

        self.properties = [
            ('Base field', self.field.field_pretty()),
            ('Label', self.label)]

        # Plot
        if K.signature()[0]:
            self.plot = encode_plot(EC_nf_plot(K,self.ainvs, self.field.generator_name()))
            self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(self.plot)
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden (can be very large)
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)]

        if self.base_change:
            self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('base-change', 'no')]
        self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))]

        self._code = None # will be set if needed by get_code()

        self.downloads = [('Download all stored data', url_for(".download_ECNF_all", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number))]
        for lang in [["Magma","magma"], ["SageMath","sage"], ["GP", "gp"]]:
            self.downloads.append(('Download {} code'.format(lang[0]),
                                   url_for(".ecnf_code_download", nf=self.field_label, conductor_label=quote(self.conductor_label),
                                           class_label=self.iso_label, number=self.number, download_type=lang[1])))
Exemple #17
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these, construct the
        # actual elliptic curve E, and compute some further (easy)
        # data about it.
        #

        # Weierstrass equation

        data = self.data = {}
        data['ainvs'] = [int(ai) for ai in self.ainvs]
        self.E = EllipticCurve(data['ainvs'])
        data['equation'] = web_latex(self.E)

        # conductor, j-invariant and discriminant

        data['conductor'] = N = ZZ(self.conductor)
        bad_primes = N.prime_factors()
        try:
            data['j_invariant'] = QQ(str(self.jinv))
        except KeyError:
            data['j_invariant'] = self.E.j_invariant()
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])
        data['disc'] = D = self.E.discriminant()
        data['disc_latex'] = web_latex(data['disc'])
        data['disc_factor'] = latex(data['disc'].factor())
        data['cond_factor'] =latex(N.factor())
        data['cond_latex'] = web_latex(N)

        # CM and endomorphism ring

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

        # modular degree

        try:
            data['degree'] = self.degree
        except AttributeError:
            try:
                data['degree'] = self.E.modular_degree()
            except RuntimeError:
                data['degree']  # invalid, but will be displayed nicely

        # Minimal quadratic twist

        E_pari = self.E.pari_curve()
        from sage.libs.pari.all import PariError
        try:
            minq, minqD = self.E.minimal_quadratic_twist()
        except PariError:  # this does occur with 164411a1
            ec.debug("PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label)
            minq = self.E
            minqD = 1
        data['minq_D'] = minqD
        if self.E == minq:
            data['minq_label'] = self.lmfdb_label
            data['minq_info'] = '(itself)'
        else:
            minq_ainvs = [str(c) for c in minq.ainvs()]
            data['minq_label'] = db_ec().find_one({'ainvs': minq_ainvs})['lmfdb_label']
            data['minq_info'] = '(by %s)' % minqD

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

        # rational and integral points

        mw = self.mw = {}

        xintpoints_projective = [self.E.lift_x(x) for x in self.xintcoords]
        xintpoints = [P.xy() for P in xintpoints_projective]
        mw['int_points'] = ', '.join(web_latex(P) for P in xintpoints)

        # Generators of infinite order

        mw['rank'] = self.rank
        try:
            self.generators = [self.E(g) for g in parse_points(self.gens)]
            mw['generators'] = [web_latex(P.xy()) for P in self.generators]
            mw['heights'] = [P.height() for P in self.generators]
        except AttributeError:
            mw['generators'] = ''
            mw['heights'] = []

        # Torsion subgroup: order, structure, generators

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

        # Images of Galois representations

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

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

        if self.twoadic_gens:
            from sage.matrix.all import Matrix
            data['twoadic_gen_matrices'] = ','.join([latex(Matrix(2,2,M)) for M in self.twoadic_gens])
            data['twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"
        # Leading term of L-function & BSD data

        bsd = self.bsd = {}

        r = self.rank
        if r >= 2:
            bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r,r)
        elif r:
            bsd['lder_name'] = "L'(E,1)"
        else:
            bsd['lder_name'] = "L(E,1)"

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

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

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


        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = (padic_db().find({'lmfdb_iso': self.lmfdb_iso}).count()) > 0
        data['p_adic_primes'] = [p for p in sage.all.prime_range(5, 100)
                                 if self.E.is_ordinary(p) and not p.divides(N)]

        # Local data

        local_data = self.local_data = []
        # if we use E.tamagawa_numbers() it calls E.local_data(p) which
        # used to crash on some curves e.g. 164411a1
        tamagawa_numbers = []
        for p in bad_primes:
            local_info = self.E.local_data(p, algorithm="generic")
            local_data_p = {}
            local_data_p['p'] = p
            local_data_p['tamagawa_number'] = local_info.tamagawa_number()
            tamagawa_numbers.append(ZZ(local_info.tamagawa_number()))
            local_data_p['kodaira_symbol'] = web_latex(local_info.kodaira_symbol()).replace('$', '')
            local_data_p['reduction_type'] = local_info.bad_reduction_type()
            local_data_p['ord_cond'] = local_info.conductor_valuation()
            local_data_p['ord_disc'] = local_info.discriminant_valuation()
            local_data_p['ord_den_j'] = max(0,-self.E.j_invariant().valuation(p))
            local_data.append(local_data_p)

        if len(bad_primes)>1:
            bsd['tamagawa_factors'] = r' \cdot '.join(str(c.factor()) for c in tamagawa_numbers)
        else:
            bsd['tamagawa_factors'] = ''
        bsd['tamagawa_product'] = sage.misc.all.prod(tamagawa_numbers)

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        data['newform'] =  web_latex(self.E.q_eigenform(10))

        self.make_code_snippets()

        self.friends = [
            ('Isogeny class ' + self.lmfdb_iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)),
            ('Minimal quadratic twist %s %s' % (data['minq_info'], data['minq_label']), url_for(".by_triple_label", conductor=minq_N, iso_label=minq_iso, number=minq_number)),
            ('All twists ', url_for(".rational_elliptic_curves", jinv=self.jinv)),
            ('L-function', url_for("l_functions.l_function_ec_page", label=self.lmfdb_label)),
            ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso)),
            ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=self.lmfdb_iso)),
            ('Modular form ' + self.lmfdb_iso.replace('.', '.2'), url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=iso))]

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

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

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

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                           ('$\Q$', url_for(".rational_elliptic_curves")),
                           ('%s' % N, url_for(".by_conductor", conductor=N)),
                           ('%s' % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)),
                           ('%s' % num,' ')]
Exemple #18
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        data['galois_images'] = [
            trim_galois_image_code(s) for s in self.mod_p_images
        ]
        data['non_maximal_primes'] = self.non_maximal_primes
        data['galois_data'] = [{
            'p': p,
            'image': im
        } for p, im in zip(data['non_maximal_primes'], data['galois_images'])]

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['cm_ramp'] = [
                p for p in ZZ(self.cm).support()
                if not p in self.non_surjective_primes
            ]
            data['cm_nramp'] = len(data['cm_ramp'])
            if data['cm_nramp'] == 1:
                data['cm_ramp'] = data['cm_ramp'][0]
            else:
                data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']])
            data['cm_sqf'] = ZZ(self.cm).squarefree_part()

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

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

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

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

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

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

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

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

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

        data['iwdata'] = []
        try:
            pp = [int(p) for p in self.iwdata]
            badp = [l['p'] for l in self.local_data]
            rtypes = [l['red'] for l in self.local_data]
            data[
                'iw_missing_flag'] = False  # flags that there is at least one "?" in the table
            data[
                'additive_shown'] = False  # flags that there is at least one additive prime in table
            for p in sorted(pp):
                rtype = ""
                if p in badp:
                    red = rtypes[badp.index(p)]
                    # Additive primes are excluded from the table
                    # if red==0:
                    #    continue
                    #rtype = ["nsmult","add", "smult"][1+red]
                    rtype = ["nonsplit", "add", "split"][1 + red]
                p = str(p)
                pdata = self.iwdata[p]
                if isinstance(pdata, type(u'?')):
                    if not rtype:
                        rtype = "ordinary" if pdata == "o?" else "ss"
                    if rtype == "add":
                        data['iwdata'] += [[p, rtype, "-", "-"]]
                        data['additive_shown'] = True
                    else:
                        data['iwdata'] += [[p, rtype, "?", "?"]]
                        data['iw_missing_flag'] = True
                else:
                    if len(pdata) == 2:
                        if not rtype:
                            rtype = "ordinary"
                        lambdas = str(pdata[0])
                        mus = str(pdata[1])
                    else:
                        rtype = "ss"
                        lambdas = ",".join([str(pdata[0]), str(pdata[1])])
                        mus = str(pdata[2])
                        mus = ",".join([mus, mus])
                    data['iwdata'] += [[p, rtype, lambdas, mus]]
        except AttributeError:
            # For curves with no Iwasawa data
            pass

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

        # Torsion growth data

        data['torsion_growth_data_exists'] = False
        try:
            tg = self.tor_gro
            data['torsion_growth_data_exists'] = True
            data['tgx'] = tgextra = []
            # find all base-changes of this curve in the database, if any
            bcs = [
                res['label']
                for res in getDBConnection().elliptic_curves.nfcurves.find(
                    {'base_change': self.lmfdb_label},
                    projection={
                        'label': True,
                        '_id': False
                    })
            ]
            bcfs = [lab.split("-")[0] for lab in bcs]
            for F, T in tg.items():
                tg1 = {}
                tg1['bc'] = "Not in database"
                if ":" in F:
                    F = F.replace(":", ".")
                    field_data = nf_display_knowl(F, getDBConnection(),
                                                  field_pretty(F))
                    deg = int(F.split(".")[0])
                    bcc = [x for x, y in zip(bcs, bcfs) if y == F]
                    if bcc:
                        from lmfdb.ecnf.main import split_full_label
                        F, NN, I, C = split_full_label(bcc[0])
                        tg1['bc'] = bcc[0]
                        tg1['bc_url'] = url_for('ecnf.show_ecnf',
                                                nf=F,
                                                conductor_label=NN,
                                                class_label=I,
                                                number=C)
                else:
                    field_data = web_latex_split_on_pm(
                        coeff_to_poly(string2list(F)))
                    deg = F.count(",")
                tg1['d'] = deg
                tg1['f'] = field_data
                tg1['t'] = '\(' + ' \\times '.join(
                    ['\Z/{}\Z'.format(n) for n in T.split(",")]) + '\)'
                tg1['m'] = 0
                tgextra.append(tg1)

            tgextra.sort(key=lambda x: x['d'])
            data['ntgx'] = len(tgextra)
            lastd = 1
            for tg in tgextra:
                d = tg['d']
                if d != lastd:
                    tg['m'] = len([x for x in tgextra if x['d'] == d])
                    lastd = d
            data['tg_maxd'] = max(db_ecstats().find_one(
                {'_id': 'torsion_growth'})['degrees'])

        except AttributeError:
            pass  # we have no torsion growth data

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

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

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

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

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

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

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]
Exemple #19
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these, construct the
        # actual elliptic curve E, and compute some further (easy)
        # data about it.
        #

        # Weierstrass equation

        data = self.data = {}
        data['ainvs'] = [int(ai) for ai in self.ainvs]
        self.E = EllipticCurve(data['ainvs'])
        data['equation'] = web_latex(self.E)

        # conductor, j-invariant and discriminant

        data['conductor'] = N = ZZ(self.conductor)
        bad_primes = N.prime_factors()
        try:
            data['j_invariant'] = QQ(str(self.jinv))
        except KeyError:
            data['j_invariant'] = self.E.j_invariant()
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])
        data['disc'] = D = self.E.discriminant()
        data['disc_latex'] = web_latex(data['disc'])
        data['disc_factor'] = latex(data['disc'].factor())
        data['cond_factor'] = latex(N.factor())
        data['cond_latex'] = web_latex(N)

        # CM and endomorphism ring

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

        # modular degree

        try:
            data['degree'] = self.degree
        except AttributeError:
            try:
                data['degree'] = self.E.modular_degree()
            except RuntimeError:
                data['degree']  # invalid, but will be displayed nicely

        # Minimal quadratic twist

        E_pari = self.E.pari_curve()
        from sage.libs.pari.all import PariError
        try:
            minq, minqD = self.E.minimal_quadratic_twist()
        except PariError:  # this does occur with 164411a1
            ec.debug(
                "PariError computing minimal quadratic twist of elliptic curve %s"
                % lmfdb_label)
            minq = self.E
            minqD = 1
        data['minq_D'] = minqD
        if self.E == minq:
            data['minq_label'] = self.lmfdb_label
            data['minq_info'] = '(itself)'
        else:
            minq_ainvs = [str(c) for c in minq.ainvs()]
            data['minq_label'] = db_ec().find_one({'ainvs':
                                                   minq_ainvs})['lmfdb_label']
            data['minq_info'] = '(by %s)' % minqD

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

        # rational and integral points

        mw = self.mw = {}

        xintpoints_projective = [self.E.lift_x(x) for x in self.xintcoords]
        xintpoints = [P.xy() for P in xintpoints_projective]
        mw['int_points'] = ', '.join(web_latex(P) for P in xintpoints)

        # Generators of infinite order

        mw['rank'] = self.rank
        try:
            self.generators = [self.E(g) for g in parse_points(self.gens)]
            mw['generators'] = [web_latex(P.xy()) for P in self.generators]
            mw['heights'] = [P.height() for P in self.generators]
        except AttributeError:
            mw['generators'] = ''
            mw['heights'] = []

        # Torsion subgroup: order, structure, generators

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

        # Images of Galois representations

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

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

        if self.twoadic_gens:
            from sage.matrix.all import Matrix
            data['twoadic_gen_matrices'] = ','.join(
                [latex(Matrix(2, 2, M)) for M in self.twoadic_gens])
            data[
                'twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"
        # Leading term of L-function & BSD data

        bsd = self.bsd = {}

        r = self.rank
        if r >= 2:
            bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r, r)
        elif r:
            bsd['lder_name'] = "L'(E,1)"
        else:
            bsd['lder_name'] = "L(E,1)"

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

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

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

        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = (padic_db().find({
                'lmfdb_iso':
                self.lmfdb_iso
            }).count()) > 0
        data['p_adic_primes'] = [
            p for p in sage.all.prime_range(5, 100)
            if self.E.is_ordinary(p) and not p.divides(N)
        ]

        # Local data

        local_data = self.local_data = []
        # if we use E.tamagawa_numbers() it calls E.local_data(p) which
        # used to crash on some curves e.g. 164411a1
        tamagawa_numbers = []
        for p in bad_primes:
            local_info = self.E.local_data(p, algorithm="generic")
            local_data_p = {}
            local_data_p['p'] = p
            local_data_p['tamagawa_number'] = local_info.tamagawa_number()
            tamagawa_numbers.append(ZZ(local_info.tamagawa_number()))
            local_data_p['kodaira_symbol'] = web_latex(
                local_info.kodaira_symbol()).replace('$', '')
            local_data_p['reduction_type'] = local_info.bad_reduction_type()
            local_data_p['ord_cond'] = local_info.conductor_valuation()
            local_data_p['ord_disc'] = local_info.discriminant_valuation()
            local_data_p['ord_den_j'] = max(0,
                                            -self.E.j_invariant().valuation(p))
            local_data.append(local_data_p)

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

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        data['newform'] = web_latex(self.E.q_eigenform(10))

        self.make_code_snippets()

        self.friends = [('Isogeny class ' + self.lmfdb_iso,
                         url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_triple_label",
                                 conductor=minq_N,
                                 iso_label=minq_iso,
                                 number=minq_number)),
                        ('All twists ',
                         url_for(".rational_elliptic_curves", jinv=self.jinv)),
                        ('L-function',
                         url_for("l_functions.l_function_ec_page",
                                 label=self.lmfdb_label)),
                        ('Symmetric square L-function',
                         url_for("l_functions.l_function_ec_sym_page",
                                 power='2',
                                 label=self.lmfdb_iso)),
                        ('Symmetric 4th power L-function',
                         url_for("l_functions.l_function_ec_sym_page",
                                 power='4',
                                 label=self.lmfdb_iso)),
                        ('Modular form ' + self.lmfdb_iso.replace('.', '.2'),
                         url_for("emf.render_elliptic_modular_forms",
                                 level=int(N),
                                 weight=2,
                                 character=1,
                                 label=iso))]

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

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

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

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

        # Create a list of the curves in the class from the database
        self.db_curves = [c for c in db_ec().find(
            {'field_label': self.field_label, 'conductor_label':
             self.conductor_label, 'iso_label': self.iso_label}).sort('number')]

        # Rank or bounds
        try:
            self.rk = web_latex(self.db_curves[0]['rank'])
        except KeyError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds'])
        except KeyError:
            self.rank_bounds = [0, sage.rings.infinity.Infinity]
            self.rk_bnds = "not recorded"


        # Extract the isogeny degree matrix from the database if possible, else create it
        if hasattr(self, 'isogeny_matrix'):
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        else:
            self.isogeny_matrix = make_iso_matrix(self.db_curves)

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        self.field = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label, lmfdb.base.getDBConnection(), self.field)
        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[c['short_label'], curve_url(c), web_ainvs(self.field_label,c['ainvs'])] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=self.conductor_label, class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0,1]
        if totally_real:
            self.hmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field_label, label=self.hmf_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0')

        if imag_quadratic:
            self.bmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])

        self.friends = []
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])]
            self.friends += [('L-function', self.urls['Lfunction'])]
        if imag_quadratic:
            self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')]

        self.properties = [('Base field', self.field),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)
                       ]
        if self.rk != '?':
            self.properties += [('Rank', '%s' % self.rk)]
        else:
            if self.rk_bnds == 'not recorded':
                self.properties += [('Rank', '%s' % self.rk_bnds)]
            else:
                self.properties += [('Rank bounds', '%s' % self.rk_bnds)]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label, self.urls['class'])]
Exemple #21
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                           ('$\Q$', url_for(".rational_elliptic_curves")),
                           ('%s' % N, url_for(".by_conductor", conductor=N)),
                           ('%s' % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)),
                           ('%s' % num,' ')]
Exemple #22
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix

            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()
        self.ncurves = size

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({"lmfdb_label": self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata["ainvs"]])
            self.cremona_labels[i - 1] = Edata["label"]
            if Edata["number"] == 1:
                self.optimal_flags[i - 1] = True
            if "degree" in Edata:
                self.degrees[i - 1] = Edata["degree"]
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)

        if self.iso == "990h":  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = newform_label(N, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso)
        newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso)

        self.curves = [
            dict(
                [
                    ("label", self.lmfdb_iso + str(i + 1)),
                    ("url", url_for(".by_triple_label", conductor=N, iso_label=iso, number=i + 1)),
                    ("cremona_label", self.cremona_labels[i]),
                    ("ainvs", str(list(c.ainvs()))),
                    ("torsion", c.torsion_order()),
                    ("degree", self.degrees[i]),
                    ("optimal", self.optimal_flags[i]),
                ]
            )
            for i, c in enumerate(self.db_curves)
        ]

        self.friends = [("L-function", self.lfunction_link)]
        if not self.CM:
            self.friends += [
                (
                    "Symmetric square L-function",
                    url_for("l_functions.l_function_ec_sym_page", power="2", label=self.lmfdb_iso),
                ),
                (
                    "Symmetric 4th power L-function",
                    url_for("l_functions.l_function_ec_sym_page", power="4", label=self.lmfdb_iso),
                ),
            ]
        if newform_exists_in_db:
            self.friends += [("Modular form " + self.newform_label, self.newform_link)]

        self.properties = [
            ("Label", self.lmfdb_iso),
            ("Number of curves", str(self.ncurves)),
            ("Conductor", "\(%s\)" % N),
            ("CM", "%s" % self.CM),
            ("Rank", "\(%s\)" % self.rank),
            ("Graph", ""),
            (None, self.graph_link),
        ]

        self.downloads = [
            ("Download coefficients of newform", url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=100)),
            ("Download stored data for all curves", url_for(".download_EC_all", label=self.lmfdb_iso)),
        ]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [
            ("Elliptic Curves", url_for("ecnf.index")),
            ("$\Q$", url_for(".rational_elliptic_curves")),
            ("%s" % N, url_for(".by_conductor", conductor=N)),
            ("%s" % iso, " "),
        ]
Exemple #23
0
    def make_class(self):

        # Create a list of the curves in the class from the database
        self.db_curves = [
            c for c in db_ecnf().find({
                'field_label': self.field_label,
                'conductor_norm': self.conductor_norm,
                'conductor_label': self.conductor_label,
                'iso_nlabel': self.iso_nlabel
            }).sort('number')
        ]

        # Rank or bounds
        try:
            self.rk = web_latex(self.db_curves[0]['rank'])
        except KeyError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds'])
        except KeyError:
            self.rank_bounds = [0, sage.rings.infinity.Infinity]
            self.rk_bnds = "not recorded"

        # Extract the isogeny degree matrix from the database if possible, else create it
        if hasattr(self, 'isogeny_matrix'):
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        else:
            self.isogeny_matrix = make_iso_matrix(self.db_curves)

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        self.field = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label,
                                            lmfdb.base.getDBConnection(),
                                            self.field)

        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[
            c['short_label'],
            curve_url(c),
            web_ainvs(self.field_label, c['ainvs'])
        ] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]
        if totally_real:
            self.hmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field_label,
                                       label=self.hmf_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page",
                                             field=self.field_label,
                                             label=self.hmf_label,
                                             character='0',
                                             number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])

        self.friends = []
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]
            self.friends += [('L-function', self.urls['Lfunction'])]
        if imag_quadratic:
            self.friends += [
                ('Bianchi Modular Form %s not available' % self.bmf_label, '')
            ]

        self.properties = [('Base field', self.field),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)]
        if self.rk != '?':
            self.properties += [('Rank', '%s' % self.rk)]
        else:
            if self.rk_bnds == 'not recorded':
                self.properties += [('Rank', '%s' % self.rk_bnds)]
            else:
                self.properties += [('Rank bounds', '%s' % self.rk_bnds)]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label,
                       self.urls['class'])]
Exemple #24
0
    def make_E(self):
        coeffs = self.ainvs  # list of 5 lists of d strings
        self.ainvs = [self.field.parse_NFelt(x) for x in coeffs]
        self.latex_ainvs = web_latex(self.ainvs)
        from sage.schemes.elliptic_curves.all import EllipticCurve

        self.E = E = EllipticCurve(self.ainvs)
        self.equn = web_latex(E)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = E.conductor()
        self.cond = web_latex(N)
        self.cond_norm = web_latex(N.norm())
        if N.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
        else:
            self.fact_cond = web_latex_ideal_fact(N.factor())
        self.fact_cond_norm = web_latex(N.norm().factor())

        D = self.field.K().ideal(E.discriminant())
        self.disc = web_latex(D)
        self.disc_norm = web_latex(D.norm())
        if D.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
        else:
            self.fact_disc = web_latex_ideal_fact(D.factor())
        self.fact_disc_norm = web_latex(D.norm().factor())

        # Minimal model?
        #
        # All curves in the database should be given
        # by models which are globally minimal if possible, else
        # minimal at all but one prime.  But we do not rely on this
        # here, and the display should be correct if either (1) there
        # exists a global minimal model but this model is not; or (2)
        # this model is non-minimal at more than one prime.
        #
        self.non_min_primes = non_minimal_primes(E)
        self.is_minimal = len(self.non_min_primes) == 0
        self.has_minimal_model = True
        if not self.is_minimal:
            self.non_min_prime = ",".join([web_latex(P) for P in self.non_min_primes])
            self.has_minimal_model = has_global_minimal_model(E)

        if not self.is_minimal:
            Dmin = minimal_discriminant_ideal(E)
            self.mindisc = web_latex(Dmin)
            self.mindisc_norm = web_latex(Dmin.norm())
            if Dmin.norm() == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
            else:
                self.fact_mindisc = web_latex_ideal_fact(Dmin.factor())
            self.fact_mindisc_norm = web_latex(Dmin.norm().factor())

        j = E.j_invariant()
        if j:
            d = j.denominator()
            n = d * j  # numerator exists for quadratic fields only!
            g = GCD(list(n))
            n1 = n / g
            self.j = web_latex(n1)
            if d != 1:
                if n1 > 1:
                    # self.j = "("+self.j+")\(/\)"+web_latex(d)
                    self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
                else:
                    self.j = web_latex(d)
                if g > 1:
                    if n1 > 1:
                        self.j = web_latex(g) + self.j
                    else:
                        self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        if j.is_zero():
            self.fact_j = web_latex(j)
        else:
            try:
                self.fact_j = web_latex(j.factor())
            except (ArithmeticError, ValueError):  # if not all prime ideal factors principal
                pass

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure)
        torsion_gens = [E([self.field.parse_NFelt(x) for x in P]) for P in self.torsion_gens]
        self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens])

        # Rank or bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.rank_bounds)
        except AttributeError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not recorded"

        # Generators
        try:
            gens = [E([self.field.parse_NFelt(x) for x in P]) for P in self.gens]
            self.gens = ", ".join([web_latex(P) for P in gens])
            if self.rk == "?":
                self.reg = "unknown"
            else:
                if gens:
                    self.reg = E.regulator_of_points(gens)
                else:
                    self.reg = 1  # otherwise we only get 1.00000...

        except AttributeError:
            self.gens = "not recorded"
            self.reg = "unknown"
            try:
                if self.rank == 0:
                    self.reg = 1
            except AttributeError:
                pass

        # Local data
        self.local_data = []
        for p in N.prime_factors():
            self.local_info = E.local_data(p, algorithm="generic")
            self.local_data.append(
                {
                    "p": web_latex(p),
                    "norm": web_latex(p.norm().factor()),
                    "tamagawa_number": self.local_info.tamagawa_number(),
                    "kodaira_symbol": web_latex(self.local_info.kodaira_symbol()).replace("$", ""),
                    "reduction_type": self.local_info.bad_reduction_type(),
                    "ord_den_j": max(0, -E.j_invariant().valuation(p)),
                    "ord_mindisc": self.local_info.discriminant_valuation(),
                    "ord_cond": self.local_info.conductor_valuation(),
                }
            )

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls["curve"] = url_for(
                ".show_ecnf",
                nf=self.field_label,
                conductor_label=quote(self.conductor_label),
                class_label=self.iso_label,
                number=self.number,
            )
        except RuntimeError:
            return
        self.urls["class"] = url_for(
            ".show_ecnf_isoclass",
            nf=self.field_label,
            conductor_label=quote(self.conductor_label),
            class_label=self.iso_label,
        )
        self.urls["conductor"] = url_for(
            ".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(self.conductor_label)
        )
        self.urls["field"] = url_for(".show_ecnf1", nf=self.field_label)

        sig = self.signature
        real_quadratic = sig == [2, 0]
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]

        if totally_real:
            self.hmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])
            self.urls["hmf"] = url_for("hmf.render_hmf_webpage", field_label=self.field.label, label=self.hmf_label)
            self.urls["Lfunction"] = url_for(
                "l_functions.l_function_hmf_page",
                field=self.field_label,
                label=self.hmf_label,
                character="0",
                number="0",
            )

        if imag_quadratic:
            self.bmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        self.friends += [("Isogeny class " + self.short_class_label, self.urls["class"])]
        self.friends += [("Twists", url_for("ecnf.index", field_label=self.field_label, jinv=self.jinv))]
        if totally_real:
            self.friends += [("Hilbert Modular Form " + self.hmf_label, self.urls["hmf"])]
            self.friends += [("L-function", self.urls["Lfunction"])]
        if imag_quadratic:
            self.friends += [("Bianchi Modular Form %s not yet available" % self.bmf_label, "")]

        self.properties = [("Base field", self.field.field_pretty()), ("Label", self.label)]

        # Plot
        if E.base_field().signature()[0]:
            self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ("Conductor", self.cond),
            ("Conductor norm", self.cond_norm),
            # See issue #796 for why this is hidden
            # ('j-invariant', self.j),
            ("CM", self.cm_bool),
        ]

        if self.base_change:
            self.properties += [("base-change", "yes: %s" % ",".join([str(lab) for lab in self.base_change]))]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [("Q-curve", self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [("Torsion order", self.ntors), ("Rank", r)]

        for E0 in self.base_change:
            self.friends += [("Base-change of %s /\(\Q\)" % E0, url_for("ec.by_ec_label", label=E0))]

        self.make_code_snippets()
Exemple #25
0
    def make_E(self):
        coeffs = self.ainvs  # list of 5 lists of d strings
        self.ainvs = [self.field.parse_NFelt(x) for x in coeffs]
        self.latex_ainvs = web_latex(self.ainvs)
        from sage.schemes.elliptic_curves.all import EllipticCurve
        self.E = E = EllipticCurve(self.ainvs)
        self.equn = web_latex(E)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = E.conductor()
        self.cond = web_latex(N)
        self.cond_norm = web_latex(N.norm())
        if N.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
        else:
            self.fact_cond = web_latex_ideal_fact(N.factor())
        self.fact_cond_norm = web_latex(N.norm().factor())

        D = self.field.K().ideal(E.discriminant())
        self.disc = web_latex(D)
        self.disc_norm = web_latex(D.norm())
        if D.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
        else:
            self.fact_disc = web_latex_ideal_fact(D.factor())
        self.fact_disc_norm = web_latex(D.norm().factor())

        # Minimal model?
        #
        # All curves in the database should be given
        # by models which are globally minimal if possible, else
        # minimal at all but one prime.  But we do not rely on this
        # here, and the display should be correct if either (1) there
        # exists a global minimal model but this model is not; or (2)
        # this model is non-minimal at more than one prime.
        #
        self.non_min_primes = non_minimal_primes(E)
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = True
        if not self.is_minimal:
            self.non_min_prime = ','.join(
                [web_latex(P) for P in self.non_min_primes])
            self.has_minimal_model = has_global_minimal_model(E)

        if not self.is_minimal:
            Dmin = minimal_discriminant_ideal(E)
            self.mindisc = web_latex(Dmin)
            self.mindisc_norm = web_latex(Dmin.norm())
            if Dmin.norm(
            ) == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
            else:
                self.fact_mindisc = web_latex_ideal_fact(Dmin.factor())
            self.fact_mindisc_norm = web_latex(Dmin.norm().factor())

        j = E.j_invariant()
        if j:
            d = j.denominator()
            n = d * j  # numerator exists for quadratic fields only!
            g = GCD(list(n))
            n1 = n / g
            self.j = web_latex(n1)
            if d != 1:
                if n1 > 1:
                    #self.j = "("+self.j+")\(/\)"+web_latex(d)
                    self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
                else:
                    self.j = web_latex(d)
                if g > 1:
                    if n1 > 1:
                        self.j = web_latex(g) + self.j
                    else:
                        self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        if j.is_zero():
            self.fact_j = web_latex(j)
        else:
            try:
                self.fact_j = web_latex(j.factor())
            except (ArithmeticError,
                    ValueError):  # if not all prime ideal factors principal
                pass

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(
                self.torsion_structure)
        torsion_gens = [
            E([self.field.parse_NFelt(x) for x in P])
            for P in self.torsion_gens
        ]
        self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens])

        # Rank etc
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "not recorded"
#       if rank in self:
#            self.r = web_latex(self.rank)

# Local data
        self.local_data = []
        for p in N.prime_factors():
            self.local_info = E.local_data(p, algorithm="generic")
            self.local_data.append({
                'p':
                web_latex(p),
                'norm':
                web_latex(p.norm().factor()),
                'tamagawa_number':
                self.local_info.tamagawa_number(),
                'kodaira_symbol':
                web_latex(self.local_info.kodaira_symbol()).replace('$', ''),
                'reduction_type':
                self.local_info.bad_reduction_type(),
                'ord_den_j':
                max(0,
                    E.j_invariant().valuation(p)),
                'ord_mindisc':
                self.local_info.discriminant_valuation()
            })

        # URLs of self and related objects:
        self.urls = {}
        self.urls['curve'] = url_for(".show_ecnf",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label,
                                     number=self.number)
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=self.conductor_label)
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        if self.field.is_real_quadratic():
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)

        if self.field.is_imag_quadratic():
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label,
                          self.urls['class'])]
        if self.field.is_real_quadratic():
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]
        if self.field.is_imag_quadratic():
            self.friends += [
                ('Bianchi Modular Form %s not yet available' % self.bmf_label,
                 '')
            ]

        self.properties = [('Base field', self.field.field_pretty()),
                           ('Label', self.label)]

        # Plot
        n1 = len(E.base_field().embeddings(RR))
        if (n1):
            self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [('Conductor', self.cond),
                            ('Conductor norm', self.cond_norm),
                            ('j-invariant', self.j), ('CM', self.cm_bool)]

        if self.base_change:
            self.properties += [
                ('base-change',
                 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))
            ]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Q-curve', self.qc)]

        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', self.rk),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0,
                              url_for("ec.by_ec_label", label=E0))]
Exemple #26
0
    def make_class(self):
        self.ECNF = ECNF.by_label(self.label)

        # Create a list of the curves in the class from the database
        self.db_curves = [
            ECNF(c) for c in db_ec().find({
                'field_label': self.field_label,
                'conductor_label': self.conductor_label,
                'iso_label': self.iso_label
            }).sort('number')
        ]
        size = len(self.db_curves)

        # Extract the isogeny degree matrix from the database if possible, else create it
        if hasattr(self, 'isogeny_matrix'):
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        else:
            self.isogeny_matrix = make_iso_matrix(self.db_curves)

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        self.curves = [[c.short_label, c.urls['curve'], c.latex_ainvs]
                       for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.ECNF.field_label)
        self.field = self.ECNF.field
        if self.field.is_real_quadratic():
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)

        if self.field.is_imag_quadratic():
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        if self.field.is_real_quadratic():
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]
        if self.field.is_imag_quadratic():
            self.friends += [
                ('Bianchi Modular Form %s not yet available' % self.bmf_label,
                 '')
            ]

        self.properties = [('Label', self.ECNF.label), (None, self.graph_link),
                           ('Conductor', '%s' % self.ECNF.cond)]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.ECNF.field_label, self.urls['field']),
                      (self.ECNF.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.ECNF.short_label,
                       self.urls['class'])]
Exemple #27
0
    def make_E(self):
        #print("Creating ECNF object for {}".format(self.label))
        #sys.stdout.flush()
        K = self.field.K()
        Kgen = str(K.gen())

        # a-invariants
        # NB Here we construct the ai as elements of K, which are used as follows:
        # (1) to compute the model discriminant (if not stored)
        # (2) to compute the latex equation (if not stored)
        # (3) to compute the plots under real embeddings of K
        # Of these, (2) is not needed and (1) will soon be obsolete;
        #  for (3) it would be possible to rewrite the function EC_nf_plot() not to need this.
        # Then we might also be able to avoid constructing the field K also.

        self.ainvs = parse_ainvs(K, self.ainvs)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant

        self.cond_norm = web_latex(self.conductor_norm)

        Dnorm = self.normdisc
        self.disc = pretty_ideal(Kgen, self.disc)

        local_data = self.local_data
        local_data.sort(key=lambda ld: ld['normp'])

        badprimes = [
            pretty_ideal(Kgen, ld['p'], enclose=False) for ld in local_data
        ]
        badnorms = [ld['normp'] for ld in local_data]
        disc_ords = [ld['ord_disc'] for ld in local_data]
        mindisc_ords = [ld['ord_disc'] for ld in local_data]
        cond_ords = [ld['ord_cond'] for ld in local_data]

        if self.conductor_norm == 1:
            self.cond = r"\((1)\)"
            self.fact_cond = self.cond
            self.fact_cond_norm = '1'
        else:
            self.cond = pretty_ideal(Kgen, self.conductor_ideal)
            self.fact_cond = latex_factorization(badprimes, cond_ords)
            self.fact_cond_norm = latex_factorization(badnorms, cond_ords)

        # Assumption: the curve models stored in the database are
        # either global minimal models or minimal at all but one
        # prime, so the list here has length 0 or 1:

        self.is_minimal = (len(self.non_min_p) == 0)
        self.has_minimal_model = self.is_minimal

        if not self.is_minimal:
            non_min_p = self.non_min_p[0]
            self.non_min_prime = pretty_ideal(Kgen, non_min_p)
            ip = [ld['p'] for ld in local_data].index(non_min_p)
            disc_ords[ip] += 12
            Dnorm_factor = local_data[ip]['normp']**12

        self.disc_norm = web_latex(Dnorm)
        signDnorm = 1 if Dnorm > 0 else -1
        if Dnorm in [1, -1]:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
            self.fact_disc_norm = str(Dnorm)
        else:
            self.fact_disc = latex_factorization(badprimes, disc_ords)
            self.fact_disc_norm = latex_factorization(badnorms,
                                                      disc_ords,
                                                      sign=signDnorm)

        if self.is_minimal:
            Dmin_norm = Dnorm
            self.mindisc = self.disc
        else:
            Dmin_norm = Dnorm // Dnorm_factor
            self.mindisc = pretty_ideal(Kgen, self.minD)

        self.mindisc_norm = web_latex(Dmin_norm)
        if Dmin_norm in [1,
                         -1]:  # since the factorization of (1) displays as "1"
            self.fact_mindisc = self.mindisc
            self.fact_mindisc_norm = self.mindisc_norm
        else:
            self.fact_mindisc = latex_factorization(badprimes, mindisc_ords)
            self.fact_mindisc_norm = latex_factorization(badnorms,
                                                         mindisc_ords,
                                                         sign=signDnorm)

        j = self.field.parse_NFelt(self.jinv)
        self.j = web_latex(j)
        self.fact_j = None
        # See issue 1258: some j factorizations work but take too long
        # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1).  Note that we do
        # store the factorization of the denominator of j and display
        # that, which is the most interesting part.

        # When the equation is stored in the database as a latex string,
        # it may have extraneous double quotes at beginning and
        # end, which we fix here.  We also strip out initial \( and \)
        # (if present) which are added in the template.
        try:
            self.equation = self.equation.replace('"', '').replace(
                r'\\(', '').replace(r'\\)', '')
        except AttributeError:
            self.equation = latex_equation(self.ainvs)

        # Images of Galois representations

        if not hasattr(self, 'galois_images'):
            #print "No Galois image data"
            self.galois_images = "?"
            self.nonmax_primes = "?"
            self.galois_data = []
        else:
            self.galois_data = [{
                'p': p,
                'image': im
            } for p, im in zip(self.nonmax_primes, self.galois_images)]

        # CM and End(E)
        self.cm_bool = "no"
        self.End = r"\(\Z\)"
        self.rational_cm = self.cm_type > 0
        if self.cm:
            self.cm_sqf = integer_squarefree_part(ZZ(self.cm))
            self.cm_bool = r"yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = r"\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = r"\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Galois images in CM case:
        if self.cm and self.galois_images != '?':
            self.cm_ramp = [
                p for p in ZZ(self.cm).support() if p not in self.nonmax_primes
            ]
            self.cm_nramp = len(self.cm_ramp)
            if self.cm_nramp == 1:
                self.cm_ramp = self.cm_ramp[0]
            else:
                self.cm_ramp = ", ".join([str(p) for p in self.cm_ramp])

        # Sato-Tate:
        self.ST = st_display_knowl('1.2.A.1.1a' if not self.cm_type else (
            '1.2.B.2.1a' if self.cm_type < 0 else '1.2.B.1.1a'))

        # Q-curve / Base change
        try:
            qc = self.q_curve
            if qc is True:
                self.qc = "yes"
            elif qc is False:
                self.qc = "no"
            else:  # just in case
                self.qc = "not determined"
        except AttributeError:
            self.qc = "not determined"

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "trivial"
        if self.tr == 1:
            self.tor_struct_pretty = r"\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(
                self.torsion_structure)

        self.torsion_gens = [
            web_point(parse_point(K, P)) for P in self.torsion_gens
        ]

        # BSD data
        #
        # We divide into 3 cases, based on rank_bounds [lb,ub],
        # analytic_rank ar, (lb=ngens always).  The flag
        # self.bsd_status is set to one of the following:
        #
        # "unconditional"
        #     lb=ar=ub: we always have reg but in some cases over sextic fields we do not have omega, Lvalue, sha.
        #     i.e. [lb,ar,ub] = [r,r,r]
        #
        # "conditional"
        #     lb=ar<ub: we always have reg but in some cases over sextic fields we do not have omega, Lvalue, sha.
        #     e.g. [lb,ar,ub] = [0,0,2], [1,1,3]
        #
        # "missing_gens"
        #     lb<ar<=ub
        #     e.g. [lb,ar,ub] = [0,1,1], [0,2,2], [1,2,2], [0,1,3]
        #
        # "incomplete"
        #     ar not computed.  (We can always set lb=0, ub=Infinity.)

        # Rank and bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rank = None
            self.rk = "not available"

        try:
            self.rk_lb, self.rk_ub = self.rank_bounds
        except AttributeError:
            self.rk_lb = 0
            self.rk_ub = Infinity
            self.rank_bounds = "not available"

        # Analytic rank
        try:
            self.ar = web_latex(self.analytic_rank)
        except AttributeError:
            self.analytic_rank = None
            self.ar = "not available"

        # for debugging:
        assert self.rk == "not available" or (self.rk_lb == self.rank
                                              and self.rank == self.rk_ub)
        assert self.ar == "not available" or (self.rk_lb <= self.analytic_rank
                                              and
                                              self.analytic_rank <= self.rk_ub)

        self.bsd_status = "incomplete"
        if self.analytic_rank is not None:
            if self.rk_lb == self.rk_ub:
                self.bsd_status = "unconditional"
            elif self.rk_lb == self.analytic_rank:
                self.bsd_status = "conditional"
            else:
                self.bsd_status = "missing_gens"

        # Regulator only in conditional/unconditional cases, or when we know the rank:
        if self.bsd_status in ["conditional", "unconditional"]:
            if self.ar == 0:
                self.reg = web_latex(1)  # otherwise we only get 1.00000...
            else:
                try:
                    self.reg = web_latex(self.reg)
                except AttributeError:
                    self.reg = "not available"
        elif self.rk != "not available":
            self.reg = web_latex(self.reg) if self.rank else web_latex(1)
        else:
            self.reg = "not available"

        # Generators
        try:
            self.gens = [web_point(parse_point(K, P)) for P in self.gens]
        except AttributeError:
            self.gens = []

        # Global period
        try:
            self.omega = web_latex(self.omega)
        except AttributeError:
            self.omega = "not available"

        # L-value
        try:
            r = int(self.analytic_rank)
            # lhs = "L(E,1) = " if r==0 else "L'(E,1) = " if r==1 else "L^{{({})}}(E,1)/{}! = ".format(r,r)
            self.Lvalue = web_latex(self.Lvalue)
        except (TypeError, AttributeError):
            self.Lvalue = "not available"

        # Tamagawa product
        tamagawa_numbers = [ZZ(_ld['cp']) for _ld in self.local_data]
        cp_fac = [cp.factor() for cp in tamagawa_numbers]
        cp_fac = [
            latex(cp) if len(cp) < 2 else '(' + latex(cp) + ')'
            for cp in cp_fac
        ]
        if len(cp_fac) > 1:
            self.tamagawa_factors = r'\cdot'.join(cp_fac)
        else:
            self.tamagawa_factors = None
        self.tamagawa_product = web_latex(prod(tamagawa_numbers, 1))

        # Analytic Sha
        try:
            self.sha = web_latex(self.sha) + " (rounded)"
        except AttributeError:
            self.sha = "not available"

        # Local data

        # The Kodaira symbol is stored as an int in pari encoding. The
        # conversion to latex must take into account the bug (in Sage
        # 9.2) for I_m^* when m has more than one digit.

        def latex_kod(kod):
            return latex(
                KodairaSymbol(kod)) if kod > -14 else 'I_{%s}^{*}' % (-kod - 4)

        for P, NP, ld in zip(badprimes, badnorms, local_data):
            ld['p'] = P
            ld['norm'] = NP
            ld['kod'] = latex_kod(ld['kod'])

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label),
                                         class_label=self.iso_label,
                                         number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=quote(
                                         self.conductor_label),
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        # Isogeny information

        self.one_deg = ZZ(self.class_deg).is_prime()
        isodegs = [str(d) for d in self.isodeg if d > 1]
        if len(isodegs) < 3:
            self.isodeg = " and ".join(isodegs)
        else:
            self.isodeg = " and ".join([", ".join(isodegs[:-1]), isodegs[-1]])

        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]

        if totally_real:
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page",
                               field_label=self.field_label,
                               conductor_label=self.conductor_label,
                               isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if sig[0] <= 2 and db.lfunc_instances.exists({'url': origin_url}):
                self.urls['Lfunction'] = lfun_url
            elif self.abs_disc**2 * self.conductor_norm < 70000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for(
                    "l_functions.l_function_hmf_page",
                    field=self.field_label,
                    label=self.hmf_label,
                    character='0',
                    number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage',
                                   field_label=self.field_label,
                                   level_label=self.conductor_label,
                                   label_suffix=self.iso_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page",
                               field_label=self.field_label,
                               conductor_label=self.conductor_label,
                               isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if db.lfunc_instances.exists({'url': origin_url}):
                self.urls['Lfunction'] = lfun_url

        # most of this code is repeated in isog_class.py
        # and should be refactored
        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label,
                          self.urls['class'])]
        self.friends += [('Twists',
                          url_for('ecnf.index',
                                  field=self.field_label,
                                  jinv=rename_j(j)))]
        if totally_real and 'Lfunction' not in self.urls:
            self.friends += [('Hilbert modular form ' + self.hmf_label,
                              self.urls['hmf'])]

        if imag_quadratic:
            if "CM" in self.label:
                self.friends += [('Bianchi modular form is not cuspidal', '')]
            elif 'Lfunction' not in self.urls:
                if db.bmf_forms.label_exists(self.bmf_label):
                    self.friends += [
                        ('Bianchi modular form %s' % self.bmf_label,
                         self.bmf_url)
                    ]
                else:
                    self.friends += [
                        ('(Bianchi modular form %s)' % self.bmf_label, '')
                    ]

        self.properties = [('Label', self.label)]

        # Plot
        if K.signature()[0]:
            self.plot = encode_plot(
                EC_nf_plot(K, self.ainvs, self.field.generator_name()))
            self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(
                self.plot)
            self.properties += [(None, self.plot_link)]
        self.properties += [('Base field', self.field.field_pretty())]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden (can be very large)
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)
        ]

        if self.base_change:
            self.base_change = [
                lab for lab in self.base_change if '?' not in lab
            ]
            self.properties += [
                ('Base change',
                 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))
            ]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Base change', 'no')]
        self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [(r'Base change of %s /\(\Q\)' % E0,
                              url_for("ec.by_ec_label", label=E0))]

        self._code = None  # will be set if needed by get_code()

        self.downloads = [('All stored data to text',
                           url_for(".download_ECNF_all",
                                   nf=self.field_label,
                                   conductor_label=quote(self.conductor_label),
                                   class_label=self.iso_label,
                                   number=self.number))]
        for lang in [["Magma", "magma"], ["GP", "gp"], ["SageMath", "sage"]]:
            self.downloads.append(
                ('Code to {}'.format(lang[0]),
                 url_for(".ecnf_code_download",
                         nf=self.field_label,
                         conductor_label=quote(self.conductor_label),
                         class_label=self.iso_label,
                         number=self.number,
                         download_type=lang[1])))
        self.downloads.append(
            ('Underlying data', url_for(".ecnf_data", label=self.label)))

        if 'Lfunction' in self.urls:
            Lfun = get_lfunction_by_url(
                self.urls['Lfunction'].lstrip('/L').rstrip('/'),
                projection=['degree', 'trace_hash', 'Lhash'])
            if Lfun is None:
                self.friends += [('L-function not available', "")]
            else:
                instances = get_instances_by_Lhash_and_trace_hash(
                    Lfun['Lhash'], Lfun['degree'], Lfun.get('trace_hash'))
                exclude = {
                    elt[1].rstrip('/').lstrip('/')
                    for elt in self.friends if elt[1]
                }
                self.friends += names_and_urls(instances, exclude=exclude)
                self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]
Exemple #28
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()
        self.ncurves = size

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata['ainvs']])
            self.cremona_labels[i - 1] = Edata['label']
            if Edata['number'] == 1:
                self.optimal_flags[i - 1] = True
            if 'degree' in Edata:
                self.degrees[i - 1] = Edata['degree']
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)


        if self.iso == '990h':  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = newform_label(N,2,1,iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso)

        self.curves = [dict([('label',self.lmfdb_iso + str(i + 1)),
                             ('url',url_for(".by_triple_label", conductor=N, iso_label=iso, number=i+1)),
                             ('cremona_label',self.cremona_labels[i]),
                             ('ainvs',str(list(c.ainvs()))),
                             ('torsion',c.torsion_order()),
                             ('degree',self.degrees[i]),
                             ('optimal',self.optimal_flags[i])])
                       for i, c in enumerate(self.db_curves)]

        self.friends =  [('L-function', self.lfunction_link)]
        if not self.CM:
            if int(N)<=300:
                self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso))]
            if int(N)<=50:
                self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', label=self.lmfdb_iso))]
        if self.newform_exists_in_db:
            self.friends +=  [('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(self.ncurves)),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank),
                           ('Graph', ''),(None, self.graph_link)
                           ]


        self.downloads = [('Download coefficients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=1000)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
        self.code = {}
        self.code['show'] = {'sage':''} # use default show names
        self.code['class'] = {'sage':'E = EllipticCurve("%s1")\n'%(self.lmfdb_iso) + 'E.isogeny_class()\n'}
        self.code['curves'] = {'sage':'E.isogeny_class().curves'}
        self.code['rank'] = {'sage':'E.rank()'}
        self.code['q_eigenform'] = {'sage':'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage':'E.isogeny_class().matrix()'}
        self.code['plot'] = {'sage':'E.isogeny_graph().plot(edge_labels=True)'}
Exemple #29
0
def plot_from_label(label):
    curve = db.g2c_curves.lookup(label)
    ratpts = db.g2c_ratpts.lookup(curve['label'])
    min_eqn = literal_eval(curve['eqn'])
    plot = encode_plot(eqn_list_to_curve_plot(min_eqn, ratpts['rat_pts']))
    return plot
Exemple #30
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these, construct the
        # actual elliptic curve E, and compute some further (easy)
        # data about it.
        #

        # Weierstrass equation

        data = self.data = {}
        data["ainvs"] = [int(ai) for ai in self.ainvs]
        self.E = EllipticCurve(data["ainvs"])
        data["equation"] = web_latex(self.E)

        # conductor, j-invariant and discriminant

        data["conductor"] = N = ZZ(self.conductor)
        bad_primes = N.prime_factors()
        try:
            data["j_invariant"] = QQ(str(self.jinv))
        except KeyError:
            data["j_invariant"] = self.E.j_invariant()
        data["j_inv_factor"] = latex(0)
        if data["j_invariant"]:
            data["j_inv_factor"] = latex(data["j_invariant"].factor())
        data["j_inv_str"] = unicode(str(data["j_invariant"]))
        data["j_inv_latex"] = web_latex(data["j_invariant"])
        data["disc"] = D = self.E.discriminant()
        data["disc_latex"] = web_latex(data["disc"])
        data["disc_factor"] = latex(data["disc"].factor())
        data["cond_factor"] = latex(N.factor())
        data["cond_latex"] = web_latex(N)

        # CM and endomorphism ring

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

        # modular degree

        try:
            data["degree"] = self.degree
        except AttributeError:
            try:
                data["degree"] = self.E.modular_degree()
            except RuntimeError:
                data["degree"]  # invalid, but will be displayed nicely

        # Minimal quadratic twist

        E_pari = self.E.pari_curve()
        from sage.libs.pari.all import PariError

        try:
            minq, minqD = self.E.minimal_quadratic_twist()
        except PariError:  # this does occur with 164411a1
            ec.debug("PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label)
            minq = self.E
            minqD = 1
        data["minq_D"] = minqD
        if self.E == minq:
            data["minq_label"] = self.lmfdb_label
            data["minq_info"] = "(itself)"
        else:
            minq_ainvs = [str(c) for c in minq.ainvs()]
            data["minq_label"] = db_ec().find_one({"jinv": str(self.E.j_invariant()), "ainvs": minq_ainvs})[
                "lmfdb_label"
            ]
            data["minq_info"] = "(by %s)" % minqD

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

        # rational and integral points

        mw = self.mw = {}

        xintpoints_projective = [self.E.lift_x(x) for x in self.xintcoords]
        xintpoints = [P.xy() for P in xintpoints_projective]
        mw["int_points"] = ", ".join(web_latex(P) for P in xintpoints)

        # Generators of infinite order

        mw["rank"] = self.rank
        try:
            self.generators = [self.E(g) for g in parse_points(self.gens)]
            mw["generators"] = [web_latex(P.xy()) for P in self.generators]
            mw["heights"] = [P.height() for P in self.generators]
        except AttributeError:
            mw["generators"] = ""
            mw["heights"] = []

        # Torsion subgroup: order, structure, generators

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

        # Images of Galois representations

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

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

        if self.twoadic_gens:
            from sage.matrix.all import Matrix

            data["twoadic_gen_matrices"] = ",".join([latex(Matrix(2, 2, M)) for M in self.twoadic_gens])
            data["twoadic_rouse_url"] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"
        # Leading term of L-function & BSD data

        bsd = self.bsd = {}

        r = self.rank
        if r >= 2:
            bsd["lder_name"] = "L^{(%s)}(E,1)/%s!" % (r, r)
        elif r:
            bsd["lder_name"] = "L'(E,1)"
        else:
            bsd["lder_name"] = "L(E,1)"

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

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

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

        data["p_adic_data_exists"] = False
        if data["Gamma0optimal"]:
            data["p_adic_data_exists"] = (padic_db().find({"lmfdb_iso": self.lmfdb_iso}).count()) > 0
        data["p_adic_primes"] = [p for p in sage.all.prime_range(5, 100) if self.E.is_ordinary(p) and not p.divides(N)]

        # Local data

        local_data = self.local_data = []
        # if we use E.tamagawa_numbers() it calls E.local_data(p) which
        # used to crash on some curves e.g. 164411a1
        tamagawa_numbers = []
        for p in bad_primes:
            local_info = self.E.local_data(p, algorithm="generic")
            local_data_p = {}
            local_data_p["p"] = p
            local_data_p["tamagawa_number"] = local_info.tamagawa_number()
            tamagawa_numbers.append(ZZ(local_info.tamagawa_number()))
            local_data_p["kodaira_symbol"] = web_latex(local_info.kodaira_symbol()).replace("$", "")
            local_data_p["reduction_type"] = local_info.bad_reduction_type()
            local_data_p["ord_cond"] = local_info.conductor_valuation()
            local_data_p["ord_disc"] = local_info.discriminant_valuation()
            local_data_p["ord_den_j"] = max(0, -self.E.j_invariant().valuation(p))
            local_data.append(local_data_p)

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

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        data["newform"] = web_latex(self.E.q_eigenform(10))
        self.newform_label = newform_label(cond, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=cond, weight=2, character=1, label=iso)
        newform_exists_in_db = is_newform_in_db(self.newform_label)
        self._code = None

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

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

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

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

        self.bread = [
            ("Elliptic Curves", url_for("ecnf.index")),
            ("$\Q$", url_for(".rational_elliptic_curves")),
            ("%s" % N, url_for(".by_conductor", conductor=N)),
            ("%s" % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)),
            ("%s" % num, " "),
        ]
Exemple #31
0
    def make_E(self):
        #print("Creating ECNF object for {}".format(self.label))
        #sys.stdout.flush()
        K = self.field.K()

        # a-invariants
        self.ainvs = parse_ainvs(K, self.ainvs)
        self.latex_ainvs = web_latex(self.ainvs)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        if self.conductor_norm == 1:
            N = K.ideal(1)
        else:
            N = ideal_from_string(K, self.conductor_ideal)
        # The following can trigger expensive computations!
        #self.cond = web_latex(N)
        self.cond = pretty_ideal(N)
        self.cond_norm = web_latex(self.conductor_norm)
        local_data = self.local_data

        # NB badprimes is a list of primes which divide the
        # discriminant of this model.  At most one of these might
        # actually be a prime of good reduction, if the curve has no
        # global minimal model.
        badprimes = [ideal_from_string(K, ld['p']) for ld in local_data]
        badnorms = [ZZ(ld['normp']) for ld in local_data]
        mindisc_ords = [ld['ord_disc'] for ld in local_data]

        # Assumption: the curve models stored in the database are
        # either global minimal models or minimal at all but one
        # prime, so the list here has length 0 or 1:

        self.non_min_primes = [ideal_from_string(K, P) for P in self.non_min_p]
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = self.is_minimal
        disc_ords = [ld['ord_disc'] for ld in local_data]
        if not self.is_minimal:
            Pmin = self.non_min_primes[0]
            P_index = badprimes.index(Pmin)
            self.non_min_prime = pretty_ideal(Pmin)
            disc_ords[P_index] += 12

        if self.conductor_norm == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
            self.fact_cond_norm = '1'
        else:
            Nfac = Factorization([(P, ld['ord_cond'])
                                  for P, ld in zip(badprimes, local_data)])
            self.fact_cond = web_latex_ideal_fact(Nfac)
            Nnormfac = Factorization([(q, ld['ord_cond'])
                                      for q, ld in zip(badnorms, local_data)])
            self.fact_cond_norm = web_latex(Nnormfac)

        # D is the discriminant ideal of the model
        D = prod([P**e for P, e in zip(badprimes, disc_ords)], K.ideal(1))
        self.disc = pretty_ideal(D)
        Dnorm = D.norm()
        self.disc_norm = web_latex(Dnorm)
        if Dnorm == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
            self.fact_disc_norm = '1'
        else:
            Dfac = Factorization([(P, e)
                                  for P, e in zip(badprimes, disc_ords)])
            self.fact_disc = web_latex_ideal_fact(Dfac)
            Dnormfac = Factorization([(q, e)
                                      for q, e in zip(badnorms, disc_ords)])
            self.fact_disc_norm = web_latex(Dnormfac)

        if not self.is_minimal:
            Dmin = ideal_from_string(K, self.minD)
            self.mindisc = pretty_ideal(Dmin)
            Dmin_norm = Dmin.norm()
            self.mindisc_norm = web_latex(Dmin_norm)
            if Dmin_norm == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
                self.fact_mindisc_norm = self.mindisc_norm
            else:
                Dminfac = Factorization(list(zip(badprimes, mindisc_ords)))
                self.fact_mindisc = web_latex_ideal_fact(Dminfac)
                Dminnormfac = Factorization(list(zip(badnorms, mindisc_ords)))
                self.fact_mindisc_norm = web_latex(Dminnormfac)

        j = self.field.parse_NFelt(self.jinv)
        # if j:
        #     d = j.denominator()
        #     n = d * j  # numerator exists for quadratic fields only!
        #     g = GCD(list(n))
        #     n1 = n / g
        #     self.j = web_latex(n1)
        #     if d != 1:
        #         if n1 > 1:
        #         # self.j = "("+self.j+")\(/\)"+web_latex(d)
        #             self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
        #         else:
        #             self.j = web_latex(d)
        #         if g > 1:
        #             if n1 > 1:
        #                 self.j = web_latex(g) + self.j
        #             else:
        #                 self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        # See issue 1258: some j factorizations work but take too long
        # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1).  Note that we do
        # store the factorization of the denominator of j and display
        # that, which is the most interesting part.

        # The equation is stored in the database as a latex string.
        # Some of these have extraneous double quotes at beginning and
        # end, shich we fix here.  We also strip out initial \( and \)
        # (if present) which are added in the template.
        self.equation = self.equation.replace('"', '').replace('\\(',
                                                               '').replace(
                                                                   '\\)', '')

        # Images of Galois representations

        if not hasattr(self, 'galois_images'):
            #print "No Galois image data"
            self.galois_images = "?"
            self.non_surjective_primes = "?"
            self.galois_data = []
        else:
            self.galois_data = [{
                'p': p,
                'image': im
            } for p, im in zip(self.non_surjective_primes, self.galois_images)]

        # CM and End(E)
        self.cm_bool = "no"
        self.End = r"\(\Z\)"
        if self.cm:
            # When we switch to storing rational cm by having |D| in
            # the column, change the following lines:
            if self.cm > 0:
                self.rational_cm = True
                self.cm = -self.cm
            else:
                self.rational_cm = K(self.cm).is_square()
            self.cm_sqf = ZZ(self.cm).squarefree_part()
            self.cm_bool = r"yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = r"\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = r"\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Galois images in CM case:
        if self.cm and self.galois_images != '?':
            self.cm_ramp = [
                p for p in ZZ(self.cm).support()
                if not p in self.non_surjective_primes
            ]
            self.cm_nramp = len(self.cm_ramp)
            if self.cm_nramp == 1:
                self.cm_ramp = self.cm_ramp[0]
            else:
                self.cm_ramp = ", ".join([str(p) for p in self.cm_ramp])

        # Sato-Tate:
        # The lines below will need to change once we have curves over non-quadratic fields
        # that contain the Hilbert class field of an imaginary quadratic field
        if self.cm:
            if self.signature == [0, 1] and ZZ(
                    -self.abs_disc * self.cm).is_square():
                self.ST = st_link_by_name(1, 2, 'U(1)')
            else:
                self.ST = st_link_by_name(1, 2, 'N(U(1))')
        else:
            self.ST = st_link_by_name(1, 2, 'SU(2)')

        # Q-curve / Base change
        try:
            qc = self.q_curve
            if qc is True:
                self.qc = "yes"
            elif qc is False:
                self.qc = "no"
            else:  # just in case
                self.qc = "not determined"
        except AttributeError:
            self.qc = "not determined"

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "trivial"
        if self.tr == 1:
            self.tor_struct_pretty = r"\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(
                self.torsion_structure)

        self.torsion_gens = [
            web_point(parse_point(K, P)) for P in self.torsion_gens
        ]

        # BSD data
        #
        # We divide into 3 cases, based on rank_bounds [lb,ub],
        # analytic_rank ar, (lb=ngens always).  The flag
        # self.bsd_status is set to one of the following:
        #
        # "unconditional"
        #     lb=ar=ub: we always have reg but in some cases over sextic fields we do not have omega, Lvalue, sha.
        #     i.e. [lb,ar,ub] = [r,r,r]
        #
        # "conditional"
        #     lb=ar<ub: we always have reg but in some cases over sextic fields we do not have omega, Lvalue, sha.
        #     e.g. [lb,ar,ub] = [0,0,2], [1,1,3]
        #
        # "missing_gens"
        #     lb<ar<=ub
        #     e.g. [lb,ar,ub] = [0,1,1], [0,2,2], [1,2,2], [0,1,3]
        #
        # "incomplete"
        #     ar not computed.  (We can always set lb=0, ub=Infinity.)

        # Rank and bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rank = None
            self.rk = "not available"

        try:
            self.rk_lb, self.rk_ub = self.rank_bounds
        except AttributeError:
            self.rk_lb = 0
            self.rk_ub = Infinity
            self.rank_bounds = "not available"

        # Analytic rank
        try:
            self.ar = web_latex(self.analytic_rank)
        except AttributeError:
            self.analytic_rank = None
            self.ar = "not available"

        # for debugging:
        assert self.rk == "not available" or (self.rk_lb == self.rank
                                              and self.rank == self.rk_ub)
        assert self.ar == "not available" or (self.rk_lb <= self.analytic_rank
                                              and
                                              self.analytic_rank <= self.rk_ub)

        self.bsd_status = "incomplete"
        if self.analytic_rank != None:
            if self.rk_lb == self.rk_ub:
                self.bsd_status = "unconditional"
            elif self.rk_lb == self.analytic_rank:
                self.bsd_status = "conditional"
            else:
                self.bsd_status = "missing_gens"

        # Regulator only in conditional/unconditional cases, or when we know the rank:
        if self.bsd_status in ["conditional", "unconditional"]:
            if self.ar == 0:
                self.reg = web_latex(1)  # otherwise we only get 1.00000...
            else:
                try:
                    self.reg = web_latex(self.reg)
                except AttributeError:
                    self.reg = "not available"
        elif self.rk != "not available":
            self.reg = web_latex(self.reg) if self.rank else web_latex(1)
        else:
            self.reg = "not available"

        # Generators
        try:
            self.gens = [web_point(parse_point(K, P)) for P in self.gens]
        except AttributeError:
            self.gens = []

        # Global period
        try:
            self.omega = web_latex(self.omega)
        except AttributeError:
            self.omega = "not available"

        # L-value
        try:
            r = int(self.analytic_rank)
            # lhs = "L(E,1) = " if r==0 else "L'(E,1) = " if r==1 else "L^{{({})}}(E,1)/{}! = ".format(r,r)
            self.Lvalue = "\\(" + str(self.Lvalue) + "\\)"
        except (TypeError, AttributeError):
            self.Lvalue = "not available"

        # Tamagawa product
        tamagawa_numbers = [ZZ(_ld['cp']) for _ld in self.local_data]
        cp_fac = [cp.factor() for cp in tamagawa_numbers]
        cp_fac = [
            latex(cp) if len(cp) < 2 else '(' + latex(cp) + ')'
            for cp in cp_fac
        ]
        if len(cp_fac) > 1:
            self.tamagawa_factors = r'\cdot'.join(cp_fac)
        else:
            self.tamagawa_factors = None
        self.tamagawa_product = web_latex(prod(tamagawa_numbers, 1))

        # Analytic Sha
        try:
            self.sha = web_latex(self.sha) + " (rounded)"
        except AttributeError:
            self.sha = "not available"

        # Local data

        # Fix for Kodaira symbols, which in the database start and end
        # with \( and \) and may have multiple backslashes.  Note that
        # to put a single backslash into a python string you have to
        # use '\\' which will display as '\\' but only counts as one
        # character in the string.  which are added in the template.
        def tidy_kod(kod):
            while '\\\\' in kod:
                kod = kod.replace('\\\\', '\\')
            kod = kod.replace('\\(', '').replace('\\)', '')
            return kod

        for P, ld in zip(badprimes, local_data):
            ld['p'] = web_latex(P)
            ld['norm'] = P.norm()
            ld['kod'] = tidy_kod(ld['kod'])

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label),
                                         class_label=self.iso_label,
                                         number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=quote(
                                         self.conductor_label),
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        # Isogeny information

        self.one_deg = ZZ(self.class_deg).is_prime()
        isodegs = [str(d) for d in self.isodeg if d > 1]
        if len(isodegs) < 3:
            self.isodeg = " and ".join(isodegs)
        else:
            self.isodeg = " and ".join([", ".join(isodegs[:-1]), isodegs[-1]])

        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]

        if totally_real:
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page",
                               field_label=self.field_label,
                               conductor_label=self.conductor_label,
                               isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if sig[0] <= 2 and db.lfunc_instances.exists({'url': origin_url}):
                self.urls['Lfunction'] = lfun_url
            elif self.abs_disc**2 * self.conductor_norm < 70000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for(
                    "l_functions.l_function_hmf_page",
                    field=self.field_label,
                    label=self.hmf_label,
                    character='0',
                    number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage',
                                   field_label=self.field_label,
                                   level_label=self.conductor_label,
                                   label_suffix=self.iso_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page",
                               field_label=self.field_label,
                               conductor_label=self.conductor_label,
                               isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if db.lfunc_instances.exists({'url': origin_url}):
                self.urls['Lfunction'] = lfun_url

        # most of this code is repeated in isog_class.py
        # and should be refactored
        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label,
                          self.urls['class'])]
        self.friends += [('Twists',
                          url_for('ecnf.index',
                                  field=self.field_label,
                                  jinv=rename_j(j)))]
        if totally_real and not 'Lfunction' in self.urls:
            self.friends += [('Hilbert modular form ' + self.hmf_label,
                              self.urls['hmf'])]

        if imag_quadratic:
            if "CM" in self.label:
                self.friends += [('Bianchi modular form is not cuspidal', '')]
            elif not 'Lfunction' in self.urls:
                if db.bmf_forms.label_exists(self.bmf_label):
                    self.friends += [
                        ('Bianchi modular form %s' % self.bmf_label,
                         self.bmf_url)
                    ]
                else:
                    self.friends += [
                        ('(Bianchi modular form %s)' % self.bmf_label, '')
                    ]

        self.properties = [('Label', self.label)]

        # Plot
        if K.signature()[0]:
            self.plot = encode_plot(
                EC_nf_plot(K, self.ainvs, self.field.generator_name()))
            self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(
                self.plot)
            self.properties += [(None, self.plot_link)]
        self.properties += [('Base field', self.field.field_pretty())]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden (can be very large)
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)
        ]

        if self.base_change:
            self.properties += [
                ('Base change',
                 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))
            ]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Base change', 'no')]
        self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [(r'Base change of %s /\(\Q\)' % E0,
                              url_for("ec.by_ec_label", label=E0))]

        self._code = None  # will be set if needed by get_code()

        self.downloads = [('All stored data to text',
                           url_for(".download_ECNF_all",
                                   nf=self.field_label,
                                   conductor_label=quote(self.conductor_label),
                                   class_label=self.iso_label,
                                   number=self.number))]
        for lang in [["Magma", "magma"], ["SageMath", "sage"], ["GP", "gp"]]:
            self.downloads.append(
                ('Code to {}'.format(lang[0]),
                 url_for(".ecnf_code_download",
                         nf=self.field_label,
                         conductor_label=quote(self.conductor_label),
                         class_label=self.iso_label,
                         number=self.number,
                         download_type=lang[1])))

        if 'Lfunction' in self.urls:
            Lfun = get_lfunction_by_url(
                self.urls['Lfunction'].lstrip('/L').rstrip('/'),
                projection=['degree', 'trace_hash', 'Lhash'])
            if Lfun is None:
                self.friends += [('L-function not available', "")]
            else:
                instances = get_instances_by_Lhash_and_trace_hash(
                    Lfun['Lhash'], Lfun['degree'], Lfun.get('trace_hash'))
                exclude = {
                    elt[1].rstrip('/').lstrip('/')
                    for elt in self.friends if elt[1]
                }
                self.friends += names_and_urls(instances, exclude=exclude)
                self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]
Exemple #32
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

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

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

        data = self.data = {}
        data['ainvs'] = self.ainvs
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:  # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])

        # extract data about MW rank, generators, heights and torsion:
        self.make_mw()

        # get more data from the database entry

        data['equation'] = self.equation
        local_data = self.local_data
        D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data])
        data['disc'] = D
        Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond'])
                              for ld in local_data])
        Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc'])
                              for ld in local_data],
                             unit=ZZ(self.signD))

        data['minq_D'] = minqD = self.min_quad_twist['disc']
        minq_label = self.min_quad_twist['label']
        data['minq_label'] = db.ec_curves.lucky({'label': minq_label},
                                                'lmfdb_label')
        data['minq_info'] = '(itself)' if minqD == 1 else '(by %s)' % minqD
        if self.degree is None:
            data['degree'] = 0  # invalid, but will be displayed nicely
        else:
            data['degree'] = self.degree
        if self.number == 1:
            data['an'] = self.anlist
            data['ap'] = self.aplist
        else:
            r = db.ec_curves.lucky({'lmfdb_iso': self.lmfdb_iso, 'number': 1})
            data['an'] = r['anlist']
            data['ap'] = r['aplist']

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

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

        data['galois_images'] = [
            trim_galois_image_code(s) for s in self.mod_p_images
        ]
        data['non_maximal_primes'] = self.non_maximal_primes
        data['galois_data'] = [{
            'p': p,
            'image': im
        } for p, im in zip(data['non_maximal_primes'], data['galois_images'])]

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['cm_ramp'] = [
                p for p in ZZ(self.cm).support()
                if not p in self.non_maximal_primes
            ]
            data['cm_nramp'] = len(data['cm_ramp'])
            if data['cm_nramp'] == 1:
                data['cm_ramp'] = data['cm_ramp'][0]
            else:
                data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']])
            data['cm_sqf'] = ZZ(self.cm).squarefree_part()

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

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

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

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

        # Leading term of L-function & other BSD data
        self.make_bsd()

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

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

        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = db.ec_padic.exists(
                {'lmfdb_iso': self.lmfdb_iso})

        # Iwasawa data (where present)

        self.make_iwasawa()

        # Torsion growth data (where present)

        self.make_torsion_growth()

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

        self.class_url = url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)
        self.friends = [('Isogeny class ' + self.lmfdb_iso, self.class_url),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_triple_label",
                                 conductor=minq_N,
                                 iso_label=minq_iso,
                                 number=minq_number)),
                        ('All twists ',
                         url_for(".rational_elliptic_curves", jinv=self.jinv)),
                        ('L-function',
                         url_for("l_functions.l_function_ec_page",
                                 conductor_label=N,
                                 isogeny_class_label=iso))]

        if not self.cm:
            if N <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=N,
                                          isogeny=iso))]
            if N <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=N,
                                          isogeny=iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

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

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

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

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

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]
Exemple #33
0
    def make_class(self):
        self.CM = self.cm
        N, iso, number = split_lmfdb_label(self.lmfdb_iso)
        self.conductor = int(N)
        # Extract the size of the isogeny class from the database
        self.ncurves = ncurves = self.class_size
        # Create a list of the curves in the class from the database
        number_key = 'number' if self.label_type == 'Cremona' else 'lmfdb_number'
        self.curves = [
            db.ec_curves.lucky({
                'iso': self.iso,
                number_key: i + 1
            }) for i in range(ncurves)
        ]

        # Set optimality flags.  The optimal curve is number 1 except
        # in one case which is labeled differently in the Cremona tables
        self.optimality_known = (self.ncurves
                                 == 1) or (self.conductor < OPTIMALITY_BOUND)
        self.optimality_bound = OPTIMALITY_BOUND
        for c in self.curves:
            c['optimal'] = (c['number'] == (3 if self.iso == '990h' else 1))
            c['ai'] = c['ainvs']
            c['curve_url_lmfdb'] = url_for(".by_triple_label",
                                           conductor=N,
                                           iso_label=iso,
                                           number=c['lmfdb_number'])
            c['curve_url_cremona'] = url_for(".by_ec_label", label=c['label'])
            if self.label_type == 'Cremona':
                c['curve_label'] = c['label']
                _, c_iso, c_number = split_cremona_label(c['label'])
            else:
                c['curve_label'] = c['lmfdb_label']
                _, c_iso, c_number = split_lmfdb_label(c['lmfdb_label'])
            c['short_label'] = "{}{}".format(c_iso, c_number)

        from sage.matrix.all import Matrix
        if self.label_type == 'Cremona':
            # permute rows/cols
            perm = lambda i: (c for c in self.curves if c['number'] == i + 1
                              ).next()['lmfdb_number'] - 1
            self.isogeny_matrix = [[
                self.isogeny_matrix[perm(i)][perm(j)] for i in range(ncurves)
            ] for j in range(ncurves)]

        self.isogeny_matrix = Matrix(self.isogeny_matrix)

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        # Create isogeny graph with appropriate vertex labels:

        self.graph = make_graph(self.isogeny_matrix,
                                [c['short_label'] for c in self.curves])
        P = self.graph.plot(edge_labels=True, vertex_size=1000)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        self.newform = web_latex(
            PowerSeriesRing(QQ, 'q')(self.anlist, 20, check=True))
        self.newform_label = db.mf_newforms.lucky(
            {
                'level': N,
                'weight': 2,
                'related_objects': {
                    '$contains': 'EllipticCurve/Q/%s/%s' % (N, iso)
                }
            }, 'label')
        self.newform_exists_in_db = self.newform_label is not None
        if self.newform_label is not None:
            char_orbit, hecke_orbit = self.newform_label.split('.')[2:]
            self.newform_link = url_for("cmf.by_url_newform_label",
                                        level=N,
                                        weight=2,
                                        char_orbit_label=char_orbit,
                                        hecke_orbit=hecke_orbit)

        self.lfunction_link = url_for("l_functions.l_function_ec_page",
                                      conductor_label=N,
                                      isogeny_class_label=iso)

        self.friends = [('L-function', self.lfunction_link)]
        if not self.CM:
            self.CM = "no"
            if int(N) <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=N,
                                          isogeny=iso))]
            if int(N) <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=N,
                                          isogeny=iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        if self.label_type == 'Cremona':
            self.title = "Elliptic Curve Isogeny Class with Cremona label {} (LMFDB label {})".format(
                self.iso, self.lmfdb_iso)
            self.iso_label = self.iso
        else:
            self.title = "Elliptic Curve Isogeny Class with LMFDB label {} (Cremona label {})".format(
                self.lmfdb_iso, self.iso)
            self.iso_label = self.lmfdb_iso

        self.properties = [
            ('Label',
             self.iso if self.label_type == 'Cremona' else self.lmfdb_iso),
            ('Number of curves', str(ncurves)), ('Conductor', '%s' % N),
            ('CM', '%s' % self.CM), ('Rank', '%s' % self.rank)
        ]
        if self.ncurves > 1:
            self.properties += [('Graph', ''), (None, self.graph_link)]

        self.downloads = [('q-expansion to text',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_iso,
                                   limit=1000)),
                          ('All stored data to text',
                           url_for(".download_EC_all", label=self.lmfdb_iso))]

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
        self.code = {}
        self.code['show'] = {'sage': ''}  # use default show names
        self.code['class'] = {
            'sage':
            'E = EllipticCurve("%s1")\n' % (self.lmfdb_iso) +
            'E.isogeny_class()\n'
        }
        self.code['curves'] = {'sage': 'E.isogeny_class().curves'}
        self.code['rank'] = {'sage': 'E.rank()'}
        self.code['q_eigenform'] = {'sage': 'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage': 'E.isogeny_class().matrix()'}
        self.code['plot'] = {
            'sage': 'E.isogeny_graph().plot(edge_labels=True)'
        }
Exemple #34
0
    def make_E(self):
        coeffs = self.ainvs  # list of 5 lists of d strings
        self.ainvs = [self.field.parse_NFelt(x) for x in coeffs]
        self.latex_ainvs = web_latex(self.ainvs)
        from sage.schemes.elliptic_curves.all import EllipticCurve
        self.E = E = EllipticCurve(self.ainvs)
        self.equn = web_latex(E)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = E.conductor()
        self.cond = web_latex(N)
        self.cond_norm = web_latex(N.norm())
        if N.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
        else:
            self.fact_cond = web_latex_ideal_fact(N.factor())
        self.fact_cond_norm = web_latex(N.norm().factor())

        D = self.field.K().ideal(E.discriminant())
        self.disc = web_latex(D)
        self.disc_norm = web_latex(D.norm())
        if D.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
        else:
            self.fact_disc = web_latex_ideal_fact(D.factor())
        self.fact_disc_norm = web_latex(D.norm().factor())

        # Minimal model?
        #
        # All curves in the database should be given
        # by models which are globally minimal if possible, else
        # minimal at all but one prime.  But we do not rely on this
        # here, and the display should be correct if either (1) there
        # exists a global minimal model but this model is not; or (2)
        # this model is non-minimal at more than one prime.
        #
        self.non_min_primes = non_minimal_primes(E)
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = True
        if not self.is_minimal:
            self.non_min_prime = ','.join([web_latex(P) for P in self.non_min_primes])
            self.has_minimal_model = has_global_minimal_model(E)

        if not self.is_minimal:
            Dmin = minimal_discriminant_ideal(E)
            self.mindisc = web_latex(Dmin)
            self.mindisc_norm = web_latex(Dmin.norm())
            if Dmin.norm() == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
            else:
                self.fact_mindisc = web_latex_ideal_fact(Dmin.factor())
            self.fact_mindisc_norm = web_latex(Dmin.norm().factor())

        j = E.j_invariant()
        if j:
            d = j.denominator()
            n = d * j  # numerator exists for quadratic fields only!
            g = GCD(list(n))
            n1 = n / g
            self.j = web_latex(n1)
            if d != 1:
                if n1 > 1:
                # self.j = "("+self.j+")\(/\)"+web_latex(d)
                    self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
                else:
                    self.j = web_latex(d)
                if g > 1:
                    if n1 > 1:
                        self.j = web_latex(g) + self.j
                    else:
                        self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        # See issue 1258: some j factorizations work bu take too long (e.g. EllipticCurve/6.6.371293.1/1.1/a/1)
        # If these are really wanted, they could be precomputed and stored in the db
        if j.is_zero():
            self.fact_j = web_latex(j)
        else:
            if self.field.K().degree() < 3: #j.numerator_ideal().norm()<1000000000000:
                try:
                    self.fact_j = web_latex(j.factor())
                except (ArithmeticError, ValueError):  # if not all prime ideal factors principal
                    pass

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm
            # The line below will need to change once we have curves over non-quadratic fields
            # that contain the Hilbert class field of an imaginary quadratic field
            if self.signature == [0,1] and ZZ(-self.abs_disc*self.cm).is_square():
                self.ST = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.U(1)'),'\\mathrm{U}(1)')
            else:
                self.ST = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.N(U(1))'),'N(\\mathrm{U}(1))')
        else:
            self.ST = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.SU(2)'),'\\mathrm{SU}(2)')

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure)
        torsion_gens = [E([self.field.parse_NFelt(x) for x in P])
                        for P in self.torsion_gens]
        self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens])

        # Rank or bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.rank_bounds)
        except AttributeError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not available"

        # Generators
        try:
            gens = [E([self.field.parse_NFelt(x) for x in P])
                    for P in self.gens]
            self.gens = ", ".join([web_latex(P) for P in gens])
            if self.rk == "?":
                self.reg = "not available"
            else:
                if gens:
                    self.reg = E.regulator_of_points(gens)
                else:
                    self.reg = 1  # otherwise we only get 1.00000...

        except AttributeError:
            self.gens = "not available"
            self.reg = "not available"
            try:
                if self.rank == 0:
                    self.reg = 1
            except AttributeError:
                pass

        # Local data
        self.local_data = []
        for p in N.prime_factors():
            self.local_info = E.local_data(p, algorithm="generic")
            self.local_data.append({'p': web_latex(p),
                                    'norm': web_latex(p.norm().factor()),
                                    'tamagawa_number': self.local_info.tamagawa_number(),
                                    'kodaira_symbol': web_latex(self.local_info.kodaira_symbol()).replace('$', ''),
                                    'reduction_type': self.local_info.bad_reduction_type(),
                                    'ord_den_j': max(0, -E.j_invariant().valuation(p)),
                                    'ord_mindisc': self.local_info.discriminant_valuation(),
                                    'ord_cond': self.local_info.conductor_valuation()
                                    })

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        sig = self.signature
        real_quadratic = sig == [2,0]
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0,1]

        if totally_real:
            self.hmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field.label, label=self.hmf_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0')

        if imag_quadratic:
            self.bmf_label = "-".join([self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])]
        self.friends += [('Twists', url_for('ecnf.index', field_label=self.field_label, jinv=self.jinv))]
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])]
            self.friends += [('L-function', self.urls['Lfunction'])]
        if imag_quadratic:
            self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')]

        self.properties = [
            ('Base field', self.field.field_pretty()),
            ('Label', self.label)]

        # Plot
        if E.base_field().signature()[0]:
            self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)]

        if self.base_change:
            self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))]

        self._code = None # will be set if needed by get_code()
Exemple #35
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()
        self.ncurves = size

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata['ainvs']])
            self.cremona_labels[i - 1] = Edata['label']
            if Edata['number'] == 1:
                self.optimal_flags[i - 1] = True
            if 'degree' in Edata:
                self.degrees[i - 1] = Edata['degree']
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)

        if self.iso == '990h':  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = newform_label(N, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms",
                                    level=N,
                                    weight=2,
                                    character=1,
                                    label=iso)
        newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page",
                                      label=self.lmfdb_iso)

        self.curves = [
            dict([('label', self.lmfdb_iso + str(i + 1)),
                  ('url',
                   url_for(".by_triple_label",
                           conductor=N,
                           iso_label=iso,
                           number=i + 1)),
                  ('cremona_label', self.cremona_labels[i]),
                  ('ainvs', str(list(c.ainvs()))),
                  ('torsion', c.torsion_order()), ('degree', self.degrees[i]),
                  ('optimal', self.optimal_flags[i])])
            for i, c in enumerate(self.db_curves)
        ]

        self.friends = [('L-function', self.lfunction_link)]
        if not self.CM:
            if int(N) <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          label=self.lmfdb_iso))]
            if int(N) <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          label=self.lmfdb_iso))]
        if newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(self.ncurves)),
                           ('Conductor', '\(%s\)' % N), ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank), ('Graph', ''),
                           (None, self.graph_link)]

        self.downloads = [('Download coefficients of newform',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_iso,
                                   limit=100)),
                          ('Download stored data for all curves',
                           url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (
                self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
Exemple #36
0
    def make_class(self):

        # Create a list of the curves in the class from the database
        self.db_curves = [
            c for c in db_ecnf().find({
                'field_label': self.field_label,
                'conductor_norm': self.conductor_norm,
                'conductor_label': self.conductor_label,
                'iso_nlabel': self.iso_nlabel
            }).sort('number')
        ]

        # Rank or bounds
        try:
            self.rk = web_latex(self.db_curves[0]['rank'])
        except KeyError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds'])
        except KeyError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not recorded"

        # Extract the isogeny degree matrix from the database
        if not hasattr(self, 'isogeny_matrix'):
            # this would happen if the class is initiated with a curve
            # which is not #1 in its class:
            self.isogeny_matrix = self.db_curves[0].isogeny_matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.one_deg = ZZ(self.class_deg).is_prime()

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(Matrix(self.isogeny_matrix))

        self.field = FIELD(self.field_label)
        self.field_name = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label,
                                            lmfdb.base.getDBConnection(),
                                            self.field_name)

        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[
            c['short_label'],
            curve_url(c),
            web_ainvs(self.field_label, c['ainvs'])
        ] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]
        if totally_real:
            self.hmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field_label,
                                       label=self.hmf_label)
            if sig[0] <= 2:
                self.urls['Lfunction'] = url_for(
                    "l_functions.l_function_ecnf_page",
                    field_label=self.field_label,
                    conductor_label=self.conductor_label,
                    isogeny_class_label=self.iso_label)
            elif self.abs_disc**2 * self.conductor_norm < 40000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for(
                    "l_functions.l_function_hmf_page",
                    field=self.field_label,
                    label=self.hmf_label,
                    character='0',
                    number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage',
                                   field_label=self.field_label,
                                   level_label=self.conductor_label,
                                   label_suffix=self.iso_label)
            self.urls['Lfunction'] = url_for(
                "l_functions.l_function_ecnf_page",
                field_label=self.field_label,
                conductor_label=self.conductor_label,
                isogeny_class_label=self.iso_label)

        self.friends = []
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]

        if imag_quadratic:
            #self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')]
            self.friends += [('Bianchi Modular Form %s' % self.bmf_label,
                              self.bmf_url)]

        if 'Lfunction' in self.urls:
            self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]

        self.properties = [('Base field', self.field_name),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)]
        if self.rk != '?':
            self.properties += [('Rank', '%s' % self.rk)]
        else:
            if self.rk_bnds == 'not recorded':
                self.properties += [('Rank', '%s' % self.rk_bnds)]
            else:
                self.properties += [('Rank bounds', '%s' % self.rk_bnds)]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label,
                       self.urls['class'])]
Exemple #37
0
    def make_object(self, curve, endo, tama, ratpts, 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'] = curve['Lhash']
        data['cond'] = ZZ(curve['cond'])
        data['cond_factor_latex'] = web_latex(factor(int(data['cond'])))
        data['analytic_rank'] = ZZ(curve['analytic_rank'])
        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['disc_key'][3:]) # use disc_key rather than abs_disc (will work when abs_disc > 2^63)
            data['disc'] = curve['disc_sign'] * curve['abs_disc']
            data['min_eqn'] = literal_eval(curve['eqn'])
            data['min_eqn_display'] = list_to_min_eqn(data['min_eqn'])
            data['disc_factor_latex'] = web_latex(factor(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(zfactor(i)) for i in data['igusa_clebsch']]
            data['igusa_factor_latex'] = [ web_latex(zfactor(j)) for j in data['igusa'] ]
            data['aut_grp_id'] = curve['aut_grp_id']
            data['geom_aut_grp_id'] = curve['geom_aut_grp_id']
            data['num_rat_wpts'] = ZZ(curve['num_rat_wpts'])
            data['two_selmer_rank'] = ZZ(curve['two_selmer_rank'])
            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['torsion_order'] = curve['torsion_order']
            data['torsion_factors'] = [ ZZ(a) for a in literal_eval(curve['torsion_subgroup']) ]
            if len(data['torsion_factors']) == 0:
                data['torsion_subgroup'] = '\mathrm{trivial}'
            else:
                data['torsion_subgroup'] = ' \\times '.join([ '\Z/{%s}\Z' % n for n in data['torsion_factors'] ])
            data['end_ring_base'] = endo['ring_base']
            data['end_ring_geom'] = endo['ring_geom']
            data['tama'] = ''
            for i in range(tama.count()):
            	item = tama.next()
            	if item['tamagawa_number'] > 0:
            		tamgwnr = str(item['tamagawa_number'])
            	else:
            		tamgwnr = 'N/A'
            	data['tama'] += tamgwnr + ' (p = ' + str(item['p']) + ')'
            	if (i+1 < tama.count()):
            		data['tama'] += ', '
            if ratpts:
                if len(ratpts['rat_pts']):
                    data['rat_pts'] = ',  '.join(web_latex('(' +' : '.join(P) + ')') for P in ratpts['rat_pts'])
                data['rat_pts_v'] =  2 if ratpts['rat_pts_v'] else 1
                # data['mw_rank'] = ratpts['mw_rank']
                # data['mw_rank_v'] = ratpts['mw_rank_v']
            else:
                data['rat_pts_v'] = 0
            if curve['two_torsion_field'][0]:
                data['two_torsion_field_knowl'] = nf_display_knowl (curve['two_torsion_field'][0], getDBConnection(), field_pretty(curve['two_torsion_field'][0]))
            else:
                t = curve['two_torsion_field']
                data['two_torsion_field_knowl'] = """splitting field of \(%s\) with Galois group %s"""%(intlist_to_poly(t[1]),group_display_knowl(t[2][0],t[2][1],getDBConnection()))
        else:
            # invariants specific to isogeny class
            curves_data = g2c_db_curves().find({"class" : curve['class']},{'_id':int(0),'label':int(1),'eqn':int(1),'disc_key':int(1)}).sort([("disc_key", ASCENDING), ("label", ASCENDING)])
            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" : list_to_min_eqn(literal_eval(c['eqn'])), "url": url_for_curve_label(c['label'])} for c in curves_data ]
            lfunc_data = g2c_db_lfunction_by_hash(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'] = """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'] = """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'] = end_alg_name(curve['real_geom_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:
            self.plot = encode_plot(eqn_list_to_curve_plot(data['min_eqn'], data['rat_pts'].split(',') if 'rat_pts' in data else []))
            plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(self.plot)

            properties += [
                (None, plot_link),
                ('Conductor',str(data['cond'])),
                ('Discriminant', str(data['disc'])),
                ]
        properties += [
            ('Sato-Tate group', data['st_group_link']),
            ('\(\\End(J_{\\overline{\\Q}}) \\otimes \\R\)', '\(%s\)' % data['real_geom_end_alg_name']),
            ('\(\\overline{\\Q}\)-simple', bool_pretty(data['is_simple_geom'])),
            ('\(\mathrm{GL}_2\)-type', bool_pretty(data['is_gl2_type'])),
            ]

        # Friends
        self.friends = friends = [('L-function', data['lfunc_url'])]
        if is_curve:
            friends.append(('Isogeny class %s.%s' % (data['slabel'][0], data['slabel'][1]), url_for(".by_url_isogeny_class_label", cond=data['slabel'][0], alpha=data['slabel'][1])))
        for friend in g2c_db_lfunction_instances().find({'Lhash':data['Lhash']},{'_id':False,'url':True}):
            if 'url' in friend:
                add_friend (friends, lfunction_friend_from_url(friend['url']))
            if 'urls' in friend:
                for url in friends['urls']:
                    add_friend (friends, lfunction_friend_from_url(friend['url']))
        if 'split_labels' in data:
            for friend_label in data['split_labels']:
                if is_curve:
                    add_friend (friends, ("Elliptic curve " + friend_label, url_for_ec(friend_label)))
                else:
                    add_friend (friends, ("EC isogeny class " + ec_label_class(friend_label), url_for_ec_class(friend_label)))
        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]))))

        # Breadcrumbs
        self.bread = bread = [
             ('Genus 2 Curves', url_for(".index")),
             ('$\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
        code['curve'] = {'sage':'R.<x> = PolynomialRing(QQ); C = HyperellipticCurve(R(%s), R(%s))'%(data['min_eqn'][0],data['min_eqn'][1]),
                              'magma':'R<x> := PolynomialRing(Rationals()); C := HyperellipticCurve(R!%s, R!%s);'%(data['min_eqn'][0],data['min_eqn'][1])}
        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['igusa_clebsch'] = {'sage':'C.igusa_clebsch_invariants(); [factor(a) for a in _]',
                                      'magma':'IgusaClebschInvariants(C); [Factorization(Integers()!a): a in $1];'}
        code['igusa'] = {'magma':'IgusaInvariants(C); [Factorization(Integers()!a): a in $1];'}
        code['g2'] = {'magma':'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']]) + '];' }
        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);'}
Exemple #38
0
    def make_E(self):
        coeffs = self.ainvs  # list of 5 lists of d strings
        self.ainvs = [self.field.parse_NFelt(x) for x in coeffs]
        self.latex_ainvs = web_latex(self.ainvs)
        from sage.schemes.elliptic_curves.all import EllipticCurve
        self.E = E = EllipticCurve(self.ainvs)
        self.equn = web_latex(E)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = E.conductor()
        self.cond = web_latex(N)
        self.cond_norm = web_latex(N.norm())
        if N.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
        else:
            self.fact_cond = web_latex_ideal_fact(N.factor())
        self.fact_cond_norm = web_latex(N.norm().factor())

        D = self.field.K().ideal(E.discriminant())
        self.disc = web_latex(D)
        self.disc_norm = web_latex(D.norm())
        if D.norm() == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
        else:
            self.fact_disc = web_latex_ideal_fact(D.factor())
        self.fact_disc_norm = web_latex(D.norm().factor())

        # Minimal model?
        #
        # All curves in the database should be given
        # by models which are globally minimal if possible, else
        # minimal at all but one prime.  But we do not rely on this
        # here, and the display should be correct if either (1) there
        # exists a global minimal model but this model is not; or (2)
        # this model is non-minimal at more than one prime.
        #
        self.non_min_primes = non_minimal_primes(E)
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = True
        if not self.is_minimal:
            self.non_min_prime = ','.join(
                [web_latex(P) for P in self.non_min_primes])
            self.has_minimal_model = has_global_minimal_model(E)

        if not self.is_minimal:
            Dmin = minimal_discriminant_ideal(E)
            self.mindisc = web_latex(Dmin)
            self.mindisc_norm = web_latex(Dmin.norm())
            if Dmin.norm(
            ) == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
            else:
                self.fact_mindisc = web_latex_ideal_fact(Dmin.factor())
            self.fact_mindisc_norm = web_latex(Dmin.norm().factor())

        j = E.j_invariant()
        if j:
            d = j.denominator()
            n = d * j  # numerator exists for quadratic fields only!
            g = GCD(list(n))
            n1 = n / g
            self.j = web_latex(n1)
            if d != 1:
                if n1 > 1:
                    # self.j = "("+self.j+")\(/\)"+web_latex(d)
                    self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
                else:
                    self.j = web_latex(d)
                if g > 1:
                    if n1 > 1:
                        self.j = web_latex(g) + self.j
                    else:
                        self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        # See issue 1258: some j factorizations work bu take too long (e.g. EllipticCurve/6.6.371293.1/1.1/a/1)
        # If these are really wanted, they could be precomputed and stored in the db
        if j.is_zero():
            self.fact_j = web_latex(j)
        else:
            if self.field.K().degree(
            ) < 3:  #j.numerator_ideal().norm()<1000000000000:
                try:
                    self.fact_j = web_latex(j.factor())
                except (ArithmeticError, ValueError
                        ):  # if not all prime ideal factors principal
                    pass

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm
            # The line below will need to change once we have curves over non-quadratic fields
            # that contain the Hilbert class field of an imaginary quadratic field
            if self.signature == [0, 1] and ZZ(
                    -self.abs_disc * self.cm).is_square():
                self.ST = '<a href="%s">$%s$</a>' % (url_for(
                    'st.by_label', label='1.2.U(1)'), '\\mathrm{U}(1)')
            else:
                self.ST = '<a href="%s">$%s$</a>' % (url_for(
                    'st.by_label', label='1.2.N(U(1))'), 'N(\\mathrm{U}(1))')
        else:
            self.ST = '<a href="%s">$%s$</a>' % (url_for(
                'st.by_label', label='1.2.SU(2)'), '\\mathrm{SU}(2)')

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(
                self.torsion_structure)
        torsion_gens = [
            E([self.field.parse_NFelt(x) for x in P])
            for P in self.torsion_gens
        ]
        self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens])

        # Rank or bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.rank_bounds)
        except AttributeError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not available"

        # Generators
        try:
            gens = [
                E([self.field.parse_NFelt(x) for x in P]) for P in self.gens
            ]
            self.gens = ", ".join([web_latex(P) for P in gens])
            if self.rk == "?":
                self.reg = "not available"
            else:
                if gens:
                    self.reg = E.regulator_of_points(gens)
                else:
                    self.reg = 1  # otherwise we only get 1.00000...

        except AttributeError:
            self.gens = "not available"
            self.reg = "not available"
            try:
                if self.rank == 0:
                    self.reg = 1
            except AttributeError:
                pass

        # Local data
        self.local_data = []
        for p in N.prime_factors():
            self.local_info = E.local_data(p, algorithm="generic")
            self.local_data.append({
                'p':
                web_latex(p),
                'norm':
                web_latex(p.norm().factor()),
                'tamagawa_number':
                self.local_info.tamagawa_number(),
                'kodaira_symbol':
                web_latex(self.local_info.kodaira_symbol()).replace('$', ''),
                'reduction_type':
                self.local_info.bad_reduction_type(),
                'ord_den_j':
                max(0, -E.j_invariant().valuation(p)),
                'ord_mindisc':
                self.local_info.discriminant_valuation(),
                'ord_cond':
                self.local_info.conductor_valuation()
            })

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label),
                                         class_label=self.iso_label,
                                         number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=quote(
                                         self.conductor_label),
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        sig = self.signature
        real_quadratic = sig == [2, 0]
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]

        if totally_real:
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page",
                                             field=self.field_label,
                                             label=self.hmf_label,
                                             character='0',
                                             number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label,
                          self.urls['class'])]
        self.friends += [('Twists',
                          url_for('ecnf.index',
                                  field_label=self.field_label,
                                  jinv=self.jinv))]
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]
            self.friends += [('L-function', self.urls['Lfunction'])]
        if imag_quadratic:
            self.friends += [
                ('Bianchi Modular Form %s not available' % self.bmf_label, '')
            ]

        self.properties = [('Base field', self.field.field_pretty()),
                           ('Label', self.label)]

        # Plot
        if E.base_field().signature()[0]:
            self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)
        ]

        if self.base_change:
            self.properties += [
                ('base-change',
                 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))
            ]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0,
                              url_for("ec.by_ec_label", label=E0))]

        self._code = None  # will be set if needed by get_code()
Exemple #39
0
    def make_object(self, curve, endo, 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'] = curve['Lhash']
        data['cond'] = ZZ(curve['cond'])
        data['cond_factor_latex'] = web_latex(factor(int(data['cond'])))
        data['analytic_rank'] = ZZ(curve['analytic_rank'])
        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['disc_key'][3:]
            )  # use disc_key rather than abs_disc (will work when abs_disc > 2^63)
            data['disc'] = curve['disc_sign'] * curve['abs_disc']
            data['min_eqn'] = literal_eval(curve['eqn'])
            data['min_eqn_display'] = list_to_min_eqn(data['min_eqn'])
            data['disc_factor_latex'] = web_latex(factor(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(zfactor(i)) for i in data['igusa_clebsch']
            ]
            data['igusa_factor_latex'] = [
                web_latex(zfactor(j)) for j in data['igusa']
            ]
            data['aut_grp_id'] = curve['aut_grp_id']
            data['geom_aut_grp_id'] = curve['geom_aut_grp_id']
            data['num_rat_wpts'] = ZZ(curve['num_rat_wpts'])
            data['two_selmer_rank'] = ZZ(curve['two_selmer_rank'])
            data['has_square_sha'] = "square" if curve[
                'has_square_sha'] else "twice a square"
            data['locally_solvable'] = "yes" if curve[
                'locally_solvable'] else "no"
            data['torsion_order'] = curve['torsion_order']
            data['torsion_factors'] = [
                ZZ(a) for a in literal_eval(curve['torsion_subgroup'])
            ]
            if len(data['torsion_factors']) == 0:
                data['torsion_subgroup'] = '\mathrm{trivial}'
            else:
                data['torsion_subgroup'] = ' \\times '.join(
                    ['\Z/{%s}\Z' % n for n in data['torsion_factors']])
            data['end_ring_base'] = endo['ring_base']
            data['end_ring_geom'] = endo['ring_geom']
        else:
            # invariants specific to isogeny class
            curves_data = g2c_db_curves().find({
                "class": curve['class']
            }, {
                '_id': int(0),
                'label': int(1),
                'eqn': int(1),
                'disc_key': int(1)
            }).sort([("disc_key", ASCENDING), ("label", ASCENDING)])
            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":
                list_to_min_eqn(literal_eval(c['eqn'])),
                "url":
                url_for_curve_label(c['label'])
            } for c in curves_data]
            lfunc_data = g2c_db_lfunction_by_hash(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'] = """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'] = """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'] = end_alg_name(
            curve['real_geom_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:
            self.plot = encode_plot(eqn_list_to_curve_plot(data['min_eqn']))
            plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            properties += [
                (None, plot_link),
                ('Conductor', str(data['cond'])),
                ('Discriminant', str(data['disc'])),
            ]
        properties += [
            ('Sato-Tate group', data['st_group_link']),
            ('\(\\End(J_{\\overline{\\Q}}) \\otimes \\R\)',
             '\(%s\)' % data['real_geom_end_alg_name']),
            ('\(\\overline{\\Q}\)-simple',
             bool_pretty(data['is_simple_geom'])),
            ('\(\mathrm{GL}_2\)-type', bool_pretty(data['is_gl2_type'])),
        ]

        # Friends
        self.friends = friends = [('L-function', data['lfunc_url'])]
        if is_curve:
            friends.append(('Isogeny class %s.%s' %
                            (data['slabel'][0], data['slabel'][1]),
                            url_for(".by_url_isogeny_class_label",
                                    cond=data['slabel'][0],
                                    alpha=data['slabel'][1])))
        for friend in g2c_db_lfunction_instances().find(
            {'Lhash': data['Lhash']}, {
                '_id': False,
                'url': True
            }):
            if 'url' in friend:
                add_friend(friends, lfunction_friend_from_url(friend['url']))
            if 'urls' in friend:
                for url in friends['urls']:
                    add_friend(friends,
                               lfunction_friend_from_url(friend['url']))
        if 'split_labels' in data:
            for friend_label in data['split_labels']:
                if is_curve:
                    add_friend(friends, ("Elliptic curve " + friend_label,
                                         url_for_ec(friend_label)))
                else:
                    add_friend(
                        friends,
                        ("EC isogeny class " + ec_label_class(friend_label),
                         url_for_ec_class(friend_label)))
        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]))))

        # Breadcrumbs
        self.bread = bread = [('Genus 2 Curves', url_for(".index")),
                              ('$\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
        code['curve'] = {
            'sage':
            'R.<x> = PolynomialRing(QQ); C = HyperellipticCurve(R(%s), R(%s))'
            % (data['min_eqn'][0], data['min_eqn'][1]),
            'magma':
            'R<x> := PolynomialRing(Rationals()); C := HyperellipticCurve(R!%s, R!%s);'
            % (data['min_eqn'][0], data['min_eqn'][1])
        }
        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['igusa_clebsch'] = {
            'sage':
            'C.igusa_clebsch_invariants(); [factor(a) for a in _]',
            'magma':
            'IgusaClebschInvariants(C); [Factorization(Integers()!a): a in $1];'
        }
        code['igusa'] = {
            'magma':
            'IgusaInvariants(C); [Factorization(Integers()!a): a in $1];'
        }
        code['g2'] = {'magma': '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)));'
        }
        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; HasPointsLocallyEverywhere(g,2) and (#Roots(ChangeRing(g,RealField())) gt 0 or LeadingCoefficient(g) gt 0);'
        }
        code['torsion_subgroup'] = {
            'magma':
            'TorsionSubgroup(Jacobian(SimplifiedModel(C))); AbelianInvariants($1);'
        }
Exemple #40
0
    def make_curve(self):
        # To start with the data fields of self are just those from the
        # databases.  We reformat these, while computing some further (easy)
        # data about the curve on the fly.

        # Initialize data:
        data = self.data = {}
        endodata = self.endodata = {}

        # Polish data from database before putting it into the data dictionary:
        disc = ZZ(self.disc_sign) * ZZ(self.disc_key[3:])
        # to deal with disc_key, uncomment line above and comment line below
        #disc = ZZ(self.disc_sign) * ZZ(self.abs_disc)
        data['disc'] = disc
        data['cond'] = ZZ(self.cond)
        data['min_eqn'] = self.min_eqn
        data['min_eqn_display'] = list_to_min_eqn(self.min_eqn)
        data['disc_factor_latex'] = web_latex(factor(data['disc']))
        data['cond_factor_latex'] = web_latex(factor(int(self.cond)))
        data['aut_grp'] = groupid_to_meaningful(self.aut_grp)
        data['geom_aut_grp'] = groupid_to_meaningful(self.geom_aut_grp)
        data['igusa_clebsch'] = [ZZ(a) for a in self.igusa_clebsch]
        data['igusa'] = [ZZ(a) for a in self.igusa]
        data['g2'] = self.g2inv
        data['ic_norm'] = data['igusa_clebsch']
        data['igusa_norm'] = data['igusa']
        # Should we ever want to normalize the invariants further, then
        # uncomment the following lines:
        #data['ic_norm'] = normalize_invariants(data['igusa_clebsch'], [2, 4, 6,
        #    10])
        #data['igusa_norm'] = normalize_invariants(data['igusa'], [2, 4, 6, 8,
        #    10])
        data['ic_norm_factor_latex'] = [web_latex(zfactor(i)) for i in
            data['ic_norm']]
        data['igusa_norm_factor_latex'] = [ web_latex(zfactor(j)) for j in
            data['igusa_norm'] ]
        data['num_rat_wpts'] = ZZ(self.num_rat_wpts)
        data['two_selmer_rank'] = ZZ(self.two_selmer_rank)
        data['analytic_rank'] = ZZ(self.analytic_rank)
        data['has_square_sha'] = "square" if self.has_square_sha else "twice a square"
        data['locally_solvable'] = "yes" if self.locally_solvable else "no"
        if len(self.torsion) == 0:
            data['tor_struct'] = '\mathrm{trivial}'
        else:
            tor_struct = [ ZZ(a) for a in self.torsion ]
            data['tor_struct'] = ' \\times '.join([ '\Z/{%s}\Z' % n for n in
                tor_struct ])

        # Data derived from Sato-Tate group:
        isogeny_class = g2cdb().isogeny_classes.find_one({'label' :
            isog_label(self.label)})
        st_data = get_st_data(isogeny_class)
        for key in st_data.keys():
            data[key] = st_data[key]

        # GL_2 statement over the base field
        endodata['gl2_statement_base'] = \
            gl2_statement_base(self.factorsRR_base, r'\(\Q\)')

        # NOTE: In what follows there is some copying of code and data that is
        # stupid from the point of view of efficiency but likely better from
        # that of maintenance.

        # Endomorphism data over QQ:
        endodata['factorsQQ_base'] = self.factorsQQ_base
        endodata['factorsRR_base'] = self.factorsRR_base
        endodata['ring_base'] = self.ring_base
        endodata['endo_statement_base'] = \
            """Endomorphism ring over \(\Q\):""" + \
            endo_statement(endodata['factorsQQ_base'],
                endodata['factorsRR_base'], endodata['ring_base'], r'')
        # Field of definition data:
        endodata['fod_label'] = self.fod_label
        endodata['fod_poly'] = intlist_to_poly(self.fod_coeffs)
        endodata['fod_statement'] = fod_statement(endodata['fod_label'],
            endodata['fod_poly'])
        # Endomorphism data over QQbar:
        endodata['factorsQQ_geom'] = self.factorsQQ_geom
        endodata['factorsRR_geom'] = self.factorsRR_geom
        endodata['ring_geom'] = self.ring_geom
        if self.fod_label != '1.1.1.1':
            endodata['gl2_statement_geom'] = \
                gl2_statement_base(self.factorsRR_geom, r'\(\overline{\Q}\)')
            endodata['endo_statement_geom'] = \
            """Endomorphism ring over \(\overline{\Q}\):""" + \
            endo_statement(endodata['factorsQQ_geom'],
                endodata['factorsRR_geom'], endodata['ring_geom'],
                r'\overline{\Q}')

        # Full endomorphism lattice minus entries already treated:
        N = len(self.lattice)
        endodata['lattice'] = (self.lattice)[1:N - 1]
        if endodata['lattice']:
            endodata['lattice_statement_preamble'] = \
                lattice_statement_preamble()
            endodata['lattice_statement'] = \
                lattice_statement(endodata['lattice'])

        # Splitting field description:
        #endodata['is_simple_base'] = self.is_simple_base
        endodata['is_simple_geom'] = self.is_simple_geom
        endodata['spl_fod_label'] = self.spl_fod_label
        endodata['spl_fod_poly'] = intlist_to_poly(self.spl_fod_coeffs)
        endodata['spl_fod_statement'] = \
            spl_fod_statement(endodata['is_simple_geom'],
                endodata['spl_fod_label'], endodata['spl_fod_poly'])

        # Isogeny factors:
        if not endodata['is_simple_geom']:
            endodata['spl_facs_coeffs'] = self.spl_facs_coeffs
            # This could be done non-uniformly as well... later.
            if len(self.spl_facs_labels) == len(self.spl_facs_coeffs):
                endodata['spl_facs_labels'] = self.spl_facs_labels
            else:
                endodata['spl_facs_labels'] = ['' for coeffs in
                    self.spl_facs_coeffs]
            endodata['spl_facs_condnorms'] = self.spl_facs_condnorms
            endodata['spl_statement'] = \
                spl_statement(endodata['spl_facs_coeffs'],
                    endodata['spl_facs_labels'],
                    endodata['spl_facs_condnorms'])

        # Title
        self.title = "Genus 2 Curve %s" % (self.label)

        # Lady Gaga box
        self.plot = encode_plot(eqn_list_to_curve_plot(self.min_eqn))
        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [
                ('Label', self.label),
               (None, self.plot_link),
               ('Conductor','%s' % self.cond),
               ('Discriminant', '%s' % data['disc']),
               ('Invariants', '%s </br> %s </br> %s </br> %s' % tuple(data['ic_norm'])),
               ('Sato-Tate group', data['st_group_href']),
               ('\(%s\)' % data['real_geom_end_alg_disp'][0],
                '\(%s\)' % data['real_geom_end_alg_disp'][1]),
               ('\(\mathrm{GL}_2\)-type','%s' % data['is_gl2_type_name'])]
        x = self.label.split('.')[1]
        self.friends = [
            ('Isogeny class %s' % isog_label(self.label),
                url_for(".by_double_iso_label",
                    conductor = self.cond,
                    iso_label = x)),
            ('L-function',
                url_for("l_functions.l_function_genus2_page",
                    cond=self.cond,x=x)),
            ('Twists',
                url_for(".index_Q",
                    g20 = self.g2inv[0],
                    g21 = self.g2inv[1],
                    g22 = self.g2inv[2]))
            #('Siegel modular form someday', '.')
            ]

        if not endodata['is_simple_geom']:
            self.friends += [('Elliptic curve %s' % lab,url_for_ec(lab)) for lab in endodata['spl_facs_labels'] if lab != '']
        #self.downloads = [('Download all stored data', '.')]

        # Breadcrumbs
        iso = self.label.split('.')[1]
        num = '.'.join(self.label.split('.')[2:4])
        self.bread = [
             ('Genus 2 Curves', url_for(".index")),
             ('$\Q$', url_for(".index_Q")),
             ('%s' % self.cond, url_for(".by_conductor", conductor=self.cond)),
             ('%s' % iso, url_for(".by_double_iso_label", conductor=self.cond,
                 iso_label=iso)),
             ('Genus 2 curve %s' % num, url_for(".by_g2c_label",
                 label=self.label))
             ]

        # Make code that is used on the page:
        self.make_code_snippets()
Exemple #41
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these, construct the
        # and compute some further (easy) data about it.
        #

        # Weierstrass equation

        data = self.data = {}

        disc = ZZ(self.disc_sign) * ZZ(self.disc_key[3:]) 
        # to deal with disc_key, uncomment line above and remove line below
        #disc = ZZ(self.disc_sign) * ZZ(self.abs_disc)
        data['disc'] = disc
        data['cond'] = ZZ(self.cond)
        data['min_eqn'] = list_to_min_eqn(self.min_eqn)
        data['disc_factor_latex'] = web_latex(factor(data['disc']))
        data['cond_factor_latex'] = web_latex(factor(int(self.cond)))
        data['aut_grp'] = groupid_to_meaningful(self.aut_grp)
        data['geom_aut_grp'] = groupid_to_meaningful(self.geom_aut_grp)
        data['igusa_clebsch'] = [ZZ(a)  for a in self.igusa_clebsch]
        if len(self.torsion) == 0:
            data['tor_struct'] = '\mathrm{trivial}'
        else:
            tor_struct = [ZZ(a)  for a in self.torsion]
            data['tor_struct'] = ' \\times '.join(['\Z/{%s}\Z' % n for n in tor_struct])
        isogeny_class = db_g2c().isogeny_classes.find_one({'label' : isog_label(self.label)})

        for endalgtype in ['end_ring', 'rat_end_alg', 'real_end_alg', 'geom_end_ring', 'rat_geom_end_alg', 'real_geom_end_alg']:
            if endalgtype in isogeny_class:
                data[endalgtype + '_name'] = end_alg_name(isogeny_class[endalgtype])
            else:
                data[endalgtype + '_name'] = ''

        data['geom_end_field'] = isogeny_class['geom_end_field']
        if data['geom_end_field'] <> '':
            data['geom_end_field_name'] = field_pretty(data['geom_end_field'])
        else:
            data['geom_end_field_name'] = ''        

        data['st_group_name'] = st_group_name(isogeny_class['st_group'])
        if isogeny_class['is_gl2_type']:
            data['is_gl2_type_name'] = 'yes'
        else:
            data['is_gl2_type_name'] = 'no'
        if 'is_simple' in isogeny_class:
            if isogeny_class['is_simple']:
                data['is_simple_name'] = 'yes'
            else:
                data['is_simple_name'] = 'no'
        else:
            data['is_simple_name'] = '?'
        if 'is_geom_simple' in isogeny_class:
            if isogeny_class['is_geom_simple']:
                data['is_geom_simple_name'] = 'yes'
            else:
                data['is_geom_simple_name'] = 'no'
        else:
            data['is_geom_simple_name'] = '?'

        x = self.label.split('.')[1]
        self.friends = [
            ('Isogeny class %s' % isog_label(self.label), url_for(".by_double_iso_label", conductor = self.cond, iso_label = x)),
            ('L-function', url_for("l_functions.l_function_genus2_page", cond=self.cond,x=x)),
            ('Siegel modular form someday', '.')]
        self.downloads = [
             ('Download Euler factors', '.')]
        iso = self.label.split('.')[1]
        num = '.'.join(self.label.split('.')[2:4])
        self.plot = encode_plot(eqn_list_to_curve_plot(self.min_eqn))
        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [('Label', self.label),
                           (None, self.plot_link),
                           ('Conductor','%s' % self.cond),
                           ('Discriminant', '%s' % data['disc']),
                           ('Invariants', '%s </br> %s </br> %s </br> %s'% tuple(data['igusa_clebsch'])), 
                           ('Sato-Tate group', '\(%s\)' % data['st_group_name']), 
                           ('\(\mathrm{End}(J_{\overline{\Q}}) \otimes \R\)','\(%s\)' % data['real_geom_end_alg_name']),
                           ('\(\mathrm{GL}_2\)-type','%s' % data['is_gl2_type_name'])]
        self.title = "Genus 2 Curve %s" % (self.label)
        self.bread = [
             ('Genus 2 Curves', url_for(".index")),
             ('$\Q$', url_for(".index_Q")),
             ('%s' % self.cond, url_for(".by_conductor", conductor=self.cond)),
             ('%s' % iso, url_for(".by_double_iso_label", conductor=self.cond, iso_label=iso)),
             ('Genus 2 curve %s' % num, url_for(".by_g2c_label", label=self.label))]
Exemple #42
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata['ainvs']])
            self.cremona_labels[i - 1] = Edata['label']
            if Edata['number'] == 1:
                self.optimal_flags[i - 1] = True
            if 'degree' in Edata:
                self.degrees[i - 1] = Edata['degree']
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)


        if self.iso == '990h':  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = lmfdb_label_regex.match(self.lmfdb_iso).groups()

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = self.lmfdb_iso.replace('.', '.2')
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=0, label=iso)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso)

        self.curves = [[self.lmfdb_iso + str(i + 1),
                        self.cremona_labels[i],
                        str(list(c.ainvs())),
                        c.torsion_order(),
                        self.degrees[i],
                        self.optimal_flags[i]]
                       for i, c in enumerate(self.db_curves)]

        self.friends = [
        ('L-function', self.lfunction_link),
        ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso)),
        ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=self.lmfdb_iso)),
        ('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           (None, self.graph_link),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank)
                           ]


        self.downloads = [('Download coeffients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=100)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves ', url_for(".rational_elliptic_curves")), ('isogeny class %s' % self.lmfdb_iso, ' ')]
Exemple #43
0
    def make_class(self):
        self.CM = self.cm
        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        # Extract the size of the isogeny class from the database
        ncurves = self.class_size
        # Create a list of the curves in the class from the database
        self.curves = [db_ec().find_one({'iso':self.iso, 'lmfdb_number': i+1})
                          for i in range(ncurves)]

        # Set optimality flags.  The optimal curve is number 1 except
        # in one case which is labeled differently in the Cremona tables
        for c in self.curves:
            c['optimal'] = (c['number']==(3 if self.label == '990h' else 1))
            c['ai'] = parse_ainvs(c['xainvs'])
            c['url'] = url_for(".by_triple_label", conductor=N, iso_label=iso, number=c['lmfdb_number'])

        from sage.matrix.all import Matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img


        self.newform =  web_latex(PowerSeriesRing(QQ, 'q')(self.anlist, 20, check=True))
        self.newform_label = newform_label(N,2,1,iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", conductor_label = N, isogeny_class_label = iso)

        self.friends =  [('L-function', self.lfunction_link)]
        if not self.CM:
            self.CM = "no"
            if int(N)<=300:
                self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor = N, isogeny = iso))]
            if int(N)<=50:
                self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor = N, isogeny = iso))]
        if self.newform_exists_in_db:
            self.friends +=  [('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(ncurves)),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank),
                           ('Graph', ''),(None, self.graph_link)
                           ]


        self.downloads = [('Download coefficients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=1000)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
        self.code = {}
        self.code['show'] = {'sage':''} # use default show names
        self.code['class'] = {'sage':'E = EllipticCurve("%s1")\n'%(self.lmfdb_iso) + 'E.isogeny_class()\n'}
        self.code['curves'] = {'sage':'E.isogeny_class().curves'}
        self.code['rank'] = {'sage':'E.rank()'}
        self.code['q_eigenform'] = {'sage':'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage':'E.isogeny_class().matrix()'}
        self.code['plot'] = {'sage':'E.isogeny_graph().plot(edge_labels=True)'}
Exemple #44
0
    def make_curve(self):
        data = self.data = {}
        lmfdb_label = self.lmfdb_label

        # Some data fields of self are just those from the database.
        # These only need some reformatting.

        data['ainvs'] = self.ainvs
        data['conductor'] = N = self.conductor
        data['j_invariant'] = QQ(tuple(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:  # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_latex'] = web_latex(data['j_invariant'])

        # retrieve local reduction data from table ec_localdata:

        self.local_data = local_data = list(
            db.ec_localdata.search({"lmfdb_label": lmfdb_label}))
        for ld in local_data:
            if ld['kodaira_symbol'] <= -14:
                # Work around bug in Sage's latex
                ld['kod'] = 'I_{%s}^{*}' % (-ld['kodaira_symbol'] - 4)
            else:
                ld['kod'] = latex(KodairaSymbol(ld['kodaira_symbol']))

        Nfac = Factorization([(ZZ(ld['prime']), ld['conductor_valuation'])
                              for ld in local_data])
        Dfac = Factorization([(ZZ(ld['prime']), ld['discriminant_valuation'])
                              for ld in local_data],
                             unit=ZZ(self.signD))
        data['disc_factor'] = latex(Dfac)
        data['disc'] = D = Dfac.value()
        data['cond_factor'] = latex(Nfac)
        data['disc_latex'] = web_latex(D)
        data['cond_latex'] = web_latex(N)

        # retrieve data about MW rank, generators, heights and
        # torsion, leading term of L-function & other BSD data from
        # table ec_mwbsd:

        self.make_mwbsd()

        # latex equation:

        latexeqn = latex_equation(self.ainvs)
        data['equation'] = raw_typeset(unlatex(latexeqn), latexeqn)

        # minimal quadratic twist:

        data['minq_D'] = minqD = self.min_quad_twist_disc
        data['minq_label'] = db.ec_curvedata.lucky(
            {'ainvs': self.min_quad_twist_ainvs},
            projection='lmfdb_label'
            if self.label_type == 'LMFDB' else 'Clabel')
        data['minq_info'] = '(itself)' if minqD == 1 else '(by {})'.format(
            minqD)

        # modular degree:

        try:
            data['degree'] = ZZ(self.degree)  # convert None to 0
        except AttributeError:  # if not computed, db has Null and the attribute is missing
            data['degree'] = 0  # invalid, but will be displayed nicely

        # coefficients of modular form / L-series:

        classdata = db.ec_classdata.lookup(self.lmfdb_iso)
        data['an'] = classdata['anlist']
        data['ap'] = classdata['aplist']

        # mod-p Galois images:

        data['galois_data'] = list(
            db.ec_galrep.search({'lmfdb_label': lmfdb_label}))
        for gd in data[
                'galois_data']:  # remove the prime prefix from each image code
            gd['image'] = trim_galois_image_code(gd['image'])

        # CM and Endo ring:

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = r"\(\Z\)"
        if self.cm:
            data['cm_ramp'] = [
                p for p in ZZ(self.cm).support() if not p in self.nonmax_primes
            ]
            data['cm_nramp'] = len(data['cm_ramp'])
            if data['cm_nramp'] == 1:
                data['cm_ramp'] = data['cm_ramp'][0]
            else:
                data['cm_ramp'] = ", ".join(str(p) for p in data['cm_ramp'])
            data['cm_sqf'] = ZZ(self.cm).squarefree_part()

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

        # Isogeny degrees:

        cond, iso, num = split_lmfdb_label(lmfdb_label)
        self.class_deg = classdata['class_deg']
        self.one_deg = ZZ(self.class_deg).is_prime()
        isodegs = [str(d) for d in self.isogeny_degrees if d > 1]
        if len(isodegs) < 3:
            data['isogeny_degrees'] = " and ".join(isodegs)
        else:
            data['isogeny_degrees'] = " and ".join(
                [", ".join(isodegs[:-1]), isodegs[-1]])

        self.make_twoadic_data()

        # Optimality

        # The optimal curve in the class is the curve whose Cremona
        # label ends in '1' except for '990h' which was labelled
        # wrongly long ago. This is proved for N up to
        # OPTIMALITY_BOUND (and when there is only one curve in an
        # isogeny class, obviously) and expected for all N.

        # Column 'optimality' is 1 for certainly optimal curves, 0 for
        # certainly non-optimal curves, and is n>1 if the curve is one
        # of n in the isogeny class which may be optimal given current
        # knowledge.

        # Column "manin_constant' is the correct Manin constant
        # assuming that the optimal curve in the class is known, or
        # otherwise if it is the curve with (Cremona) number 1.

        # The code here allows us to update the display correctly by
        # changing one line in this file (defining OPTIMALITY_BOUND)
        # without changing the data.

        data['optimality_bound'] = OPTIMALITY_BOUND
        self.cremona_bound = CREMONA_BOUND
        if N < CREMONA_BOUND:
            data[
                'manin_constant'] = self.manin_constant  # (conditional on data['optimality_known'])
        else:
            data['manin_constant'] = 0  # (meaning not available)

        if N < OPTIMALITY_BOUND:

            data['optimality_code'] = int(
                self.Cnumber == (3 if self.Ciso == '990h' else 1))
            data['optimality_known'] = True
            data['manin_known'] = True
            if self.label_type == 'Cremona':
                data[
                    'optimal_label'] = '990h3' if self.Ciso == '990h' else self.Ciso + '1'
            else:
                data[
                    'optimal_label'] = '990.i3' if self.lmfdb_iso == '990.i' else self.lmfdb_iso + '1'

        elif N < CREMONA_BOUND:

            data['optimality_code'] = self.optimality
            data['optimality_known'] = (self.optimality < 2)

            if self.optimality == 1:
                data['manin_known'] = True
                data[
                    'optimal_label'] = self.Clabel if self.label_type == 'Cremona' else self.lmfdb_label
            else:
                if self.Cnumber == 1:
                    data['manin_known'] = False
                    data[
                        'optimal_label'] = self.Clabel if self.label_type == 'Cremona' else self.lmfdb_label
                else:
                    # find curve #1 in this class and its optimailty code:
                    opt_curve = db.ec_curvedata.lucky(
                        {
                            'Ciso': self.Ciso,
                            'Cnumber': 1
                        },
                        projection=['Clabel', 'lmfdb_label', 'optimality'])
                    data['manin_known'] = (opt_curve['optimality'] == 1)
                    data['optimal_label'] = opt_curve[
                        'Clabel' if self.label_type ==
                        'Cremona' else 'lmfdb_label']

        else:
            data['optimality_code'] = None
            data['optimality_known'] = False
            data['manin_known'] = False
            data['optimal_label'] = ''

        # p-adic data:

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

        data['p_adic_data_exists'] = False
        if data['optimality_code'] == 1:
            data['p_adic_data_exists'] = db.ec_padic.exists(
                {'lmfdb_iso': self.lmfdb_iso})

        # Iwasawa data (where present)

        self.make_iwasawa()

        # Torsion growth data (where present)

        self.make_torsion_growth()

        # Newform

        rawnewform = str(PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))
        data['newform'] = raw_typeset(
            rawnewform,
            web_latex(PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True)))
        data['newform_label'] = self.newform_label = ".".join(
            [str(cond), str(2), 'a', iso])
        self.newform_link = url_for("cmf.by_url_newform_label",
                                    level=cond,
                                    weight=2,
                                    char_orbit_label='a',
                                    hecke_orbit=iso)
        self.newform_exists_in_db = db.mf_newforms.label_exists(
            self.newform_label)
        self._code = None

        if self.label_type == 'Cremona':
            self.class_url = url_for(".by_ec_label", label=self.Ciso)
            self.class_name = self.Ciso
        else:
            self.class_url = url_for(".by_ec_label", label=self.lmfdb_iso)
            self.class_name = self.lmfdb_iso
        data['class_name'] = self.class_name
        data['Cnumber'] = self.Cnumber if N < CREMONA_BOUND else None

        self.friends = [('Isogeny class ' + self.class_name, self.class_url),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_ec_label", label=data['minq_label'])),
                        ('All twists ',
                         url_for(".rational_elliptic_curves",
                                 jinv=data['j_invariant']))]

        lfun_url = url_for("l_functions.l_function_ec_page",
                           conductor_label=N,
                           isogeny_class_label=iso)
        origin_url = lfun_url.lstrip('/L/').rstrip('/')

        if db.lfunc_instances.exists({'url': origin_url}):
            self.friends += [('L-function', lfun_url)]
        else:
            self.friends += [('L-function not available', "")]

        if not self.cm:
            if N <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=N,
                                          isogeny=iso))]
            if N <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=N,
                                          isogeny=iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.downloads = [('q-expansion to text',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_label,
                                   limit=1000)),
                          ('All stored data to text',
                           url_for(".download_EC_all",
                                   label=self.lmfdb_label)),
                          ('Code to Magma',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='magma')),
                          ('Code to SageMath',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='sage')),
                          ('Code to GP',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='gp'))]

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

        self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(
            self.plot)
        self.properties = [
            ('Label', self.Clabel
             if self.label_type == 'Cremona' else self.lmfdb_label),
            (None, self.plot_link),
            ('Conductor', prop_int_pretty(data['conductor'])),
            ('Discriminant', prop_int_pretty(data['disc'])),
            ('j-invariant', '%s' % data['j_inv_latex']),
            ('CM', '%s' % data['CM']),
            ('Rank', 'unknown' if self.mwbsd['rank'] == '?' else
             prop_int_pretty(self.mwbsd['rank'])),
            ('Torsion structure', (r'\(%s\)' % self.mwbsd['tor_struct'])
             if self.mwbsd['tor_struct'] else 'trivial'),
        ]

        if self.label_type == 'Cremona':
            self.title = "Elliptic curve with Cremona label {} (LMFDB label {})".format(
                self.Clabel, self.lmfdb_label)
        elif N < CREMONA_BOUND:
            self.title = "Elliptic curve with LMFDB label {} (Cremona label {})".format(
                self.lmfdb_label, self.Clabel)
        else:
            self.title = "Elliptic curve with LMFDB label {}".format(
                self.lmfdb_label)

        self.bread = [('Elliptic curves', url_for("ecnf.index")),
                      (r'$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]
Exemple #45
0
    def make_E(self):
        coeffs = self.ainvs # list of 5 lists of d strings
        self.ainvs = [self.field.parse_NFelt(x) for x in coeffs]
        self.latex_ainvs = web_latex(self.ainvs)
        from sage.schemes.elliptic_curves.all import EllipticCurve
        self.E = E = EllipticCurve(self.ainvs)
        self.equn = web_latex(E)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = E.conductor()
        self.cond = web_latex(N)
        self.cond_norm = web_latex(N.norm())
        if N.norm()==1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
        else:
            self.fact_cond = web_latex_ideal_fact(N.factor())
        self.fact_cond_norm = web_latex(N.norm().factor())

        D = self.field.K().ideal(E.discriminant())
        self.disc = web_latex(D)
        self.disc_norm = web_latex(D.norm())
        if D.norm()==1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
        else:
            self.fact_disc = web_latex_ideal_fact(D.factor())
        self.fact_disc_norm = web_latex(D.norm().factor())

        # Minimal model?
        #
        # All curves in the database should be given
        # by models which are globally minimal if possible, else
        # minimal at all but one prime.  But we do not rely on this
        # here, and the display should be correct if either (1) there
        # exists a global minimal model but this model is not; or (2)
        # this model is non-minimal at more than one prime.
        #
        self.non_min_primes = non_minimal_primes(E)
        self.is_minimal = (len(self.non_min_primes)==0)
        self.has_minimal_model = True
        if not self.is_minimal:
            self.non_min_prime = ','.join([web_latex(P) for P in self.non_min_primes])
            self.has_minimal_model = has_global_minimal_model(E)

        if not self.is_minimal:
            Dmin = minimal_discriminant_ideal(E)
            self.mindisc = web_latex(Dmin)
            self.mindisc_norm = web_latex(Dmin.norm())
            if Dmin.norm()==1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
            else:
                self.fact_mindisc = web_latex_ideal_fact(Dmin.factor())
            self.fact_mindisc_norm = web_latex(Dmin.norm().factor())


        j = E.j_invariant()
        if j:
            d = j.denominator()
            n = d*j # numerator exists for quadratic fields only!
            g = GCD(list(n))
            n1 = n/g
            self.j = web_latex(n1)
            if d!=1:
                if n1>1:
                #self.j = "("+self.j+")\(/\)"+web_latex(d)
                    self.j = web_latex(r"\frac{%s}{%s}" % (self.j,d))
                else:
                    self.j = web_latex(d)
                if g>1:
                    if n1>1:
                        self.j = web_latex(g) + self.j
                    else:
                        self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        if j.is_zero():
            self.fact_j = web_latex(j)
        else:
            try:
                self.fact_j = web_latex(j.factor())
            except (ArithmeticError,ValueError): # if not all prime ideal factors principal
                pass

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm%4==0:
                d4 = ZZ(self.cm)//4
                self.End = "\(\Z[\sqrt{%s}]\)"%(d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError: # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr==0:
            self.tor_struct_pretty = "Trivial"
        if self.tr==1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr==2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure)
        torsion_gens = [E([self.field.parse_NFelt(x) for x in P])
                        for P in self.torsion_gens]
        self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens])


        # Rank etc
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "not recorded"
#       if rank in self:
#            self.r = web_latex(self.rank)

        # Local data
        self.local_data = []
        for p in N.prime_factors():
            self.local_info = E.local_data(p, algorithm="generic")
            self.local_data.append({'p': web_latex(p),
                               'norm': web_latex(p.norm().factor()),
                               'tamagawa_number': self.local_info.tamagawa_number(),
                               'kodaira_symbol': web_latex(self.local_info.kodaira_symbol()).replace('$', ''),
                               'reduction_type': self.local_info.bad_reduction_type(),
                                'ord_den_j': max(0,-E.j_invariant().valuation(p)),
                                'ord_mindisc': self.local_info.discriminant_valuation()
                               })

        # URLs of self and related objects:
        self.urls = {}
        self.urls['curve'] = url_for(".show_ecnf", nf = self.field_label, conductor_label=self.conductor_label, class_label = self.iso_label, number = self.number)
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf = self.field_label, conductor_label=self.conductor_label, class_label = self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf = self.field_label, conductor_label=self.conductor_label)
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        if self.field.is_real_quadratic():
            self.hmf_label = "-".join([self.field.label,self.conductor_label,self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field.label, label=self.hmf_label)

        if self.field.is_imag_quadratic():
            self.bmf_label = "-".join([self.field.label,self.conductor_label,self.iso_label])


        self.friends = []
        self.friends += [('Isogeny class '+self.short_class_label, self.urls['class'])]
        self.friends += [('Twists',url_for('ecnf.index',field_label=self.field_label,jinv=self.jinv))]
        if self.field.is_real_quadratic():
            self.friends += [('Hilbert Modular Form '+self.hmf_label, self.urls['hmf'])]
        if self.field.is_imag_quadratic():
            self.friends += [('Bianchi Modular Form %s not yet available' % self.bmf_label, '')]

        self.properties = [
            ('Base field', self.field.field_pretty()),
            ('Label' , self.label)]

        # Plot
        if E.base_field().signature()[0]:
            self.plot = encode_plot(EC_nf_plot(E,self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ('Conductor' , self.cond),
            ('Conductor norm' , self.cond_norm),
            ('j-invariant' , self.j),
            ('CM' , self.cm_bool)]

        if self.base_change:
            self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))]
        else:
            self.base_change = [] # in case it was False instead of []
            self.properties += [('Q-curve' , self.qc)]

        self.properties += [
            ('Torsion order' , self.ntors),
            ('Rank' , self.rk),
            ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0 , url_for("ec.by_ec_label", label=E0))]
Exemple #46
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

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

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

        data = self.data = {}
        data['ainvs'] = [ZZ(ai) for ai in self.ainvs]
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:  # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])

        # extract data about MW rank, generators, heights and torsion:
        self.make_mw()

        # get more data from the database entry

        data['equation'] = self.equation
        local_data = self.local_data
        D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data])
        for ld in local_data:
            ld['kod'] = ld['kod'].replace("\\\\", "\\")
        data['disc'] = D
        Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond'])
                              for ld in local_data])
        Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc'])
                              for ld in local_data],
                             unit=ZZ(self.signD))

        data['minq_D'] = minqD = self.min_quad_twist['disc']
        data['minq_label'] = self.min_quad_twist[
            'lmfdb_label'] if self.label_type == 'LMFDB' else self.min_quad_twist[
                'label']
        data['minq_info'] = '(itself)' if minqD == 1 else '(by {})'.format(
            minqD)

        if self.degree is None:
            data['degree'] = 0  # invalid, but will be displayed nicely
        else:
            data['degree'] = self.degree

        try:
            data['an'] = self.anlist
            data['ap'] = self.aplist
        except AttributeError:
            r = db.ec_curves.lucky({'lmfdb_iso': self.lmfdb_iso, 'number': 1})
            data['an'] = r['anlist']
            data['ap'] = r['aplist']

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

        data['galois_images'] = [
            trim_galois_image_code(s) for s in self.mod_p_images
        ]
        data['non_maximal_primes'] = self.non_maximal_primes
        data['galois_data'] = [{
            'p': p,
            'image': im
        } for p, im in zip(data['non_maximal_primes'], data['galois_images'])]

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['cm_ramp'] = [
                p for p in ZZ(self.cm).support()
                if not p in self.non_maximal_primes
            ]
            data['cm_nramp'] = len(data['cm_ramp'])
            if data['cm_nramp'] == 1:
                data['cm_ramp'] = data['cm_ramp'][0]
            else:
                data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']])
            data['cm_sqf'] = ZZ(self.cm).squarefree_part()

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

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

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        self.one_deg = ZZ(self.class_deg).is_prime()
        isodegs = [str(d) for d in self.isogeny_degrees if d > 1]
        if len(isodegs) < 3:
            data['isogeny_degrees'] = " and ".join(isodegs)
        else:
            data['isogeny_degrees'] = " and ".join(
                [", ".join(isodegs[:-1]), isodegs[-1]])

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

        # Leading term of L-function & other BSD data
        self.make_bsd()

        # Optimality (the optimal curve in the class is the curve
        # whose Cremona label ends in '1' except for '990h' which was
        # labelled wrongly long ago): this is proved for N up to
        # OPTIMALITY_BOUND (and when there is only one curve in an
        # isogeny class, obviously) and expected for all N.

        # Column 'optimality' is 1 for certainly optimal curves, 0 for
        # certainly non-optimal curves, and is n>1 if the curve is one
        # of n in the isogeny class which may be optimal given current
        # knowledge.

        # Column "manin_constant' is the correct Manin constant
        # assuming that the optimal curve in the class is known, or
        # otherwise if it is the curve with (Cremona) number 1.

        # The code here allows us to update the display correctly by
        # changing one line in this file (defining OPTIMALITY_BOUND)
        # without changing the data.

        data['optimality_bound'] = OPTIMALITY_BOUND
        data[
            'manin_constant'] = self.manin_constant  # (conditional on data['optimality_known'])

        if N < OPTIMALITY_BOUND:

            data['optimality_code'] = int(
                self.number == (3 if self.iso == '990h' else 1))
            data['optimality_known'] = True
            data['manin_known'] = True
            if self.label_type == 'Cremona':
                data[
                    'optimal_label'] = '990h3' if self.iso == '990h' else self.iso + '1'
            else:
                data[
                    'optimal_label'] = '990.i3' if self.lmfdb_iso == '990.i' else self.lmfdb_iso + '1'

        else:

            data['optimality_code'] = self.optimality
            data['optimality_known'] = (self.optimality < 2)

            if self.optimality == 1:
                data['manin_known'] = True
                data[
                    'optimal_label'] = self.label if self.label_type == 'Cremona' else self.lmfdb_label
            else:
                if self.number == 1:
                    data['manin_known'] = False
                    data[
                        'optimal_label'] = self.label if self.label_type == 'Cremona' else self.lmfdb_label
                else:
                    # find curve #1 in this class and its optimailty code:
                    opt_curve = db.ec_curves.lucky(
                        {
                            'iso': self.iso,
                            'number': 1
                        },
                        projection=['label', 'lmfdb_label', 'optimality'])
                    data['manin_known'] = (opt_curve['optimality'] == 1)
                    data['optimal_label'] = opt_curve[
                        'label' if self.label_type ==
                        'Cremona' else 'lmfdb_label']

        data['p_adic_data_exists'] = False
        if data['optimality_code'] == 1:
            data['p_adic_data_exists'] = db.ec_padic.exists(
                {'lmfdb_iso': self.lmfdb_iso})

        # Iwasawa data (where present)

        self.make_iwasawa()

        # Torsion growth data (where present)

        self.make_torsion_growth()

        data['newform'] = web_latex(
            PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))
        data['newform_label'] = self.newform_label = ".".join(
            [str(cond), str(2), 'a', iso])
        self.newform_link = url_for("cmf.by_url_newform_label",
                                    level=cond,
                                    weight=2,
                                    char_orbit_label='a',
                                    hecke_orbit=iso)
        self.newform_exists_in_db = db.mf_newforms.label_exists(
            self.newform_label)
        self._code = None

        if self.label_type == 'Cremona':
            self.class_url = url_for(".by_ec_label", label=self.iso)
            self.class_name = self.iso
        else:
            self.class_url = url_for(".by_double_iso_label",
                                     conductor=N,
                                     iso_label=iso)
            self.class_name = self.lmfdb_iso
        data['class_name'] = self.class_name
        data['number'] = self.number

        self.friends = [('Isogeny class ' + self.class_name, self.class_url),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_ec_label", label=data['minq_label'])),
                        ('All twists ',
                         url_for(".rational_elliptic_curves", jinv=self.jinv))]

        lfun_url = url_for("l_functions.l_function_ec_page",
                           conductor_label=N,
                           isogeny_class_label=iso)
        origin_url = lfun_url.lstrip('/L/').rstrip('/')

        if db.lfunc_instances.exists({'url': origin_url}):
            self.friends += [('L-function', lfun_url)]
        else:
            self.friends += [('L-function not available', "")]

        if not self.cm:
            if N <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=N,
                                          isogeny=iso))]
            if N <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=N,
                                          isogeny=iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.downloads = [('q-expansion to text',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_label,
                                   limit=1000)),
                          ('All stored data to text',
                           url_for(".download_EC_all",
                                   label=self.lmfdb_label)),
                          ('Code to Magma',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='magma')),
                          ('Code to SageMath',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='sage')),
                          ('Code to GP',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='gp'))]

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

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

        if self.label_type == 'Cremona':
            self.title = "Elliptic Curve with Cremona label {} (LMFDB label {})".format(
                self.label, self.lmfdb_label)
        else:
            self.title = "Elliptic Curve with LMFDB label {} (Cremona label {})".format(
                self.lmfdb_label, self.label)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]
Exemple #47
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # Create a list of the curves in the class from the database
        self.db_curves = [c for c in db_ec().find(
            {'field_label': self.field_label, 'conductor_label':
             self.conductor_label, 'iso_label': self.iso_label}).sort('number')]
        size = len(self.db_curves)

        # Extract the isogeny degree matrix from the database if possible, else create it
        if hasattr(self, 'isogeny_matrix'):
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        else:
            self.isogeny_matrix = make_iso_matrix(self.db_curves)

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        self.field = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label, lmfdb.base.getDBConnection(), self.field)
        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[c['short_label'], curve_url(c), web_ainvs(self.field_label,c['ainvs'])] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=self.conductor_label, class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        real_quadratic = self.signature == [2,0]
        imag_quadratic = self.signature == [0,1]
        if real_quadratic:
            self.hmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field_label, label=self.hmf_label)

        if imag_quadratic:
            self.bmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])

        self.friends = []
        if real_quadratic:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])]
        if imag_quadratic:
            self.friends += [('Bianchi Modular Form %s not yet available' % self.bmf_label, '')]

        self.properties = [('Base field', self.field),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)
                           ]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label, self.urls['class'])]
Exemple #49
0
    def make_object(self, curve, endo, tama, ratpts, 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(factor(int(
            data['cond']))).replace(r"-1 \cdot", "-")
        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(factor(
                data['disc'])).replace(r"-1 \cdot", "-")
            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(zfactor(i)).replace(r"-1 \cdot", "-")
                for i in data['igusa_clebsch']
            ]
            data['igusa_factor_latex'] = [
                web_latex(zfactor(j)).replace(r"-1 \cdot", "-")
                for j in data['igusa']
            ]
            data['aut_grp'] = small_group_label_display_knowl(
                '%d.%d' % tuple(literal_eval(curve['aut_grp_id'])))
            data['geom_aut_grp'] = small_group_label_display_knowl(
                '%d.%d' % tuple(literal_eval(curve['geom_aut_grp_id'])))
            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['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'])

            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]), group_display_knowl(t[2][0], t[2][1]))

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

        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'])

        # 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', str(data['cond'])),
                ('Discriminant', str(data['disc'])),
            ]
            if data['mw_rank_proved']:
                properties += [('Mordell-Weil group', data['mw_group'])]
        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'\(\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(('Isogeny class %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 EC
        ecs = []
        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(
                        ("Isogeny class " + ec_label_class(friend_label),
                         url_for_ec_class(friend_label)))

        ecs.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 + 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']
                ]) + '];'
            }
        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);'
        }
Exemple #50
0
    def make_class(self):
        # Extract the size of the isogeny class from the database
        classdata = db.ec_classdata.lucky({'lmfdb_iso': self.lmfdb_iso})
        self.class_size = ncurves = classdata['class_size']

        # Create a list of the curves in the class from the database
        number_key = 'Cnumber' if self.label_type == 'Cremona' else 'lmfdb_number'
        self.curves = [
            db.ec_curvedata.lucky({
                'lmfdb_iso': self.lmfdb_iso,
                number_key: i + 1
            }) for i in range(ncurves)
        ]

        # Set optimality flags.  The optimal curve is conditionally
        # number 1 except in one case which is labeled differently in
        # the Cremona tables.  We know which curve is optimal iff the
        # optimality code for curve #1 is 1 (except for class 990h).

        # Note that self is actually an elliptic curve, with number=1.

        # The code here allows us to update the display correctly by
        # changing one line in this file (defining OPTIMALITY_BOUND)
        # without changing the data.

        self.cremona_bound = CREMONA_BOUND
        self.optimality_bound = OPTIMALITY_BOUND
        self.optimality_known = (self.conductor < OPTIMALITY_BOUND) or (
            (self.conductor < CREMONA_BOUND) and ((self.optimality == 1) or
                                                  (self.Ciso == '990h')))
        self.optimal_label = self.Clabel if self.label_type == 'Cremona' else self.lmfdb_label

        if self.conductor < OPTIMALITY_BOUND:
            for c in self.curves:
                c['optimal'] = (c['Cnumber'] == (3 if self.Ciso == '990h' else
                                                 1))
                c['optimality_known'] = True
        elif self.conductor < CREMONA_BOUND:
            for c in self.curves:
                c['optimal'] = (c['optimality'] > 0
                                )  # this curve possibly optimal
                c['optimality_known'] = (c['optimality'] == 1
                                         )  # this curve certainly optimal
        else:
            for c in self.curves:
                c['optimal'] = None
                c['optimality_known'] = False

        for c in self.curves:
            c['ai'] = c['ainvs']
            c['curve_url_lmfdb'] = url_for(".by_triple_label",
                                           conductor=self.conductor,
                                           iso_label=self.iso_label,
                                           number=c['lmfdb_number'])
            c['curve_url_cremona'] = url_for(
                ".by_ec_label",
                label=c['Clabel']) if self.conductor < CREMONA_BOUND else "N/A"
            if self.label_type == 'Cremona':
                c['curve_label'] = c['Clabel']
                _, c_iso, c_number = split_cremona_label(c['Clabel'])
            else:
                c['curve_label'] = c['lmfdb_label']
                _, c_iso, c_number = split_lmfdb_label(c['lmfdb_label'])
            c['short_label'] = "{}{}".format(c_iso, c_number)

        from sage.matrix.all import Matrix
        M = classdata['isogeny_matrix']

        # permute rows/cols to match labelling: the rows/cols in the
        # ec_classdata table are with respect to LMFDB ordering.
        if self.label_type == 'Cremona':
            perm = lambda i: next(c for c in self.curves
                                  if c['Cnumber'] == i + 1)['lmfdb_number'] - 1
            M = [[M[perm(i)][perm(j)] for i in range(ncurves)]
                 for j in range(ncurves)]

        M = Matrix(M)

        self.isogeny_matrix_str = latex(M)

        # Create isogeny graph with appropriate vertex labels:

        self.graph = make_graph(M, [c['short_label'] for c in self.curves])
        P = self.graph.plot(edge_labels=True, vertex_size=1000)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        self.newform = raw_typeset(
            PowerSeriesRing(QQ, 'q')(classdata['anlist'], 20, check=True))
        self.newform_label = ".".join(
            [str(self.conductor),
             str(2), 'a', self.iso_label])
        self.newform_exists_in_db = db.mf_newforms.label_exists(
            self.newform_label)
        if self.newform_exists_in_db:
            char_orbit, hecke_orbit = self.newform_label.split('.')[2:]
            self.newform_link = url_for("cmf.by_url_newform_label",
                                        level=self.conductor,
                                        weight=2,
                                        char_orbit_label=char_orbit,
                                        hecke_orbit=hecke_orbit)

        self.lfunction_link = url_for("l_functions.l_function_ec_page",
                                      conductor_label=self.conductor,
                                      isogeny_class_label=self.iso_label)

        self.friends = [('L-function', self.lfunction_link)]

        if self.cm:
            # set CM field for Properties box.
            D = ZZ(self.cm).squarefree_part()
            coeffs = [(1 - D) // 4, -1, 1] if D % 4 == 1 else [-D, 0, 1]
            lab = db.nf_fields.lucky({'coeffs': coeffs}, projection='label')
            self.CMfield = field_pretty(lab)
        else:
            self.CMfield = "no"
            if self.conductor <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=self.conductor,
                                          isogeny=self.iso_label))]
            if self.conductor <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=self.conductor,
                                          isogeny=self.iso_label))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        if self.label_type == 'Cremona':
            self.title = "Elliptic curve isogeny class with Cremona label {} (LMFDB label {})".format(
                self.Ciso, self.lmfdb_iso)
        elif self.conductor < CREMONA_BOUND:
            self.title = "Elliptic curve isogeny class with LMFDB label {} (Cremona label {})".format(
                self.lmfdb_iso, self.Ciso)
        else:
            self.title = "Elliptic curve isogeny class with LMFDB label {}".format(
                self.lmfdb_iso)

        self.properties = [
            ('Label',
             self.Ciso if self.label_type == 'Cremona' else self.lmfdb_iso),
            ('Number of curves', prop_int_pretty(ncurves)),
            ('Conductor', prop_int_pretty(self.conductor)),
            ('CM', '%s' % self.CMfield), ('Rank', prop_int_pretty(self.rank))
        ]
        if ncurves > 1:
            self.properties += [('Graph', ''), (None, self.graph_link)]

        self.downloads = [('q-expansion to text',
                           url_for(".download_EC_qexp",
                                   label=self.iso_label,
                                   limit=1000)),
                          ('All stored data to text',
                           url_for(".download_EC_all", label=self.iso_label))]

        self.bread = [('Elliptic curves', url_for("ecnf.index")),
                      (r'$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % self.conductor,
                       url_for(".by_conductor", conductor=self.conductor)),
                      ('%s' % self.iso_label, ' ')]
        self.code = {}
        self.code['show'] = {'sage': ''}  # use default show names
        self.code['class'] = {
            'sage':
            'E = EllipticCurve("%s1")\n' % (self.iso_label) +
            'E.isogeny_class()\n'
        }
        self.code['curves'] = {'sage': 'E.isogeny_class().curves'}
        self.code['rank'] = {'sage': 'E.rank()'}
        self.code['q_eigenform'] = {'sage': 'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage': 'E.isogeny_class().matrix()'}
        self.code['plot'] = {
            'sage': 'E.isogeny_graph().plot(edge_labels=True)'
        }
Exemple #51
0
    def make_curve(self):
        # To start with the data fields of self are just those from the
        # databases.  We reformat these, while computing some further (easy)
        # data about the curve on the fly.

        # Initialize data:
        data = self.data = {}
        endodata = self.endodata = {}

        # Polish data from database before putting it into the data dictionary:
        disc = ZZ(self.disc_sign) * ZZ(self.disc_key[3:])
        # to deal with disc_key, uncomment line above and comment line below
        #disc = ZZ(self.disc_sign) * ZZ(self.abs_disc)
        data['disc'] = disc
        data['cond'] = ZZ(self.cond)
        data['min_eqn'] = self.min_eqn
        data['min_eqn_display'] = list_to_min_eqn(self.min_eqn)
        data['disc_factor_latex'] = web_latex(factor(data['disc']))
        data['cond_factor_latex'] = web_latex(factor(int(self.cond)))
        data['aut_grp'] = groupid_to_meaningful(self.aut_grp)
        data['geom_aut_grp'] = groupid_to_meaningful(self.geom_aut_grp)
        data['igusa_clebsch'] = [ZZ(a) for a in self.igusa_clebsch]
        data['igusa'] = [ZZ(a) for a in self.igusa]
        data['g2'] = self.g2inv
        data['ic_norm'] = data['igusa_clebsch']
        data['igusa_norm'] = data['igusa']
        # Should we ever want to normalize the invariants further, then
        # uncomment the following lines:
        #data['ic_norm'] = normalize_invariants(data['igusa_clebsch'], [2, 4, 6,
        #    10])
        #data['igusa_norm'] = normalize_invariants(data['igusa'], [2, 4, 6, 8,
        #    10])
        data['ic_norm_factor_latex'] = [
            web_latex(zfactor(i)) for i in data['ic_norm']
        ]
        data['igusa_norm_factor_latex'] = [
            web_latex(zfactor(j)) for j in data['igusa_norm']
        ]
        data['num_rat_wpts'] = ZZ(self.num_rat_wpts)
        data['two_selmer_rank'] = ZZ(self.two_selmer_rank)
        if len(self.torsion) == 0:
            data['tor_struct'] = '\mathrm{trivial}'
        else:
            tor_struct = [ZZ(a) for a in self.torsion]
            data['tor_struct'] = ' \\times '.join(
                ['\Z/{%s}\Z' % n for n in tor_struct])

        # Data derived from Sato-Tate group:
        isogeny_class = db_g2c().isogeny_classes.find_one(
            {'label': isog_label(self.label)})
        st_data = get_st_data(isogeny_class)
        for key in st_data.keys():
            data[key] = st_data[key]

        # GL_2 statement over the base field
        endodata['gl2_statement_base'] = \
            gl2_statement_base(self.factorsRR_base, r'\(\Q\)')

        # NOTE: In what follows there is some copying of code and data that is
        # stupid from the point of view of efficiency but likely better from
        # that of maintenance.

        # Endomorphism data over QQ:
        endodata['factorsQQ_base'] = self.factorsQQ_base
        endodata['factorsRR_base'] = self.factorsRR_base
        endodata['ring_base'] = self.ring_base
        endodata['endo_statement_base'] = \
            """Endomorphism ring over \(\Q\):""" + \
            endo_statement(endodata['factorsQQ_base'],
                endodata['factorsRR_base'], endodata['ring_base'], r'')
        # Field of definition data:
        endodata['fod_label'] = self.fod_label
        endodata['fod_poly'] = intlist_to_poly(self.fod_coeffs)
        endodata['fod_statement'] = fod_statement(endodata['fod_label'],
                                                  endodata['fod_poly'])
        # Endomorphism data over QQbar:
        endodata['factorsQQ_geom'] = self.factorsQQ_geom
        endodata['factorsRR_geom'] = self.factorsRR_geom
        endodata['ring_geom'] = self.ring_geom
        if self.fod_label != '1.1.1.1':
            endodata['gl2_statement_geom'] = \
                gl2_statement_base(self.factorsRR_geom, r'\(\overline{\Q}\)')
            endodata['endo_statement_geom'] = \
            """Endomorphism ring over \(\overline{\Q}\):""" + \
            endo_statement(endodata['factorsQQ_geom'],
                endodata['factorsRR_geom'], endodata['ring_geom'],
                r'\overline{\Q}')

        # Full endomorphism lattice minus entries already treated:
        N = len(self.lattice)
        endodata['lattice'] = (self.lattice)[1:N - 1]
        if endodata['lattice']:
            endodata['lattice_statement_preamble'] = \
                lattice_statement_preamble()
            endodata['lattice_statement'] = \
                lattice_statement(endodata['lattice'])

        # Splitting field description:
        #endodata['is_simple_base'] = self.is_simple_base
        endodata['is_simple_geom'] = self.is_simple_geom
        endodata['spl_fod_label'] = self.spl_fod_label
        endodata['spl_fod_poly'] = intlist_to_poly(self.spl_fod_coeffs)
        endodata['spl_fod_statement'] = \
            spl_fod_statement(endodata['is_simple_geom'],
                endodata['spl_fod_label'], endodata['spl_fod_poly'])

        # Isogeny factors:
        if not endodata['is_simple_geom']:
            endodata['spl_facs_coeffs'] = self.spl_facs_coeffs
            # This could be done non-uniformly as well... later.
            if len(self.spl_facs_labels) == len(self.spl_facs_coeffs):
                endodata['spl_facs_labels'] = self.spl_facs_labels
            else:
                endodata['spl_facs_labels'] = [
                    '' for coeffs in self.spl_facs_coeffs
                ]
            endodata['spl_facs_condnorms'] = self.spl_facs_condnorms
            endodata['spl_statement'] = \
                spl_statement(endodata['spl_facs_coeffs'],
                    endodata['spl_facs_labels'],
                    endodata['spl_facs_condnorms'])

        # Title
        self.title = "Genus 2 Curve %s" % (self.label)

        # Lady Gaga box
        self.plot = encode_plot(eqn_list_to_curve_plot(self.min_eqn))
        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [
            ('Label', self.label), (None, self.plot_link),
            ('Conductor', '%s' % self.cond),
            ('Discriminant', '%s' % data['disc']),
            ('Invariants',
             '%s </br> %s </br> %s </br> %s' % tuple(data['ic_norm'])),
            ('Sato-Tate group', '\(%s\)' % data['st_group_name']),
            ('\(%s\)' % data['real_geom_end_alg_disp'][0],
             '\(%s\)' % data['real_geom_end_alg_disp'][1]),
            ('\(\mathrm{GL}_2\)-type', '%s' % data['is_gl2_type_name'])
        ]
        x = self.label.split('.')[1]
        self.friends = [
            ('Isogeny class %s' % isog_label(self.label),
             url_for(".by_double_iso_label", conductor=self.cond,
                     iso_label=x)),
            ('L-function',
             url_for("l_functions.l_function_genus2_page", cond=self.cond,
                     x=x)),
            ('Twists',
             url_for(".index_Q",
                     g20=self.g2inv[0],
                     g21=self.g2inv[1],
                     g22=self.g2inv[2]))
            #('Twists2',
            #   url_for(".index_Q",
            #       igusa_clebsch = str(self.igusa_clebsch)))  #doesn't work.
            #('Siegel modular form someday', '.')
        ]
        self.downloads = [('Download all stored data', '.')]

        # Breadcrumbs
        iso = self.label.split('.')[1]
        num = '.'.join(self.label.split('.')[2:4])
        self.bread = [('Genus 2 Curves', url_for(".index")),
                      ('$\Q$', url_for(".index_Q")),
                      ('%s' % self.cond,
                       url_for(".by_conductor", conductor=self.cond)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=self.cond,
                               iso_label=iso)),
                      ('Genus 2 curve %s' % num,
                       url_for(".by_g2c_label", label=self.label))]

        # Make code that is used on the page:
        self.make_code_snippets()
Exemple #52
0
    def make_curve(self):
        # To start with the data fields of self are just those from the
        # databases.  We reformat these, while computing some further (easy)
        # data about the curve on the fly.

        # Initialize data:
        data = self.data = {}
        endodata = self.endodata = {}

        # Polish data from database before putting it into the data dictionary:
        disc = ZZ(self.disc_sign) * ZZ(self.disc_key[3:])
        # to deal with disc_key, uncomment line above and comment line below
        #disc = ZZ(self.disc_sign) * ZZ(self.abs_disc)
        data['disc'] = disc
        data['abs_disc'] = ZZ(self.disc_key[3:])
        data['cond'] = ZZ(self.cond)
        data['min_eqn'] = self.min_eqn
        data['min_eqn_display'] = list_to_min_eqn(self.min_eqn)
        data['disc_factor_latex'] = web_latex(factor(data['disc']))
        data['cond_factor_latex'] = web_latex(factor(int(self.cond)))
        data['aut_grp_id'] = self.aut_grp_id
        data['geom_aut_grp_id'] = self.geom_aut_grp_id
        data['igusa_clebsch'] = [ZZ(a) for a in self.igusa_clebsch]
        data['igusa'] = [ZZ(a) for a in self.igusa]
        data['g2'] = self.g2inv
        data['ic_norm'] = data['igusa_clebsch']
        data['igusa_norm'] = data['igusa']
        # Should we ever want to normalize the invariants further, then
        # uncomment the following lines:
        #data['ic_norm'] = normalize_invariants(data['igusa_clebsch'], [2, 4, 6,
        #    10])
        #data['igusa_norm'] = normalize_invariants(data['igusa'], [2, 4, 6, 8,
        #    10])
        data['ic_norm_factor_latex'] = [web_latex(zfactor(i)) for i in data['ic_norm']]
        data['igusa_norm_factor_latex'] = [ web_latex(zfactor(j)) for j in data['igusa_norm'] ]
        data['num_rat_wpts'] = ZZ(self.num_rat_wpts)
        data['two_selmer_rank'] = ZZ(self.two_selmer_rank)
        data['analytic_rank'] = ZZ(self.analytic_rank)
        data['has_square_sha'] = "square" if self.has_square_sha else "twice a square"
        data['locally_solvable'] = "yes" if self.locally_solvable else "no"
        if len(self.torsion) == 0:
            data['tor_struct'] = '\mathrm{trivial}'
        else:
            tor_struct = [ ZZ(a) for a in self.torsion ]
            data['tor_struct'] = ' \\times '.join([ '\Z/{%s}\Z' % n for n in tor_struct ])

        # Data derived from Sato-Tate group:
        isogeny_class = g2cdb().isogeny_classes.find_one({'label' : isogeny_class_label(self.label)})
        st_data = get_st_data(isogeny_class)
        for key in st_data.keys():
            data[key] = st_data[key]

        # GL_2 statement over the base field
        endodata['gl2_statement_base'] = \
            gl2_statement_base(self.factorsRR_base, r'\(\Q\)')

        # NOTE: In what follows there is some copying of code and data that is
        # stupid from the point of view of efficiency but likely better from
        # that of maintenance.

        # Endomorphism data over QQ:
        endodata['factorsQQ_base'] = self.factorsQQ_base
        endodata['factorsRR_base'] = self.factorsRR_base
        endodata['ring_base'] = self.ring_base
        endodata['endo_statement_base'] = \
            """Endomorphism ring over \(\Q\):""" + \
            endo_statement(endodata['factorsQQ_base'],
                endodata['factorsRR_base'], endodata['ring_base'], r'')
        # Field of definition data:
        endodata['fod_label'] = self.fod_label
        endodata['fod_poly'] = intlist_to_poly(self.fod_coeffs)
        endodata['fod_statement'] = fod_statement(endodata['fod_label'],
            endodata['fod_poly'])
        # Endomorphism data over QQbar:
        endodata['factorsQQ_geom'] = self.factorsQQ_geom
        endodata['factorsRR_geom'] = self.factorsRR_geom
        endodata['ring_geom'] = self.ring_geom
        if self.fod_label != '1.1.1.1':
            endodata['gl2_statement_geom'] = \
                gl2_statement_base(self.factorsRR_geom, r'\(\overline{\Q}\)')
            endodata['endo_statement_geom'] = \
                """Endomorphism ring over \(\overline{\Q}\):""" + \
                endo_statement(
                    endodata['factorsQQ_geom'],
                    endodata['factorsRR_geom'],
                    endodata['ring_geom'],
                    r'\overline{\Q}')

        # Full endomorphism lattice minus entries already treated:
        N = len(self.lattice)
        endodata['lattice'] = (self.lattice)[1:N - 1]
        if endodata['lattice']:
            endodata['lattice_statement_preamble'] = lattice_statement_preamble()
            endodata['lattice_statement'] = lattice_statement(endodata['lattice'])

        # Splitting field description:
        #endodata['is_simple_base'] = self.is_simple_base
        endodata['is_simple_geom'] = self.is_simple_geom
        endodata['spl_fod_label'] = self.spl_fod_label
        endodata['spl_fod_poly'] = intlist_to_poly(self.spl_fod_coeffs)
        endodata['spl_fod_statement'] = spl_fod_statement(
            endodata['is_simple_geom'],
            endodata['spl_fod_label'], endodata['spl_fod_poly'])

        # Isogeny factors:
        if not endodata['is_simple_geom']:
            endodata['spl_facs_coeffs'] = self.spl_facs_coeffs
            # This could be done non-uniformly as well... later.
            if len(self.spl_facs_labels) == len(self.spl_facs_coeffs):
                endodata['spl_facs_labels'] = self.spl_facs_labels
            else:
                endodata['spl_facs_labels'] = ['' for coeffs in
                    self.spl_facs_coeffs]
            endodata['spl_facs_condnorms'] = self.spl_facs_condnorms
            endodata['spl_statement'] = spl_statement(
                endodata['spl_facs_coeffs'],
                endodata['spl_facs_labels'],
                endodata['spl_facs_condnorms'])

        # Title
        self.title = "Genus 2 Curve %s" % (self.label)

        alpha = self.label.split('.')[1]
        num = self.label.split('.')[3]

        # Lady Gaga box
        self.plot = encode_plot(eqn_list_to_curve_plot(self.min_eqn))
        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = (
            ('Label', self.label),
            (None, self.plot_link),
            ('Conductor','%s' % self.cond),
            ('Discriminant', '%s' % data['disc']),
            ('Invariants', '%s </br> %s </br> %s </br> %s' % tuple(data['ic_norm'])),
            ('Sato-Tate group', data['st_group_href']),
            ('\(%s\)' % data['real_geom_end_alg_disp'][0],
             '\(%s\)' % data['real_geom_end_alg_disp'][1]),
            ('\(\mathrm{GL}_2\)-type','%s' % data['is_gl2_type_name'])
            )
        self.friends = [
            ('Isogeny class %s' % isogeny_class_label(self.label),
             url_for(".by_url_isogeny_class_label", cond = self.cond,alpha =alpha)),
            ('L-function', url_for("l_functions.l_function_genus2_page", cond=self.cond,x=alpha)),
            ('Twists', url_for(".index_Q", g20 = self.g2inv[0], g21 = self.g2inv[1], g22 = self.g2inv[2]))
            #('Siegel modular form someday', '.')
            ]

        if not endodata['is_simple_geom']:
            self.friends += [('Elliptic curve %s' % lab,url_for_ec(lab)) for lab in endodata['spl_facs_labels'] if lab != '']
        #self.downloads = [('Download all stored data', '.')]

        # Breadcrumbs
        self.bread = (
             ('Genus 2 Curves', url_for(".index")),
             ('$\Q$', url_for(".index_Q")),
             ('%s' % self.cond, url_for(".by_conductor", cond=self.cond)),
             ('%s' % alpha, url_for(".by_url_isogeny_class_label", cond=self.cond, alpha=alpha)),
             ('%s' % self.abs_disc, url_for(".by_url_isogeny_class_discriminant", cond=self.cond, alpha=alpha, disc=self.abs_disc)),
             ('%s' % num, url_for(".by_url_curve_label", cond=self.cond, alpha=alpha, disc=self.abs_disc, num=num))
             )

        # Make code that is used on the page:
        self.code = {}
        self.code['show'] = {'sage':'','magma':''} # use default show names
        self.code['curve'] = {'sage':'R.<x> = PolynomialRing(QQ); C = HyperellipticCurve(R(%s), R(%s))'%(self.data['min_eqn'][0],self.data['min_eqn'][1]),
                              'magma':'R<x> := PolynomialRing(Rationals()); C := HyperellipticCurve(R!%s, R!%s);'%(self.data['min_eqn'][0],self.data['min_eqn'][1])}
        if self.data['disc'] % 4096 == 0:
            ind2 = [a[0] for a in self.data['isogeny_class']['bad_lfactors']].index(2)
            bad2 = self.data['isogeny_class']['bad_lfactors'][ind2][1]
            magma_cond_option = ': ExcFactors:=[*<2,Valuation('+str(self.data['cond'])+',2),R!'+str(bad2)+'>*]'
        else:
            magma_cond_option = ''
        self.code['cond'] = {'magma': 'Conductor(LSeries(C%s)); Factorization($1);'% magma_cond_option}
        self.code['disc'] = {'magma':'Discriminant(C); Factorization(Integers()!$1);'}
        self.code['igusa_clebsch'] = {'sage':'C.igusa_clebsch_invariants(); [factor(a) for a in _]',
                                      'magma':'IgusaClebschInvariants(C); [Factorization(Integers()!a): a in $1];'}
        self.code['igusa'] = {'magma':'IgusaInvariants(C); [Factorization(Integers()!a): a in $1];'}
        self.code['g2'] = {'magma':'G2Invariants(C);'}
        self.code['aut'] = {'magma':'AutomorphismGroup(C); IdentifyGroup($1);'}
        self.code['autQbar'] = {'magma':'AutomorphismGroup(ChangeRing(C,AlgebraicClosure(Rationals()))); IdentifyGroup($1);'}
        self.code['num_rat_wpts'] = {'magma':'#Roots(HyperellipticPolynomials(SimplifiedModel(C)));'}
        self.code['two_selmer'] = {'magma':'TwoSelmerGroup(Jacobian(C)); NumberOfGenerators($1);'}
        self.code['has_square_sha'] = {'magma':'HasSquareSha(Jacobian(C));'}
        self.code['locally_solvable'] = {'magma':'f,h:=HyperellipticPolynomials(C); g:=4*f+h^2; HasPointsLocallyEverywhere(g,2) and (#Roots(ChangeRing(g,RealField())) gt 0 or LeadingCoefficient(g) gt 0);'}
        self.code['tor_struct'] = {'magma':'TorsionSubgroup(Jacobian(SimplifiedModel(C))); AbelianInvariants($1);'}
Exemple #53
0
    def make_E(self):
        K = self.field.K()

        # a-invariants
        self.ainvs = parse_ainvs(K, self.ainvs)
        self.latex_ainvs = web_latex(self.ainvs)
        self.numb = str(self.number)

        # Conductor, discriminant, j-invariant
        N = ideal_from_string(K, self.conductor_ideal)
        self.cond = web_latex(N)
        self.cond_norm = web_latex(self.conductor_norm)
        local_data = self.local_data

        # NB badprimes is a list of primes which divide the
        # discriminant of this model.  At most one of these might
        # actually be a prime of good reduction, if the curve has no
        # global minimal model.
        badprimes = [ideal_from_string(K, ld['p']) for ld in local_data]
        badnorms = [ZZ(ld['normp']) for ld in local_data]
        mindisc_ords = [ld['ord_disc'] for ld in local_data]

        # Assumption: the curve models stored in the database are
        # either global minimal models or minimal at all but one
        # prime, so the list here has length 0 or 1:

        self.non_min_primes = [ideal_from_string(K, P) for P in self.non_min_p]
        self.is_minimal = (len(self.non_min_primes) == 0)
        self.has_minimal_model = self.is_minimal
        disc_ords = [ld['ord_disc'] for ld in local_data]
        if not self.is_minimal:
            Pmin = self.non_min_primes[0]
            P_index = badprimes.index(Pmin)
            self.non_min_prime = web_latex(Pmin)
            disc_ords[P_index] += 12

        if self.conductor_norm == 1:  # since the factorization of (1) displays as "1"
            self.fact_cond = self.cond
            self.fact_cond_norm = self.cond
        else:
            Nfac = Factorization([(P, ld['ord_cond'])
                                  for P, ld in zip(badprimes, local_data)])
            self.fact_cond = web_latex_ideal_fact(Nfac)
            Nnormfac = Factorization([(q, ld['ord_cond'])
                                      for q, ld in zip(badnorms, local_data)])
            self.fact_cond_norm = web_latex(Nnormfac)

        # D is the discriminant ideal of the model
        D = prod([P**e for P, e in zip(badprimes, disc_ords)], K.ideal(1))
        self.disc = web_latex(D)
        Dnorm = D.norm()
        self.disc_norm = web_latex(Dnorm)
        if Dnorm == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
            self.fact_disc_norm = self.disc
        else:
            Dfac = Factorization([(P, e)
                                  for P, e in zip(badprimes, disc_ords)])
            self.fact_disc = web_latex_ideal_fact(Dfac)
            Dnormfac = Factorization([(q, e)
                                      for q, e in zip(badnorms, disc_ords)])
            self.fact_disc_norm = web_latex(Dnormfac)

        if not self.is_minimal:
            Dmin = ideal_from_string(K, self.minD)
            self.mindisc = web_latex(Dmin)
            Dmin_norm = Dmin.norm()
            self.mindisc_norm = web_latex(Dmin_norm)
            if Dmin_norm == 1:  # since the factorization of (1) displays as "1"
                self.fact_mindisc = self.mindisc
                self.fact_mindisc_norm = self.mindisc
            else:
                Dminfac = Factorization([
                    (P, e) for P, edd in zip(badprimes, mindisc_ords)
                ])
                self.fact_mindisc = web_latex_ideal_fact(Dminfac)
                Dminnormfac = Factorization([
                    (q, e) for q, e in zip(badnorms, mindisc_ords)
                ])
                self.fact_mindisc_norm = web_latex(Dminnormfac)

        j = self.field.parse_NFelt(self.jinv)
        # if j:
        #     d = j.denominator()
        #     n = d * j  # numerator exists for quadratic fields only!
        #     g = GCD(list(n))
        #     n1 = n / g
        #     self.j = web_latex(n1)
        #     if d != 1:
        #         if n1 > 1:
        #         # self.j = "("+self.j+")\(/\)"+web_latex(d)
        #             self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d))
        #         else:
        #             self.j = web_latex(d)
        #         if g > 1:
        #             if n1 > 1:
        #                 self.j = web_latex(g) + self.j
        #             else:
        #                 self.j = web_latex(g)
        self.j = web_latex(j)

        self.fact_j = None
        # See issue 1258: some j factorizations work but take too long
        # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1).  Note that we do
        # store the factorization of the denominator of j and display
        # that, which is the most interesting part.

        # Images of Galois representations

        if not hasattr(self, 'galois_images'):
            #print "No Galois image data"
            self.galois_images = "?"
            self.non_surjective_primes = "?"
            self.galois_data = []
        else:
            self.galois_data = [{
                'p': p,
                'image': im
            } for p, im in zip(self.non_surjective_primes, self.galois_images)]

        # CM and End(E)
        self.cm_bool = "no"
        self.End = "\(\Z\)"
        if self.cm:
            self.rational_cm = K(self.cm).is_square()
            self.cm_sqf = ZZ(self.cm).squarefree_part()
            self.cm_bool = "yes (\(%s\))" % self.cm
            if self.cm % 4 == 0:
                d4 = ZZ(self.cm) // 4
                self.End = "\(\Z[\sqrt{%s}]\)" % (d4)
            else:
                self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm

        # Galois images in CM case:
        if self.cm and self.galois_images != '?':
            self.cm_ramp = [
                p for p in ZZ(self.cm).support()
                if not p in self.non_surjective_primes
            ]
            self.cm_nramp = len(self.cm_ramp)
            if self.cm_nramp == 1:
                self.cm_ramp = self.cm_ramp[0]
            else:
                self.cm_ramp = ", ".join([str(p) for p in self.cm_ramp])

        # Sato-Tate:
        # The lines below will need to change once we have curves over non-quadratic fields
        # that contain the Hilbert class field of an imaginary quadratic field
        if self.cm:
            if self.signature == [0, 1] and ZZ(
                    -self.abs_disc * self.cm).is_square():
                self.ST = st_link_by_name(1, 2, 'U(1)')
            else:
                self.ST = st_link_by_name(1, 2, 'N(U(1))')
        else:
            self.ST = st_link_by_name(1, 2, 'SU(2)')

        # Q-curve / Base change
        self.qc = "no"
        try:
            if self.q_curve:
                self.qc = "yes"
        except AttributeError:  # in case the db entry does not have this field set
            pass

        # Torsion
        self.ntors = web_latex(self.torsion_order)
        self.tr = len(self.torsion_structure)
        if self.tr == 0:
            self.tor_struct_pretty = "Trivial"
        if self.tr == 1:
            self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0]
        if self.tr == 2:
            self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(
                self.torsion_structure)

        torsion_gens = [parse_point(K, P) for P in self.torsion_gens]
        self.torsion_gens = ",".join([web_point(P) for P in torsion_gens])

        # Rank or bounds
        try:
            self.rk = web_latex(self.rank)
        except AttributeError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.rank_bounds)
        except AttributeError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not available"

        # Generators
        try:
            gens = [parse_point(K, P) for P in self.gens]
            self.gens = ", ".join([web_point(P) for P in gens])
            if self.rk == "?":
                self.reg = "not available"
            else:
                if gens:
                    try:
                        self.reg = self.reg
                    except AttributeError:
                        self.reg = "not available"
                    pass  # self.reg already set
                else:
                    self.reg = 1  # otherwise we only get 1.00000...

        except AttributeError:
            self.gens = "not available"
            self.reg = "not available"
            try:
                if self.rank == 0:
                    self.reg = 1
            except AttributeError:
                pass

        # Local data
        for P, ld in zip(badprimes, local_data):
            ld['p'] = web_latex(P)
            ld['norm'] = P.norm()
            ld['kod'] = web_latex(ld['kod']).replace('$', '')

        # URLs of self and related objects:
        self.urls = {}
        # It's useful to be able to use this class out of context, when calling url_for will fail:
        try:
            self.urls['curve'] = url_for(".show_ecnf",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label),
                                         class_label=self.iso_label,
                                         number=self.number)
        except RuntimeError:
            return
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=quote(
                                         self.conductor_label),
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=quote(
                                             self.conductor_label))
        self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label)

        # Isogeny information

        if self.number == 1:
            isogmat = self.isogeny_matrix
        else:
            isogmat = db_ecnf().find_one({
                'class_label': self.class_label,
                'number': 1
            })['isogeny_matrix']
        self.class_deg = max([max(d) for d in isogmat])
        self.one_deg = ZZ(self.class_deg).is_prime()
        self.ncurves = db_ecnf().count({'class_label': self.class_label})
        isodegs = [str(d) for d in self.isogeny_degrees if d > 1]
        if len(isodegs) < 3:
            self.isogeny_degrees = " and ".join(isodegs)
        else:
            self.isogeny_degrees = " and ".join(
                [", ".join(isodegs[:-1]), isodegs[-1]])

        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]

        if totally_real:
            self.hmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field.label,
                                       label=self.hmf_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page",
                                             field=self.field_label,
                                             label=self.hmf_label,
                                             character='0',
                                             number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field.label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage',
                                   field_label=self.field_label,
                                   level_label=self.conductor_label,
                                   label_suffix=self.iso_label)

        self.friends = []
        self.friends += [('Isogeny class ' + self.short_class_label,
                          self.urls['class'])]
        self.friends += [('Twists',
                          url_for('ecnf.index',
                                  field=self.field_label,
                                  jinv=rename_j(j)))]
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]
            self.friends += [('L-function', self.urls['Lfunction'])]
        if imag_quadratic:
            #self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')]
            if "CM" in self.label:
                self.friends += [('Bianchi Modular Form is not cuspidal', '')]
            else:
                self.friends += [('Bianchi Modular Form %s' % self.bmf_label,
                                  self.bmf_url)]

        self.properties = [('Base field', self.field.field_pretty()),
                           ('Label', self.label)]

        # Plot
        if K.signature()[0]:
            self.plot = encode_plot(
                EC_nf_plot(K, self.ainvs, self.field.generator_name()))
            self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
            self.properties += [(None, self.plot_link)]

        self.properties += [
            ('Conductor', self.cond),
            ('Conductor norm', self.cond_norm),
            # See issue #796 for why this is hidden (can be very large)
            # ('j-invariant', self.j),
            ('CM', self.cm_bool)
        ]

        if self.base_change:
            self.properties += [
                ('base-change',
                 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))
            ]
        else:
            self.base_change = []  # in case it was False instead of []
            self.properties += [('Q-curve', self.qc)]

        r = self.rk
        if r == "?":
            r = self.rk_bnds
        self.properties += [
            ('Torsion order', self.ntors),
            ('Rank', r),
        ]

        for E0 in self.base_change:
            self.friends += [('Base-change of %s /\(\Q\)' % E0,
                              url_for("ec.by_ec_label", label=E0))]

        self._code = None  # will be set if needed by get_code()
Exemple #54
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

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

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

        data = self.data = {}
        data['ainvs'] = self.ainvs
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']: # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])

        # extract data about MW rank, generators, heights and torsion:
        self.make_mw()

        # get more data from the database entry

        data['equation'] = self.equation
        local_data = self.local_data
        D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data])
        data['disc'] = D
        Nfac = Factorization([(ZZ(ld['p']),ld['ord_cond']) for ld in local_data])
        Dfac = Factorization([(ZZ(ld['p']),ld['ord_disc']) for ld in local_data], unit=ZZ(self.signD))

        data['minq_D'] = minqD = self.min_quad_twist['disc']
        minq_label = self.min_quad_twist['label']
        data['minq_label'] = db.ec_curves.lucky({'label':minq_label}, 'lmfdb_label')
        data['minq_info'] = '(itself)' if minqD==1 else '(by %s)' % minqD
        if self.degree is None:
            data['degree'] = 0 # invalid, but will be displayed nicely
        else:
            data['degree'] = self.degree
        if self.number == 1:
            data['an'] = self.anlist
            data['ap'] = self.aplist
        else:
            r = db.ec_curves.lucky({'lmfdb_iso':self.lmfdb_iso, 'number':1})
            data['an'] = r['anlist']
            data['ap'] = r['aplist']

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

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

        data['galois_images'] = [trim_galois_image_code(s) for s in self.mod_p_images]
        data['non_maximal_primes'] = self.non_maximal_primes
        data['galois_data'] = [{'p': p,'image': im }
                               for p,im in zip(data['non_maximal_primes'],
                                               data['galois_images'])]

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['cm_ramp'] = [p for p in ZZ(self.cm).support() if not p in self.non_maximal_primes]
            data['cm_nramp'] = len(data['cm_ramp'])
            if data['cm_nramp']==1:
                data['cm_ramp'] = data['cm_ramp'][0]
            else:
                data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']])
            data['cm_sqf'] = ZZ(self.cm).squarefree_part()

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

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

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


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

        # Leading term of L-function & other BSD data
        self.make_bsd()

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

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


        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = db.ec_padic.exists({'lmfdb_iso': self.lmfdb_iso})

        # Iwasawa data (where present)

        self.make_iwasawa()

        # Torsion growth data (where present)

        self.make_torsion_growth()

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

        self.class_url = url_for(".by_double_iso_label", conductor=N, iso_label=iso)
        self.friends = [
            ('Isogeny class ' + self.lmfdb_iso, self.class_url),
            ('Minimal quadratic twist %s %s' % (data['minq_info'], data['minq_label']), url_for(".by_triple_label", conductor=minq_N, iso_label=minq_iso, number=minq_number)),
            ('All twists ', url_for(".rational_elliptic_curves", jinv=self.jinv)),
            ('L-function', url_for("l_functions.l_function_ec_page", conductor_label = N, isogeny_class_label = iso))]

        if not self.cm:
            if N<=300:
                self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor = N, isogeny = iso))]
            if N<=50:
                self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor = N, isogeny = iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label, self.newform_link)]

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

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


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

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

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

        # Create a list of the curves in the class from the database
        self.db_curves = list(db.ec_nfcurves.search(
            {'field_label': self.field_label,
             'conductor_norm': self.conductor_norm,
             'conductor_label': self.conductor_label,
             'iso_nlabel': self.iso_nlabel}))

        # Rank or bounds
        try:
            self.rk = web_latex(self.db_curves[0]['rank'])
        except KeyError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds'])
        except KeyError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not recorded"


        # Extract the isogeny degree matrix from the database
        if not hasattr(self, 'isogeny_matrix'):
            # this would happen if the class is initiated with a curve
            # which is not #1 in its class:
            self.isogeny_matrix = self.db_curves[0].isogeny_matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.one_deg = ZZ(self.class_deg).is_prime()

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(Matrix(self.isogeny_matrix))

        self.field = FIELD(self.field_label)
        self.field_name = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label, self.field_name)
        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[c['short_label'], curve_url(c), web_ainvs(self.field_label,c['ainvs'])] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=self.conductor_label, class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0,1]
        if totally_real:
            self.hmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field_label, label=self.hmf_label)
            if sig[0] <= 2:
                self.urls['Lfunction'] = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label)
            elif self.abs_disc ** 2 * self.conductor_norm < 40000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0')

        if imag_quadratic:
            self.bmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage', field_label=self.field_label, level_label=self.conductor_label, label_suffix=self.iso_label)
            self.urls['Lfunction'] = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label)

        self.friends = []
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])]

        if imag_quadratic:
            #self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')]
            self.friends += [('Bianchi Modular Form %s' % self.bmf_label, self.bmf_url)]

        if 'Lfunction' in self.urls:
            self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]


        self.properties = [('Base field', self.field_name),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)
                       ]
        if self.rk != '?':
            self.properties += [('Rank', '%s' % self.rk)]
        else:
            if self.rk_bnds == 'not recorded':
                self.properties += [('Rank', '%s' % self.rk_bnds)]
            else:
                self.properties += [('Rank bounds', '%s' % self.rk_bnds)]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label, self.urls['class'])]
Exemple #56
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these, construct the
        # and compute some further (easy) data about it.
        #

        # Weierstrass equation

        data = self.data = {}

        disc = ZZ(self.disc_sign) * ZZ(self.disc_key[3:]) 
        # to deal with disc_key, uncomment line above and remove line below
        #disc = ZZ(self.disc_sign) * ZZ(self.abs_disc)
        data['disc'] = disc
        data['cond'] = ZZ(self.cond)
        data['min_eqn'] = self.min_eqn
        data['min_eqn_display'] = list_to_min_eqn(self.min_eqn)
        data['disc_factor_latex'] = web_latex(factor(data['disc']))
        data['cond_factor_latex'] = web_latex(factor(int(self.cond)))
        data['aut_grp'] = groupid_to_meaningful(self.aut_grp)
        data['geom_aut_grp'] = groupid_to_meaningful(self.geom_aut_grp)
        data['igusa_clebsch'] = [ZZ(a) for a in self.igusa_clebsch]
        data['igusa'] = igusa_clebsch_to_igusa(data['igusa_clebsch'])
        data['g2'] = igusa_to_g2(data['igusa'])
        data['ic_norm'] = normalize_invariants(data['igusa_clebsch'],[1,2,3,5])
        data['igusa_norm'] = normalize_invariants(data['igusa'],[1,2,3,4,5])
        data['ic_norm_factor_latex'] = [web_latex(zfactor(i)) for i in data['ic_norm']]
        data['igusa_norm_factor_latex'] = [web_latex(zfactor(j)) for j in data['igusa_norm']]
        data['num_rat_wpts'] = ZZ(self.num_rat_wpts)
        data['two_selmer_rank'] = ZZ(self.two_selmer_rank)
        if len(self.torsion) == 0:
            data['tor_struct'] = '\mathrm{trivial}'
        else:
            tor_struct = [ZZ(a)  for a in self.torsion]
            data['tor_struct'] = ' \\times '.join(['\Z/{%s}\Z' % n for n in tor_struct])
        isogeny_class = db_g2c().isogeny_classes.find_one({'label' : isog_label(self.label)})
        end_data = get_end_data(isogeny_class)
        for key in end_data.keys():
            data[key] = end_data[key]
        x = self.label.split('.')[1]

        self.make_code_snippets()

        self.friends = [
            ('Isogeny class %s' % isog_label(self.label), url_for(".by_double_iso_label", conductor = self.cond, iso_label = x)),
            ('L-function', url_for("l_functions.l_function_genus2_page", cond=self.cond,x=x)),
            
            ('Twists',url_for(".index_Q", ic0 = self.igusa_clebsch[0], ic1 = self.igusa_clebsch[1],ic2 = self.igusa_clebsch[2],ic3 = self.igusa_clebsch[3])),
            #('Twists2',url_for(".index_Q", igusa_clebsch = str(self.igusa_clebsch)))  #doesn't work.
            #('Siegel modular form someday', '.')
            ]
        self.downloads = [
             ('Download all stored data', '.')]
        iso = self.label.split('.')[1]
        num = '.'.join(self.label.split('.')[2:4])
        self.plot = encode_plot(eqn_list_to_curve_plot(self.min_eqn))
        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [('Label', self.label),
                           (None, self.plot_link),
                           ('Conductor','%s' % self.cond),
                           ('Discriminant', '%s' % data['disc']),
                           ('Invariants', '%s </br> %s </br> %s </br> %s'% tuple(data['ic_norm'])), 
                           ('Sato-Tate group', '\(%s\)' % data['st_group_name']), 
                           ('\(%s\)' % data['real_geom_end_alg_name'][0],'\(%s\)' % data['real_geom_end_alg_name'][1]),
                           ('\(\mathrm{GL}_2\)-type','%s' % data['is_gl2_type_name'])]
        self.title = "Genus 2 Curve %s" % (self.label)
        self.bread = [
             ('Genus 2 Curves', url_for(".index")),
             ('$\Q$', url_for(".index_Q")),
             ('%s' % self.cond, url_for(".by_conductor", conductor=self.cond)),
             ('%s' % iso, url_for(".by_double_iso_label", conductor=self.cond, iso_label=iso)),
             ('Genus 2 curve %s' % num, url_for(".by_g2c_label", label=self.label))]
Exemple #57
0
    def make_class(self):
        self.CM = self.cm
        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        # Extract the size of the isogeny class from the database
        ncurves = self.class_size
        # Create a list of the curves in the class from the database
        self.curves = [db.ec_curves.lucky({'iso':self.iso, 'lmfdb_number': i+1})
                          for i in range(ncurves)]

        # Set optimality flags.  The optimal curve is number 1 except
        # in one case which is labeled differently in the Cremona tables
        for c in self.curves:
            c['optimal'] = (c['number']==(3 if self.label == '990h' else 1))
            c['ai'] = c['ainvs']
            c['url'] = url_for(".by_triple_label", conductor=N, iso_label=iso, number=c['lmfdb_number'])

        from sage.matrix.all import Matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img


        self.newform =  web_latex(PowerSeriesRing(QQ, 'q')(self.anlist, 20, check=True))
        self.newform_label = db.mf_newforms.lucky({'level':N, 'weight':2, 'related_objects':{'$contains':'EllipticCurve/Q/%s/%s' % (N, iso)}},'label')
        self.newform_exists_in_db = self.newform_label is not None
        if self.newform_label is not None:
            char_orbit, hecke_orbit = self.newform_label.split('.')[2:]
            self.newform_link = url_for("cmf.by_url_newform_label", level=N, weight=2, char_orbit_label=char_orbit, hecke_orbit=hecke_orbit)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", conductor_label = N, isogeny_class_label = iso)

        self.friends =  [('L-function', self.lfunction_link)]
        if not self.CM:
            self.CM = "no"
            if int(N)<=300:
                self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor = N, isogeny = iso))]
            if int(N)<=50:
                self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor = N, isogeny = iso))]
        if self.newform_exists_in_db:
            self.friends +=  [('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(ncurves)),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank),
                           ('Graph', ''),(None, self.graph_link)
                           ]


        self.downloads = [('Download q-expansion', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=1000)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
        self.code = {}
        self.code['show'] = {'sage':''} # use default show names
        self.code['class'] = {'sage':'E = EllipticCurve("%s1")\n'%(self.lmfdb_iso) + 'E.isogeny_class()\n'}
        self.code['curves'] = {'sage':'E.isogeny_class().curves'}
        self.code['rank'] = {'sage':'E.rank()'}
        self.code['q_eigenform'] = {'sage':'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage':'E.isogeny_class().matrix()'}
        self.code['plot'] = {'sage':'E.isogeny_graph().plot(edge_labels=True)'}
Exemple #58
0
    def make_curve(self):
        # To start with the data fields of self are just those from the
        # databases.  We reformat these, while computing some further (easy)
        # data about the curve on the fly.

        # Get data from databases:
        data = self.data = {}
        endodata = self.endodata = {}

        # Polish data from database before putting it into the data dictionary:
        disc = ZZ(self.disc_sign) * ZZ(self.disc_key[3:]) 
        # to deal with disc_key, uncomment line above and comment line below
        #disc = ZZ(self.disc_sign) * ZZ(self.abs_disc)
        data['disc'] = disc
        data['cond'] = ZZ(self.cond)
        data['min_eqn'] = self.min_eqn
        data['min_eqn_display'] = list_to_min_eqn(self.min_eqn)
        data['disc_factor_latex'] = web_latex(factor(data['disc']))
        data['cond_factor_latex'] = web_latex(factor(int(self.cond)))
        data['aut_grp'] = groupid_to_meaningful(self.aut_grp)
        data['geom_aut_grp'] = groupid_to_meaningful(self.geom_aut_grp)
        data['igusa_clebsch'] = [ZZ(a) for a in self.igusa_clebsch]
        data['igusa'] = igusa_clebsch_to_igusa(data['igusa_clebsch'])
        data['g2'] = igusa_to_g2(data['igusa'])
        data['ic_norm'] = normalize_invariants(data['igusa_clebsch'],[1,2,3,5])
        data['igusa_norm'] = normalize_invariants(data['igusa'],[1,2,3,4,5])
        data['ic_norm_factor_latex'] = [web_latex(zfactor(i)) for i in
                data['ic_norm']]
        data['igusa_norm_factor_latex'] = [web_latex(zfactor(j)) for j in
                data['igusa_norm']]
        data['num_rat_wpts'] = ZZ(self.num_rat_wpts)
        data['two_selmer_rank'] = ZZ(self.two_selmer_rank)
        if len(self.torsion) == 0:
            data['tor_struct'] = '\mathrm{trivial}'
        else:
            tor_struct = [ZZ(a)  for a in self.torsion]
            data['tor_struct'] = ' \\times '.join(['\Z/{%s}\Z' % n for n in
                tor_struct])

        # Data from old endomorphism functionality, used in isogeny class as
        # well. Calls the get_end_data function above.
        isogeny_class = db_g2c().isogeny_classes.find_one({'label' :
            isog_label(self.label)})
        end_data = get_end_data(isogeny_class)
        for key in end_data.keys():
            data[key] = end_data[key]

        # GL_2 statement over the base field
        endodata['gl2_statement_base'] = gl2_statement(self.factorsRR_base,
                r'\(\Q\)')
        
        # NOTE: In what follows there is some copying of code and data that is
        # stupid from the point of view of efficiency but likely better from
        # that of maintenance.
        
        # Endomorphism data over QQ:
        endodata['factorsQQ_base'] = self.factorsQQ_base
        endodata['factorsRR_base'] = self.factorsRR_base
        endodata['ring_base'] = self.ring_base
        endodata['endo_statement_base'] = \
        """Endomorphism ring over \(\Q\):<br>""" + \
        endo_statement(endodata['factorsQQ_base'], endodata['factorsRR_base'],
                endodata['ring_base'], r'')
        # Field of definition data:
        endodata['fod_label'] = self.fod_label
        endodata['fod_poly'] = intlist_to_poly(self.fod_coeffs)
        endodata['fod_statement'] = fod_statement(endodata['fod_label'],
                endodata['fod_poly'])
        # Endomorphism data over QQbar:
        endodata['factorsQQ_geom'] = self.factorsQQ_geom
        endodata['factorsRR_geom'] = self.factorsRR_geom
        endodata['ring_geom'] = self.ring_geom
        if self.fod_label != '1.1.1.1':
            endodata['endo_statement_geom'] = \
            """Endomorphism ring over \(\overline{\Q}\):<br>""" + \
            endo_statement(endodata['factorsQQ_geom'],
                    endodata['factorsRR_geom'], endodata['ring_geom'],
                    r'\overline{\Q}')

        # Full endomorphism lattice:
        endodata['lattice'] = self.lattice[1:len(self.lattice) - 1]
        if endodata['lattice']:
            endodata['lattice_statement_preamble'] = \
            lattice_statement_preamble()
            endodata['lattice_statement'] = \
            lattice_statement(endodata['lattice'])

        # Splitting field description:
        #endodata['is_simple_base'] = self.is_simple_base
        endodata['is_simple_geom'] = self.is_simple_geom
        endodata['spl_fod_label'] = self.spl_fod_label
        endodata['spl_fod_poly'] = intlist_to_poly(self.spl_fod_coeffs)
        endodata['spl_fod_statement'] = \
        spl_fod_statement(endodata['is_simple_geom'],
                endodata['spl_fod_label'], endodata['spl_fod_poly'])
        
        # Isogeny factors:
        if not endodata['is_simple_geom']:
            endodata['spl_facs_coeffs'] = self.spl_facs_coeffs
            # This could be done non-uniformly as well... later.
            if len(self.spl_facs_labels) == len(self.spl_facs_coeffs):
                endodata['spl_facs_labels'] = self.spl_facs_labels
            else:
                endodata['spl_facs_labels'] = ['' for coeffs in
                        self.spl_facs_coeffs]
            endodata['spl_facs_condnorms'] = self.spl_facs_condnorms
            endodata['spl_statement'] = \
            spl_statement(endodata['spl_facs_coeffs'],
                    endodata['spl_facs_labels'],
                    endodata['spl_facs_condnorms'])

        x = self.label.split('.')[1]
        self.make_code_snippets()
        self.friends = [
            ('Isogeny class %s' % isog_label(self.label), url_for(".by_double_iso_label", conductor = self.cond, iso_label = x)),
            ('L-function', url_for("l_functions.l_function_genus2_page", cond=self.cond,x=x)),
            
            ('Twists',url_for(".index_Q", ic0 = self.igusa_clebsch[0], ic1 = self.igusa_clebsch[1],ic2 = self.igusa_clebsch[2],ic3 = self.igusa_clebsch[3])),
            #('Twists2',url_for(".index_Q", igusa_clebsch = str(self.igusa_clebsch)))  #doesn't work.
            #('Siegel modular form someday', '.')
            ]
        self.downloads = [
             ('Download all stored data', '.')]
        iso = self.label.split('.')[1]
        num = '.'.join(self.label.split('.')[2:4])
        self.plot = encode_plot(eqn_list_to_curve_plot(self.min_eqn))
        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [('Label', self.label),
                           (None, self.plot_link),
                           ('Conductor','%s' % self.cond),
                           ('Discriminant', '%s' % data['disc']),
                           ('Invariants', '%s </br> %s </br> %s </br> %s'% tuple(data['ic_norm'])), 
                           ('Sato-Tate group', '\(%s\)' % data['st_group_name']), 
                           ('\(%s\)' % data['real_geom_end_alg_name'][0],'\(%s\)' % data['real_geom_end_alg_name'][1]),
                           ('\(\mathrm{GL}_2\)-type','%s' % data['is_gl2_type_name'])]
        self.title = "Genus 2 Curve %s" % (self.label)
        self.bread = [
             ('Genus 2 Curves', url_for(".index")),
             ('$\Q$', url_for(".index_Q")),
             ('%s' % self.cond, url_for(".by_conductor", conductor=self.cond)),
             ('%s' % iso, url_for(".by_double_iso_label", conductor=self.cond, iso_label=iso)),
             ('Genus 2 curve %s' % num, url_for(".by_g2c_label", label=self.label))]