Space of boundary modular symbols - Modular Symbols

Skip to content
Back to top
View this page
Edit this page

# Space of boundary modular symbols

Used mainly for computing the cuspidal subspace of modular symbols. The space of boundary symbols of sign 0 is isomorphic as a Hecke module to the dual of the space of Eisenstein series, but this does not give a useful method of computing Eisenstein series, since there is no easy way to extract the constant terms.

We represent boundary modular symbols as a sum of Manin symbols of the form \([P, u/v]\), where \(u/v\) is a cusp for our group \(G\). The group of boundary modular symbols naturally embeds into a vector space \(B_k(G)\) (see Stein, section 8.4, or Merel, section 1.4, where this space is called \(\CC[\Gamma \backslash \QQ]_k\), for a definition), which is a finite dimensional \(\QQ\) vector space, of dimension equal to the number of cusps for \(G\) (if \(k\) is even), or the number of regular cusps (if \(k\) is odd). The embedding takes \([P, u/v]\) to \(P(u,v)\cdot [(u,v)]\). We represent the basis vectors by pairs \([(u,v)]\) with u, v coprime. On \(B_k(G)\), we have the relations

\[[\gamma \cdot (u,v)] = [(u,v)]\]

for all \(\gamma \in G\) and

\[[(\lambda u, \lambda v)] = \operatorname{sign}(\lambda)^k [(u,v)]\]

for all \(\lambda \in \QQ^\times\).

It’s possible for these relations to kill a class, i.e., for a pair \([(u,v)]\) to be 0. For example, when \(N=4\) and \(k=3\) then \((-1,-2)\) is equivalent mod \(\Gamma_1(4)\) to \((1,2)\) since \(2=-2 \bmod 4\) and \(1=-1 \bmod 2\). But since \(k\) is odd, \([(-1,-2)]\) is also equivalent to \(-[(1,2)]\). Thus this symbol is equivalent to its negative, hence 0 (notice that this wouldn’t be the case in characteristic 2). This happens for any irregular cusp when the weight is odd; there are no irregular cusps on \(\Gamma_1(N)\) except when \(N = 4\), but there can be more on \(\Gamma_H\) groups. See also prop 2.30 of Stein’s Ph.D. thesis.

In addition, in the case that our space is of sign \(\sigma = 1\) or \(-1\), we also have the relation \([(-u,v)] = \sigma \cdot [(u,v)]\). This relation can also combine with the above to kill a cusp class - for instance, take (u,v) = (1,3) for \(\Gamma_1(5)\). Then since the cusp \(\tfrac{1}{3}\) is \(\Gamma_1(5)\)-equivalent to the cusp \(-\tfrac{1}{3}\), we have that \([(1,3)] = [(-1,3)]\). Now, on the minus subspace, we also have that \([(-1,3)] = -[(1,3)]\), which means this class must vanish. Notice that this cannot be used to show that \([(1,0)]\) or \([(0,1)]\) is 0.

Note

Special care must be taken when working with the images of the cusps 0 and \(\infty\) in \(B_k(G)\). For all cusps except 0 and \(\infty\), multiplying the cusp by -1 corresponds to taking \([(u,v)]\) to \([(-u,v)]\) in \(B_k(G)\). This means that \([(u,v)]\) is equivalent to \([(-u,v)]\) whenever \(\tfrac{u}{v}\) is equivalent to \(-\tfrac{u}{v}\), except in the case of 0 and \(\infty\). We have the following conditions for \([(1,0)]\) and \([(0,1)]\):

- \([(0,1)] = \sigma \cdot [(0,1)]\), so \([(0,1)]\) is 0 exactly when \(\sigma = -1\).

- \([(1,0)] = \sigma \cdot [(-1,0)]\) and \([(1,0)] = (-1)^k [(-1,0)]\), so \([(1,0)] = 0\) whenever \(\sigma \ne (-1)^k\).

Note

For all the spaces of boundary symbols below, no work is done to determine the cusps for G at creation time. Instead, cusps are added as they are discovered in the course of computation. As a result, the rank of a space can change as a computation proceeds.

REFERENCES:

- Merel, “Universal Fourier expansions of modular forms.” Springer LNM 1585 (1994), pg. 59-95.

- Stein, “Modular Forms, a computational approach.” AMS (2007).

