Ejemplo n.º 1
0
def make_order_key(order):
    order1 = int(ZZ(order).log(10))
    return '%03d%s'%(order1,str(order))
Ejemplo n.º 2
0
def decodedisc(ads, s):
    return ZZ(ads[3:]) * s
Ejemplo n.º 3
0
 def rd(self):
     return RealField(300)(ZZ(self._data['disc_abs'])).nth_root(
         self.degree())
Ejemplo n.º 4
0
def from_symbolic(exp, dR=None):
    r'''
        Method to transform a symbolic expression into a :class:`~ajpastor.dd_functions.ddFunction.DDFunction`.

        This method takes a symbolic expression an tries to cast it into a differentially definable function.
        This is closed related with the names that the module :mod:`~ajpastor.dd_functions.ddExamples` gives to 
        the functions.

        This method is the inverse of :func:`symbolic`, meaning that the output of this method after applying
        :func:`symbolic` is always an object that is equal to the first input.

        INPUT:

        * ``exp``: symbolic expression or an object that can be casted into one. We also allow lists, tuples and
          sets as possible inputs, applying this method recursively to each of its elements.
        * ``dR``: :class:`~ajpastor.dd_functions.ddFunction.DDRing` in which hierarchy we try to include
          the symbolic expression ``exp``. If ``None`` is given, we compute a :class:`~ajpastor.dd_functions.ddFunction.DDRing`
          using `x` as a variable and all other variables appearing in ``exp`` considered as parameters.

        OUTPUT:

        A :class:`~ajpastor.dd_functions.ddFunction.DDFunction` representation of ``exp``.

        TODO: add more cases from ddExamples

        EXAMPLES::

            sage: from ajpastor.dd_functions import *
            sage: var('y', 'm', 'n')
            (y, m, n)
            sage: from_symbolic(exp(x)) == Exp(x)
            True
            sage: sin_yx = from_symbolic(sin(y*x))
            sage: parent(sin_yx)
            DD-Ring over (Univariate Polynomial Ring in x over Rational Field) with parameter (y)
            sage: sin_yx.init(6, True)
            [0, y, 0, -y^3, 0, y^5]
            sage: from_symbolic(cos(x)) == Cos(x)
            True
            sage: from_symbolic(sinh(x)) == Sinh(x)
            True
            sage: from_symbolic(cosh(x)) == Cosh(x)
            True
            sage: from_symbolic(tan(x)) == Tan(x)
            True
            sage: from_symbolic(log(x + 1)) == Log(x+1)
            True
            sage: from_symbolic(bessel_J(4, x)) == BesselD(4)
            True
            sage: from_symbolic(hypergeometric([1,2,3],[5,6,7],x)) == GenericHypergeometricFunction((1,2,3),(5,6,7))
            True
    '''
    logger.debug("Looking for a DD-finite representation of %s", exp)

    if (isinstance(exp, list)):
        logger.debug("List case: converting each element")
        return [from_symbolic(el, dR) for el in exp]
    elif (isinstance(exp, tuple)):
        logger.debug("Tuple case: converting each element")
        return tuple([from_symbolic(el, dR) for el in exp])
    elif (isinstance(exp, set)):
        logger.debug("Set case: converting each element")
        return set([from_symbolic(el, dR) for el in exp])

    ## If it is not from the basic structures, we required a symbolic expression
    exp = SR(exp)

    logger.debug("Deciding the starting DDRing")
    if (not dR is None):
        logger.debug("User required solution to be in the hierarchy of %s", dR)
        if (any(v not in list(dR.variables(True)) + list(dR.parameters(True))
                for v in exp.variables())):
            raise TypeError("The symbolic expression has unknown variables")
    else:
        logger.debug("DDRing not specified: we compute one")
        params = [str(v) for v in exp.variables() if str(v) != 'x']
        if (len(params) > 0):
            dR = ParametrizedDDRing(
                DFinite, [str(v) for v in exp.variables() if str(v) != 'x'])
        else:
            dR = DFinite

    name = None
    try:
        name = exp.operator().__name__
    except AttributeError:
        try:
            name = exp.operator().name()
        except AttributeError:
            pass

    operands = exp.operands()
    if (name in ("list", "tuple")):  # special tuple and list cases
        logger.debug("Found a symbolic list or tuple")
        return tuple([from_symbolic(el, dR) for el in operands])
    elif (name == "set"):  # special set case
        logger.debug("Found a symbolic set")
        return set([from_symbolic(el, dR) for el in operands])
    elif (exp.is_rational_expression()):  # rational expression case
        logger.debug("Rational expression found")
        num = exp.numerator().polynomial(ring=dR.original_ring())
        den = exp.denominator().polynomial(ring=dR.original_ring())
        if (den == 1):
            return num

        return num / den
    elif (name == "add_vararg"):
        logger.debug("Found an addition")
        return sum([from_symbolic(el, dR) for el in operands])
    elif (name == "mul_vararg"):
        logger.debug("Found an product")
        return prod([from_symbolic(el, dR) for el in operands])
    elif (name == "pow"):
        logger.debug("Found an power")
        if (not operands[1] in QQ):
            raise TypeError("The exponent has to be a rational number")
        if (operands[1] in ZZ):
            logger.debug("Integer power: simple output")
            return pow(from_symbolic(operands[0], dR), ZZ(operands[1]))
        else:
            base = from_symbolic(operands[0], dR)
            if (is_DDFunction(base)):
                logger.debug("Fractional power: base DDFunction")
                return pow(base, QQ(operands[1]))
            else:
                logger.debug("Fractional power: base rational function")
                params = [str(el) for el in dR.parameters()]
                i = 0
                while ("y%d" % i in params):
                    i += 1

                R = PolynomialRing(dR.original_ring(), "y%d" % i)
                y = R.gens()[0]
                pq = QQ(operands[1])
                p = pq.numerator()
                q = pq.denominator()

                poly = y**q - R(str(operands[0]))**p
                x = dR.variables(True)[0]
                init = [
                    dR.coeff_field(exp.derivative(x, i)(**{
                        str(x): 0
                    })) for i in range(p + q)
                ]

                return DAlgebraic(poly, init, dR.to_depth(1))
    elif (name == "sin"):
        logger.debug("Found an sine")
        return Sin(operands[0])
    elif (name == "cos"):
        logger.debug("Found an cosine")
        return Cos(operands[0])
    elif (name == "sinh"):
        logger.debug("Found a hyperbolic sine")
        return Sinh(operands[0])
    elif (name == "cosh"):
        logger.debug("Found an hyperbolic cosine")
        return Cosh(operands[0])
    elif (name == "tan"):
        logger.debug("Found a tangent")
        return Tan(operands[0])
    elif (name == "log"):
        logger.debug("Found a logarithm")
        return Log(operands[0])
    elif (name == "exp"):
        logger.debug("Found an exponential")
        return Exp(operands[0])
    elif (name == "bessel_J"):
        logger.debug("Found an Bessel function of first kind")
        if (not (operands[0] in ZZ and operands[0] >= 0)):
            raise ValueError(
                "The Bessel has to have a non-negative integer index")
        return BesselD(ZZ(operands[0]))(from_symbolic(operands[1], dR))
    elif (name == "legendre_P"):
        logger.debug("Found an Legendre function of first kind")
        return LegendreD(operands[0], 0, 1)(from_symbolic(operands[1], dR))
    elif (name == "gen_legendre_P"):
        logger.debug("Found an generic Legendre function of first kind")
        return LegendreD(operands[0], operands[1],
                         1)(from_symbolic(operands[1], dR))
    elif (name == "legendre_Q"):
        logger.debug("Found an Legendre function of second kind")
        return LegendreD(operands[0], 0, 2)(from_symbolic(operands[1], dR))
    elif (name == "gen_legendre_Q"):
        logger.debug("Found an generic Legendre function of second kind")
        return LegendreD(operands[0], operands[1],
                         2)(from_symbolic(operands[1], dR))
    elif (name == "chebyshev_T"):
        logger.debug("Found an Chebyshev function of first kind")
        return ChebyshevD(operands[0], 1)(from_symbolic(operands[1], dR))
    elif (name == "chebyshev_U"):
        logger.debug("Found an Chebyshev function of second kind")
        return ChebyshevD(operands[0], 2)(from_symbolic(operands[1], dR))
    elif (name == "hypergeometric"):
        return GenericHypergeometricFunction(from_symbolic(operands[0], dR),
                                             from_symbolic(operands[1],
                                                           dR))(from_symbolic(
                                                               operands[2],
                                                               dR))
    else:
        raise NotImplementedError(
            "The operator %s is not valid for 'from_symbolic'" % name)
