示例#1
0
def hecke_series_degree_bound(p,N,k,m):
    r"""
    Returns the ``Wan bound`` on the degree of the characteristic series of the
    Atkin operator on p-adic overconvergent modular forms of level
    `\Gamma_0(N)` and weight k when reduced modulo `p^m`. This bound depends
    only upon p, `k \pmod{p-1}`, and N. It uses Lemma 3.1 in [DW]_.

    INPUT:

    - ``p`` -- prime at least 5.
    - ``N`` -- positive integer not divisible by p.
    - ``k`` -- even integer.
    - ``m`` -- positive integer.

    OUTPUT:

    A non-negative integer.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import hecke_series_degree_bound
        sage: hecke_series_degree_bound(13,11,100,5)
        39

    REFERENCES:

    .. [DW] Daqing Wan, "Dimension variation of classical and p-adic modular
       forms", Invent. Math. 133, (1998) 449-463.
    """
    k0 = k % (p-1)
    ds = [dimension_modular_forms(N, k0)]
    ms = [ds[0]]
    sum = 0
    u = 1

    ord = 0
    while ord < m:
        ds.append(dimension_modular_forms(N,k0 + u*(p-1)))
        ms.append(ds[u] - ds[u-1])
        sum = sum + u*ms[u]
        ord = floor(((p-1)/(p+1))*sum - ds[u])
        u = u + 1

    return (ds[u-1] - 1)
示例#2
0
def hecke_series_degree_bound(p, N, k, m):
    r"""
    Returns the ``Wan bound`` on the degree of the characteristic series of the
    Atkin operator on p-adic overconvergent modular forms of level
    `\Gamma_0(N)` and weight k when reduced modulo `p^m`. This bound depends
    only upon p, `k \pmod{p-1}`, and N. It uses Lemma 3.1 in [DW]_.

    INPUT:

    - ``p`` -- prime at least 5.
    - ``N`` -- positive integer not divisible by p.
    - ``k`` -- even integer.
    - ``m`` -- positive integer.

    OUTPUT:

    A non-negative integer.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import hecke_series_degree_bound
        sage: hecke_series_degree_bound(13,11,100,5)
        39

    REFERENCES:

    .. [DW] Daqing Wan, "Dimension variation of classical and p-adic modular
       forms", Invent. Math. 133, (1998) 449-463.
    """
    k0 = k % (p - 1)
    ds = [dimension_modular_forms(N, k0)]
    ms = [ds[0]]
    sum = 0
    u = 1

    ord = 0
    while ord < m:
        ds.append(dimension_modular_forms(N, k0 + u * (p - 1)))
        ms.append(ds[u] - ds[u - 1])
        sum = sum + u * ms[u]
        ord = floor(((p - 1) / (p + 1)) * sum - ds[u])
        u = u + 1

    return (ds[u - 1] - 1)
