Beispiel #1
0
    def label(self) -> str:
        """
        Return canonical label that defines this newform modular
        abelian variety.

        OUTPUT:

        string

        EXAMPLES::

            sage: A = AbelianVariety('43b')
            sage: A.label()
            '43b'
        """
        G = self.__f.group()
        if is_Gamma0(G):
            group = ''
        elif is_Gamma1(G):
            group = 'G1'
        elif is_GammaH(G):
            group = 'GH[' + ','.join(str(z)
                                     for z in G._generators_for_H()) + ']'
        return '%s%s%s' % (self.level(),
                           cremona_letter_code(self.factor_number()), group)
Beispiel #2
0
def dimension_new_cusp_forms(X, k=2, p=0):
    """
    Return the dimension of the new (or `p`-new) subspace of
    cusp forms for the character or group `X`.

    INPUT:

    -  ``X`` -- integer, congruence subgroup or Dirichlet
       character

    -  ``k`` -- weight (integer)

    -  ``p`` -- 0 or a prime

    EXAMPLES::

        sage: from sage.modular.dims import dimension_new_cusp_forms
        sage: dimension_new_cusp_forms(100,2)
        1

        sage: dimension_new_cusp_forms(Gamma0(100),2)
        1
        sage: dimension_new_cusp_forms(Gamma0(100),4)
        5

        sage: dimension_new_cusp_forms(Gamma1(100),2)
        141
        sage: dimension_new_cusp_forms(Gamma1(100),4)
        463

        sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,2)
        2
        sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,4)
        8

        sage: sum(dimension_new_cusp_forms(e,3) for e in DirichletGroup(30))
        12
        sage: dimension_new_cusp_forms(Gamma1(30),3)
        12

    Check that :trac:`12640` is fixed::

        sage: dimension_new_cusp_forms(DirichletGroup(1)(1), 12)
        1
        sage: dimension_new_cusp_forms(DirichletGroup(2)(1), 24)
        1
    """
    if is_GammaH(X):
        return X.dimension_new_cusp_forms(k, p=p)
    elif isinstance(X, dirichlet.DirichletCharacter):
        N = X.modulus()
        if N <= 2:
            return Gamma0(N).dimension_new_cusp_forms(k, p=p)
        else:
            # Gamma1(N) for N<=2 just returns Gamma0(N), which has no
            # eps parameter. See trac #12640.
            return Gamma1(N).dimension_new_cusp_forms(k, eps=X, p=p)
    elif isinstance(X, (int, Integer)):
        return Gamma0(X).dimension_new_cusp_forms(k, p=p)
    raise TypeError(f"X (={X}) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH")
Beispiel #3
0
def dimension_new_cusp_forms(X, k=2, p=0):
    """
    Return the dimension of the new (or `p`-new) subspace of
    cusp forms for the character or group `X`.
    
    INPUT:
    
    
    -  ``X`` - integer, congruence subgroup or Dirichlet
       character
    
    -  ``k`` - weight (integer)
    
    -  ``p`` - 0 or a prime
    
    
    EXAMPLES::
    
        sage: dimension_new_cusp_forms(100,2)
        1
    
    ::
    
        sage: dimension_new_cusp_forms(Gamma0(100),2)
        1
        sage: dimension_new_cusp_forms(Gamma0(100),4)
        5
    
    ::
    
        sage: dimension_new_cusp_forms(Gamma1(100),2)
        141
        sage: dimension_new_cusp_forms(Gamma1(100),4)
        463
    
    ::
    
        sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,2)
        2
        sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,4)
        8
    
    ::
    
        sage: sum(dimension_new_cusp_forms(e,3) for e in DirichletGroup(30))
        12
        sage: dimension_new_cusp_forms(Gamma1(30),3)
        12
    """
    if is_GammaH(X):
        return X.dimension_new_cusp_forms(k,p=p)
    elif isinstance(X, dirichlet.DirichletCharacter):
        return Gamma1(X.modulus()).dimension_new_cusp_forms(k,eps=X,p=p)
    elif isinstance(X, (int,long,Integer)):
        return Gamma0(X).dimension_new_cusp_forms(k,p=p)
    else:
        raise TypeError, "X (=%s) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH" % X
Beispiel #4
0
    def label(self):
        """
        Return canonical label that defines this newform modular
        abelian variety.

        OUTPUT:
            string

        EXAMPLES::

            sage: A = AbelianVariety('43b')
            sage: A.label()
            '43b'
        """
        G = self.__f.group()
        if is_Gamma0(G):
            group = ''
        elif is_Gamma1(G):
            group = 'G1'
        elif is_GammaH(G):
            group = 'GH[' + ','.join([str(z) for z in G._generators_for_H()]) + ']'
        return '%s%s%s'%(self.level(), cremona_letter_code(self.factor_number()), group)