Ejemplo n.º 5
0
def set_info_for_web_newform(level=None,
                             weight=None,
                             character=None,
                             label=None,
                             **kwds):
    r"""
    Set the info for on modular form.

    """
    info = to_dict(kwds)
    info['level'] = level
    info['weight'] = weight
    info['character'] = character
    info['label'] = label
    if level is None or weight is None or character is None or label is None:
        s = "In set info for one form but do not have enough args!"
        s += "level={0},weight={1},character={2},label={3}".format(
            level, weight, character, label)
        emf_logger.critical(s)
    emf_logger.debug("In set_info_for_one_mf: info={0}".format(info))
    prec = my_get(info, 'prec', default_prec, int)
    bprec = my_get(info, 'bprec', default_display_bprec, int)
    emf_logger.debug("PREC: {0}".format(prec))
    emf_logger.debug("BITPREC: {0}".format(bprec))
    try:
        WNF = WebNewForm_cached(level=level,
                                weight=weight,
                                character=character,
                                label=label)
        if not WNF.has_updated():
            raise IndexError(
                "Unfortunately, we do not have this newform in the database.")
        info['character_order'] = WNF.character.order
        info['code'] = WNF.code
        emf_logger.debug("defined webnewform for rendering!")
    except IndexError as e:
        info['error'] = e.message
    url0 = url_for("mf.modular_form_main_page")
    url1 = url_for("emf.render_elliptic_modular_forms")
    url2 = url_for("emf.render_elliptic_modular_forms", level=level)
    url3 = url_for("emf.render_elliptic_modular_forms",
                   level=level,
                   weight=weight)
    url4 = url_for("emf.render_elliptic_modular_forms",
                   level=level,
                   weight=weight,
                   character=character)
    bread = [(MF_TOP, url0), (EMF_TOP, url1)]
    bread.append(("Level %s" % level, url2))
    bread.append(("Weight %s" % weight, url3))
    bread.append(("Character \( %s \)" % (WNF.character.latex_name), url4))
    bread.append(
        ("Newform %d.%d.%d.%s" % (level, weight, int(character), label), ''))
    info['bread'] = bread

    properties2 = list()
    friends = list()
    space_url = url_for('emf.render_elliptic_modular_forms',
                        level=level,
                        weight=weight,
                        character=character)
    friends.append(
        ('\( S_{%s}(%s, %s)\)' %
         (WNF.weight, WNF.level, WNF.character.latex_name), space_url))
    if hasattr(WNF.base_ring, "lmfdb_url") and WNF.base_ring.lmfdb_url:
        friends.append(('Number field ' + WNF.base_ring.lmfdb_pretty,
                        WNF.base_ring.lmfdb_url))
    if hasattr(WNF.coefficient_field,
               "lmfdb_url") and WNF.coefficient_field.lmfdb_label:
        friends.append(('Number field ' + WNF.coefficient_field.lmfdb_pretty,
                        WNF.coefficient_field.lmfdb_url))
    friends = uniq(friends)
    friends.append(("Dirichlet character \(" + WNF.character.latex_name + "\)",
                    WNF.character.url()))

    if WNF.dimension == 0 and not info.has_key('error'):
        info['error'] = "This space is empty!"
    info['title'] = 'Newform ' + WNF.hecke_orbit_label
    info['learnmore'] = [('History of modular forms',
                          url_for('.holomorphic_mf_history'))]
    if 'error' in info:
        return info
    ## Until we have figured out how to do the embeddings correctly we don't display the Satake
    ## parameters for non-trivial characters....

    ## Example to illustrate the different cases
    ## base              = CyclotomicField(n) -- of degree phi(n)
    ## coefficient_field = NumberField( p(x)) for some p in base['x'] of degree m
    ##   we would then have cdeg = m*phi(n) and bdeg = phi(n)
    ##   and rdeg = m
    ## Unfortunately, for e.g. base = coefficient_field = CyclotomicField(6)
    ## we get coefficient_field.relative_degree() == 2 although it should be 1
    cdeg = WNF.coefficient_field.absolute_degree()
    bdeg = WNF.base_ring.absolute_degree()
    if cdeg == 1:
        rdeg = 1
    else:
        ## just setting rdeg = WNF.coefficient_field.relative_degree() does not give correct result...
        ##
        rdeg = QQ(cdeg) / QQ(bdeg)
    cf_is_QQ = (cdeg == 1)
    br_is_QQ = (bdeg == 1)
    if cf_is_QQ:
        info['satake'] = WNF.satake
    if WNF.complexity_of_first_nonvanishing_coefficients(
    ) > default_max_height:
        info['qexp'] = ""
        info['qexp_display'] = ''
        info['hide_qexp'] = True
        n, c = WNF.first_nonvanishing_coefficient()
        info['trace_nv'] = latex(WNF.first_nonvanishing_coefficient_trace())
        info['norm_nv'] = '\\approx ' + latex(
            WNF.first_nonvanishing_coefficient_norm().n())
        info['index_nv'] = n
    else:
        if WNF.prec < prec:
            #get WNF record at larger prec
            WNF.prec = prec
            WNF.update_from_db()
        info['qexp'] = WNF.q_expansion_latex(prec=10, name='\\alpha ')
        info['qexp_display'] = url_for(".get_qexp_latex",
                                       level=level,
                                       weight=weight,
                                       character=character,
                                       label=label)
        info["hide_qexp"] = False
    info['max_cn_qexp'] = WNF.q_expansion.prec()
    ## All combinations should be tested...
    ## 13/4/4/a -> base ring = coefficient_field = QQ(zeta_6)
    ## 13/3/8/a ->  base_ring = QQ(zeta_4), coefficient_field has poly x^2+(2\zeta_4+2x-3\zeta_$ over base_ring
    ## 13/4/3/a ->  base_ring = coefficient_field = QQ(zeta_3)
    ## 13/4/1/a -> all rational
    ## 13/6/1/a/ -> base_ring = QQ, coefficient_field = Q(sqrt(17))
    ## These are variables which needs to be set properly below
    info['polvars'] = {'base_ring': 'x', 'coefficient_field': '\\alpha'}
    if not cf_is_QQ:
        if rdeg > 1:  # not WNF.coefficient_field == WNF.base_ring:
            ## Here WNF.base_ring should be some cyclotomic field and we have an extension over this.
            p1 = WNF.coefficient_field.relative_polynomial()
            c_pol_ltx = web_latex_poly(p1,
                                       '\\alpha')  # make the variable \alpha
            c_pol_ltx_x = web_latex_poly(p1, 'x')
            zeta = p1.base_ring().gens()[0]
            #           p2 = zeta.minpoly() #this is not used anymore
            #           b_pol_ltx = web_latex_poly(p2, latex(zeta)) #this is not used anymore
            z1 = zeta.multiplicative_order()
            info['coeff_field'] = [
                WNF.coefficient_field.absolute_polynomial_latex('x'),
                c_pol_ltx_x, z1
            ]
            if hasattr(WNF.coefficient_field,
                       "lmfdb_url") and WNF.coefficient_field.lmfdb_url:
                info['coeff_field_pretty'] = [
                    WNF.coefficient_field.lmfdb_url,
                    WNF.coefficient_field.lmfdb_pretty,
                    WNF.coefficient_field.lmfdb_label
                ]
            if z1 == 4:
                info[
                    'polynomial_st'] = '<div class="where">where</div> {0}\(\mathstrut=0\) and \(\zeta_4=i\).</div><br/>'.format(
                        c_pol_ltx)
                info['polvars']['base_ring'] = 'i'
            elif z1 <= 2:
                info[
                    'polynomial_st'] = '<div class="where">where</div> {0}\(\mathstrut=0\).</div><br/>'.format(
                        c_pol_ltx)
            else:
                info[
                    'polynomial_st'] = '<div class="where">where</div> %s\(\mathstrut=0\) and \(\zeta_{%s}=e^{\\frac{2\\pi i}{%s}}\) ' % (
                        c_pol_ltx, z1, z1)
                info['polvars']['base_ring'] = '\zeta_{{ {0} }}'.format(z1)
                if z1 == 3:
                    info[
                        'polynomial_st'] += 'is a primitive cube root of unity.'
                else:
                    info[
                        'polynomial_st'] += 'is a primitive {0}-th root of unity.'.format(
                            z1)
        elif not br_is_QQ:
            ## Now we have base and coefficient field being equal, meaning that since the coefficient field is not QQ it is some cyclotomic field
            ## generated by some \zeta_n
            p1 = WNF.coefficient_field.absolute_polynomial()
            z1 = WNF.coefficient_field.gens()[0].multiplicative_order()
            c_pol_ltx = web_latex_poly(p1, '\\zeta_{{{0}}}'.format(z1))
            c_pol_ltx_x = web_latex_poly(p1, 'x')
            info['coeff_field'] = [
                WNF.coefficient_field.absolute_polynomial_latex('x'),
                c_pol_ltx_x
            ]
            if hasattr(WNF.coefficient_field,
                       "lmfdb_url") and WNF.coefficient_field.lmfdb_url:
                info['coeff_field_pretty'] = [
                    WNF.coefficient_field.lmfdb_url,
                    WNF.coefficient_field.lmfdb_pretty,
                    WNF.coefficient_field.lmfdb_label
                ]
            if z1 == 4:
                info[
                    'polynomial_st'] = '<div class="where">where \(\zeta_4=e^{{\\frac{{\\pi i}}{{ 2 }} }}=i \).</div>'.format(
                        c_pol_ltx)
                info['polvars']['coefficient_field'] = 'i'
            elif z1 <= 2:
                info['polynomial_st'] = ''
            else:
                info[
                    'polynomial_st'] = '<div class="where">where \(\zeta_{{{0}}}=e^{{\\frac{{2\\pi i}}{{ {0} }} }}\) '.format(
                        z1)
                info['polvars']['coefficient_field'] = '\zeta_{{{0}}}'.format(
                    z1)
                if z1 == 3:
                    info[
                        'polynomial_st'] += 'is a primitive cube root of unity.</div>'
                else:
                    info[
                        'polynomial_st'] += 'is a primitive {0}-th root of unity.</div>'.format(
                            z1)
    else:
        info['polynomial_st'] = ''
    if info["hide_qexp"]:
        info['polynomial_st'] = ''
    info['degree'] = int(cdeg)
    if cdeg == 1:
        info['is_rational'] = 1
        info['coeff_field_pretty'] = [
            WNF.coefficient_field.lmfdb_url, WNF.coefficient_field.lmfdb_pretty
        ]
    else:
        info['is_rational'] = 0
    emf_logger.debug("PREC2: {0}".format(prec))
    info['embeddings'] = WNF._embeddings[
        'values']  #q_expansion_embeddings(prec, bprec,format='latex')
    info['embeddings_len'] = len(info['embeddings'])
    properties2 = [('Level', str(level)), ('Weight', str(weight)),
                   ('Character', '$' + WNF.character.latex_name + '$'),
                   ('Label', WNF.hecke_orbit_label),
                   ('Dimension of Galois orbit', str(WNF.dimension))]
    if (ZZ(level)).is_squarefree():
        info['twist_info'] = WNF.twist_info
        if isinstance(info['twist_info'],
                      list) and len(info['twist_info']) > 0:
            info['is_minimal'] = info['twist_info'][0]
            if (info['twist_info'][0]):
                s = 'Is minimal<br>'
            else:
                s = 'Is a twist of lower level<br>'
            properties2 += [('Twist info', s)]
    else:
        info['twist_info'] = 'Twist info currently not available.'
        properties2 += [('Twist info', 'not available')]
    args = list()
    for x in range(5, 200, 10):
        args.append({'digits': x})
    alev = None
    CM = WNF._cm_values
    if CM is not None:
        if CM.has_key('tau') and len(CM['tau']) != 0:
            info['CM_values'] = CM
    info['is_cm'] = WNF.is_cm
    if WNF.is_cm == 1:
        info['cm_field'] = "2.0.{0}.1".format(-WNF.cm_disc)
        info['cm_disc'] = WNF.cm_disc
        info['cm_field_knowl'] = nf_display_knowl(
            info['cm_field'], getDBConnection(),
            field_pretty(info['cm_field']))
        info['cm_field_url'] = url_for("number_fields.by_label",
                                       label=info["cm_field"])
    if WNF.is_cm is None or WNF.is_cm == -1:
        s = '- Unknown (insufficient data)<br>'
    elif WNF.is_cm == 1:
        s = 'Yes<br>'
    else:
        s = 'No<br>'
    properties2.append(('CM', s))
    alev = WNF.atkin_lehner_eigenvalues()
    info['atkinlehner'] = None
    if isinstance(alev, dict) and len(alev.keys()) > 0 and level != 1:
        s1 = " Atkin-Lehner eigenvalues "
        s2 = ""
        for Q in alev.keys():
            s2 += "\( \omega_{ %s } \) : %s <br>" % (Q, alev[Q])
        properties2.append((s1, s2))
        emf_logger.debug("properties={0}".format(properties2))
        # alev = WNF.atkin_lehner_eigenvalues_for_all_cusps()
        # if isinstance(alev,dict) and len(alev.keys())>0:
        #     emf_logger.debug("alev={0}".format(alev))
        #     info['atkinlehner'] = list()
        #     for Q in alev.keys():
        #         s = "\(" + latex(c) + "\)"
        #         Q = alev[c][0]
        #         ev = alev[c][1]
        #         info['atkinlehner'].append([Q, c, ev])
    if (level == 1):
        poly = WNF.explicit_formulas.get('as_polynomial_in_E4_and_E6', '')
        if poly != '':
            d, monom, coeffs = poly
            emf_logger.critical("poly={0}".format(poly))
            info['explicit_formulas'] = '\('
            for i in range(len(coeffs)):
                c = QQ(coeffs[i])
                s = ""
                if d > 1 and i > 0 and c > 0:
                    s = "+"
                if c < 0:
                    s = "-"
                if c.denominator() > 1:
                    cc = "\\frac{{ {0} }}{{ {1} }}".format(
                        abs(c.numerator()), c.denominator())
                else:
                    cc = str(abs(c))
                s += "{0} \cdot ".format(cc)
                a = monom[i][0]
                b = monom[i][1]
                if a == 1:
                    a = ""
                if b == 1:
                    b = ""
                if a == 0 and b != 0:
                    s += "E_6^{{ {0} }}(z)".format(b)
                elif b == 0 and a != 0:
                    s += "E_4^{{ {0} }}(z)".format(a)
                else:
                    s += "E_4^{{ {0} }}(z) \cdot E_6^{{ {1} }}(z)".format(a, b)
                info['explicit_formulas'] += s
            info['explicit_formulas'] += " \)"
    # cur_url = '?&level=' + str(level) + '&weight=' + str(weight) + '&character=' + str(character) + '&label=' + str(label) # never used
    if len(WNF.parent.hecke_orbits) > 1:
        for label_other in WNF.parent.hecke_orbits.keys():
            if (label_other != label):
                s = 'Modular form '
                if character:
                    s += newform_label(level, weight, character, label_other)
                else:
                    s += newform_label(level, weight, 1, label_other)

                url = url_for('emf.render_elliptic_modular_forms',
                              level=level,
                              weight=weight,
                              character=character,
                              label=label_other)
                friends.append((s, url))

    s = 'L-Function '
    if character:
        s += newform_label(level, weight, character, label)
    else:
        s += newform_label(level, weight, 1, label)
    # url =
    # "/L/ModularForm/GL2/Q/holomorphic?level=%s&weight=%s&character=%s&label=%s&number=%s"
    # %(level,weight,character,label,0)
    url = '/L' + url_for('emf.render_elliptic_modular_forms',
                         level=level,
                         weight=weight,
                         character=character,
                         label=label)
    if WNF.coefficient_field_degree > 1:
        for h in range(WNF.coefficient_field_degree):
            s0 = s + ".{0}".format(h)
            url0 = url + "{0}/".format(h)
            friends.append((s0, url0))
    else:
        friends.append((s, url))
    # if there is an elliptic curve over Q associated to self we also list that
    if WNF.weight == 2 and WNF.coefficient_field_degree == 1:
        llabel = str(level) + '.' + label
        s = 'Elliptic curve isogeny class ' + llabel
        url = '/EllipticCurve/Q/' + llabel
        friends.append((s, url))
    info['properties2'] = properties2
    info['friends'] = friends
    info['max_cn'] = WNF.max_available_prec()
    return info
