Esempio n. 1
0
def set_info_for_navigation(info, is_set, sbar):
    r"""
    Set information for the navigation page.
    """
    (friends, lifts) = sbar
    ## We always print the list of weights
    info['initial_list_of_weights'] = print_list_of_weights()
# ajax_more2(print_list_of_weights,{'kstart':[0,10,25,50],'klen':[15,15,15]},text=['<<','>>'])
    ## And the  list of characters if we know the level.

    if(is_set['level']):
        s = "<option value=" + str(0) + ">Trivial character</option>"
        D = DirichletGroup(info['level'])
        if(is_set['weight'] and is_even(info['weight'])):
            if(is_fundamental_discriminant(info['level'])):
                x = kronecker_character(info['level'])
                xi = D.list().index(x)
                s = s + "<option value=" + str(xi) + ">Kronecker character</option>"
        for x in D:
            if(is_set['weight'] and is_even(info['weight']) and x.is_odd()):
                continue
            if(is_set['weight'] and is_odd(info['weight']) and x.is_even()):
                continue
            xi = D.list().index(x)
#                       s=s+"<option value="+str(xi)+">\(\chi_{"+str(xi)+"}\)</option>"
            s = s + "<option value=" + str(xi) + ">" + str(xi) + "</option>"
        info['list_of_characters'] = s
    friends.append(('L-function', '/Lfunction/ModularForm/GL2/Q/holomorphic/'))
    lifts.append(('Half-Integral Weight Forms', '/ModularForm/Mp2/Q'))
    lifts.append(('Siegel Modular Forms', '/ModularForm/GSp4/Q'))
    return (info, lifts)
Esempio n. 2
0
 def central_character(self):
     r"""
     Return the central character of this representation. This is the
     restriction to `\QQ_p^\times` of the unique smooth character `\omega`
     of `\mathbf{A}^\times / \QQ^\times` such that `\omega(\varpi_\ell) =
     \ell^j \varepsilon(\ell)` for all primes `\ell \nmid Np`, where
     `\varpi_\ell` is a uniformiser at `\ell`, `\varepsilon` is the
     Nebentypus character of the newform `f`, and `j` is the twist factor
     (see the documentation for :func:`~LocalComponent`).
     
     EXAMPLES::
     
         sage: LocalComponent(Newform('27a'), 3).central_character()
         Character of Q_3*, of level 0, mapping 3 |--> 1
         
         sage: LocalComponent(Newforms(Gamma1(5), 5, names='c')[0], 5).central_character()
         Character of Q_5*, of level 1, mapping 2 |--> c0 + 1, 5 |--> 125
         
         sage: LocalComponent(Newforms(DirichletGroup(24)([1, -1,-1]), 3, names='a')[0], 2).central_character()
         Character of Q_2*, of level 3, mapping 7 |--> 1, 5 |--> -1, 2 |--> -2
     """
     from sage.rings.arith import crt
     chi = self.newform().character()
     f = self.prime() ** self.conductor()
     N = self.newform().level() // f
     G = DirichletGroup(f, self.coefficient_field())
     chip = G([chi(crt(ZZ(x), 1, f, N)) for x in G.unit_gens()]).primitive_character()
     a = crt(1, self.prime(), f, N)        
     
     if chip.conductor() == 1:
         return SmoothCharacterGroupQp(self.prime(), self.coefficient_field()).character(0, [chi(a) * self.prime()**self.twist_factor()])
     else:
         return SmoothCharacterGroupQp(self.prime(), self.coefficient_field()).character(chip.conductor().valuation(self.prime()), list((~chip).values_on_gens()) + [chi(a) * self.prime()**self.twist_factor()])
def dc_calc_gauss(modulus, number):
    arg = request.args.get("val", [])
    if not arg:
        return flask.abort(404)
    try:
        from sage.modular.dirichlet import DirichletGroup

        chi = DirichletGroup(modulus)[number]
        gauss_sum_numerical = chi.gauss_sum_numerical(100, int(arg))
        return "\(%s\)" % (latex(gauss_sum_numerical))
    except Exception, e:
        return "<span style='color:red;'>ERROR: %s</span>" % e
def dc_calc_kloosterman(modulus, number):
    arg = request.args.get("val", [])
    if not arg:
        return flask.abort(404)
    try:
        arg = map(int, arg.split(","))
        from sage.modular.dirichlet import DirichletGroup

        chi = DirichletGroup(modulus)[number]
        kloosterman_sum_numerical = chi.kloosterman_sum_numerical(100, arg[0], arg[1])
        return "\(%s\)" % (latex(kloosterman_sum_numerical))
    except Exception, e:
        return "<span style='color:red;'>ERROR: %s</span>" % e
def dc_calc_jacobi(modulus, number):
    arg = request.args.get("val", [])
    if not arg:
        return flask.abort(404)
    try:
        arg = map(int, arg.split("."))
        mod = arg[0]
        num = arg[1]
        from sage.modular.dirichlet import DirichletGroup

        chi = DirichletGroup(modulus)[number]
        psi = DirichletGroup(mod)[num]
        jacobi_sum = chi.jacobi_sum(psi)
        return "\(%s\)" % (latex(jacobi_sum))
    except Exception, e:
        return "<span style='color:red;'>ERROR: %s</span>" % e
Esempio n. 6
0
def print_list_of_characters(level=1, weight=2):
    r"""
    Prints a list of characters compatible with the weight and level.
    """
    emf_logger.debug("print_list_of_chars")
    D = DirichletGroup(level)
    res = list()
    for j in range(len(D.list())):
        if D.list()[j].is_even() and is_even(weight):
            res.append(j)
        if D.list()[j].is_odd() and is_odd(weight):
            res.append(j)
    s = ""
    for j in res:
        s += "\(\chi_{" + str(j) + "}\)"
    return s
def render_elliptic_modular_form_space(level=None, weight=None, character=None, label=None, **kwds):
    r"""
    Render the webpage for a elliptic modular forms space.
    """
    emf_logger.debug("In render_elliptic_modular_form_space kwds: {0}".format(kwds))
    emf_logger.debug("Input: level={0},weight={1},character={2},label={3}".format(level, weight, character, label))
    info = to_dict(kwds)
    info["level"] = level
    info["weight"] = weight
    info["character"] = character
    # if kwds.has_key('character') and kwds['character']=='*':
    #    return render_elliptic_modular_form_space_list_chars(level,weight)
    if character == 0:
        dimtbl = DimensionTable()
    else:
        dimtbl = DimensionTable(1)
    if not dimtbl.is_in_db(level, weight, character):
        emf_logger.debug("Data not available")
        if character == 0:
            d = dimension_new_cusp_forms(level, weight)
        else:
            D = DirichletGroup(level)
            x = D.galois_orbits(reps_only=True)[character]
            d = dimension_new_cusp_forms(x, weight)
        if d > 0:
            return render_template("not_available.html")
        else:
            info["is_empty"] = True
            return render_template("emf_space.html", **info)

    emf_logger.debug("Created dimension table in render_elliptic_modular_form_space")
    info = set_info_for_modular_form_space(**info)
    emf_logger.debug("keys={0}".format(info.keys()))
    if "download" in kwds and "error" not in kwds:
        return send_file(info["tempfile"], as_attachment=True, attachment_filename=info["filename"])
    if "dimension_newspace" in kwds and kwds["dimension_newspace"] == 1:
        # if there is only one orbit we list it
        emf_logger.debug("Dimension of newforms is one!")
        info["label"] = "a"
        return redirect(url_for("emf.render_elliptic_modular_forms", **info))
    info["title"] = "Newforms of weight %s on \(\Gamma_{0}(%s)\)" % (weight, level)
    bread = [(EMF_TOP, url_for("emf.render_elliptic_modular_forms"))]
    bread.append(("Level %s" % level, url_for("emf.render_elliptic_modular_forms", level=level)))
    bread.append(("Weight %s" % weight, url_for("emf.render_elliptic_modular_forms", level=level, weight=weight)))
    # emf_logger.debug("friends={0}".format(friends))
    info["bread"] = bread
    return render_template("emf_space.html", **info)
Esempio n. 8
0
    def _Weyl_law_consts(self):
        r"""
        Compute constants for the Weyl law on self._G

        OUTPUT:

        - tuple of real numbers

        EXAMPLES::


            sage: M=MaassWaveForms(MySubgroup(Gamma0(1)))
            sage: M._Weyl_law_consts()
            (0, 2/pi, (log(pi) - log(2) + 2)/pi, 0, -2)
        """
        import mpmath
        pi=mpmath.fp.pi
        ix=Integer(self._G.index())
        nc=Integer(len(self._G.cusps()))
        if(self._G.is_congruence()):
            lvl=Integer(self._G.level())
        else:
            lvl=0
        n2=Integer(self._G.nu2())
        n3=Integer(self._G.nu3())
        c1=ix/Integer(12)
        c2=Integer(2)*nc/pi
        c3=nc*(Integer(2)-ln(Integer(2))+ln(pi))/pi
        if(lvl<>0):
            A=1
            for q in divisors(lvl):
                num_prim_dc=0
                DG=DirichletGroup(q)
                for chi in DG.list():
                    if(chi.is_primitive()):
                        num_prim_dc=num_prim_dc+1
                for m in divisors(lvl):
                    if(lvl % (m*q) == 0   and m % q ==0 ): 
                        fak=(q*lvl)/gcd(m,lvl/m)
                        A=A*Integer(fak)**num_prim_dc        
            c4=-ln(A)/pi
        else:
            c4=Integer(0)
        # constant term
        c5=-ix/144+n2/8+n3*2/9-nc/4-1
        return (c1,c2,c3,c4,c5)
Esempio n. 9
0
    def __init__(self, parent, k, chi=None):
        r"""
        Create a locally algebraic weight-character.

        EXAMPLES::

            sage: pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0)
            (13, 29, [2 + 2*29 + ... + O(29^20)])
        """
        WeightCharacter.__init__(self, parent)
        k = ZZ(k)
        self._k = k
        if chi is None: 
            chi = trivial_character(self._p, QQ)
        n = ZZ(chi.conductor())
        if n == 1: 
            n = self._p
        if not n.is_power_of(self._p):
            raise ValueError, "Character must have %s-power conductor" % p
        self._chi = DirichletGroup(n, chi.base_ring())(chi)
