Ejemplo n.º 1
0
    def _dim_eisenstein(self):
        """
        Return the dimension of the Eisenstein subspace of this modular
        symbols space, computed using a dimension formula.

        EXAMPLES::

            sage: m = ModularForms(GammaH(13,[4]), 2); m
            Modular Forms space of dimension 3 for Congruence Subgroup Gamma_H(13) with H generated by [4] of weight 2 over Rational Field
            sage: m._dim_eisenstein()
            3

            sage: m = ModularForms(DirichletGroup(13).0,7); m
            Modular Forms space of dimension 8, character [zeta12] and weight 7 over Cyclotomic Field of order 12 and degree 4
            sage: m._dim_eisenstein()
            2
            sage: m._dim_cuspidal()
            6

        Test that :trac:`24030` is fixed::

            sage: ModularForms(GammaH(40, [21]), 1).dimension() # indirect doctest
            16
        """
        if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
            return self.group().dimension_eis(self.weight(), self.character())
        else:
            return self.group().dimension_eis(self.weight())
Ejemplo n.º 2
0
    def _dim_eisenstein(self):
        """
        Return the dimension of the Eisenstein subspace of this modular
        symbols space, computed using a dimension formula.

        EXAMPLES::

            sage: m = ModularForms(GammaH(13,[4]), 2); m
            Modular Forms space of dimension 3 for Congruence Subgroup Gamma_H(13) with H generated by [4] of weight 2 over Rational Field
            sage: m._dim_eisenstein()
            3

            sage: m = ModularForms(DirichletGroup(13).0,7); m
            Modular Forms space of dimension 8, character [zeta12] and weight 7 over Cyclotomic Field of order 12 and degree 4
            sage: m._dim_eisenstein()
            2
            sage: m._dim_cuspidal()
            6

        Test that :trac:`24030` is fixed::

            sage: ModularForms(GammaH(40, [21]), 1).dimension() # indirect doctest
            16
        """
        if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
            return self.group().dimension_eis(self.weight(), self.character())
        else:
            return self.group().dimension_eis(self.weight())
Ejemplo n.º 3
0
    def _dim_cuspidal(self):
        r"""
        Return the dimension of the cuspidal subspace of this ambient
        modular forms space.

        For weights `k \ge 2` this is computed using a
        dimension formula. For weight 1, it will trigger a computation of a
        basis of `q`-expansions using Schaeffer's algorithm, unless this space
        is a space of Eisenstein forms only, in which case we just return 0.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[3]), 2); m
            Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [3] of weight 2 over Rational Field
            sage: m._dim_cuspidal()
            1
            sage: m = ModularForms(DirichletGroup(389,CyclotomicField(4)).0,3); m._dim_cuspidal()
            64
            sage: m = ModularForms(GammaH(31, [7]), 1)
            sage: m._dim_cuspidal()
            1
            sage: m = ModularForms(GammaH(31, [7]), 1, eis_only=True)
            sage: m._dim_cuspidal()
            0
        """
        if self._eis_only:
            return 0
        if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
            return self.group().dimension_cusp_forms(self.weight(),
                                                     self.character())
        else:
            return self.group().dimension_cusp_forms(self.weight())
    def newform_decomposition(self, names=None):
        """
        Return the newforms of the simple subvarieties in the decomposition of
        self as a product of simple subvarieties, up to isogeny.

        OUTPUT:

        - an array of newforms

        EXAMPLES::

            sage: J0(81).newform_decomposition('a')
            [q - 2*q^4 + O(q^6), q - 2*q^4 + O(q^6), q + a0*q^2 + q^4 - a0*q^5 + O(q^6)]

            sage: J1(19).newform_decomposition('a')
            [q - 2*q^3 - 2*q^4 + 3*q^5 + O(q^6),
             q + a1*q^2 + (-1/9*a1^5 - 1/3*a1^4 - 1/3*a1^3 + 1/3*a1^2 - a1 - 1)*q^3 + (4/9*a1^5 + 2*a1^4 + 14/3*a1^3 + 17/3*a1^2 + 6*a1 + 2)*q^4 + (-2/3*a1^5 - 11/3*a1^4 - 10*a1^3 - 14*a1^2 - 15*a1 - 9)*q^5 + O(q^6)]
        """
        if self.dimension() == 0:
            return []
        G = self.group()
        if not (is_Gamma0(G) or is_Gamma1(G)):
            return [S.newform(names=names) for S in self.decomposition()]
        Gtype = G.parent()
        N = G.level()
        preans = [Newforms(Gtype(d), names=names) *
                  len(Integer(N/d).divisors()) for d in N.divisors()]
        ans = [newform for l in preans for newform in l]
        return ans