Ejemplo n.º 6
0
def nice_coset_reps(G):
    r"""
        Compute a better/nicer list of right coset representatives [V_j]
        i.e. SL2Z = \cup G V_j
        Use this routine for known congruence subgroups.

        EXAMPLES::


            sage: G=MySubgroup(Gamma0(5))
            sage: G._get_coset_reps_from_G(Gamma0(5))
            [[1 0]
            [0 1], [ 0 -1]
            [ 1  0], [ 0 -1]
            [ 1  1], [ 0 -1]
            [ 1 -1], [ 0 -1]
            [ 1  2], [ 0 -1]
            [ 1 -2]]
    
        """
    cl = list()
    S, T = SL2Z.gens()
    lvl = G.generalised_level()
    # Start with identity rep.
    cl.append(SL2Z([1, 0, 0, 1]))
    if (not S in G):
        cl.append(S)
    # If the original group is given as a Gamma0 then
    # the reps are not the one we want
    # I.e. we like to have a fundamental domain in
    # -1/2 <=x <= 1/2 for Gamma0, Gamma1, Gamma
    for j in range(1, ZZ(ceil(RR(lvl / 2.0)) + 2)):
        for ep in [1, -1]:
            if (len(cl) >= G.index()):
                break
            # The ones about 0 are all of this form
            A = SL2Z([0, -1, 1, ep * j])
            # just make sure they are inequivalent
            try:
                for V in cl:
                    if ((A <> V and A * V**-1 in G) or cl.count(A) > 0):
                        raise StopIteration()
                cl.append(A)
            except StopIteration:
                pass
    # We now addd the rest of the "flips" of these reps.
    # So that we end up with a connected domain
    i = 1
    while (True):
        lold = len(cl)
        for V in cl:
            for A in [S, T, T**-1]:
                B = V * A
                try:
                    for W in cl:
                        if ((B * W**-1 in G) or cl.count(B) > 0):
                            raise StopIteration()
                    cl.append(B)
                except StopIteration:
                    pass
        if (len(cl) >= G.index() or lold >= len(cl)):
            # If we either did not addd anything or if we addded enough
            # we exit
            break
    # If we missed something (which is unlikely)
    if (len(cl) <> G.index()):
        print "cl=", cl
        raise ValueError, "Problem getting coset reps! Need %s and got %s" % (
            G.index(), len(cl))
    return cl