Esempio n. 10
0
def set_table(info, is_set, make_link=True):  # level_min,level_max,weight=2,chi=0,make_link=True):
    r"""
    make a bunch of html tables with information about spaces of modular forms
    with parameters in the given ranges.
    Should use database in the future...
    """
    D = 0
    rowlen = 10  # split into rows of this length...
    rowlen0 = rowlen
    rowlen1 = rowlen
    characters = dict()
    if('level_min' in info):
        level_min = int(info['level_min'])
    else:
        level_min = 1
    if('level_max' in info):
        level_max = int(info['level_max'])
    else:
        level_max = 50
    if (level_max - level_min + 1) < rowlen:
        rowlen0 = level_max - level_min + 1
    if(info['list_chars'] != '0'):
        char1 = 1
    else:
        char1 = 0
    if(is_set['weight']):
        weight = int(info['weight'])
    else:
        weight = 2
    ## setup the table
    # print "char11=",char1
    tbl = dict()
    if(char1 == 1):
        tbl['header'] = 'Dimension of \( S_{' + str(weight) + '}(N,\chi_{n})\)'
    else:
        tbl['header'] = 'Dimension of \( S_{' + str(weight) + '}(N)\)'
    tbl['headersv'] = list()
    tbl['headersh'] = list()
    tbl['corner_label'] = ""
    tbl['data'] = list()
    tbl['data_format'] = 'html'
    tbl['class'] = "dimension_table"
    tbl['atts'] = "border=\"0\" class=\"data_table\""
    num_rows = ceil(QQ(level_max - level_min + 1) / QQ(rowlen0))
    print "num_rows=", num_rows
    for i in range(1, rowlen0 + 1):
        tbl['headersh'].append(i + level_min - 1)

    for r in range(num_rows):
        tbl['headersv'].append(r * rowlen0)
    print "level_min=", level_min
    print "level_max=", level_max
    print "char=", char1
    for r in range(num_rows):
        row = list()
        for k in range(1, rowlen0 + 1):
            row.append("")
        # print "row nr. ",r
        for k in range(1, rowlen0 + 1):
            N = level_min - 1 + r * rowlen0 + k
            s = "<a name=\"#" + str(N) + "\"></a>"
            # print "col ",k,"=",N
            if(N > level_max or N < 1):
                continue
            if(char1 == 0):
                d = dimension_cusp_forms(N, weight)
                print "d=", d
                if(make_link):
                    url = "?weight=" + str(weight) + "&level=" + str(N) + "&character=0"
                    row.append(s + "<a target=\"mainWindow\" href=\"" + url + "\">" + str(d) + "</a>")
                else:
                    row.append(s + str(d))

                # print "dim(",N,weight,")=",d
            else:

                D = DirichletGroup(N)
                print "D=", D
                s = "<a name=\"#" + str(N) + "\"></a>"
                small_tbl = dict()
                # small_tbl['header']='Dimension of \( S_{'+str(weight)+'}(N)\)'
                small_tbl['headersv'] = ['\( d \)']
                small_tbl['headersh'] = list()
                small_tbl['corner_label'] = "\( n \)"
                small_tbl['data'] = list()
                small_tbl['atts'] = "border=\"1\" padding=\"1\""
                small_tbl['data_format'] = 'html'
                row1 = list()
                # num_small_rows = ceil(QQ(level_max) / QQ(rowlen))
                ii = 0
                for chi in range(0, len(D.list())):
                    x = D[chi]
                    S = CuspForms(x, weight)
                    d = S.dimension()
                    if(d == 0):
                        continue
                    small_tbl['headersh'].append(chi)
                    if(make_link):
                        url = "?weight=" + str(weight) + "&level=" + str(N) + "&character=" + str(chi)
                        row1.append("<a target=\"mainWindow\" href=\"" + url + "\">" + str(d) + "</a>")
                    else:
                        row1.append(d)
                    ii = ii + 1
                    print "d=", d
                    if(ii > rowlen1 and len(row1) > 0):
                        ## we make a new table since we may not have regularly dstributed labels
                        # print "Break line! Make new table!"
                        small_tbl['data'].append(row1)
                        s = s + html_table(small_tbl)
                        small_tbl['headersh'] = list()
                        small_tbl['data'] = list()
                        row1 = list()
                        ii = 0

                if(len(row1) > 0):
                    small_tbl['data'].append(row1)
                if(len(row1) > 0 or len(small_tbl['data']) > 0):
                    # print "small_tbl=",small_tbl
                    ss = html_table(small_tbl)
                    # print "ss=",ss
                    s = s + ss
                    # s=s+"\( \chi_{"+str(chi)+"}\) :"+str(d)

                    # print N,k,chi,d
                # print s
                else:
                    s = "All spaces are zero-dimensional!"
                row.append(s)
        print "row=", row
        tbl['data'].append(row)
    s = html_table(tbl)
    s = s + "\n <br> \(N=" + str(rowlen0) + "\cdot row+col\)"
    print "Whole table=", s
    ## ugly solution. but we have latex in the data fields...
    ss = re.sub('texttt', '', s)
    info['popup_table'] = ss
    # info['sidebar']=set_sidebar([navigation,parents,siblings,friends,lifts])
    return info
Esempio n. 11
0
 def line(N):
     G = DirichletGroup(N)
     return [(_, G[_].is_primitive()) for _ in range(len(G))]