Beispiel #5
0
def ModularForms(group  = 1,
                 weight = 2,
                 base_ring = None,
                 use_cache = True,
                 prec = defaults.DEFAULT_PRECISION):
    r"""
    Create an ambient space of modular forms.

    INPUT:


    -  ``group`` - A congruence subgroup or a Dirichlet
       character eps.

    -  ``weight`` - int, the weight, which must be an
       integer = 1.

    -  ``base_ring`` - the base ring (ignored if group is
       a Dirichlet character)


    Create using the command ModularForms(group, weight, base_ring)
    where group could be either a congruence subgroup or a Dirichlet
    character.

    EXAMPLES: First we create some spaces with trivial character::

        sage: ModularForms(Gamma0(11),2).dimension()
        2
        sage: ModularForms(Gamma0(1),12).dimension()
        2

    If we give an integer N for the congruence subgroup, it defaults to
    `\Gamma_0(N)`::

        sage: ModularForms(1,12).dimension()
        2
        sage: ModularForms(11,4)
        Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(11) of weight 4 over Rational Field

    We create some spaces for `\Gamma_1(N)`.

    ::

        sage: ModularForms(Gamma1(13),2)
        Modular Forms space of dimension 13 for Congruence Subgroup Gamma1(13) of weight 2 over Rational Field
        sage: ModularForms(Gamma1(13),2).dimension()
        13
        sage: [ModularForms(Gamma1(7),k).dimension() for k in [2,3,4,5]]
        [5, 7, 9, 11]
        sage: ModularForms(Gamma1(5),11).dimension()
        12

    We create a space with character::

        sage: e = (DirichletGroup(13).0)^2
        sage: e.order()
        6
        sage: M = ModularForms(e, 2); M
        Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 6 and degree 2
        sage: f = M.T(2).charpoly('x'); f
        x^3 + (-2*zeta6 - 2)*x^2 - 2*zeta6*x + 14*zeta6 - 7
        sage: f.factor()
        (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)

    We can also create spaces corresponding to the groups `\Gamma_H(N)` intermediate
    between `\Gamma_0(N)` and `\Gamma_1(N)`::

        sage: G = GammaH(30, [11])
        sage: M = ModularForms(G, 2); M
        Modular Forms space of dimension 20 for Congruence Subgroup Gamma_H(30) with H generated by [11] of weight 2 over Rational Field
        sage: M.T(7).charpoly().factor()  # long time (7s on sage.math, 2011)
        (x + 4) * x^2 * (x - 6)^4 * (x + 6)^4 * (x - 8)^7 * (x^2 + 4)

    More examples of spaces with character::

        sage: e = DirichletGroup(5, RationalField()).gen(); e
        Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1

        sage: m = ModularForms(e, 2); m
        Modular Forms space of dimension 2, character [-1] and weight 2 over Rational Field
        sage: m == loads(dumps(m))
        True
        sage: m.T(2).charpoly('x')
        x^2 - 1
        sage: m = ModularForms(e, 6); m.dimension()
        4
        sage: m.T(2).charpoly('x')
        x^4 - 917*x^2 - 42284

    This came up in a subtle bug (trac #5923)::

        sage: ModularForms(gp(1), gap(12))
        Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field

    This came up in another bug (related to trac #8630)::

        sage: chi = DirichletGroup(109, CyclotomicField(3)).0
        sage: ModularForms(chi, 2, base_ring = CyclotomicField(15))
        Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 over Cyclotomic Field of order 15 and degree 8

    We create some weight 1 spaces. The first example works fine, since we can prove purely by Riemann surface theory that there are no weight 1 cusp forms::

        sage: M = ModularForms(Gamma1(11), 1); M
        Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(11) of weight 1 over Rational Field
        sage: M.basis()
        [
        1 + 22*q^5 + O(q^6),
        q + 4*q^5 + O(q^6),
        q^2 - 4*q^5 + O(q^6),
        q^3 - 5*q^5 + O(q^6),
        q^4 - 3*q^5 + O(q^6)
        ]
        sage: M.cuspidal_subspace().basis()
        [
        ]
        sage: M == M.eisenstein_subspace()
        True

    This example doesn't work so well, because we can't calculate the cusp
    forms; but we can still work with the Eisenstein series.

        sage: M = ModularForms(Gamma1(57), 1); M
        Modular Forms space of dimension (unknown) for Congruence Subgroup Gamma1(57) of weight 1 over Rational Field
        sage: M.basis()
        Traceback (most recent call last):
        ...
        NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general
        sage: M.cuspidal_subspace().basis()
        Traceback (most recent call last):
        ...
        NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general

        sage: E = M.eisenstein_subspace(); E
        Eisenstein subspace of dimension 36 of Modular Forms space of dimension (unknown) for Congruence Subgroup Gamma1(57) of weight 1 over Rational Field
        sage: (E.0 + E.2).q_expansion(40)
        1 + q^2 + 1473/2*q^36 - 1101/2*q^37 + q^38 - 373/2*q^39 + O(q^40)

    """
    if isinstance(group, dirichlet.DirichletCharacter):
        if base_ring is None:
            base_ring = group.minimize_base_ring().base_ring()
    if base_ring is None:
        base_ring = rings.QQ

    if isinstance(group, dirichlet.DirichletCharacter) \
           or arithgroup.is_CongruenceSubgroup(group):
        level = group.level()
    else:
        level = group

    key = canonical_parameters(group, level, weight, base_ring)

    if use_cache and _cache.has_key(key):
         M = _cache[key]()
         if not (M is None):
             M.set_precision(prec)
             return M

    (level, group, weight, base_ring) = key

    M = None
    if arithgroup.is_Gamma0(group):
        M = ambient_g0.ModularFormsAmbient_g0_Q(group.level(), weight)
        if base_ring != rings.QQ:
            M = ambient_R.ModularFormsAmbient_R(M, base_ring)

    elif arithgroup.is_Gamma1(group):
        M = ambient_g1.ModularFormsAmbient_g1_Q(group.level(), weight)
        if base_ring != rings.QQ:
            M = ambient_R.ModularFormsAmbient_R(M, base_ring)

    elif arithgroup.is_GammaH(group):
        M = ambient_g1.ModularFormsAmbient_gH_Q(group, weight)
        if base_ring != rings.QQ:
            M = ambient_R.ModularFormsAmbient_R(M, base_ring)

    elif isinstance(group, dirichlet.DirichletCharacter):
        eps = group
        if eps.base_ring().characteristic() != 0:
            # TODO -- implement this
            # Need to add a lift_to_char_0 function for characters,
            # and need to still remember eps.
            raise NotImplementedError, "currently the character must be over a ring of characteristic 0."
        eps = eps.minimize_base_ring()
        if eps.is_trivial():
            return ModularForms(eps.modulus(), weight, base_ring,
                                use_cache = use_cache,
                                prec = prec)
        M = ambient_eps.ModularFormsAmbient_eps(eps, weight)
        if base_ring != eps.base_ring():
            M = M.base_extend(base_ring) # ambient_R.ModularFormsAmbient_R(M, base_ring)

    if M is None:
        raise NotImplementedError, \
           "computation of requested space of modular forms not defined or implemented"

    M.set_precision(prec)
    _cache[key] = weakref.ref(M)
    return M