Ejemplo n.º 7
0
def elliptic_curve_search(info, query):
    parse_rational(info, query, 'jinv', 'j-invariant')
    parse_ints(info, query, 'conductor')
    parse_ints(info, query, 'torsion', 'torsion order')
    parse_ints(info, query, 'rank')
    parse_ints(info, query, 'sha', 'analytic order of &#1064;')
    parse_ints(info, query, 'num_int_pts', 'num_int_pts')
    parse_floats(info, query, 'regulator', 'regulator')
    parse_bool(info, query, 'semistable', 'semistable')
    parse_bracketed_posints(info,
                            query,
                            'torsion_structure',
                            maxlength=2,
                            check_divisibility='increasing')
    # speed up slow torsion_structure searches by also setting torsion
    #if 'torsion_structure' in query and not 'torsion' in query:
    #    query['torsion'] = reduce(mul,[int(n) for n in query['torsion_structure']],1)
    if 'include_cm' in info:
        if info['include_cm'] == 'exclude':
            query['cm'] = 0
        elif info['include_cm'] == 'only':
            query['cm'] = {'$ne': 0}
    #parse_ints(info,query,field='cm_disc',qfield='cm')
    if 'cm_disc' in info:
        query['cm'] = info['cm_disc']
    parse_element_of(info,
                     query,
                     field='isodeg',
                     qfield='isogeny_degrees',
                     split_interval=1000)
    #parse_ints(info,query,field='isodeg',qfield='isogeny_degrees')
    parse_primes(info,
                 query,
                 'surj_primes',
                 name='maximal primes',
                 qfield='nonmax_primes',
                 mode='exclude')
    parse_primes(info,
                 query,
                 'nonsurj_primes',
                 name='non-maximal primes',
                 qfield='nonmax_primes',
                 mode=info.get('surj_quantifier'),
                 radical='nonmax_rad')
    parse_primes(info,
                 query,
                 'bad_primes',
                 name='bad primes',
                 qfield='bad_primes',
                 mode=info.get('bad_quantifier'))
    # The button which used to be labelled Optimal only no/yes"
    # (default no) has been renamed "Curves per isogeny class all/one"
    # (default one) but the only change in behavious is that we no
    # longer treat class 990h (where the optial curve is #3 not #1) as
    # special: the "one" option just restricts to curves whose
    # 'number' is 1.
    if 'optimal' in info and info['optimal'] == 'on':
        query.update({'number': 1})

        # Old behaviour was as follows:
        # For all isogeny classes except 990h the optimal curve is number 1, while for class 990h it is number 3.
        # So setting query['number'] = 1 is nearly correct, but fails on 990h3.
        # Instead, we use this more complicated query:
        # query.update({"$or":[{'iso':'990h', 'number':3}, {'iso':{'$ne':'990h'},'number':1}]})

    info['curve_ainvs'] = lambda dbc: str([ZZ(ai) for ai in dbc['ainvs']])
    info['curve_url_LMFDB'] = lambda dbc: url_for(".by_triple_label",
                                                  conductor=dbc['conductor'],
                                                  iso_label=split_lmfdb_label(
                                                      dbc['lmfdb_iso'])[1],
                                                  number=dbc['lmfdb_number'])
    info['iso_url_LMFDB'] = lambda dbc: url_for(".by_double_iso_label",
                                                conductor=dbc['conductor'],
                                                iso_label=split_lmfdb_label(
                                                    dbc['lmfdb_iso'])[1])
    info['curve_url_Cremona'] = lambda dbc: url_for(".by_ec_label",
                                                    label=dbc['label'])
    info['iso_url_Cremona'] = lambda dbc: url_for(".by_ec_label",
                                                  label=dbc['iso'])
Ejemplo n.º 8
0
                reduction_cost_model=BKZ.sieve))
# BKZ cost models: CLASSICAL - 0.292*beta + 16.4 + log(8*d,2) - dual
# i.e. BKZ.sieve =  lambda beta, d, B: ZZ(2)**RR(0.292*beta + 16.4 + log(8*d,2))
print("CLASSICAL DUAL")
print(
    dual_scale(n,
               alpha,
               q,
               secret_distribution=secret_distribution,
               m=m,
               success_probability=success_probability,
               reduction_cost_model=BKZ.sieve))

# For more conservative parameters, both classical and quantum
# BKZ cost models: CLASSICAL - 0.292 beta - primal
reduction_cost_model = lambda beta, d, B: ZZ(_sage_const_2)**RR(
    _sage_const_0p292 * beta)
print("CLASSICAL PRIMAL (conservative)")
print(
    primal_usvp(n,
                alpha,
                q,
                secret_distribution=secret_distribution,
                m=m,
                success_probability=success_probability,
                reduction_cost_model=reduction_cost_model))
# BKZ cost models: CLASSICAL - 0.292 beta - dual
print("CLASSICAL DUAL (conservative)")
print(
    dual_scale(n,
               alpha,
Ejemplo n.º 9
0
    def init_tensor_product(self, V, W):
        """
        We are given two Galois representations and we
        will return their tensor product.
        """
        self.original_object = V.original_object + W.original_object
        self.object_type = "tensorproduct"
        self.V1 = V
        self.V2 = W
        self.dim = V.dim * W.dim
        self.motivic_weight = V.motivic_weight + W.motivic_weight
        self.langlands = False  # status 2014 :)
        self.besancon_bound = min(V.besancon_bound, W.besancon_bound)

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

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

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

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

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

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

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

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

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

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

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

        self.coefficient_type = max(V.coefficient_type, W.coefficient_type)
        self.coefficient_period = ZZ(V.coefficient_period).lcm(
            W.coefficient_period)
        self.ld.gp().quit()
Ejemplo n.º 10
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)'
        }
Ejemplo n.º 11
0
def render_group_webpage(args):
    data = None
    info = {}
    if 'label' in args:
        label = clean_input(args['label'])
        label = label.replace('t', 'T')
        C = base.getDBConnection()
        data = C.transitivegroups.groups.find_one({'label': label})
        if data is None:
            bread = get_bread([("Search error", ' ')])
            info['err'] = "Group " + label + " was not found in the database."
            info['label'] = label
            return search_input_error(info, bread)
        data['label_raw'] = label.lower()
        title = 'Galois Group: ' + label
        wgg = WebGaloisGroup.from_data(data)
        n = data['n']
        t = data['t']
        data['yesno'] = yesno
        order = data['order']
        data['orderfac'] = latex(ZZ(order).factor())
        orderfac = latex(ZZ(order).factor())
        data['ordermsg'] = "$%s=%s$" % (order, latex(orderfac))
        if order == 1:
            data['ordermsg'] = "$1$"
        if ZZ(order).is_prime():
            data['ordermsg'] = "$%s$ (is prime)" % order
        pgroup = len(ZZ(order).prime_factors()) < 2
        if n == 1:
            G = gap.SmallGroup(n, t)
        else:
            G = gap.TransitiveGroup(n, t)
        if ZZ(order) < ZZ('10000000000'):
            ctable = chartable(n, t)
        else:
            ctable = 'Group too large'
        data['gens'] = generators(n, t)
        if n == 1 and t == 1:
            data['gens'] = 'None needed'
        data['chartable'] = ctable
        data['parity'] = "$%s$" % data['parity']
        data['cclasses'] = conjclasses(G, n)
        data['subinfo'] = subfield_display(C, n, data['subs'])
        data['resolve'] = resolve_display(C, data['resolve'])
        data['otherreps'] = wgg.otherrep_list()
        if len(data['otherreps']) == 0:
            data['otherreps'] = "There is no other low degree representation."
        query = {'galois': bson.SON([('n', n), ('t', t)])}
        C = base.getDBConnection()
        intreps = C.transitivegroups.Gmodules.find({
            'n': n,
            't': t
        }).sort('index', pymongo.ASCENDING)
        # turn cursor into a list
        intreps = [z for z in intreps]
        if len(intreps) > 0:
            data['int_rep_classes'] = [str(z[0]) for z in intreps[0]['gens']]
            for onerep in intreps:
                onerep['gens'] = [
                    list_to_latex_matrix(z[1]) for z in onerep['gens']
                ]
            data['int_reps'] = intreps
            data['int_reps_complete'] = int_reps_are_complete(intreps)
            dcq = data['moddecompuniq']
            if dcq[0] == 0:
                data['decompunique'] = 0
            else:
                data['decompunique'] = dcq[0]
                data['isoms'] = [[mult2mult(z[0]),
                                  mult2mult(z[1])] for z in dcq[1]]
                data['isoms'] = [[
                    modules2string(n, t, z[0]),
                    modules2string(n, t, z[1])
                ] for z in data['isoms']]
                #print dcq[1]
                #print data['isoms']

        friends = []
        one = C.numberfields.fields.find_one(query)
        if one:
            friends.append(
                ('Number fields with this Galois group',
                 url_for('number_fields.number_field_render_webpage') +
                 "?galois_group=%dT%d" % (n, t)))
        prop2 = [
            ('Label', label),
            ('Order', '\(%s\)' % order),
            ('n', '\(%s\)' % data['n']),
            ('Cyclic', yesno(data['cyc'])),
            ('Abelian', yesno(data['ab'])),
            ('Solvable', yesno(data['solv'])),
            ('Primitive', yesno(data['prim'])),
            ('$p$-group', yesno(pgroup)),
        ]
        pretty = group_display_pretty(n, t, C)
        if len(pretty) > 0:
            prop2.extend([('Group:', pretty)])
            info['pretty_name'] = pretty
        data['name'] = re.sub(r'_(\d+)', r'_{\1}', data['name'])
        data['name'] = re.sub(r'\^(\d+)', r'^{\1}', data['name'])
        info.update(data)

        bread = get_bread([(label, ' ')])
        return render_template("gg-show-group.html",
                               credit=GG_credit,
                               title=title,
                               bread=bread,
                               info=info,
                               properties2=prop2,
                               friends=friends)