Esempio n. 12
0
    def dimension_eis(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of Eisenstein series forms for self,
        or the dimension of the subspace corresponding to the given character
        if one is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          Eisenstein series of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Möbius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        AUTHORS:

        - William Stein - Cohen--Oesterle algorithm

        - Jordi Quer - algorithm based on GammaH subgroups

        - David Loeffler (2009) - code refactoring

        EXAMPLES:

        The following two computations use different algorithms::

            sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
            sage: [Gamma1(36).dimension_eis(1,eps,algorithm="Quer") for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]

        So do these::

            sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
            sage: [Gamma1(48).dimension_eis(3,eps,algorithm="Quer") for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
        """
        from .all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_eis(self, k)

        N = self.level()
        K = eps.base_ring()
        eps = DirichletGroup(N, K)(eps)

        if eps.is_trivial():
            return Gamma0(N).dimension_eis(k)

        # Note case of k = 0 and trivial character already dealt with separately, so k <= 0 here is valid:
        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k % 2) == 0
                                                            and eps.is_odd()):
            return ZZ(0)

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N, (eps**d).kernel())
                dim = dim + moebius(d) * G.dimension_eis(k)
            return dim // phi(n)

        elif algorithm == "CohenOesterle":
            from sage.modular.dims import CohenOesterle
            j = 2 - k
            # We use the Cohen-Oesterle formula in a subtle way to
            # compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on
            # computing with modular forms).
            alpha = -ZZ(
                K(Gamma0(N).index() *
                  (j - 1) / ZZ(12)) + CohenOesterle(eps, j))
            if k == 1:
                return alpha
            else:
                return alpha - self.dimension_cusp_forms(k, eps)

        else:  #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError("Unrecognised algorithm in dimension_eis")
Esempio n. 13
0
    def dimension_new_cusp_forms(self,
                                 k=2,
                                 eps=None,
                                 p=0,
                                 algorithm="CohenOesterle"):
        r"""
        Dimension of the new subspace (or `p`-new subspace) of cusp forms of
        weight `k` and character `\varepsilon`.

        INPUT:

        - ``k`` - an integer (default: 2)

        - ``eps`` - a Dirichlet character

        -  ``p`` - a prime (default: 0); just the `p`-new subspace if given

        - ``algorithm`` - either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Möbius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        EXAMPLES::

            sage: G = DirichletGroup(9)
            sage: eps = G.0^3
            sage: eps.conductor()
            3
            sage: [Gamma1(9).dimension_new_cusp_forms(k, eps) for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]
            sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [2..10]]
            [0, 0, 0, 2, 0, 4, 0, 6, 0]
            sage: [Gamma1(9).dimension_new_cusp_forms(k, eps, 3) for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]

        Double check using modular symbols (independent calculation)::

            sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace().dimension()  for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]
            sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace(3).dimension()  for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]

        Another example at level 33::

            sage: G = DirichletGroup(33)
            sage: eps = G.1
            sage: eps.conductor()
            11
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1) for k in [2..4]]
            [0, 4, 0]
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1, algorithm="Quer") for k in [2..4]]
            [0, 4, 0]
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2) for k in [2..4]]
            [2, 0, 6]
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2, p=3) for k in [2..4]]
            [2, 0, 6]

        """

        if eps is None:
            return GammaH_class.dimension_new_cusp_forms(self, k, p)

        N = self.level()
        eps = DirichletGroup(N, eps.base_ring())(eps)

        if eps.is_trivial():
            from .all import Gamma0
            return Gamma0(N).dimension_new_cusp_forms(k, p)

        from .congroup_gammaH import mumu

        if p == 0 or N % p != 0 or eps.conductor().valuation(p) == N.valuation(
                p):
            D = [eps.conductor() * d for d in divisors(N // eps.conductor())]
            return sum([
                Gamma1_constructor(M).dimension_cusp_forms(
                    k, eps.restrict(M), algorithm) * mumu(N // M) for M in D
            ])
        eps_p = eps.restrict(N // p)
        old = Gamma1_constructor(N // p).dimension_cusp_forms(
            k, eps_p, algorithm)
        return self.dimension_cusp_forms(k, eps, algorithm) - 2 * old
Esempio n. 14
0
    def multiple_of_order(self, maxp=None, proof=True):
        """
        Return a multiple of the order.

        INPUT:

        - ``proof`` -- a boolean (default: True)

        The computation of the rational torsion order of J1(p) is conjectural
        and will only be used if proof=False. See Section 6.2.3 of [CES2003]_.

        EXAMPLES::

            sage: J = J1(11); J
            Abelian variety J1(11) of dimension 1
            sage: J.rational_torsion_subgroup().multiple_of_order()
            5

            sage: J = J0(17)
            sage: J.rational_torsion_subgroup().order()
            4

        This is an example where proof=False leads to a better bound and better
        performance. ::

            sage: J = J1(23)
            sage: J.rational_torsion_subgroup().multiple_of_order() # long time (2s)
            9406793
            sage: J.rational_torsion_subgroup().multiple_of_order(proof=False)
            408991
        """

        try:
            if proof:
                return self._multiple_of_order
            else:
                return self._multiple_of_order_proof_false
        except AttributeError:
            pass

        A = self.abelian_variety()
        N = A.level()

        if A.dimension() == 0:
            self._multiple_of_order = ZZ(1)
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._multiple_of_order = QQ((A.level()-1)/12).numerator()
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # The elliptic curve case
        if A.dimension() == 1:
            self._multiple_of_order = A.elliptic_curve().torsion_order()
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # The conjectural J1(p) case
        if not proof and A.is_J1() and N.is_prime():
            epsilons = [epsilon for epsilon in DirichletGroup(N)
                        if not epsilon.is_trivial() and epsilon.is_even()]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._multiple_of_order_proof_false = ZZ(N/(2**(N-3))*prod(bernoullis))
            return self._multiple_of_order_proof_false

        # The Gamma0 and Gamma1 case
        if all((is_Gamma0(G) or is_Gamma1(G) for G in A.groups())):
            self._multiple_of_order = self.multiple_of_order_using_frobp()
            return self._multiple_of_order

        # Unhandled case
        raise NotImplementedError("No implemented algorithm")
Esempio n. 15
0
def make_table_of_spaces_fixed_level(level=1,
                                     character=0,
                                     weight_block=0,
                                     **kwds):
    r"""
    """
    wlen = 15
    print "make table: ", level, character, weight_block
    w_start = wlen * weight_block
    w_stop = wlen * (weight_block + 1)
    s = "<table><thead></thead><tbody>\n"
    s += "<tr><td>Weight \(k\):</td>"
    dims = dict()
    links = dict()
    character = int(character)
    x = trivial_character(level)
    if character > 0:
        D = DirichletGroup(level).list()
        x = D[int(character)]
    if x.is_even() and is_odd(w_start):
        w_start = w_start + 1
        w_stop = w_stop + 1
    if x.is_odd() and is_even(w_start):
        w_start = w_start + 1
        w_stop = w_stop + 1
    weights = list()
    for weight in range(w_start, w_start + 2 * wlen, 2):
        weights.append(weight)
    for weight in weights:
        s += "<td> %s </td>" % weight
    s += "</tr><tr>"
    if character > 0:
        s += "<td>Dimension:"  # of  \(S^{\\textrm{new}}_{k}(%s),\chi_{%s}\):" % (level,character)
    else:
        s += "<td>Dimension:"  # of \(S^{\\textrm{new}}_{k}(%s)\):" % (level)
    for weight in weights:
        if character > 0:
            dims[weight] = dimension_new_cusp_forms(x, weight)
        else:
            dims[weight] = dimension_new_cusp_forms(level, weight)
        s += "<td> %s </td>" % dims[weight]
    j = 0  # we display ony even weight if the character is even
    print "w_start=", w_start
    print "w_stop=", w_stop
    for weight in weights:
        if weight not in dims:
            continue
        if dims[weight] > 0:
            url = url_for('emf.render_elliptic_modular_forms',
                          level=level,
                          weight=weight)
            if character > 0:
                lab = "\(S^{\\textrm{}}_{%s}(%s,\chi_{%s})\)" % (weight, level,
                                                                 character)
            else:
                # lab = " \(S_{%s}(%s)\)" %(weight,level)
                lab = " S<sup><small></small></sup><sub><small>%s</small></sub>(%s)" % (
                    weight, level)
            links[
                weight] = "<a  style=\"display:inline\" href=\"%s\">%s</a>" % (
                    url, lab)
        else:
            links[weight] = ""
        j += 1
        if j >= wlen:
            exit
    l = max(map(len_as_printed, map(str, links))) * 10.0
    s += "</tr><tr>"
    s += "<td>Link to space:</td>"
    for weight in weights:
        if weight in links:
            s += "<td width=\"%s\">%s</td>" % (l + 50, links[weight])
    s += "</tr></tbody></table>"
    # print s
    return s
Esempio n. 16
0
 def dimension_of_ordinary_subspace(self, p=None, cusp=False):
     """
     If ``cusp`` is ``True``, return dimension of cuspidal ordinary
     subspace. This does a weight 2 computation with sage's ModularSymbols.
     
     EXAMPLES::
     
         sage: M = OverconvergentModularSymbols(11, 0, sign=-1, p=3, prec_cap=4, base=ZpCA(3, 8))
         sage: M.dimension_of_ordinary_subspace()
         2
         sage: M.dimension_of_ordinary_subspace(cusp=True)
         2
         sage: M = OverconvergentModularSymbols(11, 0, sign=1, p=3, prec_cap=4, base=ZpCA(3, 8))
         sage: M.dimension_of_ordinary_subspace(cusp=True)
         2
         sage: M.dimension_of_ordinary_subspace()
         4
         sage: M = OverconvergentModularSymbols(11, 0, sign=0, p=3, prec_cap=4, base=ZpCA(3, 8))
         sage: M.dimension_of_ordinary_subspace()
         6
         sage: M.dimension_of_ordinary_subspace(cusp=True)
         4
         sage: M = OverconvergentModularSymbols(11, 0, sign=1, p=11, prec_cap=4, base=ZpCA(11, 8))
         sage: M.dimension_of_ordinary_subspace(cusp=True)
         1
         sage: M.dimension_of_ordinary_subspace()
         2
         sage: M = OverconvergentModularSymbols(11, 2, sign=1, p=11, prec_cap=4, base=ZpCA(11, 8))
         sage: M.dimension_of_ordinary_subspace(cusp=True)
         0
         sage: M.dimension_of_ordinary_subspace()
         1
         sage: M = OverconvergentModularSymbols(11, 10, sign=1, p=11, prec_cap=4, base=ZpCA(11, 8))
         sage: M.dimension_of_ordinary_subspace(cusp=True)
         1
         sage: M.dimension_of_ordinary_subspace()
         2
     
     An example with odd weight and hence non-trivial character::
     
         sage: K = Qp(11, 6)
         sage: DG = DirichletGroup(11, K)
         sage: chi = DG([K(378703)])
         sage: MM = FamiliesOfOMS(chi, 1, p=11, prec_cap=[4, 4], base_coeffs=ZpCA(11, 4), sign=-1)
         sage: MM.dimension_of_ordinary_subspace()
         1
     """
     try:
         p = self.prime()
     except AttributeError:
         if p is None:
             raise ValueError("If self doesn't have a prime, must specify p.")
     try:
         return self._ord_dim_dict[(p, cusp)]
     except AttributeError:
         self._ord_dim_dict = {}
     except KeyError:
         pass
     from sage.modular.dirichlet import DirichletGroup
     from sage.rings.finite_rings.constructor import GF
     try:
         chi = self.character()
     except AttributeError:
         chi = DirichletGroup(self.level(), GF(p))[0]
     if chi is None:
         chi = DirichletGroup(self.level(), GF(p))[0]
     
     from sage.modular.modsym.modsym import ModularSymbols
     r = self.weight() % (p-1)
     if chi.is_trivial():
         N = chi.modulus()
         if N % p != 0:
             N *= p
         else:
             e = N.valuation(p)
             N.divide_knowing_divisible_by(p ** (e-1))
         chi = DirichletGroup(N, GF(p))[0]
     elif chi.modulus() % p != 0:
         chi = DirichletGroup(chi.modulus() * p, GF(p))(chi)
     DG = DirichletGroup(chi.modulus(), GF(p))
     if r == 0:
         from sage.modular.arithgroup.congroup_gamma0 import Gamma0_constructor as Gamma0
         verbose("in dim: %s, %s, %s"%(self.sign(), chi, p))
         M = ModularSymbols(DG(chi), 2, self.sign(), GF(p))
     else:
         psi = [GF(p)(u) ** r for u in DG.unit_gens()]    #mod p Teichmuller^r
         psi = DG(psi)
         M = ModularSymbols(DG(chi) * psi, 2, self.sign(), GF(p))
     if cusp:
         M = M.cuspidal_subspace()
     hecke_poly = M.hecke_polynomial(p)
     verbose("in dim: %s"%(hecke_poly))
     x = hecke_poly.parent().gen()
     d = hecke_poly.degree() - hecke_poly.ord(x)
     self._ord_dim_dict[(p, cusp)] = d
     return d
Esempio n. 17
0
    def possible_orders(self, proof=True):
        """
        Return the possible orders of this torsion subgroup. Outside of special
        cases, this is done by computing a divisor and multiple of the order.

        INPUT:

        - ``proof`` -- a boolean (default: True)

        OUTPUT:

        - an array of positive integers

        The computation of the rational torsion order of J1(p) is conjectural
        and will only be used if proof=False. See Section 6.2.3 of [CES2003]_.

        EXAMPLES::

            sage: J0(11).rational_torsion_subgroup().possible_orders()
            [5]
            sage: J0(33).rational_torsion_subgroup().possible_orders()
            [100, 200]

            sage: J1(13).rational_torsion_subgroup().possible_orders()
            [19]
            sage: J1(16).rational_torsion_subgroup().possible_orders()
            [1, 2, 4, 5, 10, 20]
        """
        try:
            if proof:
                return self._possible_orders
            else:
                return self._possible_orders_proof_false
        except AttributeError:
            pass

        A = self.abelian_variety()
        N = A.level()
        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._possible_orders = [QQ((A.level()-1)/12).numerator()]
            self._possible_orders_proof_false = self._possible_orders
            return self._possible_orders

        # the elliptic curve case
        if A.dimension() == 1:
            self._possible_orders = [A.elliptic_curve().torsion_order()]
            self._possible_orders_proof_false = self._possible_orders
            return self._possible_orders

        # the conjectural J1(p) case
        if not proof and A.is_J1() and N.is_prime():
            epsilons = [epsilon for epsilon in DirichletGroup(N)
                        if not epsilon.is_trivial() and epsilon.is_even()]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._possible_orders_proof_false = [ZZ(N/(2**(N-3))*prod(bernoullis))]
            return self._possible_orders_proof_false

        u = self.multiple_of_order()
        l = self.divisor_of_order()

        assert u % l == 0
        O = [l * d for d in divisors(u//l)]
        self._possible_orders = O
        if u == l:
            self._possible_orders_proof_false = O
        return O
Esempio n. 18
0
def hecke_operator_on_basis(B, n, k, eps=None, already_echelonized=False):
    r"""
    Given a basis `B` of `q`-expansions for a space of modular forms
    with character `\varepsilon` to precision at least `\#B\cdot n+1`,
    this function computes the matrix of `T_n` relative to `B`.

    .. note::

       If the elements of B are not known to sufficient precision,
       this function will report that the vectors are linearly
       dependent (since they are to the specified precision).

    INPUT:

    - ``B`` - list of q-expansions

    - ``n`` - an integer >= 1

    - ``k`` - an integer

    - ``eps`` - Dirichlet character

    - ``already_echelonized`` -- bool (default: False); if True, use that the
      basis is already in Echelon form, which saves a lot of time.

    EXAMPLES::

        sage: sage.modular.modform.constructor.ModularForms_clear_cache()
        sage: ModularForms(1,12).q_expansion_basis()
        [
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6),
        1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6)
        ]
        sage: hecke_operator_on_basis(ModularForms(1,12).q_expansion_basis(), 3, 12)
        Traceback (most recent call last):
        ...
        ValueError: The given basis vectors must be linearly independent.

        sage: hecke_operator_on_basis(ModularForms(1,12).q_expansion_basis(30), 3, 12)
        [   252      0]
        [     0 177148]

    TESTS:

    This shows that the problem with finite fields reported at trac #8281 is solved::

        sage: bas_mod5 = [f.change_ring(GF(5)) for f in victor_miller_basis(12, 20)]
        sage: hecke_operator_on_basis(bas_mod5, 2, 12)
        [4 0]
        [0 1]

    This shows that empty input is handled sensibly (trac #12202)::

        sage: x = hecke_operator_on_basis([], 3, 12); x
        []
        sage: x.parent()
        Full MatrixSpace of 0 by 0 dense matrices over Cyclotomic Field of order 1 and degree 1
        sage: y = hecke_operator_on_basis([], 3, 12, eps=DirichletGroup(13).0^2); y
        []
        sage: y.parent()
        Full MatrixSpace of 0 by 0 dense matrices over Cyclotomic Field of order 12 and degree 4
    """
    if not isinstance(B, (list, tuple)):
        raise TypeError, "B (=%s) must be a list or tuple" % B
    if len(B) == 0:
        if eps is None:
            R = CyclotomicField(1)
        else:
            R = eps.base_ring()
        return MatrixSpace(R, 0)(0)
    f = B[0]
    R = f.base_ring()
    if eps is None:
        eps = DirichletGroup(1, R).gen(0)
    all_powerseries = True
    for x in B:
        if not is_PowerSeries(x):
            all_powerseries = False
    if not all_powerseries:
        raise TypeError, "each element of B must be a power series"
    n = Integer(n)
    k = Integer(k)
    prec = (f.prec() - 1) // n
    A = R**prec
    V = A.span_of_basis([g.padded_list(prec) for g in B],
                        already_echelonized=already_echelonized)
    return _hecke_operator_on_basis(B, V, n, k, eps)
Esempio n. 19
0
class AlgebraicWeight(WeightCharacter):
    r"""
    A point in weight space corresponding to a locally algebraic character, of
    the form `x \mapsto \chi(x) x^k` where `k` is an integer and `\chi` is a
    Dirichlet character modulo `p^n` for some `n`.

    TESTS::

        sage: w = pAdicWeightSpace(23)(12, DirichletGroup(23, QQ).0) # exact
        sage: w == loads(dumps(w))
        True
        sage: w = pAdicWeightSpace(23)(12, DirichletGroup(23, Qp(23)).0) # inexact
        sage: w == loads(dumps(w))
        True
        sage: w is loads(dumps(w)) # elements are not globally unique
        False
    """

    def __init__(self, parent, k, chi=None):
        r"""
        Create a locally algebraic weight-character.

        EXAMPLES::

            sage: pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0)
            (13, 29, [2 + 2*29 + ... + O(29^20)])
        """
        WeightCharacter.__init__(self, parent)
        k = ZZ(k)
        self._k = k
        if chi is None: 
            chi = trivial_character(self._p, QQ)
        n = ZZ(chi.conductor())
        if n == 1: 
            n = self._p
        if not n.is_power_of(self._p):
            raise ValueError, "Character must have %s-power conductor" % p
        self._chi = DirichletGroup(n, chi.base_ring())(chi)

    def __call__(self, x):
        r"""
        Evaluate this character at an element of `\ZZ_p^\times`.

        EXAMPLES:

        Exact answers are returned when this is possible::

            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, QQ).0)
            sage: kappa(1)
            1
            sage: kappa(0)
            0
            sage: kappa(12)
            -106993205379072
            sage: kappa(-1)
            -1
            sage: kappa(13 + 4*29 + 11*29^2 + O(29^3))
            9 + 21*29 + 27*29^2 + O(29^3)

        When the character chi is defined over a p-adic field, the results returned are inexact::

            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14)
            sage: kappa(1)
            1 + O(29^20)
            sage: kappa(0)
            0
            sage: kappa(12)
            17 + 11*29 + 7*29^2 + 4*29^3 + 5*29^4 + 2*29^5 + 13*29^6 + 3*29^7 + 18*29^8 + 21*29^9 + 28*29^10 + 28*29^11 + 28*29^12 + 28*29^13 + 28*29^14 + 28*29^15 + 28*29^16 + 28*29^17 + 28*29^18 + 28*29^19 + O(29^20)
            sage: kappa(12) == -106993205379072
            True
            sage: kappa(-1) == -1
            True
            sage: kappa(13 + 4*29 + 11*29^2 + O(29^3))
            9 + 21*29 + 27*29^2 + O(29^3)
        """
        if isinstance(x, pAdicGenericElement):
            if x.parent().prime() != self._p:
                raise TypeError, "x must be an integer or a %s-adic integer" % self._p
            if self._p**(x.precision_absolute()) < self._chi.conductor():
                raise Exception, "Precision too low"
            xint = x.lift()
        else:
            xint = x
        if (xint % self._p == 0): return 0
        return self._chi(xint) * x**self._k 

    def k(self):
        r"""
        If this character is `x \mapsto x^k \chi(x)` for an integer `k` and a
        Dirichlet character `\chi`, return `k`.

        EXAMPLE::
        
            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14)
            sage: kappa.k()
            13
        """
        return self._k

    def chi(self):
        r"""
        If this character is `x \mapsto x^k \chi(x)` for an integer `k` and a
        Dirichlet character `\chi`, return `\chi`.
        
        EXAMPLE::
        
            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14)
            sage: kappa.chi()
            Dirichlet character modulo 29 of conductor 29 mapping 2 |--> 28 + 28*29 + 28*29^2 + ... + O(29^20)
        """
        return self._chi

    def _repr_(self):
        r"""
        String representation of self.

        EXAMPLES::

            sage: pAdicWeightSpace(17)(2)._repr_()
            '2'
            sage: pAdicWeightSpace(17)(2, DirichletGroup(17, QQ).0)._repr_()
            '(2, 17, [-1])'
            sage: pAdicWeightSpace(17)(2, DirichletGroup(17, QQ).0^2)._repr_()
            '2'
        """
        if self._chi.is_trivial():
            return "%s" % self._k
        else:
            return "(%s, %s, %s)" % (self._k, self._chi.modulus(), self._chi._repr_short_())

    def teichmuller_type(self):
        r"""
        Return the Teichmuller type of this weight-character `\kappa`, which is
        the unique `t \in \ZZ/(p-1)\ZZ` such that `\kappa(\mu) =
        \mu^t` for \mu a `(p-1)`-st root of 1.

        For `p = 2` this doesn't make sense, but we still want the Teichmuller
        type to correspond to the index of the component of weight space in
        which `\kappa` lies, so we return 1 if `\kappa` is odd and 0 otherwise.

        EXAMPLE::

            sage: pAdicWeightSpace(11)(2, DirichletGroup(11,QQ).0).teichmuller_type()
            7
            sage: pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0).teichmuller_type()
            14
            sage: pAdicWeightSpace(2)(3, DirichletGroup(4,QQ).0).teichmuller_type()
            0
        """
        # Special case p == 2
        if self._p == 2:
            if self.is_even():
                return IntegerModRing(2)(0)
            else:
                return IntegerModRing(2)(1)
        m = IntegerModRing(self._p).multiplicative_generator()
        x = [y for y in IntegerModRing(self._chi.modulus()) if y == m and y**(self._p - 1) == 1]
        if len(x) != 1: raise ArithmeticError
        x = x[0]
        f = IntegerModRing(self._p)(self._chi(x)).log(m)
        return IntegerModRing(self._p - 1)(self._k + f)

    def Lvalue(self):
        r"""
        Return the value of the p-adic L-function of `\QQ` evaluated at
        this weight-character. If the character is `x \mapsto x^k \chi(x)`
        where `k > 0` and `\chi` has conductor a power of `p`, this is an
        element of the number field generated by the values of `\chi`, equal to
        the value of the complex L-function `L(1-k, \chi)`. If `\chi` is
        trivial, it is equal to `(1 - p^{k-1})\zeta(1-k)`.

        At present this is not implemented in any other cases, except the
        trivial character (for which the value is `\infty`).

        TODO: Implement this more generally using the Amice transform machinery
        in sage/schemes/elliptic_curves/padic_lseries.py, which should clearly
        be factored out into a separate class.

        EXAMPLES::

            sage: pAdicWeightSpace(7)(4).Lvalue() == (1 - 7^3)*zeta__exact(-3)
            True
            sage: pAdicWeightSpace(7)(5, DirichletGroup(7, Qp(7)).0^4).Lvalue()
            0
            sage: pAdicWeightSpace(7)(6, DirichletGroup(7, Qp(7)).0^4).Lvalue()
            1 + 2*7 + 7^2 + 3*7^3 + 3*7^5 + 4*7^6 + 2*7^7 + 5*7^8 + 2*7^9 + 3*7^10 + 6*7^11 + 2*7^12 + 3*7^13 + 5*7^14 + 6*7^15 + 5*7^16 + 3*7^17 + 6*7^18 + O(7^19)
        """
        if self._k > 0:
            return -self._chi.bernoulli(self._k)/self._k
        if self.is_trivial():
            return Infinity
        else:
            raise NotImplementedError, "Don't know how to compute value of this L-function"
Esempio n. 20
0
class AlgebraicWeight(WeightCharacter):
    r"""
    A point in weight space corresponding to a locally algebraic character, of
    the form `x \mapsto \chi(x) x^k` where `k` is an integer and `\chi` is a
    Dirichlet character modulo `p^n` for some `n`.

    TESTS::

        sage: w = pAdicWeightSpace(23)(12, DirichletGroup(23, QQ).0) # exact
        sage: w == loads(dumps(w))
        True
        sage: w = pAdicWeightSpace(23)(12, DirichletGroup(23, Qp(23)).0) # inexact
        sage: w == loads(dumps(w))
        True
        sage: w is loads(dumps(w)) # elements are not globally unique
        False
    """
    def __init__(self, parent, k, chi=None):
        r"""
        Create a locally algebraic weight-character.

        EXAMPLES::

            sage: pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0)
            (13, 29, [2 + 2*29 + ... + O(29^20)])
        """
        WeightCharacter.__init__(self, parent)
        k = ZZ(k)
        self._k = k
        if chi is None:
            chi = trivial_character(self._p, QQ)
        n = ZZ(chi.conductor())
        if n == 1:
            n = self._p
        if not n.is_power_of(self._p):
            raise ValueError("Character must have %s-power conductor" % p)
        self._chi = DirichletGroup(n, chi.base_ring())(chi)

    def __call__(self, x):
        r"""
        Evaluate this character at an element of `\ZZ_p^\times`.

        EXAMPLES:

        Exact answers are returned when this is possible::

            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, QQ).0)
            sage: kappa(1)
            1
            sage: kappa(0)
            0
            sage: kappa(12)
            -106993205379072
            sage: kappa(-1)
            -1
            sage: kappa(13 + 4*29 + 11*29^2 + O(29^3))
            9 + 21*29 + 27*29^2 + O(29^3)

        When the character chi is defined over a p-adic field, the results returned are inexact::

            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14)
            sage: kappa(1)
            1 + O(29^20)
            sage: kappa(0)
            0
            sage: kappa(12)
            17 + 11*29 + 7*29^2 + 4*29^3 + 5*29^4 + 2*29^5 + 13*29^6 + 3*29^7 + 18*29^8 + 21*29^9 + 28*29^10 + 28*29^11 + 28*29^12 + 28*29^13 + 28*29^14 + 28*29^15 + 28*29^16 + 28*29^17 + 28*29^18 + 28*29^19 + O(29^20)
            sage: kappa(12) == -106993205379072
            True
            sage: kappa(-1) == -1
            True
            sage: kappa(13 + 4*29 + 11*29^2 + O(29^3))
            9 + 21*29 + 27*29^2 + O(29^3)
        """
        if isinstance(x, pAdicGenericElement):
            if x.parent().prime() != self._p:
                raise TypeError("x must be an integer or a %s-adic integer" %
                                self._p)
            if self._p**(x.precision_absolute()) < self._chi.conductor():
                raise PrecisionError("Precision too low")
            xint = x.lift()
        else:
            xint = x
        if (xint % self._p == 0): return 0
        return self._chi(xint) * x**self._k

    def k(self):
        r"""
        If this character is `x \mapsto x^k \chi(x)` for an integer `k` and a
        Dirichlet character `\chi`, return `k`.

        EXAMPLES::

            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14)
            sage: kappa.k()
            13
        """
        return self._k

    def chi(self):
        r"""
        If this character is `x \mapsto x^k \chi(x)` for an integer `k` and a
        Dirichlet character `\chi`, return `\chi`.

        EXAMPLES::

            sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14)
            sage: kappa.chi()
            Dirichlet character modulo 29 of conductor 29 mapping 2 |--> 28 + 28*29 + 28*29^2 + ... + O(29^20)
        """
        return self._chi

    def __hash__(self):
        r"""
        TESTS::

            sage: w = pAdicWeightSpace(23)(12, DirichletGroup(23, QQ).0)
            sage: hash(w)
            2363715643371367891  # 64-bit
            -1456525869          # 32-bit
        """
        if self._chi.is_trivial():
            return hash(self._k)
        else:
            return hash((self._k, self._chi.modulus(), self._chi))

    def _repr_(self):
        r"""
        String representation of self.

        EXAMPLES::

            sage: pAdicWeightSpace(17)(2)._repr_()
            '2'
            sage: pAdicWeightSpace(17)(2, DirichletGroup(17, QQ).0)._repr_()
            '(2, 17, [-1])'
            sage: pAdicWeightSpace(17)(2, DirichletGroup(17, QQ).0^2)._repr_()
            '2'
        """
        if self._chi.is_trivial():
            return "%s" % self._k
        else:
            return "(%s, %s, %s)" % (self._k, self._chi.modulus(),
                                     self._chi._repr_short_())

    def teichmuller_type(self):
        r"""
        Return the Teichmuller type of this weight-character `\kappa`, which is
        the unique `t \in \ZZ/(p-1)\ZZ` such that `\kappa(\mu) =
        \mu^t` for \mu a `(p-1)`-st root of 1.

        For `p = 2` this doesn't make sense, but we still want the Teichmuller
        type to correspond to the index of the component of weight space in
        which `\kappa` lies, so we return 1 if `\kappa` is odd and 0 otherwise.

        EXAMPLES::

            sage: pAdicWeightSpace(11)(2, DirichletGroup(11,QQ).0).teichmuller_type()
            7
            sage: pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0).teichmuller_type()
            14
            sage: pAdicWeightSpace(2)(3, DirichletGroup(4,QQ).0).teichmuller_type()
            0
        """
        # Special case p == 2
        if self._p == 2:
            if self.is_even():
                return IntegerModRing(2)(0)
            else:
                return IntegerModRing(2)(1)
        m = IntegerModRing(self._p).multiplicative_generator()
        x = [
            y for y in IntegerModRing(self._chi.modulus())
            if y == m and y**(self._p - 1) == 1
        ]
        if len(x) != 1: raise ArithmeticError
        x = x[0]
        f = IntegerModRing(self._p)(self._chi(x)).log(m)
        return IntegerModRing(self._p - 1)(self._k + f)

    def Lvalue(self):
        r"""
        Return the value of the p-adic L-function of `\QQ` evaluated at
        this weight-character. If the character is `x \mapsto x^k \chi(x)`
        where `k > 0` and `\chi` has conductor a power of `p`, this is an
        element of the number field generated by the values of `\chi`, equal to
        the value of the complex L-function `L(1-k, \chi)`. If `\chi` is
        trivial, it is equal to `(1 - p^{k-1})\zeta(1-k)`.

        At present this is not implemented in any other cases, except the
        trivial character (for which the value is `\infty`).

        TODO: Implement this more generally using the Amice transform machinery
        in sage/schemes/elliptic_curves/padic_lseries.py, which should clearly
        be factored out into a separate class.

        EXAMPLES::

            sage: pAdicWeightSpace(7)(4).Lvalue() == (1 - 7^3)*zeta__exact(-3)
            True
            sage: pAdicWeightSpace(7)(5, DirichletGroup(7, Qp(7)).0^4).Lvalue()
            0
            sage: pAdicWeightSpace(7)(6, DirichletGroup(7, Qp(7)).0^4).Lvalue()
            1 + 2*7 + 7^2 + 3*7^3 + 3*7^5 + 4*7^6 + 2*7^7 + 5*7^8 + 2*7^9 + 3*7^10 + 6*7^11 + 2*7^12 + 3*7^13 + 5*7^14 + 6*7^15 + 5*7^16 + 3*7^17 + 6*7^18 + O(7^19)
        """
        if self._k > 0:
            return -self._chi.bernoulli(self._k) / self._k
        if self.is_trivial():
            return Infinity
        else:
            raise NotImplementedError(
                "Don't know how to compute value of this L-function")
Esempio n. 21
0
    def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of cusp forms for self, or the
        dimension of the subspace corresponding to the given character if one
        is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          forms of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Moebius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        EXAMPLES:

        We compute the same dimension in two different ways ::

            sage: K = CyclotomicField(3)
            sage: eps = DirichletGroup(7*43,K).0^2
            sage: G = Gamma1(7*43)

        Via Cohen--Oesterle: ::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps)
            28

        Via Quer's method: ::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer")
            28

        Some more examples: ::

            sage: G.<eps> = DirichletGroup(9)
            sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]]
            [0, 0, 1, 0, 3, 0, 5, 0, 7, 0]
            sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]]
            [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]
        """

        from all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_cusp_forms(self, k)

        N = self.level()
        if eps.base_ring().characteristic() != 0:
            raise ValueError

        eps = DirichletGroup(N, eps.base_ring())(eps)

        if eps.is_trivial():
            return Gamma0(N).dimension_cusp_forms(k)

        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k % 2) == 0
                                                            and eps.is_odd()):
            return ZZ(0)

        if k == 1:
            try:
                n = self.dimension_cusp_forms(1)
                if n == 0:
                    return ZZ(0)
                else:  # never happens at present
                    raise NotImplementedError, "Computations of dimensions of spaces of weight 1 cusp forms not implemented at present"
            except NotImplementedError:
                raise

        # now the main part

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N, (eps**d).kernel())
                dim = dim + moebius(d) * G.dimension_cusp_forms(k)
            return dim // phi(n)

        elif algorithm == "CohenOesterle":
            K = eps.base_ring()
            from sage.modular.dims import CohenOesterle
            from all import Gamma0
            return ZZ(
                K(Gamma0(N).index() * (k - 1) / ZZ(12)) +
                CohenOesterle(eps, k))

        else:  #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError, "Unrecognised algorithm in dimension_cusp_forms"