Ejemplo n.º 5
0
 def _dim_eisenstein(self):
     """
     Return the dimension of the Eisenstein subspace of this modular
     symbols space, computed using a dimension formula.
     
     EXAMPLES::
     
         sage: m = ModularForms(GammaH(13,[4]), 2); m
         Modular Forms space of dimension 3 for Congruence Subgroup Gamma_H(13) with H generated by [4] of weight 2 over Rational Field
         sage: m._dim_eisenstein()
         3 
     """
     try:
         return self.__the_dim_eisenstein
     except AttributeError:
         if self.weight() == 1:
             self.__the_dim_eisenstein = len(self.eisenstein_params())
         else:
             if arithgroup.is_Gamma1(
                     self.group()) and self.character() is not None:
                 self.__the_dim_eisenstein = self.group().dimension_eis(
                     self.weight(), self.character())
             else:
                 self.__the_dim_eisenstein = self.group().dimension_eis(
                     self.weight())
     return self.__the_dim_eisenstein
Ejemplo n.º 6
0
 def eisenstein_params(self):
     """
     Return parameters that define all Eisenstein series in self.
     
     OUTPUT: an immutable Sequence
     
     EXAMPLES::
     
         sage: m = ModularForms(Gamma0(22), 2)
         sage: v = m.eisenstein_params(); v
         [(Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 2), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 11), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 22)]
         sage: type(v)
         <class 'sage.structure.sequence.Sequence_generic'>
     """
     try:
         return self.__eisenstein_params
     except AttributeError:
         eps = self.character()
         if eps == None:
             if arithgroup.is_Gamma1(self.group()):
                 eps = self.level()
             else:
                 raise NotImplementedError
         params = eis_series.compute_eisenstein_params(eps, self.weight())
         self.__eisenstein_params = Sequence(params, immutable=True)
     return self.__eisenstein_params