class sage.modular.modsym.boundary.BoundarySpace(group=Modular Group SL(2, Z), weight=2, sign=0, base_ring=Rational Field, character=None)

  Bases: `HeckeModule_generic`

  Space of boundary symbols for a congruence subgroup of SL_2(Z).

  This class is an abstract base class, so only derived classes should be instantiated.

  INPUT:

  - `weight` – integer; the weight

  - `group` – arithgroup.congroup_generic.CongruenceSubgroup, a congruence subgroup

  - `sign` – integer; either -1, 0, or 1

  - `base_ring` – commutative ring (defaults to the rational numbers)

  EXAMPLES:

  Sage

      sage: B = ModularSymbols(Gamma0(11),2).boundary_space()
      sage: isinstance(B, sage.modular.modsym.boundary.BoundarySpace)
      True
      sage: B == loads(dumps(B))
      True

  Python

      >>> from sage.all import *
      >>> B = ModularSymbols(Gamma0(Integer(11)),Integer(2)).boundary_space()
      >>> isinstance(B, sage.modular.modsym.boundary.BoundarySpace)
      True
      >>> B == loads(dumps(B))
      True

  character()

    Return the Dirichlet character associated to this space of boundary modular symbols.

    EXAMPLES:

    Sage

        sage: ModularSymbols(DirichletGroup(7).0, 6).boundary_space().character()
        Dirichlet character modulo 7 of conductor 7 mapping 3 |--> zeta6

    Python

        >>> from sage.all import *
        >>> ModularSymbols(DirichletGroup(Integer(7)).gen(0), Integer(6)).boundary_space().character()
        Dirichlet character modulo 7 of conductor 7 mapping 3 |--> zeta6

  free_module()

    Return the underlying free module for `self`.

    EXAMPLES:

    Sage

        sage: B = ModularSymbols(Gamma1(7), 5, sign=-1).boundary_space()
        sage: B.free_module()
        Sparse vector space of dimension 0 over Rational Field
        sage: x = B(Cusp(0)) ; y = B(Cusp(1/7)) ; B.free_module()
        Sparse vector space of dimension 1 over Rational Field

    Python

        >>> from sage.all import *
        >>> B = ModularSymbols(Gamma1(Integer(7)), Integer(5), sign=-Integer(1)).boundary_space()
        >>> B.free_module()
        Sparse vector space of dimension 0 over Rational Field
        >>> x = B(Cusp(Integer(0))) ; y = B(Cusp(Integer(1)/Integer(7))) ; B.free_module()
        Sparse vector space of dimension 1 over Rational Field

  gen(i=0)

    Return the i-th generator of this space.

    EXAMPLES:

    Sage

        sage: B = ModularSymbols(Gamma0(24), 4).boundary_space()
        sage: B.gen(0)
        Traceback (most recent call last):
        ...
        ValueError: only 0 generators known for
        Space of Boundary Modular Symbols for
        Congruence Subgroup Gamma0(24) of weight 4 over Rational Field
        sage: B(Cusp(1/3))
        [1/3]
        sage: B.gen(0)
        [1/3]

    Python

        >>> from sage.all import *
        >>> B = ModularSymbols(Gamma0(Integer(24)), Integer(4)).boundary_space()
        >>> B.gen(Integer(0))
        Traceback (most recent call last):
        ...
        ValueError: only 0 generators known for
        Space of Boundary Modular Symbols for
        Congruence Subgroup Gamma0(24) of weight 4 over Rational Field
        >>> B(Cusp(Integer(1)/Integer(3)))
        [1/3]
        >>> B.gen(Integer(0))
        [1/3]

  group()

    Return the congruence subgroup associated to this space of boundary modular symbols.

    EXAMPLES:

    Sage

        sage: ModularSymbols(GammaH(14,[9]), 2).boundary_space().group()
        Congruence Subgroup Gamma_H(14) with H generated by [9]

    Python

        >>> from sage.all import *
        >>> ModularSymbols(GammaH(Integer(14),[Integer(9)]), Integer(2)).boundary_space().group()
        Congruence Subgroup Gamma_H(14) with H generated by [9]

  is_ambient()

    Return `True` if `self` is a space of boundary symbols associated to an ambient space of modular symbols.

    EXAMPLES:

    Sage

        sage: M = ModularSymbols(Gamma1(6), 4)
        sage: M.is_ambient()
        True
        sage: M.boundary_space().is_ambient()
        True

    Python

        >>> from sage.all import *
        >>> M = ModularSymbols(Gamma1(Integer(6)), Integer(4))
        >>> M.is_ambient()
        True
        >>> M.boundary_space().is_ambient()
        True

  rank()

    The rank of the space generated by boundary symbols that have been found so far in the course of computing the boundary map.

    Warning

    This number may change as more elements are coerced into this space!! (This is an implementation detail that will likely change.)

    EXAMPLES:

    Sage

        sage: M = ModularSymbols(Gamma0(72), 2) ; B = M.boundary_space()
        sage: B.rank()
        0
        sage: _ = [ B(x) for x in M.basis() ]
        sage: B.rank()
        16

    Python

        >>> from sage.all import *
        >>> M = ModularSymbols(Gamma0(Integer(72)), Integer(2)) ; B = M.boundary_space()
        >>> B.rank()
        0
        >>> _ = [ B(x) for x in M.basis() ]
        >>> B.rank()
        16

    Test that Issue #7837 is fixed:

    Sage

        sage: ModularSymbols(Gamma1(4),7).boundary_map().codomain().dimension()
        2
        sage: ModularSymbols(Gamma1(4),7, sign=1).boundary_map().codomain().dimension()
        1
        sage: ModularSymbols(Gamma1(4),7, sign=-1).boundary_map().codomain().dimension()
        1

    [Python]

        >>> from sage.all import *
        >>> ModularSymbols(Gamma1(Integer(4)),Integer(7)).boundary_map().codomain().dimension()
        2
        >>> ModularSymbols(Gamma1(Integer(4)),Integer(7), sign=Integer(1)).boundary_map().codomain().dimension()
        1
        >>> ModularSymbols(Gamma1(Integer(4)),Integer(7), sign=-Integer(1)).boundary_map().codomain().dimension()
        1

  sign()

    Return the sign of the complex conjugation involution on this space of boundary modular symbols.

    EXAMPLES:

    Sage

        sage: ModularSymbols(13,2,sign=-1).boundary_space().sign()
        -1

    Python

        >>> from sage.all import *
        >>> ModularSymbols(Integer(13),Integer(2),sign=-Integer(1)).boundary_space().sign()
        -1

  weight()

    Return the weight of this space of boundary modular symbols.

    EXAMPLES:

    Sage

        sage: ModularSymbols(Gamma1(9), 5).boundary_space().weight()
        5

    Python

        >>> from sage.all import *
        >>> ModularSymbols(Gamma1(Integer(9)), Integer(5)).boundary_space().weight()
        5