Beispiel #6
0
def ModularSymbols(group=1,
                   weight=2,
                   sign=0,
                   base_ring=None,
                   use_cache=True,
                   custom_init=None):
    r"""
    Create an ambient space of modular symbols.

    INPUT:

    - ``group`` - A congruence subgroup or a Dirichlet character eps.
    - ``weight`` - int, the weight, which must be >= 2.
    - ``sign`` - int, The sign of the involution on modular symbols
      induced by complex conjugation. The default is 0, which means
      "no sign", i.e., take the whole space.
    - ``base_ring`` - the base ring. Defaults to `\QQ` if no character
      is given, or to the minimal extension of `\QQ` containing the
      values of the character.
    - ``custom_init`` - a function that is called with self as input
      before any computations are done using self; this could be used
      to set a custom modular symbols presentation.  If self is
      already in the cache and use_cache=True, then this function is
      not called.

    EXAMPLES: First we create some spaces with trivial character::

        sage: ModularSymbols(Gamma0(11),2).dimension()
        3
        sage: ModularSymbols(Gamma0(1),12).dimension()
        3

    If we give an integer N for the congruence subgroup, it defaults to
    `\Gamma_0(N)`::

        sage: ModularSymbols(1,12,-1).dimension()
        1
        sage: ModularSymbols(11,4, sign=1)
        Modular Symbols space of dimension 4 for Gamma_0(11) of weight 4 with sign 1 over Rational Field

    We create some spaces for `\Gamma_1(N)`.

    ::

        sage: ModularSymbols(Gamma1(13),2)
        Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Rational Field
        sage: ModularSymbols(Gamma1(13),2, sign=1).dimension()
        13
        sage: ModularSymbols(Gamma1(13),2, sign=-1).dimension()
        2
        sage: [ModularSymbols(Gamma1(7),k).dimension() for k in [2,3,4,5]]
        [5, 8, 12, 16]
        sage: ModularSymbols(Gamma1(5),11).dimension()
        20

    We create a space for `\Gamma_H(N)`::

        sage: G = GammaH(15,[4,13])
        sage: M = ModularSymbols(G,2)
        sage: M.decomposition()
        [
        Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] of weight 2 with sign 0 and over Rational Field,
        Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] of weight 2 with sign 0 and over Rational Field
        ]

    We create a space with character::

        sage: e = (DirichletGroup(13).0)^2
        sage: e.order()
        6
        sage: M = ModularSymbols(e, 2); M
        Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2
        sage: f = M.T(2).charpoly('x'); f
        x^4 + (-zeta6 - 1)*x^3 - 8*zeta6*x^2 + (10*zeta6 - 5)*x + 21*zeta6 - 21
        sage: f.factor()
        (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)^2

    We create a space with character over a larger base ring than the values of the character::

        sage: ModularSymbols(e, 2, base_ring = CyclotomicField(24))
        Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta24^4], sign 0, over Cyclotomic Field of order 24 and degree 8

    More examples of spaces with character::

        sage: e = DirichletGroup(5, RationalField()).gen(); e
        Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1

        sage: m = ModularSymbols(e, 2); m
        Modular Symbols space of dimension 2 and level 5, weight 2, character [-1], sign 0, over Rational Field

    ::

        sage: m.T(2).charpoly('x')
        x^2 - 1
        sage: m = ModularSymbols(e, 6); m.dimension()
        6
        sage: m.T(2).charpoly('x')
        x^6 - 873*x^4 - 82632*x^2 - 1860496

    We create a space of modular symbols with nontrivial character in
    characteristic 2.

    ::

        sage: G = DirichletGroup(13,GF(4,'a')); G
        Group of Dirichlet characters modulo 13 with values in Finite Field in a of size 2^2
        sage: e = G.list()[2]; e
        Dirichlet character modulo 13 of conductor 13 mapping 2 |--> a + 1
        sage: M = ModularSymbols(e,4); M
        Modular Symbols space of dimension 8 and level 13, weight 4, character [a + 1], sign 0, over Finite Field in a of size 2^2
        sage: M.basis()
        ([X*Y,(1,0)], [X*Y,(1,5)], [X*Y,(1,10)], [X*Y,(1,11)], [X^2,(0,1)], [X^2,(1,10)], [X^2,(1,11)], [X^2,(1,12)])
        sage: M.T(2).matrix()
        [    0     0     0     0     0     0     1     1]
        [    0     0     0     0     0     0     0     0]
        [    0     0     0     0     0 a + 1     1     a]
        [    0     0     0     0     0     1 a + 1     a]
        [    0     0     0     0 a + 1     0     1     1]
        [    0     0     0     0     0     a     1     a]
        [    0     0     0     0     0     0 a + 1     a]
        [    0     0     0     0     0     0     1     0]

    We illustrate the custom_init function, which can be used to make
    arbitrary changes to the modular symbols object before its
    presentation is computed::

        sage: ModularSymbols_clear_cache()
        sage: def custom_init(M):
        ....:     M.customize='hi'
        sage: M = ModularSymbols(1,12, custom_init=custom_init)
        sage: M.customize
        'hi'

    We illustrate the relation between custom_init and use_cache::

        sage: def custom_init(M):
        ....:     M.customize='hi2'
        sage: M = ModularSymbols(1,12, custom_init=custom_init)
        sage: M.customize
        'hi'
        sage: M = ModularSymbols(1,12, custom_init=custom_init, use_cache=False)
        sage: M.customize
        'hi2'

    TESTS:

    We test use_cache::

        sage: ModularSymbols_clear_cache()
        sage: M = ModularSymbols(11,use_cache=False)
        sage: sage.modular.modsym.modsym._cache
        {}
        sage: M = ModularSymbols(11,use_cache=True)
        sage: sage.modular.modsym.modsym._cache
        {(Congruence Subgroup Gamma0(11), 2, 0, Rational Field): <weakref at ...; to 'ModularSymbolsAmbient_wt2_g0_with_category' at ...>}
        sage: M is ModularSymbols(11,use_cache=True)
        True
        sage: M is ModularSymbols(11,use_cache=False)
        False
    """
    from . import ambient
    key = canonical_parameters(group, weight, sign, base_ring)

    if use_cache and key in _cache:
        M = _cache[key]()
        if M is not None:
            return M

    (group, weight, sign, base_ring) = key

    M = None
    if arithgroup.is_Gamma0(group):
        if weight == 2:
            M = ambient.ModularSymbolsAmbient_wt2_g0(group.level(),
                                                     sign,
                                                     base_ring,
                                                     custom_init=custom_init)
        else:
            M = ambient.ModularSymbolsAmbient_wtk_g0(group.level(),
                                                     weight,
                                                     sign,
                                                     base_ring,
                                                     custom_init=custom_init)

    elif arithgroup.is_Gamma1(group):

        M = ambient.ModularSymbolsAmbient_wtk_g1(group.level(),
                                                 weight,
                                                 sign,
                                                 base_ring,
                                                 custom_init=custom_init)

    elif arithgroup.is_GammaH(group):

        M = ambient.ModularSymbolsAmbient_wtk_gamma_h(group,
                                                      weight,
                                                      sign,
                                                      base_ring,
                                                      custom_init=custom_init)

    elif isinstance(group, tuple):
        eps = group[0]
        M = ambient.ModularSymbolsAmbient_wtk_eps(eps,
                                                  weight,
                                                  sign,
                                                  base_ring,
                                                  custom_init=custom_init)

    if M is None:
        raise NotImplementedError(
            "computation of requested space of modular symbols not defined or implemented"
        )

    if use_cache:
        _cache[key] = weakref.ref(M)
    return M