Ejemplo n.º 7
0
    def newform_decomposition(self, names=None):
        """
        Return the newforms of the simple subvarieties in the decomposition of
        self as a product of simple subvarieties, up to isogeny.

        OUTPUT:

        - an array of newforms

        EXAMPLES::

            sage: J0(81).newform_decomposition('a')
            [q - 2*q^4 + O(q^6), q - 2*q^4 + O(q^6), q + a0*q^2 + q^4 - a0*q^5 + O(q^6)]

            sage: J1(19).newform_decomposition('a')
            [q - 2*q^3 - 2*q^4 + 3*q^5 + O(q^6),
             q + a1*q^2 + (-1/9*a1^5 - 1/3*a1^4 - 1/3*a1^3 + 1/3*a1^2 - a1 - 1)*q^3 + (4/9*a1^5 + 2*a1^4 + 14/3*a1^3 + 17/3*a1^2 + 6*a1 + 2)*q^4 + (-2/3*a1^5 - 11/3*a1^4 - 10*a1^3 - 14*a1^2 - 15*a1 - 9)*q^5 + O(q^6)]
        """
        if self.dimension() == 0:
            return []
        G = self.group()
        if not (is_Gamma0(G) or is_Gamma1(G)):
            return [S.newform(names=names) for S in self.decomposition()]
        Gtype = G.parent()
        N = G.level()
        preans = [
            Newforms(Gtype(d), names=names) * len((N // d).divisors())
            for d in N.divisors()
        ]
        return [newform for l in preans for newform in l]
Ejemplo n.º 8
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)
Ejemplo n.º 9
0
    def eisenstein_params(self):
        """
        Return parameters that define all Eisenstein series in self.

        OUTPUT: an immutable Sequence

        EXAMPLES::

            sage: m = ModularForms(Gamma0(22), 2)
            sage: v = m.eisenstein_params(); v
            [(Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 2), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 11), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 22)]
            sage: type(v)
            <class 'sage.structure.sequence.Sequence_generic'>
        """
        try:
            return self.__eisenstein_params
        except AttributeError:
            eps = self.character()
            if eps is None:
                if arithgroup.is_Gamma1(self.group()):
                    eps = self.level()
                else:
                    raise NotImplementedError
            params = eis_series.compute_eisenstein_params(eps, self.weight())
            self.__eisenstein_params = Sequence(params, immutable=True)
        return self.__eisenstein_params
Ejemplo n.º 10
0
    def _p_stabilize_parent_space(self, p, new_base_ring):
        r"""
        Return the space of Pollack-Stevens modular symbols of level
        `p N`, with changed base ring.  This is used internally when
        constructing the `p`-stabilization of a modular symbol.

        INPUT:

        - ``p`` -- prime number
        - ``new_base_ring`` -- the base ring of the result

        OUTPUT:

        The space of modular symbols of level `p N`, where `N` is the level
        of this space.

        EXAMPLES::

            sage: D = OverconvergentDistributions(2, 7)
            sage: M = PollackStevensModularSymbols(Gamma(13), coefficients=D)
            sage: M._p_stabilize_parent_space(7, M.base_ring())
            Space of overconvergent modular symbols for Congruence Subgroup
            Gamma(91) with sign 0 and values in Space of 7-adic distributions
            with k=2 action and precision cap 20

            sage: D = OverconvergentDistributions(4, 17)
            sage: M = PollackStevensModularSymbols(Gamma1(3), coefficients=D)
            sage: M._p_stabilize_parent_space(17, Qp(17))
            Space of overconvergent modular symbols for Congruence
            Subgroup Gamma1(51) with sign 0 and values in Space of
            17-adic distributions with k=4 action and precision cap 20
        """
        N = self.level()
        if N % p == 0:
            raise ValueError("the level is not prime to p")
        from sage.modular.arithgroup.all import (Gamma, is_Gamma, Gamma0,
                                                 is_Gamma0, Gamma1, is_Gamma1)
        G = self.group()
        if is_Gamma0(G):
            G = Gamma0(N * p)
        elif is_Gamma1(G):
            G = Gamma1(N * p)
        elif is_Gamma(G):
            G = Gamma(N * p)
        else:
            raise NotImplementedError
        return PollackStevensModularSymbols(
            G,
            coefficients=self.coefficient_module().change_ring(new_base_ring),
            sign=self.sign())
Ejemplo n.º 11
0
    def _p_stabilize_parent_space(self, p, new_base_ring):
        r"""
        Return the space of Pollack-Stevens modular symbols of level
        `p N`, with changed base ring.  This is used internally when
        constructing the `p`-stabilization of a modular symbol.

        INPUT:

        - ``p`` -- prime number
        - ``new_base_ring`` -- the base ring of the result

        OUTPUT:

        The space of modular symbols of level `p N`, where `N` is the level
        of this space.

        EXAMPLES::

            sage: D = OverconvergentDistributions(2, 7)
            sage: M = PollackStevensModularSymbols(Gamma(13), coefficients=D)
            sage: M._p_stabilize_parent_space(7, M.base_ring())
            Space of overconvergent modular symbols for Congruence Subgroup
            Gamma(91) with sign 0 and values in Space of 7-adic distributions
            with k=2 action and precision cap 20

            sage: D = OverconvergentDistributions(4, 17)
            sage: M = PollackStevensModularSymbols(Gamma1(3), coefficients=D)
            sage: M._p_stabilize_parent_space(17, Qp(17))
            Space of overconvergent modular symbols for Congruence
            Subgroup Gamma1(51) with sign 0 and values in Space of
            17-adic distributions with k=4 action and precision cap 20
        """
        N = self.level()
        if N % p == 0:
            raise ValueError("the level is not prime to p")
        from sage.modular.arithgroup.all import (Gamma, is_Gamma, Gamma0,
                                                 is_Gamma0, Gamma1, is_Gamma1)
        G = self.group()
        if is_Gamma0(G):
            G = Gamma0(N * p)
        elif is_Gamma1(G):
            G = Gamma1(N * p)
        elif is_Gamma(G):
            G = Gamma(N * p)
        else:
            raise NotImplementedError
        return PollackStevensModularSymbols(G, coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign())
Ejemplo n.º 12
0
    def _dim_new_cuspidal(self):
        """
        Return the dimension of the new cuspidal subspace, computed using
        dimension formulas.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[2]), 2); m._dim_new_cuspidal()
            1
        """
        try:
            return self.__the_dim_new_cuspidal
        except AttributeError:
            if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
                self.__the_dim_new_cuspidal = self.group().dimension_new_cusp_forms(self.weight(), self.character())
            else:
                self.__the_dim_new_cuspidal = self.group().dimension_new_cusp_forms(self.weight())
        return self.__the_dim_new_cuspidal
Ejemplo n.º 13
0
    def _dim_new_cuspidal(self):
        """
        Return the dimension of the new cuspidal subspace, computed using
        dimension formulas.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[2]), 2); m._dim_new_cuspidal()
            1
        """
        try:
            return self.__the_dim_new_cuspidal
        except AttributeError:
            if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
                self.__the_dim_new_cuspidal = self.group().dimension_new_cusp_forms(self.weight(), self.character())
            else:
                self.__the_dim_new_cuspidal = self.group().dimension_new_cusp_forms(self.weight())
        return self.__the_dim_new_cuspidal
Ejemplo n.º 14
0
    def _dim_cuspidal(self):
        """
        Return the dimension of the cuspidal subspace of this ambient
        modular forms space, computed using a dimension formula.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[4]), 2); m
            Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [4] of weight 2 over Rational Field
            sage: m._dim_cuspidal()
            1
        """
        try:
            return self.__the_dim_cuspidal
        except AttributeError:
            if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
               self.__the_dim_cuspidal = self.group().dimension_cusp_forms(self.weight(), self.character())
            else:
               self.__the_dim_cuspidal = self.group().dimension_cusp_forms(self.weight())
        return self.__the_dim_cuspidal
Ejemplo n.º 15
0
    def _dim_cuspidal(self):
        """
        Return the dimension of the cuspidal subspace of this ambient
        modular forms space, computed using a dimension formula.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[4]), 2); m
            Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [4] of weight 2 over Rational Field
            sage: m._dim_cuspidal()
            1
        """
        try:
            return self.__the_dim_cuspidal
        except AttributeError:
            if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
               self.__the_dim_cuspidal = self.group().dimension_cusp_forms(self.weight(), self.character())
            else:
               self.__the_dim_cuspidal = self.group().dimension_cusp_forms(self.weight())
        return self.__the_dim_cuspidal
Ejemplo n.º 16
0
    def _dim_new_cuspidal(self):
        """
        Return the dimension of the new cuspidal subspace, computed using
        dimension formulas.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[2]), 2); m._dim_new_cuspidal()
            1
            sage: m = ModularForms(DirichletGroup(33).0,7); m
            Modular Forms space of dimension 26, character [-1, 1] and weight 7 over Rational Field
            sage: m._dim_new_cuspidal()
            20
            sage: m._dim_cuspidal()
            22
        """
        if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
            return self.group().dimension_new_cusp_forms(self.weight(), self.character())
        else:
            return self.group().dimension_new_cusp_forms(self.weight())
Ejemplo n.º 17
0
    def _dim_new_cuspidal(self):
        """
        Return the dimension of the new cuspidal subspace, computed using
        dimension formulas.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[2]), 2); m._dim_new_cuspidal()
            1
            sage: m = ModularForms(DirichletGroup(33).0,7); m
            Modular Forms space of dimension 26, character [-1, 1] and weight 7 over Rational Field
            sage: m._dim_new_cuspidal()
            20
            sage: m._dim_cuspidal()
            22
        """
        if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
            return self.group().dimension_new_cusp_forms(self.weight(), self.character())
        else:
            return self.group().dimension_new_cusp_forms(self.weight())
Ejemplo n.º 18
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)
Ejemplo n.º 19
0
    def _dim_cuspidal(self):
        """
        Return the dimension of the cuspidal subspace of this ambient
        modular forms space, computed using a dimension formula.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[3]), 2); m
            Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [3] of weight 2 over Rational Field
            sage: m._dim_cuspidal()
            1
            sage: m = ModularForms(DirichletGroup(389,CyclotomicField(4)).0,3); m._dim_cuspidal()
            64
        """
        if self._eis_only:
            return 0
        if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
            if self.weight() != 1:
                return self.group().dimension_cusp_forms(self.weight(), self.character())
            else:
                return weight1.dimension_cusp_forms(self.character())
        else:
           return self.group().dimension_cusp_forms(self.weight())