class sage.modular.modsym.boundary.BoundarySpaceElement(parent, x)

  Bases: `HeckeModuleElement`

  Create a boundary symbol.

  INPUT:

  - `parent` – BoundarySpace; a space of boundary modular symbols

  - `x` – dictionary with integer keys and values in the base field of parent

  EXAMPLES:

  Sage

      sage: B = ModularSymbols(Gamma0(32), sign=-1).boundary_space()
      sage: B(Cusp(1,8))
      [1/8]
      sage: B.0
      [1/8]
      sage: type(B.0)
      <class 'sage.modular.modsym.boundary.BoundarySpaceElement'>

  Python

      >>> from sage.all import *
      >>> B = ModularSymbols(Gamma0(Integer(32)), sign=-Integer(1)).boundary_space()
      >>> B(Cusp(Integer(1),Integer(8)))
      [1/8]
      >>> B.gen(0)
      [1/8]
      >>> type(B.gen(0))
      <class 'sage.modular.modsym.boundary.BoundarySpaceElement'>

  coordinate_vector()

    Return `self` as a vector on the \(\QQ\)-vector space with basis `self.parent()._known_cusps()`.

    EXAMPLES:

    Sage

        sage: B = ModularSymbols(18,4,sign=1).boundary_space()
        sage: x = B(Cusp(1/2)) ; x
        [1/2]
        sage: x.coordinate_vector()
        (1)
        sage: ((18/5)*x).coordinate_vector()
        (18/5)
        sage: B(Cusp(0))
        [0]
        sage: x.coordinate_vector()
        (1)
        sage: x = B(Cusp(1/2)) ; x
        [1/2]
        sage: x.coordinate_vector()
        (1, 0)

    Python

        >>> from sage.all import *
        >>> B = ModularSymbols(Integer(18),Integer(4),sign=Integer(1)).boundary_space()
        >>> x = B(Cusp(Integer(1)/Integer(2))) ; x
        [1/2]
        >>> x.coordinate_vector()
        (1)
        >>> ((Integer(18)/Integer(5))*x).coordinate_vector()
        (18/5)
        >>> B(Cusp(Integer(0)))
        [0]
        >>> x.coordinate_vector()
        (1)
        >>> x = B(Cusp(Integer(1)/Integer(2))) ; x
        [1/2]
        >>> x.coordinate_vector()
        (1, 0)

class sage.modular.modsym.boundary.BoundarySpace_wtk_eps(eps, weight, sign=0)

  Bases: `BoundarySpace`

  Space of boundary modular symbols with given weight, character, and sign.

  INPUT:

  - `eps` – dirichlet.DirichletCharacter, the

      “Nebentypus” character

  - `weight` – integer; the weight = 2

  - `sign` – integer; either -1, 0, or 1

  EXAMPLES:

  Sage

      sage: B = ModularSymbols(DirichletGroup(6).0, 4).boundary_space() ; B
      Boundary Modular Symbols space of level 6, weight 4, character [-1] and dimension 0 over Rational Field
      sage: type(B)
      <class 'sage.modular.modsym.boundary.BoundarySpace_wtk_eps_with_category'>
      sage: B == loads(dumps(B))
      True

  Python

      >>> from sage.all import *
      >>> B = ModularSymbols(DirichletGroup(Integer(6)).gen(0), Integer(4)).boundary_space() ; B
      Boundary Modular Symbols space of level 6, weight 4, character [-1] and dimension 0 over Rational Field
      >>> type(B)
      <class 'sage.modular.modsym.boundary.BoundarySpace_wtk_eps_with_category'>
      >>> B == loads(dumps(B))
      True