Beispiel #7
0
def dimension_new_cusp_forms(X, k=2, p=0):
    """
    Return the dimension of the new (or `p`-new) subspace of
    cusp forms for the character or group `X`.

    INPUT:


    -  ``X`` - integer, congruence subgroup or Dirichlet
       character

    -  ``k`` - weight (integer)

    -  ``p`` - 0 or a prime


    EXAMPLES::

        sage: dimension_new_cusp_forms(100,2)
        1

    ::

        sage: dimension_new_cusp_forms(Gamma0(100),2)
        1
        sage: dimension_new_cusp_forms(Gamma0(100),4)
        5

    ::

        sage: dimension_new_cusp_forms(Gamma1(100),2)
        141
        sage: dimension_new_cusp_forms(Gamma1(100),4)
        463

    ::

        sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,2)
        2
        sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,4)
        8

    ::

        sage: sum(dimension_new_cusp_forms(e,3) for e in DirichletGroup(30))
        12
        sage: dimension_new_cusp_forms(Gamma1(30),3)
        12

    Check that :trac:`12640` is fixed::

        sage: dimension_new_cusp_forms(DirichletGroup(1)(1), 12)
        1
        sage: dimension_new_cusp_forms(DirichletGroup(2)(1), 24)
        1
    """
    if is_GammaH(X):
        return X.dimension_new_cusp_forms(k,p=p)
    elif isinstance(X, dirichlet.DirichletCharacter):
        N = X.modulus()
        if N <= 2:
            return Gamma0(N).dimension_new_cusp_forms(k,p=p)
        else:
            # Gamma1(N) for N<=2 just returns Gamma0(N), which has no eps parameter. See trac #12640.
            return Gamma1(N).dimension_new_cusp_forms(k,eps=X,p=p)
    elif isinstance(X, (int,long,Integer)):
        return Gamma0(X).dimension_new_cusp_forms(k,p=p)
    else:
        raise TypeError("X (=%s) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH" % X)