Ejemplo n.º 20
0
    def _dim_eisenstein(self):
        """
        Return the dimension of the Eisenstein subspace of this modular
        symbols space, computed using a dimension formula.

        EXAMPLES::

            sage: m = ModularForms(GammaH(13,[4]), 2); m
            Modular Forms space of dimension 3 for Congruence Subgroup Gamma_H(13) with H generated by [4] of weight 2 over Rational Field
            sage: m._dim_eisenstein()
            3
        """
        try:
            return self.__the_dim_eisenstein
        except AttributeError:
            if self.weight() == 1:
                self.__the_dim_eisenstein = len(self.eisenstein_params())
            else:
                if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
                    self.__the_dim_eisenstein = self.group().dimension_eis(self.weight(), self.character())
                else:
                    self.__the_dim_eisenstein = self.group().dimension_eis(self.weight())
        return self.__the_dim_eisenstein
Ejemplo n.º 21
0
    def _dim_cuspidal(self):
        """
        Return the dimension of the cuspidal subspace of this ambient
        modular forms space, computed using a dimension formula.

        EXAMPLES::

            sage: m = ModularForms(GammaH(11,[3]), 2); m
            Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [3] of weight 2 over Rational Field
            sage: m._dim_cuspidal()
            1
            sage: m = ModularForms(DirichletGroup(389,CyclotomicField(4)).0,3); m._dim_cuspidal()
            64
        """
        if self._eis_only:
            return 0
        if arithgroup.is_Gamma1(self.group()) and self.character() is not None:
            if self.weight() != 1:
                return self.group().dimension_cusp_forms(
                    self.weight(), self.character())
            else:
                return weight1.dimension_cusp_forms(self.character())
        else:
            return self.group().dimension_cusp_forms(self.weight())