Ejemplo n.º 12
0
def find_inverse_images_of_twists(k, N=1, chi=0, fi=0, prec=10, verbose=0):
    r"""
    Checks if f is minimal and if not, returns the associated
    minimal form to precision prec.

    INPUT:

    - ''k'' -- positive integer : the weight
    - ''N'' -- positive integer (default 1) : level
    - ''chi'' -- non-neg. integer (default 0) use character nr. chi
    - ''fi'' -- non-neg. integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi]
    - ''prec'' -- integer (the number of coefficients to get)
    - ''verbose'' -- integer 
    OUTPUT:

    -''[t,l]'' -- tuple of a Bool t and a list l. The list l contains all tuples of forms which twists to the given form.
              The actual minimal one is the first element of this list.

    EXAMPLES::



    """
    (t, f) = _get_newform(k, N, chi, fi)

    if (not t):
        return f
    if (is_squarefree(ZZ(N))):
        return [True, f]
    # We need to check all square factors of N
    logger.info("investigating: %s" % f)
    N_sqfree = squarefree_part(ZZ(N))
    Nsq = ZZ(N / N_sqfree)
    twist_candidates = list()
    KF = f.base_ring()
    # check how many Hecke eigenvalues we need to check
    max_nump = number_of_hecke_to_check(f)
    maxp = max(primes_first_n(max_nump))
    for d in divisors(N):
        # we look at all d such that d^2 divdes N
        if (not ZZ(d**2).divides(ZZ(N))):
            continue
        D = DirichletGroup(d)
        # check possible candidates to twist into f
        # g in S_k(M,chi) wit M=N/d^2
        M = ZZ(N / d**2)
        logger.info("Checking level %s" % M)
        for xig in range(euler_phi(M)):
            (t, glist) = _get_newform(k, M, xig)
            if (not t):
                return glist
            for g in glist:
                logger.debug("Comparing to function %s" % g)
                KG = g.base_ring()
                # we now see if twisting of g by xi in D gives us f
                for xi in D:
                    try:
                        for p in primes_first_n(max_nump):
                            if (ZZ(p).divides(ZZ(N))):
                                continue
                            bf = f.q_expansion(maxp + 1)[p]
                            bg = g.q_expansion(maxp + 1)[p]
                            if (bf == 0 and bg == 0):
                                continue
                            elif (bf == 0 and bg <> 0 or bg == 0 and bf <> 0):
                                raise StopIteration()
                            if (ZZ(p).divides(xi.conductor())):
                                raise ArithmeticError, ""
                            xip = xi(p)
                            # make a preliminary check that the base rings match with respect to being real or not
                            try:
                                QQ(xip)
                                XF = QQ
                                if (KF <> QQ or KG <> QQ):
                                    raise StopIteration
                            except TypeError:
                                # we have a  non-rational (i.e. complex) value of the character
                                XF = xip.parent()
                                if ((KF == QQ or KF.is_totally_real()) and
                                    (KG == QQ or KG.is_totally_real())):
                                    raise StopIteration
                            ## it is diffcult to compare elements from diferent rings in general but we make some checcks
                            ## is it possible to see if there is a larger ring which everything can be coerced into?
                            ok = False
                            try:
                                a = KF(bg / xip)
                                b = KF(bf)
                                ok = True
                                if (a <> b):
                                    raise StopIteration()
                            except TypeError:
                                pass
                            try:
                                a = KG(bg)
                                b = KG(xip * bf)
                                ok = True
                                if (a <> b):
                                    raise StopIteration()
                            except TypeError:
                                pass
                            if (
                                    not ok
                            ):  # we could coerce and the coefficients were equal
                                return "Could not compare against possible candidates!"
                            # otherwise if we are here we are ok and found a candidate
                        twist_candidates.append([dd, g.q_expansion(prec), xi])
                    except StopIteration:
                        # they are not equal
                        pass
    #logger.debug("Candidates=%s" % twist_candidates)
    if (len(twist_candidates) == 0):
        return (True, None)
    else:
        return (False, twist_candidates)
Ejemplo n.º 13
0
def get_satake_parameters(k, N=1, chi=0, fi=0, prec=10, bits=53, angles=False):
    r""" Compute the Satake parameters and return an html-table.
    
    INPUT:
    - ''k'' -- positive integer : the weight
    - ''N'' -- positive integer (default 1) : level
    - ''chi'' -- non-neg. integer (default 0) use character nr. chi    - ''fi'' -- non-neg. integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi]
    -''prec'' -- compute parameters for p <=prec
    -''bits'' -- do real embedings intoi field of bits precision
    -''angles''-- return the angles t_p instead of the alpha_p
                  here alpha_p=p^((k-1)/2)exp(i*t_p)

    """
    (t, f) = _get_newform(k, N, chi, fi)
    if (not t):
        return f
    K = f.base_ring()
    RF = RealField(bits)
    CF = ComplexField(bits)
    if (K <> QQ):
        M = len(K.complex_embeddings())
        ems = dict()
        for j in range(M):
            ems[j] = list()
    ps = prime_range(prec)
    alphas = list()
    for p in ps:
        ap = f.coefficients(ZZ(prec))[p]
        if (K == QQ):
            f1 = QQ(4 * p**(k - 1) - ap**2)
            alpha_p = (QQ(ap) + I * f1.sqrt()) / QQ(2)
            #beta_p=(QQ(ap)-I*f1.sqrt())/QQ(2)
            #satake[p]=(alpha_p,beta_p)
            ab = RF(p**((k - 1) / 2))
            norm_alpha = alpha_p / ab
            t_p = CF(norm_alpha).argument()
            if (angles):
                alphas.append(t_p)
            else:
                alphas.append(alpha_p)

        else:
            for j in range(M):
                app = ap.complex_embeddings(bits)[j]
                f1 = (4 * p**(k - 1) - app**2)
                alpha_p = (app + I * f1.sqrt()) / RealField(bits)(2)
                ab = RF(p**((k - 1) / 2))
                norm_alpha = alpha_p / ab
                t_p = CF(norm_alpha).argument()
                if (angles):
                    ems[j].append(t_p)
                else:
                    ems[j].append(alpha_p)

    tbl = dict()
    tbl['headersh'] = ps
    if (K == QQ):
        tbl['headersv'] = [""]
        tbl['data'] = [alphas]
        tbl['corner_label'] = "$p$"
    else:
        tbl['data'] = list()
        tbl['headersv'] = list()
        tbl['corner_label'] = "Embedding \ $p$"
        for j in ems.keys():
            tbl['headersv'].append(j)
            tbl['data'].append(ems[j])
    #logger.debug(tbl)
    s = html_table(tbl)
    return s