Beispiel #8
0
    def is_gamma_h_equiv(self, other, G):
        r"""
        Return a pair (b, t), where b is True or False as self and other
        are equivalent under the action of G, and t is 1 or -1, as
        described below.

        Two cusps `u1/v1` and `u2/v2` are equivalent modulo
        Gamma_H(N) if and only if `v1 =  h*v2 (\mathrm{mod} N)` and
        `u1 =  h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` or
        `v1 = -h*v2 (mod N)` and
        `u1 = -h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` for some
        `h \in H`. Then t is 1 or -1 as c and c' fall into the
        first or second case, respectively.

        INPUT:


        -  ``other`` - Cusp

        -  ``G`` - a congruence subgroup Gamma_H(N)


        OUTPUT:


        -  ``bool`` - True if self and other are equivalent

        -  ``int`` - -1, 0, 1; extra info


        EXAMPLES::

            sage: x = Cusp(2,3)
            sage: y = Cusp(4,5)
            sage: x.is_gamma_h_equiv(y,GammaH(13,[2]))
            (True, 1)
            sage: x.is_gamma_h_equiv(y,GammaH(13,[5]))
            (False, 0)
            sage: x.is_gamma_h_equiv(y,GammaH(5,[]))
            (False, 0)
            sage: x.is_gamma_h_equiv(y,GammaH(23,[4]))
            (True, -1)

        Enumerating the cusps for a space of modular symbols uses this
        function.

        ::

            sage: G = GammaH(25,[6]) ; M = G.modular_symbols() ; M
            Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field
            sage: M.cusps()
            [33/100, 1/3, 31/125, 1/4, 1/15, -7/15, 7/15, 4/15, 1/20, 3/20, 7/20, 9/20]
            sage: len(M.cusps())
            12

        This is always one more than the associated space of weight 2 Eisenstein
        series.

        ::

            sage: G.dimension_eis(2)
            11
            sage: M.cuspidal_subspace()
            Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field
            sage: G.dimension_cusp_forms(2)
            0
        """
        from sage.modular.arithgroup.all import is_GammaH
        if not isinstance(other, Cusp):
            other = Cusp(other)
        if not is_GammaH(G):
            raise TypeError("G must be a group GammaH(N).")

        H = G._list_of_elements_in_H()
        N = ZZ(G.level())
        u1 = self.__a
        v1 = self.__b
        u2 = other.__a
        v2 = other.__b
        g = v1.gcd(N)

        for h in H:
            v_tmp = (h * v1) % N
            u_tmp = (h * u2) % N
            if (v_tmp - v2) % N == 0 and (u_tmp - u1) % g == 0:
                return True, 1
            if (v_tmp + v2) % N == 0 and (u_tmp + u1) % g == 0:
                return True, -1
        return False, 0