示例#3
0
def complementary_spaces_modp(N, p, k0, n, elldash, LWBModp, bound):
    r"""
    Returns a list of lists of lists of lists ``[j,a]``. The pairs ``[j,a]``
    encode the choice of the `a`-th element in the `j`-th list of the input
    ``LWBModp``, i.e., the `a`-th element in a particular basis modulo
    `(p,q^\text{elldash})` for the space of modular forms of level
    `\Gamma_0(N)` and weight `2(j+1)`. The list ``[[j_1,a_1],...,[j_r,a_r]]``
    then encodes the product of the r modular forms associated to each
    ``[j_i,a_i]``; this has weight `k + (p-1)i` for some `0 \le i \le n`; here
    the i is such that this *list of lists* occurs in the ith list of the
    output. The ith list of the output thus encodes a choice of basis for the
    complementary space `W_i` which occurs in Step 2 of Algorithm 2 in [AGBL]_.
    The idea is that one searches for this space `W_i` first modulo
    `(p,q^\text{elldash})` and then, having found the correct products of
    generating forms, one can reconstruct these spaces modulo
    `(p^\text{mdash},q^\text{elldashp})` using the output of this function.
    (This idea is based upon a suggestion of John Voight.)

    INPUT:

    - ``N`` -- positive integer at least 2 and not divisible by p (level).
    - ``p`` -- prime at least 5.
    - ``k0`` -- integer in range 0 to `p-1`.
    - ``n,elldash`` -- positive integers.
    - ``LWBModp`` -- list of lists of `q`-expansions over `GF(p)`.
    - ``bound`` -- positive even integer (twice the length of the list ``LWBModp``).

    OUTPUT:

    - list of list of list of lists.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import random_low_weight_bases, complementary_spaces_modp
        sage: LWB = random_low_weight_bases(2,5,2,4,6)
        sage: LWBModp = [[f.change_ring(Zmod(5)) for f in x] for x in LWB]
        sage: complementary_spaces_modp(2,5,0,3,4,LWBModp,6) # random, indirect doctest
        [[[]], [[[0, 0], [0, 0]]], [[[0, 0], [2, 1]]], [[[0, 0], [0, 0], [0, 0], [2, 1]]]]
    """
    CompSpacesCode = []
    ell = dimension_modular_forms(N, k0 + n * (p - 1))
    TotalBasisModp = matrix(GF(p), ell, elldash)
    # zero matrix

    for i in xrange(n + 1):
        NewBasisCodemi = random_new_basis_modp(N, p, k0 + i * (p - 1), LWBModp,
                                               TotalBasisModp, elldash, bound)
        # TotalBasisModp is passed by reference and updated in function
        CompSpacesCode.append(NewBasisCodemi)

    return CompSpacesCode
示例#4
0
def complementary_spaces_modp(N,p,k0,n,elldash,LWBModp,bound):
    r"""
    Returns a list of lists of lists of lists ``[j,a]``. The pairs ``[j,a]``
    encode the choice of the `a`-th element in the `j`-th list of the input
    ``LWBModp``, i.e., the `a`-th element in a particular basis modulo
    `(p,q^\text{elldash})` for the space of modular forms of level
    `\Gamma_0(N)` and weight `2(j+1)`. The list ``[[j_1,a_1],...,[j_r,a_r]]``
    then encodes the product of the r modular forms associated to each
    ``[j_i,a_i]``; this has weight `k + (p-1)i` for some `0 \le i \le n`; here
    the i is such that this *list of lists* occurs in the ith list of the
    output. The ith list of the output thus encodes a choice of basis for the
    complementary space `W_i` which occurs in Step 2 of Algorithm 2 in [AGBL]_.
    The idea is that one searches for this space `W_i` first modulo
    `(p,q^\text{elldash})` and then, having found the correct products of
    generating forms, one can reconstruct these spaces modulo
    `(p^\text{mdash},q^\text{elldashp})` using the output of this function.
    (This idea is based upon a suggestion of John Voight.)

    INPUT:

    - ``N`` -- positive integer at least 2 and not divisible by p (level).
    - ``p`` -- prime at least 5.
    - ``k0`` -- integer in range 0 to `p-1`.
    - ``n,elldash`` -- positive integers.
    - ``LWBModp`` -- list of lists of `q`-expansions over `GF(p)`.
    - ``bound`` -- positive even integer (twice the length of the list ``LWBModp``).

    OUTPUT:

    - list of list of list of lists.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import random_low_weight_bases, complementary_spaces_modp
        sage: LWB = random_low_weight_bases(2,5,2,4,6)
        sage: LWBModp = [[f.change_ring(Zmod(5)) for f in x] for x in LWB]
        sage: complementary_spaces_modp(2,5,0,3,4,LWBModp,6) # random, indirect doctest
        [[[]], [[[0, 0], [0, 0]]], [[[0, 0], [2, 1]]], [[[0, 0], [0, 0], [0, 0], [2, 1]]]]
    """
    CompSpacesCode = []
    ell = dimension_modular_forms(N,k0 + n*(p-1))
    TotalBasisModp = matrix(GF(p),ell,elldash); # zero matrix

    for i in xrange(n+1):
        NewBasisCodemi = random_new_basis_modp(N,p,k0 + i*(p-1),LWBModp,TotalBasisModp,elldash,bound)
        # TotalBasisModp is passed by reference and updated in function
        CompSpacesCode.append(NewBasisCodemi)

    return CompSpacesCode