Esempio n. 22
0
def make_table_of_dimensions(level_start=1,
                             level_stop=50,
                             weight_start=1,
                             weight_stop=24,
                             char=0,
                             **kwds):
    r"""
    make an html table with information about spaces of modular forms
    with parameters in the given ranges. using a fixed character.
    Should use database in the future...
    """
    D = 0
    rowlen = 15  # split into rows of this length...
    rowlen0 = rowlen
    rowlen1 = rowlen
    characters = dict()
    level = 'N'
    weight = 'k'
    print "char=", char
    if level_start == level_stop:
        level = level_start
        count_min = weight_start
        count_max = weight_stop
        if (weight_stop - weight_start + 1) < rowlen:
            rowlen0 = weight_stop - weight_start + 1
    if weight_start == weight_stop:
        weight = weight_start
        count_min = level_start
        count_max = level_stop
        if (level_stop - level_start + 1) < rowlen:
            rowlen0 = level_stop - level_start + 1
    # else:
    #    return ""
    tbl = dict()
    if (char == 0):
        tbl['header'] = ''  # Dimension of \( S_{'+str(weight)+'}('+str(level)+',\chi_{n})\)'
        charst = ""
    else:
        # s = 'Dimension of \( S_{'+str(weight)+'}('+str(level)+')\)'
        # s += ' (trivial character)'
        charst = ",\chi_{%s}" % char
        tbl['header'] = ''
    tbl['headersv'] = list()
    tbl['headersh'] = list()
    if weight == 'k':
        tbl['corner_label'] = "weight \(k\):"
    else:
        tbl['corner_label'] = "level \(N\):"
    tbl['data'] = list()
    tbl['data_format'] = 'html'
    tbl['class'] = "dimension_table"
    tbl['atts'] = "border=\"1\" class=\"nt_data\" padding=\"25\" width=\"100%\""
    num_rows = ceil(QQ(count_max - count_min + 1) / QQ(rowlen0))
    print "num_rows=", num_rows
    for i in range(1, rowlen0 + 1):
        tbl['headersh'].append(i + count_min - 1)
    if level_start == level_stop:
        st = "Dimension of \(S_{k}(%s%s) \):" % (level, charst)
        tbl['headersv'] = [st]
    else:
        st = "Dimension of \(S_{%s}(N%s) \):" % (weight, charst)
        tbl['headersv'] = [st]
    tbl['headersv'].append('Link to space:')
    # make a dummy table first
    # num_rows = (num_rows-1)*2
    for r in range(num_rows * 2):
        row = []
        for k in range(1, rowlen0 + 1):
            row.append("")
        tbl['data'].append(row)
    tbl['data_format'] = dict()
    for k in range(0, rowlen0):
        tbl['data_format'][k] = 'html'

    print "nu_rows=", len(tbl['data'])
    print "num_cols=", rowlen0
    print "num_cols=", [len(r) for r in tbl['data']]
    for r in range(num_rows):
        for k in range(0, rowlen0):
            cnt = count_min + r * rowlen0 + k
            if level_start == level_stop:
                weight = cnt
            else:
                level = cnt
            url = url_for('emf.render_elliptic_modular_forms',
                          level=level,
                          weight=weight)
            if (cnt > count_max or cnt < count_min):
                tbl['data'][2 * r][k] = ""
                continue
            # s="<a name=\"#%s,%s\"></a>" % (level,weight)
            if (char == 0):
                d = dimension_cusp_forms(level, weight)
            else:
                x = DirichletGroup(level)[char]
                d = dimension_cusp_forms(x, weight)
            tbl['data'][2 * r][k] = str(d)
            if d > 0:
                s = "\(S_{%s}(%s)\)" % (weight, level)
                ss = "<a  href=\"" + url + "\">" + s + "</a>"
                tbl['data'][2 * r + 1][k] = ss
            # else:
            #    tbl['data'][2*r+1][k]="\(\emptyset\)"
            #    ss = make_table_of_characters(level,weight)
            #    tbl['data'][2*r+1][k]=ss
            # tbl['data'][r][k]=s
            # print "row=",row
            # tbl['data'][r]=row
    # print "tbl=",tbl
    s = html_table(tbl)
    # s=s+"\n <br> \(N="+str(rowlen0)+"\cdot row+col\)"
    # print "SS=",s
    return s