Beispiel #9
0
def ModularSymbols(group  = 1,
                   weight = 2,
                   sign   = 0,
                   base_ring = None,
                   use_cache = True,
                   custom_init=None):
    r"""
    Create an ambient space of modular symbols.

    INPUT:

    - ``group`` - A congruence subgroup or a Dirichlet character eps.
    - ``weight`` - int, the weight, which must be = 2.
    - ``sign`` - int, The sign of the involution on modular symbols
      induced by complex conjugation. The default is 0, which means
      "no sign", i.e., take the whole space.
    - ``base_ring`` - the base ring. Defaults to `\QQ` if no character
      is given, or to the minimal extension of `\QQ` containing the
      values of the character.
    - ``custom_init`` - a function that is called with self as input
      before any computations are done using self; this could be used
      to set a custom modular symbols presentation.  If self is
      already in the cache and use_cache=True, then this function is
      not called.

    EXAMPLES: First we create some spaces with trivial character::

        sage: ModularSymbols(Gamma0(11),2).dimension()
        3
        sage: ModularSymbols(Gamma0(1),12).dimension()
        3

    If we give an integer N for the congruence subgroup, it defaults to
    `\Gamma_0(N)`::

        sage: ModularSymbols(1,12,-1).dimension()
        1
        sage: ModularSymbols(11,4, sign=1)
        Modular Symbols space of dimension 4 for Gamma_0(11) of weight 4 with sign 1 over Rational Field

    We create some spaces for `\Gamma_1(N)`.

    ::

        sage: ModularSymbols(Gamma1(13),2)
        Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Rational Field
        sage: ModularSymbols(Gamma1(13),2, sign=1).dimension()
        13
        sage: ModularSymbols(Gamma1(13),2, sign=-1).dimension()
        2
        sage: [ModularSymbols(Gamma1(7),k).dimension() for k in [2,3,4,5]]
        [5, 8, 12, 16]
        sage: ModularSymbols(Gamma1(5),11).dimension()
        20

    We create a space for `\Gamma_H(N)`::

        sage: G = GammaH(15,[4,13])
        sage: M = ModularSymbols(G,2)
        sage: M.decomposition()
        [
        Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 13] of weight 2 with sign 0 and over Rational Field,
        Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 13] of weight 2 with sign 0 and over Rational Field
        ]

    We create a space with character::

        sage: e = (DirichletGroup(13).0)^2
        sage: e.order()
        6
        sage: M = ModularSymbols(e, 2); M
        Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2
        sage: f = M.T(2).charpoly('x'); f
        x^4 + (-zeta6 - 1)*x^3 - 8*zeta6*x^2 + (10*zeta6 - 5)*x + 21*zeta6 - 21
        sage: f.factor()
        (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)^2

    We create a space with character over a larger base ring than the values of the character::

        sage: ModularSymbols(e, 2, base_ring = CyclotomicField(24))
        Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta24^4], sign 0, over Cyclotomic Field of order 24 and degree 8

    More examples of spaces with character::

        sage: e = DirichletGroup(5, RationalField()).gen(); e
        Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1

        sage: m = ModularSymbols(e, 2); m
        Modular Symbols space of dimension 2 and level 5, weight 2, character [-1], sign 0, over Rational Field

    ::

        sage: m.T(2).charpoly('x')
        x^2 - 1
        sage: m = ModularSymbols(e, 6); m.dimension()
        6
        sage: m.T(2).charpoly('x')
        x^6 - 873*x^4 - 82632*x^2 - 1860496

    We create a space of modular symbols with nontrivial character in
    characteristic 2.

    ::

        sage: G = DirichletGroup(13,GF(4,'a')); G
        Group of Dirichlet characters modulo 13 with values in Finite Field in a of size 2^2
        sage: e = G.list()[2]; e
        Dirichlet character modulo 13 of conductor 13 mapping 2 |--> a + 1
        sage: M = ModularSymbols(e,4); M
        Modular Symbols space of dimension 8 and level 13, weight 4, character [a + 1], sign 0, over Finite Field in a of size 2^2
        sage: M.basis()
        ([X*Y,(1,0)], [X*Y,(1,5)], [X*Y,(1,10)], [X*Y,(1,11)], [X^2,(0,1)], [X^2,(1,10)], [X^2,(1,11)], [X^2,(1,12)])
        sage: M.T(2).matrix()
        [    0     0     0     0     0     0     1     1]
        [    0     0     0     0     0     0     0     0]
        [    0     0     0     0     0 a + 1     1     a]
        [    0     0     0     0     0     1 a + 1     a]
        [    0     0     0     0 a + 1     0     1     1]
        [    0     0     0     0     0     a     1     a]
        [    0     0     0     0     0     0 a + 1     a]
        [    0     0     0     0     0     0     1     0]

    We illustrate the custom_init function, which can be used to make
    arbitrary changes to the modular symbols object before its
    presentation is computed::

        sage: ModularSymbols_clear_cache()
        sage: def custom_init(M):
        ....:     M.customize='hi'
        sage: M = ModularSymbols(1,12, custom_init=custom_init)
        sage: M.customize
        'hi'

    We illustrate the relation between custom_init and use_cache::

        sage: def custom_init(M):
        ....:     M.customize='hi2'
        sage: M = ModularSymbols(1,12, custom_init=custom_init)
        sage: M.customize
        'hi'
        sage: M = ModularSymbols(1,12, custom_init=custom_init, use_cache=False)
        sage: M.customize
        'hi2'

    TESTS:

    We test use_cache::

        sage: ModularSymbols_clear_cache()
        sage: M = ModularSymbols(11,use_cache=False)
        sage: sage.modular.modsym.modsym._cache
        {}
        sage: M = ModularSymbols(11,use_cache=True)
        sage: sage.modular.modsym.modsym._cache
        {(Congruence Subgroup Gamma0(11), 2, 0, Rational Field): <weakref at ...; to 'ModularSymbolsAmbient_wt2_g0_with_category' at ...>}
        sage: M is ModularSymbols(11,use_cache=True)
        True
        sage: M is ModularSymbols(11,use_cache=False)
        False
    """
    from . import ambient
    key = canonical_parameters(group, weight, sign, base_ring)

    if use_cache and key in _cache:
         M = _cache[key]()
         if not (M is None): return M

    (group, weight, sign, base_ring) = key

    M = None
    if arithgroup.is_Gamma0(group):
            if weight == 2:
                M = ambient.ModularSymbolsAmbient_wt2_g0(
                    group.level(),sign, base_ring, custom_init=custom_init)
            else:
                M = ambient.ModularSymbolsAmbient_wtk_g0(
                    group.level(), weight, sign, base_ring, custom_init=custom_init)

    elif arithgroup.is_Gamma1(group):

        M = ambient.ModularSymbolsAmbient_wtk_g1(group.level(),
                            weight, sign, base_ring, custom_init=custom_init)

    elif arithgroup.is_GammaH(group):

        M = ambient.ModularSymbolsAmbient_wtk_gamma_h(group,
                            weight, sign, base_ring, custom_init=custom_init)

    elif isinstance(group, tuple):
        eps = group[0]
        M = ambient.ModularSymbolsAmbient_wtk_eps(eps,
                            weight, sign, base_ring, custom_init=custom_init)

    if M is None:
        raise NotImplementedError("computation of requested space of modular symbols not defined or implemented")

    if use_cache:
        _cache[key] = weakref.ref(M)
    return M