Ejemplo n.º 14
0
def get_values_at_CM_points(k, N=1, chi=0, fi=0, digits=12, verbose=0):
    r""" Computes and returns a list of values of f at a collection of CM points as complex floating point numbers.

    INPUT:

    - ''k'' -- positive integer : the weight
    - ''N'' -- positive integer (default 1) : level
    - ''chi'' -- non-neg. integer (default 0) use character nr. chi    - ''fi'' -- non-neg. integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi]
    -''digits'' -- we want this number of corrrect digits in the value

    OUTPUT:
    -''s'' string representation of a dictionary {I:f(I):rho:f(rho)}.

    TODO: Get explicit, algebraic values if possible!
    """
    (t, f) = _get_newform(k, N, chi, fi)
    if (not t):
        return f
    bits = max(53, ceil(digits * 4))
    CF = ComplexField(bits)
    RF = ComplexField(bits)
    eps = RF(10**-(digits + 1))
    logger.debug("eps=" % eps)
    K = f.base_ring()
    cm_vals = dict()
    # the points we want are i and rho. More can be added later...
    rho = CyclotomicField(3).gen()
    zi = CyclotomicField(4).gen()
    points = [rho, zi]
    maxprec = 1000  # max size of q-expansion
    minprec = 10  # max size of q-expansion
    for tau in points:
        q = CF(exp(2 * pi * I * tau))
        fexp = dict()
        if (K == QQ):
            v1 = CF(0)
            v2 = CF(1)
            try:
                for prec in range(minprec, maxprec, 10):
                    logger.debug("prec=%s" % prec)
                    v2 = f.q_expansion(prec)(q)
                    err = abs(v2 - v1)
                    logger.debug("err=%s" % err)
                    if (err < eps):
                        raise StopIteration()
                    v1 = v2
                cm_vals[tau] = ""
            except StopIteration:
                cm_vals[tau] = str(fq)
        else:
            v1 = dict()
            v2 = dict()
            err = dict()
            cm_vals[tau] = dict()
            for h in range(K.degree()):
                v1[h] = 1
                v2[h] = 0
            try:
                for prec in range(minprec, maxprec, 10):
                    logger.debug("prec=%s" % prec)
                    for h in range(K.degree()):
                        fexp[h] = list()
                        v2[h] = 0
                        for n in range(prec):
                            c = f.coefficients(ZZ(prec))[n]
                            cc = c.complex_embeddings(CF.prec())[h]
                            v2[h] = v2[h] + cc * q**n
                        err[h] = abs(v2[h] - v1[h])
                        logger.debug("v1[%s]=%s" % (h, v1[h]))
                        logger.debug("v2[%s]=%s" % (h, v2[h]))
                        logger.debug("err[%s]=%s" % (h, err[h]))
                        if (max(err.values()) < eps):
                            raise StopIteration()
                        v1[h] = v2[h]
            except StopIteration:
                pass
            for h in range(K.degree()):
                if (err[h] < eps):
                    cm_vals[tau][h] = v2[h]
                else:
                    cm_vals[tau][h] = ""

    logger.debug("vals=%s" % cm_vals)
    logger.debug("errs=%s" % err)
    tbl = dict()
    tbl['corner_label'] = ['$\tau$']
    tbl['headersh'] = ['$\\rho=\zeta_{3}$', '$i$']
    if (K == QQ):
        tbl['headersv'] = ['$f(\\tau)$']
        tbl['data'] = [cm_vals]
    else:
        tbl['data'] = list()
        tbl['headersv'] = list()
        for h in range(K.degree()):
            tbl['headersv'].append("$\sigma_{%s}(f(\\tau))$" % h)
            row = list()
            for tau in points:
                row.append(cm_vals[tau][h])
            tbl['data'].append(row)

    s = html_table(tbl)
    #s=html.table([cm_vals.keys(),cm_vals.values()])
    return s
Ejemplo n.º 15
0
    def test_all(self):
        todo = []
        from lmfdb import db
        maxNk2 = db.mf_newforms.max('Nk2')
        for Nk2 in range(1, maxNk2 + 1):
            for N in ZZ(Nk2).divisors():
                k = sqrt(Nk2 / N)
                if k in ZZ:
                    todo.append((N, int(k)))
        formerrors = list(self.all_newforms(todo))
        spaceserrors = list(self.all_newspaces(todo))
        errors = []
        res = []
        for k, io in enumerate([formerrors, spaceserrors]):
            for i, o in io:
                if not isinstance(o, list):
                    if k == 0:
                        command = "all_newforms"
                    else:
                        command = "all_newspaces"
                    errors.append([command, i])
                else:
                    res.extend(o)

        if not errors:
            print("No errors while running the tests!")
        else:
            print("Unexpected errors occurring while running:")
            for e in errors:
                print(e)

        broken_urls = [u for l, u in res if u is None]
        working_urls = [(l, u) for l, u in res if u is not None]
        working_urls.sort(key=lambda elt: elt[0])
        just_times = [l for l, u in working_urls]
        total = len(working_urls)
        if not broken_urls:
            print("All the pages passed the tests")
            if total > 0:
                print("Average loading time: %.2f" %
                      (sum(just_times) / total, ))
                print("Min: %.2f Max %.2f" % (just_times[0], just_times[-1]))
                print("Quartiles: %.2f %.2f %.2f" % tuple([
                    just_times[max(0,
                                   int(total * f) - 1)]
                    for f in [0.25, 0.5, 0.75]
                ]))
                print("Slowest pages:")
                for t, u in working_urls[-10:]:
                    print("%.2f - %s" % (t, u))
            if total > 2:
                print("Histogram")
                h = 0.5
                nbins = (just_times[-1] - just_times[0]) / h
                while nbins < 50:
                    h *= 0.5
                    nbins = (just_times[-1] - just_times[0]) / h
                nbins = ceil(nbins)
                bins = [0] * nbins
                i = 0
                for elt in just_times:
                    while elt > (i + 1) * h + just_times[0]:
                        i += 1
                    bins[i] += 1
                for i, b in enumerate(bins):
                    d = 100 * float(b) / total
                    print('%.2f\t|' % ((i + 0.5) * h + just_times[0]) + '-' *
                          (int(d) - 1) + '| - %.2f%%' % d)
        else:
            print("These pages didn't pass the tests:")
            for u in broken_urls:
                print(u)
Ejemplo n.º 16
0
    def __init__(self, data):
        # Need to set mf_dim, eis_dim, cusp_dim, new_dim, old_dim
        self.__dict__.update(data)
        if self.level == 1 or ZZ(self.level).is_prime():
            self.factored_level = ''
        else:
            self.factored_level = ' = ' + ZZ(self.level).factor()._latex_()
        self.has_projective_image_types = all(typ + '_dim' in data
                                              for typ in ('dihedral', 'a4',
                                                          's4', 'a5'))
        # The following can be removed once we change the behavior of lucky to include Nones
        self.num_forms = data.get('num_forms')
        self.trace_bound = data.get('trace_bound')
        self.has_trace_form = (data.get('traces') is not None)
        self.char_conrey = self.conrey_indexes[0]
        self.char_conrey_str = '\chi_{%s}(%s,\cdot)' % (self.level,
                                                        self.char_conrey)
        self.newforms = list(
            db.mf_newforms.search({'space_label': self.label}, projection=2))
        oldspaces = db.mf_subspaces.search(
            {
                'label': self.label,
                'sub_level': {
                    '$ne': self.level
                }
            }, [
                'sub_level', 'sub_char_orbit_index', 'sub_conrey_indexes',
                'sub_mult'
            ])
        self.oldspaces = [(old['sub_level'], old['sub_char_orbit_index'],
                           old['sub_conrey_indexes'][0], old['sub_mult'])
                          for old in oldspaces]
        self.dim_grid = DimGrid.from_db(data)
        self.plot = db.mf_newspace_portraits.lookup(self.label,
                                                    projection="portrait")

        # Properties
        self.properties = [('Label', self.label)]
        if self.plot is not None and self.dim > 0:
            self.properties += [
                (None,
                 '<img src="{0}" width="200" height="200"/>'.format(self.plot))
            ]
        self.properties += [
            ('Level', str(self.level)),
            ('Weight', str(self.weight)),
            ('Character orbit', self.char_orbit_label),
            ('Rep. character', r'\(%s\)' % self.char_conrey_str),
            ('Character field',
             r'\(\Q%s\)' % ('' if self.char_degree == 1 else r'(\zeta_{%s})' %
                            self.char_order)),
            ('Dimension', str(self.dim)),
        ]
        if self.num_forms is not None:
            self.properties.append(('Newforms', str(self.num_forms)))
        self.properties.append(('Sturm bound', str(self.sturm_bound)))
        if data.get('trace_bound') is not None:
            self.properties.append(('Trace bound', str(self.trace_bound)))
        # Work around search results not including None
        if data.get('num_forms') is None:
            self.num_forms = None

        # Breadcrumbs
        self.bread = get_bread(level=self.level,
                               weight=self.weight,
                               char_orbit_label=self.char_orbit_label)

        # Downloads
        self.downloads = [
            ('Trace form to text',
             url_for('cmf.download_traces', label=self.label)),
            ('All stored data to text',
             url_for('.download_newspace', label=self.label)),
        ]

        if self.conrey_indexes[0] == 1:
            self.trivial_character = True
            character_str = "Trivial Character"
            if self.dim == 0:
                self.dim_str = r"\(%s\)" % (self.dim)
            else:
                self.minus_dim = self.dim - self.plus_dim
                self.dim_str = r"\(%s + %s\)" % (self.plus_dim, self.minus_dim)
        else:
            self.trivial_character = False
            character_str = r"Character {level}.{orbit_label}".format(
                level=self.level, orbit_label=self.char_orbit_label)
            # character_str = r"Character \(\chi_{{{level}}}({conrey}, \cdot)\)".format(level=self.level, conrey=self.conrey_indexes[0])
            self.dim_str = r"\(%s\)" % (self.dim)
        self.title = r"Space of Modular Forms of Level %s, Weight %s, and %s" % (
            self.level, self.weight, character_str)
        gamma1_link = '/ModularForm/GL2/Q/holomorphic/%d/%d' % (self.level,
                                                                self.weight)
        self.friends = [('Newspace %d.%d' % (self.level, self.weight),
                         gamma1_link)]