Ejemplo n.º 22
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
Ejemplo n.º 23
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
Ejemplo n.º 24
0
    def multiple_of_order_using_frobp(self, maxp=None):
        """
        Return a multiple of the order of this torsion group.

        In the `Gamma_0` case, the multiple is computed using characteristic
        polynomials of Hecke operators of odd index not dividing the level. In
        the `Gamma_1` case, the multiple is computed by expressing the
        frobenius polynomial in terms of the characteristic polynomial of left
        multiplication by `a_p` for odd primes p not dividing the level.

        INPUT:


        -  ``maxp`` - (default: None) If maxp is None (the
           default), return gcd of best bound computed so far with bound
           obtained by computing GCD's of orders modulo p until this gcd
           stabilizes for 3 successive primes. If maxp is given, just use all
           primes up to and including maxp.


        EXAMPLES::

            sage: J = J0(11)
            sage: G = J.rational_torsion_subgroup()
            sage: G.multiple_of_order_using_frobp(11)
            5

        Increasing maxp may yield a tighter bound. If maxp=None, then Sage
        will use more primes until the multiple stabilizes for 3 successive
        primes.  ::

            sage: J = J0(389)
            sage: G = J.rational_torsion_subgroup(); G
            Torsion subgroup of Abelian variety J0(389) of dimension 32
            sage: G.multiple_of_order_using_frobp()
            97
            sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,11)]
            [92645296242160800, 7275, 291]
            sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,13)]
            [92645296242160800, 7275, 291, 97]
            sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,19)]
            [92645296242160800, 7275, 291, 97, 97, 97]

        We can compute the multiple of order of the torsion subgroup for Gamma0
        and Gamma1 varieties, and their products. ::

            sage: A = J0(11) * J0(33)
            sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
            1000

            sage: A = J1(23)
            sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
            9406793
            sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp(maxp=50)
            408991

            sage: A = J1(19) * J0(21)
            sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
            35064

        The next example illustrates calling this function with a larger
        input and how the result may be cached when maxp is None::

            sage: T = J0(43)[1].rational_torsion_subgroup()
            sage: T.multiple_of_order_using_frobp()
            14
            sage: T.multiple_of_order_using_frobp(50)
            7
            sage: T.multiple_of_order_using_frobp()
            7

        This function is not implemented for general congruence subgroups
        unless the dimension is zero. ::

            sage: A = JH(13,[2]); A
            Abelian variety J0(13) of dimension 0
            sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
            1

            sage: A = JH(15, [2]); A
            Abelian variety JH(15,[2]) of dimension 1
            sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
            Traceback (most recent call last):
            ...
            NotImplementedError: torsion multiple only implemented for Gamma0 and Gamma1
        """
        if maxp is None:
            try:
                return self.__multiple_of_order_using_frobp
            except AttributeError:
                pass
        A = self.abelian_variety()
        if A.dimension() == 0:
            T = ZZ(1)
            self.__multiple_of_order_using_frobp = T
            return T
        if not all((is_Gamma0(G) or is_Gamma1(G) for G in A.groups())):
            raise NotImplementedError("torsion multiple only implemented for Gamma0 and Gamma1")

        bnd = ZZ(0)
        N = A.level()
        cnt = 0
        if maxp is None:
            X = Primes()
        else:
            X = prime_range(maxp+1)
        for p in X:
            if (2*N) % p == 0:
                continue

            if (len(A.groups()) == 1 and is_Gamma0(A.groups()[0])):
                f = A.hecke_polynomial(p)
                b = ZZ(f(p+1))
            else:
                from .constructor import AbelianVariety
                D = [AbelianVariety(f) for f in
                     A.newform_decomposition('a')]
                b = 1
                for simple in D:
                    G = simple.newform_level()[1]
                    if is_Gamma0(G):
                        f = simple.hecke_polynomial(p)
                        b *= ZZ(f(p+1))
                    else:
                        f = simple.newform('a')
                        Kf = f.base_ring()
                        eps = f.character()
                        Qe = eps.base_ring()

                        if Kf != QQ:
                            # relativize number fields to compute charpoly of
                            # left multiplication of ap on Kf as a Qe-vector
                            # space.
                            Lf = Kf.relativize(Qe.gen(), 'a')
                            to_Lf = Lf.structure()[1]

                            name = Kf._names[0]
                            ap = to_Lf(f.modular_symbols(1).eigenvalue(p, name))

                            G_ps = ap.matrix().charpoly()
                            b *= ZZ(Qe(G_ps(1 + to_Lf(eps(p))*p)).norm())
                        else:
                            ap = f.modular_symbols(1).eigenvalue(p)
                            b *= ZZ(1 + eps(p)*p - ap)

            if bnd == 0:
                bnd = b
            else:
                bnd_last = bnd
                bnd = ZZ(gcd(bnd, b))
                if bnd == bnd_last:
                    cnt += 1
                else:
                    cnt = 0
                if maxp is None and cnt >= 2:
                    break

        # The code below caches the computed bound and
        # will be used if this function is called
        # again with maxp equal to None (the default).
        if maxp is None:
            # maxp is None but self.__multiple_of_order_using_frobp  is
            # not set, since otherwise we would have immediately
            # returned at the top of this function
            self.__multiple_of_order_using_frobp = bnd
        else:
            # maxp is given -- record new info we get as
            # a gcd...
            try:
                self.__multiple_of_order_using_frobp = \
                        gcd(self.__multiple_of_order_using_frobp, bnd)
            except AttributeError:
                # ... except in the case when
                # self.__multiple_of_order_using_frobp was never set.  In this
                # case, we just set it as long as the gcd stabilized for 3 in a
                # row.
                if cnt >= 2:
                    self.__multiple_of_order_using_frobp = bnd
        return bnd