Beispiel #10
0
    def is_gamma_h_equiv(self, other, G):
        """
        Return a pair (b, t), where b is True or False as self and other
        are equivalent under the action of G, and t is 1 or -1, as
        described below.

        Two cusps `u1/v1` and `u2/v2` are equivalent modulo
        Gamma_H(N) if and only if `v1 =  h*v2 (\mathrm{mod} N)` and
        `u1 =  h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` or
        `v1 = -h*v2 (mod N)` and
        `u1 = -h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` for some
        `h \in H`. Then t is 1 or -1 as c and c' fall into the
        first or second case, respectively.

        INPUT:


        -  ``other`` - Cusp

        -  ``G`` - a congruence subgroup Gamma_H(N)


        OUTPUT:


        -  ``bool`` - True if self and other are equivalent

        -  ``int`` - -1, 0, 1; extra info


        EXAMPLES::

            sage: x = Cusp(2,3)
            sage: y = Cusp(4,5)
            sage: x.is_gamma_h_equiv(y,GammaH(13,[2]))
            (True, 1)
            sage: x.is_gamma_h_equiv(y,GammaH(13,[5]))
            (False, 0)
            sage: x.is_gamma_h_equiv(y,GammaH(5,[]))
            (False, 0)
            sage: x.is_gamma_h_equiv(y,GammaH(23,[4]))
            (True, -1)

        Enumerating the cusps for a space of modular symbols uses this
        function.

        ::

            sage: G = GammaH(25,[6]) ; M = G.modular_symbols() ; M
            Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field
            sage: M.cusps()
            [37/75, 1/2, 31/125, 1/4, -2/5, 2/5, -1/5, 1/10, -3/10, 1/15, 7/15, 9/20]
            sage: len(M.cusps())
            12

        This is always one more than the associated space of weight 2 Eisenstein
        series.

        ::

            sage: G.dimension_eis(2)
            11
            sage: M.cuspidal_subspace()
            Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field
            sage: G.dimension_cusp_forms(2)
            0
        """
        from sage.modular.arithgroup.all import is_GammaH
        if not isinstance(other, Cusp):
            other = Cusp(other)
        if not is_GammaH(G):
            raise TypeError, "G must be a group GammaH(N)."

        H = G._list_of_elements_in_H()
        N = ZZ(G.level())
        u1 = self.__a
        v1 = self.__b
        u2 = other.__a
        v2 = other.__b
        g = v1.gcd(N)

        for h in H:
            v_tmp = (h*v1)%N
            u_tmp = (h*u2)%N
            if (v_tmp - v2)%N == 0 and (u_tmp - u1)%g == 0:
                return True, 1
            if (v_tmp + v2)%N == 0 and (u_tmp + u1)%g == 0:
                return True, -1
        return False, 0