Ejemplo n.º 17
0
Archivo: main.py Proyecto: koffie/lmfdb
def make_cond_key(D):
    D1 = ZZ(D)
    if D1 < 1: D1 = ZZ(1)
    D1 = int(D1.log(10))
    return '%04d%s' % (D1, str(D))
Ejemplo n.º 18
0
 def __init__(self, level, weight):
     data = db.mf_gamma1.lucky({'level': level, 'weight': weight})
     if data is None:
         raise ValueError("Space not in database")
     self.__dict__.update(data)
     self.weight_parity = -1 if (self.weight % 2) == 1 else 1
     if level == 1 or ZZ(level).is_prime():
         self.factored_level = ''
     else:
         self.factored_level = ' = ' + ZZ(level).factor()._latex_()
     self.has_projective_image_types = all(typ + '_dim' in data
                                           for typ in ('dihedral', 'a4',
                                                       's4', 'a5'))
     # The following can be removed once we change the behavior of lucky to include Nones
     self.num_forms = data.get('num_forms')
     self.num_spaces = data.get('num_spaces')
     self.trace_bound = data.get('trace_bound')
     self.has_trace_form = (data.get('traces') is not None)
     # by default we sort on char_orbit_index
     newspaces = list(
         db.mf_newspaces.search({
             'level': level,
             'weight': weight,
             'char_parity': self.weight_parity
         }))
     oldspaces = db.mf_gamma1_subspaces.search(
         {
             'level': level,
             'sub_level': {
                 '$ne': level
             },
             'weight': weight
         }, ['sub_level', 'sub_mult'])
     self.oldspaces = [(old['sub_level'], old['sub_mult'])
                       for old in oldspaces]
     self.dim_grid = sum(
         DimGrid.from_db(space)
         for space in newspaces) if newspaces else DimGrid()
     #self.mf_dim = sum(space['mf_dim'] for space in newspaces)
     #self.eis_dim = sum(space['eis_dim'] for space in newspaces)
     #self.eis_new_dim = sum(space['eis_new_dim'] for space in newspaces)
     #self.eis_old_dim = self.eis_dim - self.eis_new_dim
     #self.cusp_dim = sum(space['cusp_dim'] for space in newspaces)
     self.new_dim = sum(space['dim'] for space in newspaces)
     self.old_dim = sum(
         (space['cusp_dim'] - space['dim']) for space in newspaces)
     self.decomp = []
     newforms = list(
         db.mf_newforms.search({
             'level': level,
             'weight': weight
         }, [
             'label', 'space_label', 'dim', 'level', 'char_orbit_label',
             'hecke_orbit', 'char_degree'
         ]))
     self.has_uncomputed_char = False
     for space in newspaces:
         if space.get('num_forms') is None:
             self.decomp.append((space, None))
             self.has_uncomputed_char = True
         else:
             self.decomp.append((space, [
                 form for form in newforms
                 if form['space_label'] == space['label']
             ]))
     self.plot = db.mf_gamma1_portraits.lookup(self.label,
                                               projection="portrait")
     self.properties = [
         ('Label', self.label),
     ]
     if self.plot is not None and self.new_dim > 0:
         self.properties += [
             (None,
              '<a href="{0}"><img src="{0}" width="200" height="200"/></a>'.
              format(self.plot))
         ]
     self.properties += [('Level', str(self.level)),
                         ('Weight', str(self.weight)),
                         ('Dimension', str(self.new_dim))]
     if self.num_spaces is not None:
         self.properties.append(('Nonzero newspaces', str(self.num_spaces)))
     if self.num_forms is not None:
         self.properties.append(('Newforms', str(self.num_forms)))
     self.properties.append(('Sturm bound', str(self.sturm_bound)))
     if self.trace_bound is not None:
         self.properties.append(('Trace bound', str(self.trace_bound)))
     self.bread = get_bread(level=self.level, weight=self.weight)
     # Downloads
     self.downloads = [('Trace form to text',
                        url_for('cmf.download_traces', label=self.label)),
                       ('All stored data to text',
                        url_for('cmf.download_full_space',
                                label=self.label))]
     self.title = r"Space of Modular Forms of Level %s and Weight %s" % (
         self.level, self.weight)
     self.friends = []
Ejemplo n.º 19
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);'
        }
Ejemplo n.º 20
0
def field_of_constant_degree_of_polynomial(G, return_field=False):
    r""" Return the degree of the field of constants of a polynomial.

    INPUT:

    - ``G`` -- an irreducible monic polynomial over a rational function field
    - ``return_field`` -- a boolean (default:`False`)

    OUTPUT: the degree of the field of constants of the function field defined
    by ``G``. If ``return_field`` is ``True`` then the actual field of constants
    is returned. This is currently implemented for finite fields only.

    This is a helper function for ``SmoothProjectiveCurve.field_of_constants_degree``.

    """
    from sage.rings.function_field.function_field import RationalFunctionField
    from sage.rings.function_field.constructor import FunctionField
    from sage.rings.number_field.number_field import NumberFields
    from sage.arith.misc import primes
    from mclf.semistable_reduction.reduction_trees import make_function_field
    F = G.base_ring()
    assert isinstance(F, RationalFunctionField)
    K = F.constant_base_field()
    R = F._ring   # the polynomial ring underlying F
    n = G.degree()
    if K.is_finite():
        d = 1    # will be the degree of the field of constants at the end
        for p in primes(2,n+1):
            while p.divides(n):
                try:
                    K1 = K.extension(p)
                except:
                    # if K is not a true finite field the above fails
                    # we use a helper function which construct an extension
                    # of the desired degree
                    K1 = extension_of_finite_field(K, p)
                F1 = FunctionField(K1, F.variable_name())
                G1 = G.change_ring(F1)
                G2 = G1.factor()[0][0]   # the first irreducible factor of G1
                if G2.degree() < n:      # G becomes reducible over K1
                    d = d*p              # we replace G by G2 and adapt
                    K = K1               # the values of n, d, K, G
                    G = G2
                    n = G.degree()
                else:                    # G is irreducible over K1
                    break                # we try the next prime
        if return_field:
            return K
        else:
            return d
    elif K in NumberFields():
        from sage.rings.integer_ring import ZZ
        from sage.rings.all import GaussValuation
        if return_field:
            raise NotImplementedError('Computation of field of constants for number fields is not yet implemented.')
        d = n
        count = 0
        for p in K.primes_of_bounded_norm_iter(ZZ(1000)):
            vp = K.valuation(p)
            v0 = F.valuation(GaussValuation(R, vp))
            v = GaussValuation(G.parent(), v0)
            if v(G) == 0:
                Gb = v.reduce(G)
                Fb, _, _ = make_function_field(Gb.base_ring())
                Gb = Gb.change_ring(Fb)
                if Gb.is_irreducible():
                    dp = field_of_constant_degree_of_polynomial(Gb)
                    d = d.gcd(dp)
                    count += 1
            if d == 1 or count > 10:
                break
        return d
    else:
        raise NotImplementedError('Constant base field has to be finite or a number field.')