示例#5
0
def level1_UpGj(p, klist, m):
    r"""
    Returns a list `[A_k]` of square matrices over ``IntegerRing(p^m)``
    parameterised by the weights k in ``klist``. The matrix `A_k` is the finite
    square matrix which occurs on input p,k and m in Step 6 of Algorithm 1 in
    [AGBL]_. Notational change from paper: In Step 1 following Wan we defined
    j by `k = k_0 + j(p-1)` with `0 \le k_0 < p-1`. Here we replace j by
    ``kdiv`` so that we may use j as a column index for matrices.

    INPUT:

    - ``p`` -- prime at least 5.
    - ``klist`` -- list of integers congruent modulo `(p-1)` (the weights).
    - ``m`` -- positive integer.

    OUTPUT:

    - list of square matrices.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import level1_UpGj
        sage: level1_UpGj(7,[100],5)
        [
        [    1   980  4802     0     0]
        [    0 13727 14406     0     0]
        [    0 13440  7203     0     0]
        [    0  1995  4802     0     0]
        [    0  9212 14406     0     0]
        ]
    """
    # Step 1
    t = cputime()

    k0 = klist[0] % (p - 1)
    n = floor(((p + 1) / (p - 1)) * (m + 1))
    ell = dimension_modular_forms(1, k0 + n * (p - 1))
    ellp = ell * p
    mdash = m + ceil(n / (p + 1))

    verbose("done step 1", t)
    t = cputime()
    # Steps 2 and 3

    e, Ep1 = katz_expansions(k0, p, ellp, mdash, n)

    verbose("done steps 2+3", t)
    t = cputime()
    # Step 4

    G = compute_G(p, Ep1)
    Alist = []

    verbose("done step 4a", t)
    t = cputime()
    for k in klist:
        k = ZZ(k)  # convert to sage integer
        kdiv = k // (p - 1)
        Gkdiv = G**kdiv
        u = []
        for i in xrange(0, ell):
            ei = e[i]
            ui = Gkdiv * ei
            u.append(ui)

        verbose("done step 4b", t)
        t = cputime()
        # Step 5 and computation of T in Step 6

        S = e[0][0].parent()
        T = matrix(S, ell, ell)

        for i in xrange(0, ell):
            for j in xrange(0, ell):
                T[i, j] = u[i][p * j]

        verbose("done step 5", t)
        t = cputime()
        # Step 6: solve T = AE using fact E is upper triangular.
        # Warning: assumes that T = AE (rather than pT = AE) has
        # a solution over Z/(p^mdash). This has always been the case in
        # examples computed by the author, see Note 3.1.

        A = matrix(S, ell, ell)
        verbose("solving a square matrix problem of dimension %s" % ell, t)

        for i in xrange(0, ell):
            Ti = T[i]
            for j in xrange(0, ell):
                ej = Ti.parent()([e[j][l] for l in xrange(0, ell)])
                lj = ZZ(ej[j])
                A[i, j] = S(ZZ(Ti[j]) / lj)
                Ti = Ti - A[i, j] * ej

        Alist.append(MatrixSpace(Zmod(p**m), ell, ell)(A))
        verbose("done step 6", t)

    return Alist