Beispiel #11
0
def ModularForms(group=1,
                 weight=2,
                 base_ring=None,
                 eis_only=False,
                 use_cache=True,
                 prec=defaults.DEFAULT_PRECISION):
    r"""
    Create an ambient space of modular forms.

    INPUT:

    - ``group`` - A congruence subgroup or a Dirichlet character eps.

    - ``weight`` - int, the weight, which must be an integer >= 1.

    - ``base_ring`` - the base ring (ignored if group is a Dirichlet character)

    - ``eis_only`` - if True, compute only the Eisenstein part of the space.
      Only permitted (and only useful) in weight 1, where computing dimensions
      of cusp form spaces is expensive.

    Create using the command ModularForms(group, weight, base_ring)
    where group could be either a congruence subgroup or a Dirichlet
    character.

    EXAMPLES: First we create some spaces with trivial character::

        sage: ModularForms(Gamma0(11),2).dimension()
        2
        sage: ModularForms(Gamma0(1),12).dimension()
        2

    If we give an integer N for the congruence subgroup, it defaults to
    `\Gamma_0(N)`::

        sage: ModularForms(1,12).dimension()
        2
        sage: ModularForms(11,4)
        Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(11) of weight 4 over Rational Field

    We create some spaces for `\Gamma_1(N)`.

    ::

        sage: ModularForms(Gamma1(13),2)
        Modular Forms space of dimension 13 for Congruence Subgroup Gamma1(13) of weight 2 over Rational Field
        sage: ModularForms(Gamma1(13),2).dimension()
        13
        sage: [ModularForms(Gamma1(7),k).dimension() for k in [2,3,4,5]]
        [5, 7, 9, 11]
        sage: ModularForms(Gamma1(5),11).dimension()
        12

    We create a space with character::

        sage: e = (DirichletGroup(13).0)^2
        sage: e.order()
        6
        sage: M = ModularForms(e, 2); M
        Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 6 and degree 2
        sage: f = M.T(2).charpoly('x'); f
        x^3 + (-2*zeta6 - 2)*x^2 - 2*zeta6*x + 14*zeta6 - 7
        sage: f.factor()
        (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)

    We can also create spaces corresponding to the groups `\Gamma_H(N)` intermediate
    between `\Gamma_0(N)` and `\Gamma_1(N)`::

        sage: G = GammaH(30, [11])
        sage: M = ModularForms(G, 2); M
        Modular Forms space of dimension 20 for Congruence Subgroup Gamma_H(30) with H generated by [11] of weight 2 over Rational Field
        sage: M.T(7).charpoly().factor()  # long time (7s on sage.math, 2011)
        (x + 4) * x^2 * (x - 6)^4 * (x + 6)^4 * (x - 8)^7 * (x^2 + 4)

    More examples of spaces with character::

        sage: e = DirichletGroup(5, RationalField()).gen(); e
        Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1

        sage: m = ModularForms(e, 2); m
        Modular Forms space of dimension 2, character [-1] and weight 2 over Rational Field
        sage: m == loads(dumps(m))
        True
        sage: m.T(2).charpoly('x')
        x^2 - 1
        sage: m = ModularForms(e, 6); m.dimension()
        4
        sage: m.T(2).charpoly('x')
        x^4 - 917*x^2 - 42284

    This came up in a subtle bug (:trac:`5923`)::

        sage: ModularForms(gp(1), gap(12))
        Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field

    This came up in another bug (related to :trac:`8630`)::

        sage: chi = DirichletGroup(109, CyclotomicField(3)).0
        sage: ModularForms(chi, 2, base_ring = CyclotomicField(15))
        Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 over Cyclotomic Field of order 15 and degree 8

    We create some weight 1 spaces. Here modular symbol algorithms do not work.
    In some small examples we can prove using Riemann--Roch that there are no
    cusp forms anyway, so the entire space is Eisenstein::

        sage: M = ModularForms(Gamma1(11), 1); M
        Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(11) of weight 1 over Rational Field
        sage: M.basis()
        [
        1 + 22*q^5 + O(q^6),
        q + 4*q^5 + O(q^6),
        q^2 - 4*q^5 + O(q^6),
        q^3 - 5*q^5 + O(q^6),
        q^4 - 3*q^5 + O(q^6)
        ]
        sage: M.cuspidal_subspace().basis()
        [
        ]
        sage: M == M.eisenstein_subspace()
        True

    When this does not work (which happens as soon as the level is more than
    about 30), we use the Hecke stability algorithm of George Schaeffer::

        sage: M = ModularForms(Gamma1(57), 1); M # long time
        Modular Forms space of dimension 38 for Congruence Subgroup Gamma1(57) of weight 1 over Rational Field
        sage: M.cuspidal_submodule().basis() # long time
        [
        q - q^4 + O(q^6),
        q^3 - q^4 + O(q^6)
        ]

    The Eisenstein subspace in weight 1 can be computed quickly, without
    triggering the expensive computation of the cuspidal part::

        sage: E = EisensteinForms(Gamma1(59), 1); E # indirect doctest
        Eisenstein subspace of dimension 29 of Modular Forms space for Congruence Subgroup Gamma1(59) of weight 1 over Rational Field
        sage: (E.0 + E.2).q_expansion(40)
        1 + q^2 + 196*q^29 - 197*q^30 - q^31 + q^33 + q^34 + q^37 + q^38 - q^39 + O(q^40)

    """
    if isinstance(group, dirichlet.DirichletCharacter):
        if base_ring is None:
            base_ring = group.minimize_base_ring().base_ring()
    if base_ring is None:
        base_ring = rings.QQ

    if isinstance(group, dirichlet.DirichletCharacter) \
           or arithgroup.is_CongruenceSubgroup(group):
        level = group.level()
    else:
        level = group

    eis_only = bool(eis_only)
    key = canonical_parameters(group, level, weight, base_ring) + (eis_only, )

    if eis_only and weight != 1:
        raise ValueError("eis_only parameter only valid in weight 1")

    if use_cache and key in _cache:
        M = _cache[key]()
        if not (M is None):
            M.set_precision(prec)
            return M

    (level, group, weight, base_ring, eis_only) = key

    M = None
    if arithgroup.is_Gamma0(group):
        M = ModularFormsAmbient_g0_Q(group.level(), weight)
        if base_ring != rings.QQ:
            M = ambient_R.ModularFormsAmbient_R(M, base_ring)

    elif arithgroup.is_Gamma1(group):
        M = ModularFormsAmbient_g1_Q(group.level(), weight, eis_only)
        if base_ring != rings.QQ:
            M = ambient_R.ModularFormsAmbient_R(M, base_ring)

    elif arithgroup.is_GammaH(group):
        M = ModularFormsAmbient_gH_Q(group, weight, eis_only)
        if base_ring != rings.QQ:
            M = ambient_R.ModularFormsAmbient_R(M, base_ring)

    elif isinstance(group, dirichlet.DirichletCharacter):
        eps = group
        if eps.base_ring().characteristic() != 0:
            # TODO -- implement this
            # Need to add a lift_to_char_0 function for characters,
            # and need to still remember eps.
            raise NotImplementedError(
                "currently the character must be over a ring of characteristic 0."
            )
        eps = eps.minimize_base_ring()
        if eps.is_trivial():
            return ModularForms(eps.modulus(),
                                weight,
                                base_ring,
                                use_cache=use_cache,
                                prec=prec)
        M = ModularFormsAmbient_eps(eps, weight, eis_only=eis_only)
        if base_ring != eps.base_ring():
            M = M.base_extend(
                base_ring)  # ambient_R.ModularFormsAmbient_R(M, base_ring)

    if M is None:
        raise NotImplementedError(
            "computation of requested space of modular forms not defined or implemented"
        )

    M.set_precision(prec)
    _cache[key] = weakref.ref(M)
    return M