Esempio n. 23
0
    def dimension_of_ordinary_subspace(self, p=None, cusp=False):
        """
        If ``cusp`` is ``True``, return dimension of cuspidal ordinary
        subspace. This does a weight 2 computation with sage's ModularSymbols.
        
        EXAMPLES::
        
            sage: M = OverconvergentModularSymbols(11, 0, sign=-1, p=3, prec_cap=4, base=ZpCA(3, 8))
            sage: M.dimension_of_ordinary_subspace()
            2
            sage: M.dimension_of_ordinary_subspace(cusp=True)
            2
            sage: M = OverconvergentModularSymbols(11, 0, sign=1, p=3, prec_cap=4, base=ZpCA(3, 8))
            sage: M.dimension_of_ordinary_subspace(cusp=True)
            2
            sage: M.dimension_of_ordinary_subspace()
            4
            sage: M = OverconvergentModularSymbols(11, 0, sign=0, p=3, prec_cap=4, base=ZpCA(3, 8))
            sage: M.dimension_of_ordinary_subspace()
            6
            sage: M.dimension_of_ordinary_subspace(cusp=True)
            4
            sage: M = OverconvergentModularSymbols(11, 0, sign=1, p=11, prec_cap=4, base=ZpCA(11, 8))
            sage: M.dimension_of_ordinary_subspace(cusp=True)
            1
            sage: M.dimension_of_ordinary_subspace()
            2
            sage: M = OverconvergentModularSymbols(11, 2, sign=1, p=11, prec_cap=4, base=ZpCA(11, 8))
            sage: M.dimension_of_ordinary_subspace(cusp=True)
            0
            sage: M.dimension_of_ordinary_subspace()
            1
            sage: M = OverconvergentModularSymbols(11, 10, sign=1, p=11, prec_cap=4, base=ZpCA(11, 8))
            sage: M.dimension_of_ordinary_subspace(cusp=True)
            1
            sage: M.dimension_of_ordinary_subspace()
            2
        
        An example with odd weight and hence non-trivial character::
        
            sage: K = Qp(11, 6)
            sage: DG = DirichletGroup(11, K)
            sage: chi = DG([K(378703)])
            sage: MM = FamiliesOfOMS(chi, 1, p=11, prec_cap=[4, 4], base_coeffs=ZpCA(11, 4), sign=-1)
            sage: MM.dimension_of_ordinary_subspace()
            1
        """
        try:
            p = self.prime()
        except AttributeError:
            if p is None:
                raise ValueError(
                    "If self doesn't have a prime, must specify p.")
        try:
            return self._ord_dim_dict[(p, cusp)]
        except AttributeError:
            self._ord_dim_dict = {}
        except KeyError:
            pass
        from sage.modular.dirichlet import DirichletGroup
        from sage.rings.finite_rings.constructor import GF
        try:
            chi = self.character()
        except AttributeError:
            chi = DirichletGroup(self.level(), GF(p))[0]
        if chi is None:
            chi = DirichletGroup(self.level(), GF(p))[0]

        from sage.modular.modsym.modsym import ModularSymbols
        r = self.weight() % (p - 1)
        if chi.is_trivial():
            N = chi.modulus()
            if N % p != 0:
                N *= p
            else:
                e = N.valuation(p)
                N.divide_knowing_divisible_by(p**(e - 1))
            chi = DirichletGroup(N, GF(p))[0]
        elif chi.modulus() % p != 0:
            chi = DirichletGroup(chi.modulus() * p, GF(p))(chi)
        DG = DirichletGroup(chi.modulus(), GF(p))
        if r == 0:
            from sage.modular.arithgroup.congroup_gamma0 import Gamma0_constructor as Gamma0
            verbose("in dim: %s, %s, %s" % (self.sign(), chi, p))
            M = ModularSymbols(DG(chi), 2, self.sign(), GF(p))
        else:
            psi = [GF(p)(u)**r for u in DG.unit_gens()]  #mod p Teichmuller^r
            psi = DG(psi)
            M = ModularSymbols(DG(chi) * psi, 2, self.sign(), GF(p))
        if cusp:
            M = M.cuspidal_subspace()
        hecke_poly = M.hecke_polynomial(p)
        verbose("in dim: %s" % (hecke_poly))
        x = hecke_poly.parent().gen()
        d = hecke_poly.degree() - hecke_poly.ord(x)
        self._ord_dim_dict[(p, cusp)] = d
        return d