class sage.modular.modsym.boundary.BoundarySpace_wtk_g0(level, weight, sign, F)

  Bases: `BoundarySpace`

  Initialize a space of boundary symbols of weight k for Gamma_0(N) over base field F.

  INPUT:

  - `level` – integer; the level

  - `weight` – integer; weight = 2

  - `sign` – integer; either -1, 0, or 1

  - `F` – field

  EXAMPLES:

  Sage

      sage: B = ModularSymbols(Gamma0(2), 5).boundary_space()
      sage: type(B)
      <class 'sage.modular.modsym.boundary.BoundarySpace_wtk_g0_with_category'>
      sage: B == loads(dumps(B))
      True

  Python

      >>> from sage.all import *
      >>> B = ModularSymbols(Gamma0(Integer(2)), Integer(5)).boundary_space()
      >>> type(B)
      <class 'sage.modular.modsym.boundary.BoundarySpace_wtk_g0_with_category'>
      >>> B == loads(dumps(B))
      True

class sage.modular.modsym.boundary.BoundarySpace_wtk_g1(level, weight, sign, F)

  Bases: `BoundarySpace`

  Initialize a space of boundary modular symbols for Gamma1(N).

  INPUT:

  - `level` – integer; the level

  - `weight` – integer; the weight = 2

  - `sign` – integer; either -1, 0, or 1

  - `F` – base ring

  EXAMPLES:

  Sage

      sage: from sage.modular.modsym.boundary import BoundarySpace_wtk_g1
      sage: B = BoundarySpace_wtk_g1(17, 2, 0, QQ) ; B
      Boundary Modular Symbols space for Gamma_1(17) of weight 2 over Rational Field
      sage: B == loads(dumps(B))
      True

  Python

      >>> from sage.all import *
      >>> from sage.modular.modsym.boundary import BoundarySpace_wtk_g1
      >>> B = BoundarySpace_wtk_g1(Integer(17), Integer(2), Integer(0), QQ) ; B
      Boundary Modular Symbols space for Gamma_1(17) of weight 2 over Rational Field
      >>> B == loads(dumps(B))
      True

class sage.modular.modsym.boundary.BoundarySpace_wtk_gamma_h(group, weight, sign, F)

  Bases: `BoundarySpace`

  Initialize a space of boundary modular symbols for GammaH(N).

  INPUT:

  - `group` – congruence subgroup Gamma_H(N)

  - `weight` – integer; the weight = 2

  - `sign` – integer; either -1, 0, or 1

  - `F` – base ring

  EXAMPLES:

  Sage

      sage: from sage.modular.modsym.boundary import BoundarySpace_wtk_gamma_h
      sage: B = BoundarySpace_wtk_gamma_h(GammaH(13,[3]), 2, 0, QQ) ; B
      Boundary Modular Symbols space for Congruence Subgroup Gamma_H(13) with H generated by [3] of weight 2 over Rational Field
      sage: B == loads(dumps(B))
      True

  Python

      >>> from sage.all import *
      >>> from sage.modular.modsym.boundary import BoundarySpace_wtk_gamma_h
      >>> B = BoundarySpace_wtk_gamma_h(GammaH(Integer(13),[Integer(3)]), Integer(2), Integer(0), QQ) ; B
      Boundary Modular Symbols space for Congruence Subgroup Gamma_H(13) with H generated by [3] of weight 2 over Rational Field
      >>> B == loads(dumps(B))
      True

  A test case from Issue #6072:

  Sage

      sage: ModularSymbols(GammaH(8,[5]), 3).boundary_map()
      Hecke module morphism boundary map defined by the matrix
      [-1  0  0  0]
      [ 0 -1  0  0]
      [ 0  0 -1  0]
      [ 0  0  0 -1]
      Domain: Modular Symbols space of dimension 4 for Congruence Subgroup ...
      Codomain: Boundary Modular Symbols space for Congruence Subgroup Gamma_H(8) ...

  [Python]

      >>> from sage.all import *
      >>> ModularSymbols(GammaH(Integer(8),[Integer(5)]), Integer(3)).boundary_map()
      Hecke module morphism boundary map defined by the matrix
      [-1  0  0  0]
      [ 0 -1  0  0]
      [ 0  0 -1  0]
      [ 0  0  0 -1]
      Domain: Modular Symbols space of dimension 4 for Congruence Subgroup ...
      Codomain: Boundary Modular Symbols space for Congruence Subgroup Gamma_H(8) ...