Ejemplo n.º 25
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")
Ejemplo n.º 26
0
def canonical_parameters(group, level, weight, base_ring):
    """
    Given a group, level, weight, and base_ring as input by the user,
    return a canonicalized version of them, where level is a Sage
    integer, group really is a group, weight is a Sage integer, and
    base_ring a Sage ring. Note that we can't just get the level from
    the group, because we have the convention that the character for
    Gamma1(N) is None (which makes good sense).

    INPUT:


    -  ``group`` - int, long, Sage integer, group,
       dirichlet character, or

    -  ``level`` - int, long, Sage integer, or group

    -  ``weight`` - coercible to Sage integer

    -  ``base_ring`` - commutative Sage ring


    OUTPUT:


    -  ``level`` - Sage integer

    -  ``group`` - congruence subgroup

    -  ``weight`` - Sage integer

    -  ``ring`` - commutative Sage ring


    EXAMPLES::

        sage: from sage.modular.modform.constructor import canonical_parameters
        sage: v = canonical_parameters(5, 5, int(7), ZZ); v
        (5, Congruence Subgroup Gamma0(5), 7, Integer Ring)
        sage: type(v[0]), type(v[1]), type(v[2]), type(v[3])
        (<type 'sage.rings.integer.Integer'>,
         <class 'sage.modular.arithgroup.congroup_gamma0.Gamma0_class_with_category'>,
         <type 'sage.rings.integer.Integer'>,
         <type 'sage.rings.integer_ring.IntegerRing_class'>)
        sage: canonical_parameters( 5, 7, 7, ZZ )
        Traceback (most recent call last):
        ...
        ValueError: group and level do not match.
    """
    weight = rings.Integer(weight)
    if weight <= 0:
        raise NotImplementedError, "weight must be at least 1"

    if isinstance(group, dirichlet.DirichletCharacter):
        if ( group.level() != rings.Integer(level) ):
            raise ValueError, "group.level() and level do not match."
        group = group.minimize_base_ring()
        level = rings.Integer(level)

    elif arithgroup.is_CongruenceSubgroup(group):
        if ( rings.Integer(level) != group.level() ):
            raise ValueError, "group.level() and level do not match."
        # normalize the case of SL2Z
        if arithgroup.is_SL2Z(group) or \
           arithgroup.is_Gamma1(group) and group.level() == rings.Integer(1):
            group = arithgroup.Gamma0(rings.Integer(1))

    elif group is None:
        pass

    else:
        try:
            m = rings.Integer(group)
        except TypeError:
            raise TypeError, "group of unknown type."
        level = rings.Integer(level)
        if ( m != level ):
            raise ValueError, "group and level do not match."
        group = arithgroup.Gamma0(m)

    if not is_CommutativeRing(base_ring):
        raise TypeError, "base_ring (=%s) must be a commutative ring"%base_ring

    # it is *very* important to include the level as part of the data
    # that defines the key, since dirichlet characters of different
    # levels can compare equal, but define much different modular
    # forms spaces.
    return level, group, weight, base_ring
Ejemplo n.º 27
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
Ejemplo n.º 28
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