Esempio n. 24
0
    def dimension_eis(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of Eisenstein series forms for self,
        or the dimension of the subspace corresponding to the given character
        if one is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          Eisenstein series of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Moebius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        AUTHORS:

        - William Stein - Cohen--Oesterle algorithm

        - Jordi Quer - algorithm based on GammaH subgroups

        - David Loeffler (2009) - code refactoring

        EXAMPLES:

        The following two computations use different algorithms: ::

            sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
            sage: [Gamma1(36).dimension_eis(1,eps,algorithm="Quer") for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]

        So do these: ::

            sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
            sage: [Gamma1(48).dimension_eis(3,eps,algorithm="Quer") for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
        """
        from all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_eis(self, k)

        N = self.level()
        eps = DirichletGroup(N)(eps)

        if eps.is_trivial():
            return Gamma0(N).dimension_eis(k)

        # Note case of k = 0 and trivial character already dealt with separately, so k <= 0 here is valid:
        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()):
            return ZZ(0)

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N,(eps**d).kernel())
                dim = dim + moebius(d)*G.dimension_eis(k)
            return dim//phi(n)

        elif algorithm == "CohenOesterle":
            from sage.modular.dims import CohenOesterle
            K = eps.base_ring()
            j = 2-k
            # We use the Cohen-Oesterle formula in a subtle way to
            # compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on
            # computing with modular forms).
            alpha = -ZZ( K(Gamma0(N).index()*(j-1)/ZZ(12)) + CohenOesterle(eps,j) )
            if k == 1:
                return alpha
            else:
                return alpha - self.dimension_cusp_forms(k, eps)

        else: #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError, "Unrecognised algorithm in dimension_eis"
Esempio n. 25
0
def half_integral_weight_modform_basis(chi, k, prec):
    r"""
    A basis for the space of weight `k/2` forms with character
    `\chi`. The modulus of `\chi` must be divisible by
    `16` and `k` must be odd and `>1`.
    
    INPUT:
    
    
    -  ``chi`` - a Dirichlet character with modulus
       divisible by 16
    
    -  ``k`` - an odd integer = 1
    
    -  ``prec`` - a positive integer
    
    
    OUTPUT: a list of power series
    
    .. warning::

       1. This code is very slow because it requests computation of a
          basis of modular forms for integral weight spaces, and that
          computation is still very slow.
    
       2. If you give an input prec that is too small, then the output
          list of power series may be larger than the dimension of the
          space of half-integral forms.
    
    EXAMPLES:
    
    We compute some half-integral weight forms of level 16\*7
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16*7).0^2,3,30)
        [q - 2*q^2 - q^9 + 2*q^14 + 6*q^18 - 2*q^21 - 4*q^22 - q^25 + O(q^30),
         q^2 - q^14 - 3*q^18 + 2*q^22 + O(q^30),
         q^4 - q^8 - q^16 + q^28 + O(q^30),
         q^7 - 2*q^15 + O(q^30)]
    
    The following illustrates that choosing too low of a precision can
    give an incorrect answer.
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16*7).0^2,3,20)
        [q - 2*q^2 - q^9 + 2*q^14 + 6*q^18 + O(q^20),
         q^2 - q^14 - 3*q^18 + O(q^20),
         q^4 - 2*q^8 + 2*q^12 - 4*q^16 + O(q^20),
         q^7 - 2*q^8 + 4*q^12 - 2*q^15 - 6*q^16 + O(q^20),
         q^8 - 2*q^12 + 3*q^16 + O(q^20)]
    
    We compute some spaces of low level and the first few possible
    weights.
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 3, 10)
        []
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 5, 10)
        [q - 2*q^3 - 2*q^5 + 4*q^7 - q^9 + O(q^10)]
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 7, 10)
        [q - 2*q^2 + 4*q^3 + 4*q^4 - 10*q^5 - 16*q^7 + 19*q^9 + O(q^10),
         q^2 - 2*q^3 - 2*q^4 + 4*q^5 + 4*q^7 - 8*q^9 + O(q^10),
         q^3 - 2*q^5 - 2*q^7 + 4*q^9 + O(q^10)]
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 9, 10)
        [q - 2*q^2 + 4*q^3 - 8*q^4 + 14*q^5 + 16*q^6 - 40*q^7 + 16*q^8 - 57*q^9 + O(q^10),
         q^2 - 2*q^3 + 4*q^4 - 8*q^5 - 8*q^6 + 20*q^7 - 8*q^8 + 32*q^9 + O(q^10),
         q^3 - 2*q^4 + 4*q^5 + 4*q^6 - 10*q^7 - 16*q^9 + O(q^10),
         q^4 - 2*q^5 - 2*q^6 + 4*q^7 + 4*q^9 + O(q^10),
         q^5 - 2*q^7 - 2*q^9 + O(q^10)]

    This example once raised an error (see trac #5792).

    ::

        sage: half_integral_weight_modform_basis(trivial_character(16),9,10)
        [q - 2*q^2 + 4*q^3 - 8*q^4 + 4*q^6 - 16*q^7 + 48*q^8 - 15*q^9 + O(q^10),
         q^2 - 2*q^3 + 4*q^4 - 2*q^6 + 8*q^7 - 24*q^8 + O(q^10),
         q^3 - 2*q^4 - 4*q^7 + 12*q^8 + O(q^10),
         q^4 - 6*q^8 + O(q^10)]

    
    ALGORITHM: Basmaji (page 55 of his Essen thesis, "Ein Algorithmus
    zur Berechnung von Hecke-Operatoren und Anwendungen auf modulare
    Kurven", http://wstein.org/scans/papers/basmaji/).
    
    Let `S = S_{k+1}(\epsilon)` be the space of cusp forms of
    even integer weight `k+1` and character
    `\varepsilon = \chi \psi^{(k+1)/2}`, where `\psi`
    is the nontrivial mod-4 Dirichlet character. Let `U` be the
    subspace of `S \times S` of elements `(a,b)` such
    that `\Theta_2 a = \Theta_3 b`. Then `U` is
    isomorphic to `S_{k/2}(\chi)` via the map
    `(a,b) \mapsto a/\Theta_3`.
    """

    if chi.modulus() % 16:
        raise ValueError, "the character must have modulus divisible by 16"

    if not k % 2:
        raise ValueError, "k (=%s) must be odd" % k

    if k < 3:
        raise ValueError, "k (=%s) must be at least 3" % k

    chi = chi.minimize_base_ring()
    psi = chi.parent()(DirichletGroup(4, chi.base_ring()).gen())
    eps = chi * psi**((k + 1) // 2)
    eps = eps.minimize_base_ring()
    M = constructor.ModularForms(eps, (k + 1) // 2)
    C = M.cuspidal_subspace()
    B = C.basis()

    # This computation of S below -- of course --dominates the whole function.
    #from sage.misc.all import cputime
    #tm  = cputime()
    #print "Computing basis..."
    S = [f.q_expansion(prec) for f in B]
    #print "Time to compute basis", cputime(tm)

    T2 = theta2_qexp(prec)
    T3 = theta_qexp(prec)
    n = len(S)
    MS = MatrixSpace(M.base_ring(), 2 * n, prec)
    A = copy(MS.zero_matrix())

    for i in range(n):
        T2f = T2 * S[i]
        T3f = T3 * S[i]
        for j in range(prec):
            A[i, j] = T2f[j]
            A[n + i, j] = -T3f[j]

    B = A.kernel().basis()
    a_vec = [sum([b[i] * S[i] for i in range(n)]) for b in B]
    if len(a_vec) == 0:
        return []
    R = a_vec[0].parent()
    t3 = R(T3)
    return [R(a) / t3 for a in a_vec]
Esempio n. 26
0
    def dimension_new_cusp_forms(self, k=2, eps=None, p=0, algorithm="CohenOesterle"):
        r"""
        Dimension of the new subspace (or `p`-new subspace) of cusp forms of
        weight `k` and character `\varepsilon`.

        INPUT:

        - ``k`` - an integer (default: 2)

        - ``eps`` - a Dirichlet character

        -  ``p`` - a prime (default: 0); just the `p`-new subspace if given

        - ``algorithm`` - either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Moebius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        EXAMPLES::

            sage: G = DirichletGroup(9)
            sage: eps = G.0^3
            sage: eps.conductor()
            3
            sage: [Gamma1(9).dimension_new_cusp_forms(k, eps) for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]
            sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [2..10]]
            [0, 0, 0, 2, 0, 4, 0, 6, 0]
            sage: [Gamma1(9).dimension_new_cusp_forms(k, eps, 3) for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]

        Double check using modular symbols (independent calculation)::

            sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace().dimension()  for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]
            sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace(3).dimension()  for k in [2..10]]
            [0, 0, 0, 2, 0, 2, 0, 2, 0]

        Another example at level 33::

            sage: G = DirichletGroup(33)
            sage: eps = G.1
            sage: eps.conductor()
            11
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1) for k in [2..4]]
            [0, 4, 0]
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1, algorithm="Quer") for k in [2..4]]
            [0, 4, 0]
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2) for k in [2..4]]
            [2, 0, 6]
            sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2, p=3) for k in [2..4]]
            [2, 0, 6]

        """

        if eps == None:
            return GammaH_class.dimension_new_cusp_forms(self, k, p)

        N = self.level()
        eps = DirichletGroup(N)(eps)

        from all import Gamma0

        if eps.is_trivial():
            return Gamma0(N).dimension_new_cusp_forms(k, p)

        from congroup_gammaH import mumu

        if p == 0 or N%p != 0 or eps.conductor().valuation(p) == N.valuation(p):
            D = [eps.conductor()*d for d in divisors(N//eps.conductor())]
            return sum([Gamma1_constructor(M).dimension_cusp_forms(k, eps.restrict(M), algorithm)*mumu(N//M) for M in D])
        eps_p = eps.restrict(N//p)
        old = Gamma1_constructor(N//p).dimension_cusp_forms(k, eps_p, algorithm)
        return self.dimension_cusp_forms(k, eps, algorithm) - 2*old
Esempio n. 27
0
    def divisor_of_order(self):
        """
        Return a divisor of the order of this torsion subgroup of a modular
        abelian variety.

        OUTPUT:

        A divisor of this torsion subgroup.

        EXAMPLES::

            sage: t = J0(37)[1].rational_torsion_subgroup()
            sage: t.divisor_of_order()
            3

            sage: J = J1(19)
            sage: J.rational_torsion_subgroup().divisor_of_order()
            4383

            sage: J = J0(45)
            sage: J.rational_cusp_subgroup().order()
            32
            sage: J.rational_cuspidal_subgroup().order()
            64
            sage: J.rational_torsion_subgroup().divisor_of_order()
            64
        """
        try:
            return self._divisor_of_order
        except AttributeError:
            pass

        A = self.abelian_variety()
        N = A.level()

        if A.dimension() == 0:
            self._divisor_of_order = ZZ(1)
            return self._divisor_of_order

        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._divisor_of_order = QQ((A.level()-1)/12).numerator()
            return self._divisor_of_order

        # The elliptic curve case
        if A.dimension() == 1:
            self._divisor_of_order = A.elliptic_curve().torsion_order()
            return self._divisor_of_order

        # The J1(p) case
        if A.is_J1() and N.is_prime():
            epsilons = [epsilon for epsilon in DirichletGroup(N)
                        if not epsilon.is_trivial() and epsilon.is_even()]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._divisor_of_order = ZZ(N/(2**(N-3))*prod(bernoullis))
            return self._divisor_of_order

        # The Gamma0 case
        if all(is_Gamma0(G) for G in A.groups()):
            self._divisor_of_order = A.rational_cuspidal_subgroup().order()
            return self._divisor_of_order

        # Unhandled case
        self._divisor_of_order = ZZ(1)
        return self._divisor_of_order
Esempio n. 28
0
    def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of cusp forms for self, or the
        dimension of the subspace corresponding to the given character if one
        is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          forms of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Möbius inversion using the subgroups GammaH (a method due to Jordi
          Quer). Ignored for weight 1.

        EXAMPLES:

        We compute the same dimension in two different ways ::

            sage: K = CyclotomicField(3)
            sage: eps = DirichletGroup(7*43,K).0^2
            sage: G = Gamma1(7*43)

        Via Cohen--Oesterle::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps)
            28

        Via Quer's method::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer")
            28

        Some more examples::

            sage: G.<eps> = DirichletGroup(9)
            sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]]
            [0, 0, 1, 0, 3, 0, 5, 0, 7, 0]
            sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]]
            [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]

        In weight 1, we can sometimes rule out cusp forms existing via
        Riemann-Roch, but if this does not work, we trigger computation of the
        cusp forms space via Schaeffer's algorithm::

            sage: chi = [u for u in DirichletGroup(40) if u(-1) == -1 and u(21) == 1][0]
            sage: Gamma1(40).dimension_cusp_forms(1, chi)
            0
            sage: G = DirichletGroup(57); chi = (G.0) * (G.1)^6
            sage: Gamma1(57).dimension_cusp_forms(1, chi)
            1
        """
        from .all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_cusp_forms(self, k)

        N = self.level()
        K = eps.base_ring()
        eps = DirichletGroup(N, K)(eps)

        if K.characteristic() != 0:
            raise NotImplementedError(
                'dimension_cusp_forms() is only implemented for rings of characteristic 0'
            )

        if eps.is_trivial():
            return Gamma0(N).dimension_cusp_forms(k)

        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k % 2) == 0
                                                            and eps.is_odd()):
            return ZZ(0)

        if k == 1:
            from sage.modular.modform.weight1 import dimension_wt1_cusp_forms
            return dimension_wt1_cusp_forms(eps)

        # now the main part

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N, (eps**d).kernel())
                dim = dim + moebius(d) * G.dimension_cusp_forms(k)
            return dim // phi(n)

        elif algorithm == "CohenOesterle":
            from sage.modular.dims import CohenOesterle
            return ZZ(
                K(Gamma0(N).index() * (k - 1) / ZZ(12)) +
                CohenOesterle(eps, k))

        else:  #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError("Unrecognised algorithm in dimension_cusp_forms")