示例#6
0
def compute_Wi(k, p, h, hj, E4, E6):
    r"""
    This function computes a list `W_i` of q-expansions, together with an
    auxilliary quantity `h^j` (see below) which is to be used on the next
    call of this function. (The precision is that of input q-expansions.)

    The list `W_i` is a certain subset of a basis of the modular forms of
    weight `k` and level 1. Suppose `(a, b)` is the pair of non-negative
    integers with `4a + 6b = k` and `a` minimal among such pairs. Then this
    space has a basis given by

    .. math::

        \{ \Delta^j E_6^{b - 2j} E_4^a : 0 \le j < d\}

    where `d` is the dimension.

    What this function returns is the subset of the above basis corresponding
    to `e \le j < d` where `e` is the dimension of the space of modular forms
    of weight `k - (p-1)`. This set is a basis for the complement of the image
    of the weight `k - (p-1)` forms under multiplication by `E_{p-1}`.

    This function is used repeatedly in the construction of the Katz expansion
    basis. Hence considerable care is taken to reuse steps in the computation
    wherever possible: we keep track of powers of the form `h = \Delta /
    E_6^2`.

    INPUT:

    - ``k`` -- non-negative integer.
    - ``p`` -- prime at least 5.
    - ``h`` -- q-expansion of `h` (to some finite precision).
    - ``hj`` -- q-expansion of h^j where j is the dimension of the space of
      modular forms of level 1 and weight `k - (p-1)` (to same finite
      precision).
    - ``E4`` -- q-expansion of ``E_4`` (to same finite precision).
    - ``E6`` -- q-expansion of ``E_6`` (to same finite precision).

    The Eisenstein series q-expansions should be normalized to have constant
    term 1.

    OUTPUT:

    - list of q-expansions (to same finite precision), and q-expansion.

    EXAMPLES:

        sage: from sage.modular.overconvergent.hecke_series import compute_Wi
        sage: p = 17
        sage: prec = 10
        sage: k = 24
        sage: S = Zmod(17^3)
        sage: E4 = eisenstein_series_qexp(4, prec, K=S, normalization="constant")
        sage: E6 = eisenstein_series_qexp(6, prec, K=S, normalization="constant")
        sage: h = delta_qexp(prec, K=S) / E6^2
        sage: j = dimension_modular_forms(1, k - (p-1))
        sage: hj = h**j
        sage: c = compute_Wi(k,p,h,hj,E4,E6); c
        ([q + 3881*q^2 + 4459*q^3 + 4665*q^4 + 2966*q^5 + 1902*q^6 + 1350*q^7 + 3836*q^8 + 1752*q^9 + O(q^10), q^2 + 4865*q^3 + 1080*q^4 + 4612*q^5 + 1343*q^6 + 1689*q^7 + 3876*q^8 + 1381*q^9 + O(q^10)], q^3 + 2952*q^4 + 1278*q^5 + 3225*q^6 + 1286*q^7 + 589*q^8 + 122*q^9 + O(q^10))
        sage: c == ([delta_qexp(10) * E6^2, delta_qexp(10)^2], h**3)
        True
    """

    # Define a and b
    a = k % 3
    b = (k // 2) % 2

    # Compute dimensions required for Miller basis
    d = dimension_modular_forms(1, k) - 1
    e = dimension_modular_forms(1, k - (p - 1)) - 1

    # This next line is a bit of a bottleneck, particularly when m is large but
    # p is small. It would be good to reuse values calculated on the previous
    # call here somehow.
    r = E6**(2 * d + b) * E4**a

    prec = E4.prec()  # everything gets trucated to this precision

    # Construct basis for Wi
    Wi = []
    for j in xrange(e + 1, d + 1):
        # compute aj = delta^j*E6^(2*(d-j) + b)*E4^a
        verbose("k = %s, computing Delta^%s E6^%s E4^%s" % (k, j, 2 *
                                                            (d - j) + b, a),
                level=2)
        aj = (hj * r).truncate_powerseries(prec)
        hj = (hj * h).truncate_powerseries(prec)
        Wi.append(aj)

    return Wi, hj
示例#7
0
def random_new_basis_modp(N, p, k, LWBModp, TotalBasisModp, elldash, bound):
    r"""
    Returns ``NewBasisCode``. Here `NewBasisCode` is a list of lists of lists
    ``[j,a]``. This encodes a choice of basis for the ith complementary space
    `W_i`, as explained in the documentation for the function
    :func:`complementary_spaces_modp`.

    INPUT:

    - ``N`` -- positive integer at least 2 and not divisible by p (level).
    - ``p`` -- prime at least 5.
    - ``k`` -- non-negative integer.
    - ``LWBModp`` -- list of list of q-expansions modulo
      `(p,q^\text{elldash})`.
    - ``TotalBasisModp`` -- matrix over GF(p).
    - ``elldash`` - positive integer.
    - ``bound`` -- positive even integer (twice the length of the list
      ``LWBModp``).

    OUTPUT:

    - A list of lists of lists ``[j,a]``.

    .. note::

        As well as having a non-trivial return value, this function also
        modifies the input matrix ``TotalBasisModp``.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import random_low_weight_bases, complementary_spaces_modp
        sage: LWB = random_low_weight_bases(2,5,2,4,6)
        sage: LWBModp = [ [f.change_ring(GF(5)) for f in x] for x in LWB]
        sage: complementary_spaces_modp(2,5,2,3,4,LWBModp,4) # random, indirect doctest
        [[[[0, 0]]], [[[0, 0], [1, 1]]], [[[0, 0], [1, 0], [1, 1]]], [[[0, 0], [1, 0], [1, 1], [1, 1]]]]

    """

    R = LWBModp[0][0].parent()

    # Case k0 + i(p-1) = 0 + 0(p-1) = 0

    if k == 0:
        TotalBasisModp[0, 0] = 1
        return [[]]

    # Case k = k0 + i(p-1) > 0

    di = dimension_modular_forms(N, k)
    diminus1 = dimension_modular_forms(N, k - (p - 1))
    mi = di - diminus1

    NewBasisCode = []
    rk = diminus1
    for i in xrange(1, mi + 1):
        while (rk < diminus1 + i):
            # take random product of basis elements
            exps = random_solution(bound // 2, k // 2)
            TotalBasisi = R(1)
            TotalBasisiCode = []
            for j in xrange(len(exps)):
                for l in xrange(exps[j]):
                    a = ZZ.random_element(len(LWBModp[j]))
                    TotalBasisi = TotalBasisi * LWBModp[j][a]
                    TotalBasisiCode.append([j, a])
            TotalBasisModp[rk] = [TotalBasisi[j] for j in range(elldash)]
            TotalBasisModp.echelonize()
            rk = TotalBasisModp.rank()
        NewBasisCode.append(TotalBasisiCode)  # this choice increased the rank

    return NewBasisCode
示例#8
0
def level1_UpGj(p,klist,m):
    r"""
    Returns a list `[A_k]` of square matrices over ``IntegerRing(p^m)``
    parameterised by the weights k in ``klist``. The matrix `A_k` is the finite
    square matrix which occurs on input p,k and m in Step 6 of Algorithm 1 in
    [AGBL]_. Notational change from paper: In Step 1 following Wan we defined
    j by `k = k_0 + j(p-1)` with `0 \le k_0 < p-1`. Here we replace j by
    ``kdiv`` so that we may use j as a column index for matrices.

    INPUT:

    - ``p`` -- prime at least 5.
    - ``klist`` -- list of integers congruent modulo `(p-1)` (the weights).
    - ``m`` -- positive integer.

    OUTPUT:

    - list of square matrices.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import level1_UpGj
        sage: level1_UpGj(7,[100],5)
        [
        [    1   980  4802     0     0]
        [    0 13727 14406     0     0]
        [    0 13440  7203     0     0]
        [    0  1995  4802     0     0]
        [    0  9212 14406     0     0]
        ]
    """
    # Step 1
    t = cputime()

    k0 = klist[0] % (p-1)
    n = floor(((p+1)/(p-1)) * (m+1))
    ell = dimension_modular_forms(1, k0 + n*(p-1))
    ellp = ell*p
    mdash = m + ceil(n/(p+1))

    verbose("done step 1", t)
    t = cputime()
    # Steps 2 and 3

    e,Ep1 = katz_expansions(k0,p,ellp,mdash,n)

    verbose("done steps 2+3", t)
    t=cputime()
    # Step 4

    G = compute_G(p, Ep1)
    Alist = []

    verbose("done step 4a", t)
    t=cputime()
    for k in klist:
        k = ZZ(k) # convert to sage integer
        kdiv = k // (p-1)
        Gkdiv = G**kdiv
        u = []
        for i in xrange(0,ell):
            ei = e[i]
            ui = Gkdiv*ei
            u.append(ui)

        verbose("done step 4b", t)
        t = cputime()
        # Step 5 and computation of T in Step 6

        S = e[0][0].parent()
        T = matrix(S,ell,ell)

        for i in xrange(0,ell):
            for j in xrange(0,ell):
                T[i,j] = u[i][p*j]

        verbose("done step 5", t)
        t = cputime()
        # Step 6: solve T = AE using fact E is upper triangular.
        # Warning: assumes that T = AE (rather than pT = AE) has
        # a solution over Z/(p^mdash). This has always been the case in
        # examples computed by the author, see Note 3.1.

        A = matrix(S,ell,ell)
        verbose("solving a square matrix problem of dimension %s" % ell, t)

        for i in xrange(0,ell):
            Ti = T[i]
            for j in xrange(0,ell):
                ej = Ti.parent()([e[j][l] for l in xrange(0,ell)])
                lj = ZZ(ej[j])
                A[i,j] = S(ZZ(Ti[j])/lj)
                Ti = Ti - A[i,j]*ej

        Alist.append(MatrixSpace(Zmod(p**m),ell,ell)(A))
        verbose("done step 6", t)

    return Alist
示例#9
0
def compute_Wi(k,p,h,hj,E4,E6):
    r"""
    This function computes a list `W_i` of q-expansions, together with an
    auxilliary quantity `h^j` (see below) which is to be used on the next
    call of this function. (The precision is that of input q-expansions.)

    The list `W_i` is a certain subset of a basis of the modular forms of
    weight `k` and level 1. Suppose `(a, b)` is the pair of non-negative
    integers with `4a + 6b = k` and `a` minimal among such pairs. Then this
    space has a basis given by

    .. math::

        \{ \Delta^j E_6^{b - 2j} E_4^a : 0 \le j < d\}

    where `d` is the dimension.

    What this function returns is the subset of the above basis corresponding
    to `e \le j < d` where `e` is the dimension of the space of modular forms
    of weight `k - (p-1)`. This set is a basis for the complement of the image
    of the weight `k - (p-1)` forms under multiplication by `E_{p-1}`.

    This function is used repeatedly in the construction of the Katz expansion
    basis. Hence considerable care is taken to reuse steps in the computation
    wherever possible: we keep track of powers of the form `h = \Delta /
    E_6^2`.

    INPUT:

    - ``k`` -- non-negative integer.
    - ``p`` -- prime at least 5.
    - ``h`` -- q-expansion of `h` (to some finite precision).
    - ``hj`` -- q-expansion of h^j where j is the dimension of the space of
      modular forms of level 1 and weight `k - (p-1)` (to same finite
      precision).
    - ``E4`` -- q-expansion of ``E_4`` (to same finite precision).
    - ``E6`` -- q-expansion of ``E_6`` (to same finite precision).

    The Eisenstein series q-expansions should be normalized to have constant
    term 1.

    OUTPUT:

    - list of q-expansions (to same finite precision), and q-expansion.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import compute_Wi
        sage: p = 17
        sage: prec = 10
        sage: k = 24
        sage: S = Zmod(17^3)
        sage: E4 = eisenstein_series_qexp(4, prec, K=S, normalization="constant")
        sage: E6 = eisenstein_series_qexp(6, prec, K=S, normalization="constant")
        sage: h = delta_qexp(prec, K=S) / E6^2
        sage: j = dimension_modular_forms(1, k - (p-1))
        sage: hj = h**j
        sage: c = compute_Wi(k,p,h,hj,E4,E6); c
        ([q + 3881*q^2 + 4459*q^3 + 4665*q^4 + 2966*q^5 + 1902*q^6 + 1350*q^7 + 3836*q^8 + 1752*q^9 + O(q^10), q^2 + 4865*q^3 + 1080*q^4 + 4612*q^5 + 1343*q^6 + 1689*q^7 + 3876*q^8 + 1381*q^9 + O(q^10)], q^3 + 2952*q^4 + 1278*q^5 + 3225*q^6 + 1286*q^7 + 589*q^8 + 122*q^9 + O(q^10))
        sage: c == ([delta_qexp(10) * E6^2, delta_qexp(10)^2], h**3)
        True
    """

    # Define a and b
    a = k % 3
    b = (k // 2) % 2

    # Compute dimensions required for Miller basis
    d = dimension_modular_forms(1, k) - 1
    e = dimension_modular_forms(1, k-(p-1)) - 1

    # This next line is a bit of a bottleneck, particularly when m is large but
    # p is small. It would be good to reuse values calculated on the previous
    # call here somehow.
    r = E6**(2*d + b) * E4**a

    prec = E4.prec() # everything gets trucated to this precision

    # Construct basis for Wi
    Wi = []
    for j in xrange(e+1,d+1):
        # compute aj = delta^j*E6^(2*(d-j) + b)*E4^a
        verbose("k = %s, computing Delta^%s E6^%s E4^%s" % (k, j, 2*(d-j) + b, a), level=2)
        aj = (hj * r).truncate_powerseries(prec)
        hj = (hj * h).truncate_powerseries(prec)
        Wi.append(aj)

    return Wi,hj
示例#10
0
def random_new_basis_modp(N,p,k,LWBModp,TotalBasisModp,elldash,bound):
    r"""
    Returns ``NewBasisCode``. Here `NewBasisCode` is a list of lists of lists
    ``[j,a]``. This encodes a choice of basis for the ith complementary space
    `W_i`, as explained in the documentation for the function
    :func:`complementary_spaces_modp`.

    INPUT:

    - ``N`` -- positive integer at least 2 and not divisible by p (level).
    - ``p`` -- prime at least 5.
    - ``k`` -- non-negative integer.
    - ``LWBModp`` -- list of list of q-expansions modulo
      `(p,q^\text{elldash})`.
    - ``TotalBasisModp`` -- matrix over GF(p).
    - ``elldash`` - positive integer.
    - ``bound`` -- positive even integer (twice the length of the list
      ``LWBModp``).

    OUTPUT:

    - A list of lists of lists ``[j,a]``.

    .. note::

        As well as having a non-trivial return value, this function also
        modifies the input matrix ``TotalBasisModp``.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import random_low_weight_bases, complementary_spaces_modp
        sage: LWB = random_low_weight_bases(2,5,2,4,6)
        sage: LWBModp = [ [f.change_ring(GF(5)) for f in x] for x in LWB]
        sage: complementary_spaces_modp(2,5,2,3,4,LWBModp,4) # random, indirect doctest
        [[[[0, 0]]], [[[0, 0], [1, 1]]], [[[0, 0], [1, 0], [1, 1]]], [[[0, 0], [1, 0], [1, 1], [1, 1]]]]

    """

    R = LWBModp[0][0].parent()

    # Case k0 + i(p-1) = 0 + 0(p-1) = 0

    if k == 0:
        TotalBasisModp[0,0] = 1
        return [[]]

    # Case k = k0 + i(p-1) > 0

    di = dimension_modular_forms(N, k)
    diminus1 = dimension_modular_forms(N, k-(p-1))
    mi = di - diminus1

    NewBasisCode = []
    rk = diminus1
    for i in xrange(1,mi+1):
        while (rk < diminus1 + i):
            # take random product of basis elements
            exps = random_solution(bound // 2, k // 2)
            TotalBasisi = R(1)
            TotalBasisiCode = []
            for j in xrange(len(exps)):
                for l in xrange(exps[j]):
                    a = ZZ.random_element(len(LWBModp[j]))
                    TotalBasisi = TotalBasisi*LWBModp[j][a]
                    TotalBasisiCode.append([j,a])
            TotalBasisModp[rk] = [TotalBasisi[j] for j in range(elldash)]
            TotalBasisModp.echelonize()
            rk = TotalBasisModp.rank()
        NewBasisCode.append(TotalBasisiCode) # this choice increased the rank

    return NewBasisCode
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