Ejemplo n.º 21
0
def render_by_label(label):
    """ render html page for Sato-Tate group sepecified by label """
    if re.match(MU_LABEL_RE, label):
        n = ZZ(label.split('.')[2])
        if n > 10**20:
            flash_error(
                "number of components %s is too large, it should be less than 10^{20}$.",
                n)
            return redirect(url_for(".index"))
        return render_st_group(mu_info(n), portrait=mu_portrait(n))
    if re.match(NU1_MU_LABEL_RE, label):
        w = ZZ(label.split('.')[0])
        n = ZZ(label.split('.')[3][1:])
        if 2 * n > 10**20:
            flash_error(
                "number of components %s is too large, it should be less than 10^{20}$.",
                2 * n)
            return redirect(url_for(".index"))
        return render_st_group(nu1_mu_info(w, n), portrait=nu1_mu_portrait(n))
    if re.match(SU2_MU_LABEL_RE, label):
        w = ZZ(label.split('.')[0])
        n = ZZ(label.split('.')[3][1:])
        if n > 10**20:
            flash_error(
                "number of components %s is too large, it should be less than 10^{20}$.",
                n)
            return redirect(url_for(".index"))
        return render_st_group(su2_mu_info(w, n), portrait=su2_mu_portrait(n))
    data = db.gps_sato_tate.lookup(label)
    info = {}
    if data is None:
        flash_error(
            "%s is not the label of a Sato-Tate group currently in the database.",
            label)
        return redirect(url_for(".index"))
    for attr in [
            'label', 'weight', 'degree', 'name', 'pretty', 'real_dimension',
            'components'
    ]:
        info[attr] = data[attr]
    info['ambient'] = st_ambient(info['weight'], info['degree'])
    info['connected'] = boolean_name(info['components'] == 1)
    info['rational'] = boolean_name(info.get('rational', True))
    st0 = db.gps_sato_tate0.lucky({'name': data['identity_component']})
    if not st0:
        flash_error(
            "%s is not the label of a Sato-Tate identity component currently in the database.",
            data['identity_component'])
        return redirect(url_for(".index"))
    info['st0_name'] = st0['name']
    info['identity_component'] = st0['pretty']
    info['st0_description'] = st0['description']
    G = db.gps_small.lookup(data['component_group'])
    if not G:
        flash_error(
            "%s is not the label of a Sato-Tate component group currently in the database.",
            data['component_group'])
        return redirect(url_for(".index"))
    info['component_group'] = G['pretty']
    info['cyclic'] = boolean_name(G['cyclic'])
    info['abelian'] = boolean_name(G['abelian'])
    info['solvable'] = boolean_name(G['solvable'])
    info['gens'] = comma_separated_list(
        [string_matrix(m) for m in data['gens']])
    info['numgens'] = len(info['gens'])
    info['subgroups'] = comma_separated_list(
        [st_link(sub) for sub in data['subgroups']])
    info['supgroups'] = comma_separated_list(
        [st_link(sup) for sup in data['supgroups']])
    if data['moments']:
        info['moments'] = [['x'] + [
            '\\mathrm{E}[x^{%d}]' % m
            for m in range(len(data['moments'][0]) - 1)
        ]]
        info['moments'] += data['moments']
    if data['counts']:
        c = data['counts']
        info['probabilities'] = [[
            '\\mathrm{P}[%s=%d]=\\frac{%d}{%d}' %
            (c[i][0], c[i][1][j][0], c[i][1][j][1], data['components'])
            for j in range(len(c[i][1]))
        ] for i in range(len(c))]
    return render_st_group(info, portrait=data.get('trace_histogram'))
Ejemplo n.º 22
0
    def genus(self):
        r""" Return the genus of the curve.

        The genus of the curve is defined as the dimension of
        the cohomology group `H^1(X,\mathcal{O}_X)`, as a vector space
        *over the field of constants `k_c`*.

        The genus `g` of the curve `X` is computed using the Riemann-Hurwitz
        formula, applied to the cover `X\to\mathbb{P}^1` corresponding to the
        underlying realization of the function field of `X` as a finite
        separable extension of a rational function field. See:

        - Hartshorne, *Algebraic Geometry*, Corollary IV.2.4

        If the constant base field is finite, we compute the degree of the
        'ramification divisor'. If it is not, we assume that the characteristic
        is zero, and we use the 'tame' Riemann Hurwitz Formula.

        EXAMPLES::

            sage: from mclf import *
            sage: F0.<x> = FunctionField(GF(2))
            sage: R.<T> = F0[]
            sage: G = T^2 + T + x^3 + x + 1
            sage: F.<y> = F0.extension(G)
            sage: Y = SmoothProjectiveCurve(F)
            sage: Y.genus()
            1
            sage: G = T^2 + x^3 + x + 1
            sage: F.<y> = F0.extension(G)
            sage: Y = SmoothProjectiveCurve(F)
            sage: Y.genus()
            0

        """
        if hasattr(self,"_genus"):
            return self._genus
        if not self._is_separable:
            self._genus = self.separable_model().genus()
            return self._genus
        FY = self.function_field()
        FX = self.rational_function_field()
        if FX is FY:
            return 0
        n = self.covering_degree()/self.field_of_constants_degree()

        if self.constant_base_field().is_finite():
            r = self.degree(self.ramification_divisor())
                   # if k is finite, we can't use the 'tame' RHF
        else:      # if k has characteristic zero, we use the RHF
            G = FY.polynomial()
            V = [(FX.valuation(1/FX.gen()), 1)]
            D = G.discriminant()
            for f, m in D.factor():
                V.append((FX.valuation(f), f.numerator().degree()))
            r = 0
            for v, d in V:
                v = v/v(v.uniformizer())
                W = v.extensions(FY)
                for w in W:
                    e, f = e_f_of_valuation(w)
                    r += d*f*(e-1)

        g = ZZ(-n + r/2 + 1)
        self._genus = g
        return self._genus
Ejemplo n.º 23
0
 def _call_(self, x):
     return ZZ(x.get_str())
Ejemplo n.º 24
0
def ideal_from_label(K, lab):
    r"""Returns the ideal with label lab in the quadratic field K.
    """
    N, c, d = [ZZ(c) for c in lab.split(".")]
    a = N // d
    return K.ideal(a, K([c, d]))
Ejemplo n.º 25
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.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()
Ejemplo n.º 26
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'])]
Ejemplo n.º 27
0
 def disc(self):
     return ZZ(self._data['disc_abs']) * self._data['disc_sign']
Ejemplo n.º 28
0
def nf_string_to_label(F):  # parse Q, Qsqrt2, Qsqrt-4, Qzeta5, etc
    if F == 'Q':
        return '1.1.1.1'
    if F == 'Qi' or F == 'Q(i)':
        return '2.0.4.1'
    # Change unicode dash with minus sign
    F = F.replace(u'\u2212', '-')
    # remove non-ascii characters from F
    F = F.decode('utf8').encode('ascii', 'ignore')
    if len(F) == 0:
        raise ValueError("Entry for the field was left blank.  You need to enter a field label, field name, or a polynomial.")
    if F[0] == 'Q':
        if '(' in F and ')' in F:
            F=F.replace('(','').replace(')','')
        if F[1:5] in ['sqrt', 'root']:
            try:
                d = ZZ(str(F[5:])).squarefree_part()
            except (TypeError, ValueError):
                d = 0
            if d == 0:
                raise ValueError("After {0}, the remainder must be a nonzero integer.  Use {0}5 or {0}-11 for example.".format(F[:5]))
            if d == 1:
                return '1.1.1.1'
            if d % 4 in [2, 3]:
                D = 4 * d
            else:
                D = d
            absD = D.abs()
            s = 0 if D < 0 else 2
            return '2.%s.%s.1' % (s, str(absD))
        if F[1:5] == 'zeta':
            if '_' in F:
                F = F.replace('_','')
            try:
                d = ZZ(str(F[5:]))
            except ValueError:
                d = 0
            if d < 1:
                raise ValueError("After {0}, the remainder must be a positive integer.  Use {0}5 for example.".format(F[:5]))
            if d % 4 == 2:
                d /= 2  # Q(zeta_6)=Q(zeta_3), etc)
            if d == 1:
                return '1.1.1.1'
            deg = euler_phi(d)
            if deg > 23:
                raise ValueError('%s is not in the database.' % F)
            adisc = CyclotomicField(d).discriminant().abs()  # uses formula!
            return '%s.0.%s.1' % (deg, adisc)
        raise ValueError('It is not a valid field name or label, or a defining polynomial.')
    # check if a polynomial was entered
    F = F.replace('X', 'x')
    if 'x' in F:
        F1 = F.replace('^', '**')
        # print F
        from lmfdb.number_fields.number_field import poly_to_field_label
        F1 = poly_to_field_label(F1)
        if F1:
            return F1
        raise ValueError('%s does not define a number field in the database.'%F)
    # Expand out factored labels, like 11.11.11e20.1
    if not re.match(r'\d+\.\d+\.[0-9e_]+\.\d+',F):
        raise ValueError("It must be of the form d.r.D.n, such as 2.2.5.1.")
    parts = F.split(".")
    def raise_power(ab):
        if ab.count("e") == 0:
            return ZZ(ab)
        elif ab.count("e") == 1:
            a,b = ab.split("e")
            return ZZ(a)**ZZ(b)
        else:
            raise ValueError("Malformed absolute discriminant.  It must be a sequence of strings AeB for A and B integers, joined by _s.  For example, 2e7_3e5_11.")
    parts[2] = str(prod(raise_power(c) for c in parts[2].split("_")))
    return ".".join(parts)
Ejemplo n.º 29
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)
        if Dnorm == 1:  # since the factorization of (1) displays as "1"
            self.fact_disc = self.disc
            self.fact_disc_norm = '1'
        else:
            self.fact_disc = latex_factorization(badprimes, disc_ords)
            self.fact_disc_norm = latex_factorization(badnorms, disc_ords)

        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 == 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)

        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.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 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 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"], ["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])))

        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', "")]
Ejemplo n.º 30
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(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:
            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)

        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
                    except AttributeError:
                        self.reg = "not available"
                    # 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

        # 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.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)
            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 = [('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 += [(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', "")]