Esempio n. 29
0
def hecke_operator_on_qexp(f,
                           n,
                           k,
                           eps=None,
                           prec=None,
                           check=True,
                           _return_list=False):
    r"""
    Given the `q`-expansion `f` of a modular form with character
    `\varepsilon`, this function computes the image of `f` under the
    Hecke operator `T_{n,k}` of weight `k`.

    EXAMPLES::

        sage: M = ModularForms(1,12)
        sage: hecke_operator_on_qexp(M.basis()[0], 3, 12)
        252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + O(q^5)
        sage: hecke_operator_on_qexp(M.basis()[0], 1, 12, prec=7)
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 + O(q^7)
        sage: hecke_operator_on_qexp(M.basis()[0], 1, 12)
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + O(q^14)

        sage: M.prec(20)
        20
        sage: hecke_operator_on_qexp(M.basis()[0], 3, 12)
        252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + 1217160*q^5 - 1524096*q^6 + O(q^7)
        sage: hecke_operator_on_qexp(M.basis()[0], 1, 12)
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + 401856*q^14 + 1217160*q^15 + 987136*q^16 - 6905934*q^17 + 2727432*q^18 + 10661420*q^19 - 7109760*q^20 + O(q^21)

        sage: (hecke_operator_on_qexp(M.basis()[0], 1, 12)*252).add_bigoh(7)
        252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + 1217160*q^5 - 1524096*q^6 + O(q^7)

        sage: hecke_operator_on_qexp(M.basis()[0], 6, 12)
        -6048*q + 145152*q^2 - 1524096*q^3 + O(q^4)

    An example on a formal power series::

        sage: R.<q> = QQ[[]]
        sage: f = q + q^2 + q^3 + q^7 + O(q^8)
        sage: hecke_operator_on_qexp(f, 3, 12)
        q + O(q^3)
        sage: hecke_operator_on_qexp(delta_qexp(24), 3, 12).prec()
        8
        sage: hecke_operator_on_qexp(delta_qexp(25), 3, 12).prec()
        9

    An example of computing `T_{p,k}` in characteristic `p`::

        sage: p = 199
        sage: fp = delta_qexp(prec=p^2+1, K=GF(p))
        sage: tfp = hecke_operator_on_qexp(fp, p, 12)
        sage: tfp == fp[p] * fp
        True
        sage: tf = hecke_operator_on_qexp(delta_qexp(prec=p^2+1), p, 12).change_ring(GF(p))
        sage: tfp == tf
        True
    """
    if eps is None:
        # Need to have base_ring=ZZ to work over finite fields, since
        # ZZ can coerce to GF(p), but QQ can't.
        eps = DirichletGroup(1, base_ring=ZZ).gen(0)
    if check:
        if not (is_PowerSeries(f) or is_ModularFormElement(f)):
            raise TypeError, "f (=%s) must be a power series or modular form" % f
        if not is_DirichletCharacter(eps):
            raise TypeError, "eps (=%s) must be a Dirichlet character" % eps
        k = Integer(k)
        n = Integer(n)
    v = []

    if prec is None:
        if is_ModularFormElement(f):
            # always want at least three coefficients, but not too many, unless
            # requested
            pr = max(f.prec(), f.parent().prec(), (n + 1) * 3)
            pr = min(pr, 100 * (n + 1))
            prec = pr // n + 1
        else:
            prec = (f.prec() / ZZ(n)).ceil()
            if prec == Infinity: prec = f.parent().default_prec() // n + 1

    if f.prec() < prec:
        f._compute_q_expansion(prec)

    p = Integer(f.base_ring().characteristic())
    if k != 1 and p.is_prime() and n.is_power_of(p):
        # if computing T_{p^a} in characteristic p, use the simpler (and faster)
        # formula
        v = [f[m * n] for m in range(prec)]
    else:
        l = k - 1
        for m in range(prec):
            am = sum([eps(d) * d**l * f[m*n//(d*d)] for \
                      d in divisors(gcd(n, m)) if (m*n) % (d*d) == 0])
            v.append(am)
    if _return_list:
        return v
    if is_ModularFormElement(f):
        R = f.parent()._q_expansion_ring()
    else:
        R = f.parent()
    return R(v, prec)
Esempio n. 30
0
def set_table(
        info,
        is_set,
        make_link=True):  # level_min,level_max,weight=2,chi=0,make_link=True):
    r"""
    make a bunch of html tables with information about spaces of modular forms
    with parameters in the given ranges.
    Should use database in the future...
    """
    D = 0
    rowlen = 10  # split into rows of this length...
    rowlen0 = rowlen
    rowlen1 = rowlen
    characters = dict()
    if ('level_min' in info):
        level_min = int(info['level_min'])
    else:
        level_min = 1
    if ('level_max' in info):
        level_max = int(info['level_max'])
    else:
        level_max = 50
    if (level_max - level_min + 1) < rowlen:
        rowlen0 = level_max - level_min + 1
    if (info['list_chars'] != '0'):
        char1 = 1
    else:
        char1 = 0
    if (is_set['weight']):
        weight = int(info['weight'])
    else:
        weight = 2
    ## setup the table
    # print "char11=",char1
    tbl = dict()
    if (char1 == 1):
        tbl['header'] = 'Dimension of \( S_{' + str(weight) + '}(N,\chi_{n})\)'
    else:
        tbl['header'] = 'Dimension of \( S_{' + str(weight) + '}(N)\)'
    tbl['headersv'] = list()
    tbl['headersh'] = list()
    tbl['corner_label'] = ""
    tbl['data'] = list()
    tbl['data_format'] = 'html'
    tbl['class'] = "dimension_table"
    tbl['atts'] = "border=\"0\" class=\"data_table\""
    num_rows = ceil(QQ(level_max - level_min + 1) / QQ(rowlen0))
    print "num_rows=", num_rows
    for i in range(1, rowlen0 + 1):
        tbl['headersh'].append(i + level_min - 1)

    for r in range(num_rows):
        tbl['headersv'].append(r * rowlen0)
    print "level_min=", level_min
    print "level_max=", level_max
    print "char=", char1
    for r in range(num_rows):
        row = list()
        for k in range(1, rowlen0 + 1):
            row.append("")
        # print "row nr. ",r
        for k in range(1, rowlen0 + 1):
            N = level_min - 1 + r * rowlen0 + k
            s = "<a name=\"#" + str(N) + "\"></a>"
            # print "col ",k,"=",N
            if (N > level_max or N < 1):
                continue
            if (char1 == 0):
                d = dimension_cusp_forms(N, weight)
                print "d=", d
                if (make_link):
                    url = "?weight=" + str(weight) + "&level=" + str(
                        N) + "&character=0"
                    row.append(s + "<a target=\"mainWindow\" href=\"" + url +
                               "\">" + str(d) + "</a>")
                else:
                    row.append(s + str(d))

                # print "dim(",N,weight,")=",d
            else:

                D = DirichletGroup(N)
                print "D=", D
                s = "<a name=\"#" + str(N) + "\"></a>"
                small_tbl = dict()
                # small_tbl['header']='Dimension of \( S_{'+str(weight)+'}(N)\)'
                small_tbl['headersv'] = ['\( d \)']
                small_tbl['headersh'] = list()
                small_tbl['corner_label'] = "\( n \)"
                small_tbl['data'] = list()
                small_tbl['atts'] = "border=\"1\" padding=\"1\""
                small_tbl['data_format'] = 'html'
                row1 = list()
                # num_small_rows = ceil(QQ(level_max) / QQ(rowlen))
                ii = 0
                for chi in range(0, len(D.list())):
                    x = D[chi]
                    S = CuspForms(x, weight)
                    d = S.dimension()
                    if (d == 0):
                        continue
                    small_tbl['headersh'].append(chi)
                    if (make_link):
                        url = "?weight=" + str(weight) + "&level=" + str(
                            N) + "&character=" + str(chi)
                        row1.append("<a target=\"mainWindow\" href=\"" + url +
                                    "\">" + str(d) + "</a>")
                    else:
                        row1.append(d)
                    ii = ii + 1
                    print "d=", d
                    if (ii > rowlen1 and len(row1) > 0):
                        ## we make a new table since we may not have regularly dstributed labels
                        # print "Break line! Make new table!"
                        small_tbl['data'].append(row1)
                        s = s + html_table(small_tbl)
                        small_tbl['headersh'] = list()
                        small_tbl['data'] = list()
                        row1 = list()
                        ii = 0

                if (len(row1) > 0):
                    small_tbl['data'].append(row1)
                if (len(row1) > 0 or len(small_tbl['data']) > 0):
                    # print "small_tbl=",small_tbl
                    ss = html_table(small_tbl)
                    # print "ss=",ss
                    s = s + ss
                    # s=s+"\( \chi_{"+str(chi)+"}\) :"+str(d)

                    # print N,k,chi,d
                # print s
                else:
                    s = "All spaces are zero-dimensional!"
                row.append(s)
        print "row=", row
        tbl['data'].append(row)
    s = html_table(tbl)
    s = s + "\n <br> \(N=" + str(rowlen0) + "\cdot row+col\)"
    print "Whole table=", s
    ## ugly solution. but we have latex in the data fields...
    ss = re.sub('texttt', '', s)
    info['popup_table'] = ss
    # info['sidebar']=set_sidebar([navigation,parents,siblings,friends,lifts])
    return info
Esempio n. 31
0
    def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of cusp forms for self, or the
        dimension of the subspace corresponding to the given character if one
        is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          forms of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Moebius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        EXAMPLES:

        We compute the same dimension in two different ways ::

            sage: K = CyclotomicField(3)
            sage: eps = DirichletGroup(7*43,K).0^2
            sage: G = Gamma1(7*43)

        Via Cohen--Oesterle: ::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps)
            28

        Via Quer's method: ::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer")
            28

        Some more examples: ::

            sage: G.<eps> = DirichletGroup(9)
            sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]]
            [0, 0, 1, 0, 3, 0, 5, 0, 7, 0]
            sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]]
            [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]
        """

        from all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_cusp_forms(self, k)

        N = self.level()
        if eps.base_ring().characteristic() != 0:
            raise ValueError

        eps = DirichletGroup(N, eps.base_ring())(eps)

        if eps.is_trivial():
            return Gamma0(N).dimension_cusp_forms(k)

        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()):
            return ZZ(0)

        if k == 1:
            try:
                n = self.dimension_cusp_forms(1)
                if n == 0:
                    return ZZ(0)
                else: # never happens at present
                    raise NotImplementedError, "Computations of dimensions of spaces of weight 1 cusp forms not implemented at present"
            except NotImplementedError:
                raise

        # now the main part

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N,(eps**d).kernel())
                dim = dim + moebius(d)*G.dimension_cusp_forms(k)
            return dim//phi(n)

        elif algorithm == "CohenOesterle":
            K = eps.base_ring()
            from sage.modular.dims import CohenOesterle
            from all import Gamma0
            return ZZ( K(Gamma0(N).index() * (k-1)/ZZ(12)) + CohenOesterle(eps,k) )

        else: #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError, "Unrecognised algorithm in dimension_cusp_forms"
def product_space(chi, k, weights=False, base_ring=None, verbose=False):
    r"""
    Computes all eisenstein series, and products of pairs of eisenstein series
    of lower weight, lying in the space of modular forms of weight $k$ and
    nebentypus $\chi$.
    INPUT:
     - chi - Dirichlet character, the nebentypus of the target space
     - k - an integer, the weight of the target space
    OUTPUT:
     - a matrix of coefficients of q-expansions, which are the products of
     Eisenstein series in M_k(chi).

    WARNING: It is only for principal chi that we know that the resulting
    space is the whole space of modular forms.
    """

    if weights == False:
        weights = srange(1, k / 2 + 1)
    weight_dict = {}
    weight_dict[-1] = [w for w in weights if w % 2]  # Odd weights
    weight_dict[1] = [w for w in weights if not w % 2]  # Even weights

    try:
        N = chi.modulus()
    except AttributeError:
        if chi.parent() == ZZ:
            N = chi
            chi = DirichletGroup(N)[0]

    Id = DirichletGroup(1)[0]
    if chi(-1) != (-1)**k:
        raise ValueError('chi(-1)!=(-1)^k')
    sturm = ModularForms(N, k).sturm_bound() + 1
    if N > 1:
        target_dim = dimension_modular_forms(chi, k)
    else:
        target_dim = dimension_modular_forms(1, k)
    D = DirichletGroup(N)
    # product_space should ideally be called over number fields. Over complex
    # numbers the exact linear algebra solutions might not exist.
    if base_ring == None:
        base_ring = CyclotomicField(euler_phi(N))

    Q = PowerSeriesRing(base_ring, 'q')
    q = Q.gen()

    d = len(D)
    prim_chars = [phi.primitive_character() for phi in D]
    divs = divisors(N)

    products = Matrix(base_ring, [])
    indexlist = []
    rank = 0
    if verbose:
        print(D)
        print('Sturm bound', sturm)
        #TODO: target_dim needs refinment in the case of weight 2.
        print('Target dimension', target_dim)
    for i in srange(0, d):  # First character
        phi = prim_chars[i]
        M1 = phi.conductor()
        for j in srange(0, d):  # Second character
            psi = prim_chars[j]
            M2 = psi.conductor()
            if not M1 * M2 in divs:
                continue
            parity = psi(-1) * phi(-1)
            for t1 in divs:
                if not M1 * M2 * t1 in divs:
                    continue
                #TODO: THE NEXT CONDITION NEEDS TO BE CORRECTED. THIS IS JUST A TEST
                if phi.bar() == psi and not (
                        k == 2):  #and i==0 and j==0 and t1==1):
                    E = eisenstein_series_at_inf(phi, psi, k, sturm, t1,
                                                 base_ring).padded_list()
                    try:
                        products.T.solve_right(vector(base_ring, E))
                    except ValueError:
                        products = Matrix(products.rows() + [E])
                        indexlist.append([k, i, j, t1])
                        rank += 1
                        if verbose:
                            print('Added ', [k, i, j, t1])
                            print('Rank is now', rank)
                        if rank == target_dim:
                            return products, indexlist
                for t in divs:
                    if not M1 * M2 * t1 * t in divs:
                        continue
                    for t2 in divs:
                        if not M1 * M2 * t1 * t2 * t in divs:
                            continue
                        for l in weight_dict[parity]:
                            if l == 1 and phi.is_odd():
                                continue
                            if i == 0 and j == 0 and (l == 2 or l == k - 2):
                                continue
                            #TODO: THE NEXT CONDITION NEEDS TO BE REMOVED. THIS IS JUST A TEST
                            if l == 2 or l == k - 2:
                                continue
                            E1 = eisenstein_series_at_inf(
                                phi, psi, l, sturm, t1 * t, base_ring)
                            E2 = eisenstein_series_at_inf(
                                phi**(-1), psi**(-1), k - l, sturm, t2 * t,
                                base_ring)
                            #If chi is non-principal this needs to be changed to be something like chi*phi^(-1) instead of phi^(-1)
                            E = (E1 * E2 + O(q**sturm)).padded_list()
                            try:
                                products.T.solve_right(vector(base_ring, E))
                            except ValueError:
                                products = Matrix(products.rows() + [E])
                                indexlist.append([l, k - l, i, j, t1, t2, t])
                                rank += 1
                                if verbose:
                                    print('Added ',
                                          [l, k - l, i, j, t1, t2, t])
                                    print('Rank', rank)
                                if rank == target_dim:
                                    return products, indexlist
    return products, indexlist