Congruence subgroup \(\Gamma_1(N)\) - Arithmetic Subgroups of $\SL_2(\ZZ)$

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

# Congruence subgroup \(\Gamma_1(N)\)

class sage.modular.arithgroup.congroup_gamma1.Gamma1_class(level)

  Bases: `GammaH_class`

  The congruence subgroup \(\Gamma_1(N)\).

  dimension_cusp_forms(k=2, eps=None, algorithm='CohenOesterle')

    Return the dimension of the space of cusp forms for `self`, or the dimension of the subspace corresponding to the given character if one is supplied.

    INPUT:

    - `k` – integer (default: 2); the weight

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

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

    EXAMPLES:

    We compute the same dimension in two different ways

    Sage

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

    Python

        >>> from sage.all import *
        >>> # needs sage.rings.number_field
        >>> K = CyclotomicField(Integer(3))
        >>> eps = DirichletGroup(Integer(7)*Integer(43),K).gen(0)**Integer(2)
        >>> G = Gamma1(Integer(7)*Integer(43))

    Via Cohen–Oesterle:

    Sage

        sage: Gamma1(7*43).dimension_cusp_forms(2, eps)                             # needs sage.rings.number_field
        28

    [Python]

        >>> from sage.all import *
        >>> Gamma1(Integer(7)*Integer(43)).dimension_cusp_forms(Integer(2), eps)                             # needs sage.rings.number_field
        28

    Via Quer’s method:

    Sage

        sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm='Quer')           # needs sage.rings.number_field
        28

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(7)*Integer(43)).dimension_cusp_forms(Integer(2), eps, algorithm='Quer')           # needs sage.rings.number_field
        28

    Some more examples:

    Sage

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

    [Python]

        >>> from sage.all import *
        >>> G = DirichletGroup(Integer(9), names=('eps',)); (eps,) = G._first_ngens(1)
        >>> [Gamma1(Integer(9)).dimension_cusp_forms(k, eps) for k in (ellipsis_range(Integer(1),Ellipsis,Integer(10)))]
        [0, 0, 1, 0, 3, 0, 5, 0, 7, 0]
        >>> [Gamma1(Integer(9)).dimension_cusp_forms(k, eps**Integer(2)) for k in (ellipsis_range(Integer(1),Ellipsis,Integer(10)))]
        [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]

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

    Sage

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

    Python

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

  dimension_eis(k=2, eps=None, algorithm='CohenOesterle')

    Return the dimension of the space of Eisenstein series forms for self, or the dimension of the subspace corresponding to the given character if one is supplied.

    INPUT:

    - `k` – integer (default: 2); the weight

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

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

    AUTHORS:

    - William Stein - Cohen–Oesterle algorithm

    - Jordi Quer - algorithm based on GammaH subgroups

    - David Loeffler (2009) - code refactoring

    EXAMPLES:

    The following two computations use different algorithms:

    Sage

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

    Python

        >>> from sage.all import *
        >>> [Gamma1(Integer(36)).dimension_eis(Integer(1),eps) for eps in DirichletGroup(Integer(36))]
        [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
        >>> [Gamma1(Integer(36)).dimension_eis(Integer(1),eps,algorithm='Quer') for eps in DirichletGroup(Integer(36))]
        [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]

    So do these:

    Sage

        sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)]
        [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
        sage: [Gamma1(48).dimension_eis(3,eps,algorithm='Quer') for eps in DirichletGroup(48)]
        [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]

    [Python]

        >>> from sage.all import *
        >>> [Gamma1(Integer(48)).dimension_eis(Integer(3),eps) for eps in DirichletGroup(Integer(48))]
        [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
        >>> [Gamma1(Integer(48)).dimension_eis(Integer(3),eps,algorithm='Quer') for eps in DirichletGroup(Integer(48))]
        [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]

  dimension_modular_forms(k=2, eps=None, algorithm='CohenOesterle')

    Return the dimension of the space of modular forms for `self`, or the dimension of the subspace corresponding to the given character if one is supplied.

    INPUT:

    - `k` – integer (default: 2); the weight

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

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

    EXAMPLES:

    Sage

        sage: # needs sage.rings.number_field
        sage: K = CyclotomicField(3)
        sage: eps = DirichletGroup(7*43,K).0^2
        sage: G = Gamma1(7*43)
        sage: G.dimension_modular_forms(2, eps)
        32
        sage: G.dimension_modular_forms(2, eps, algorithm='Quer')
        32

    Python

        >>> from sage.all import *
        >>> # needs sage.rings.number_field
        >>> K = CyclotomicField(Integer(3))
        >>> eps = DirichletGroup(Integer(7)*Integer(43),K).gen(0)**Integer(2)
        >>> G = Gamma1(Integer(7)*Integer(43))
        >>> G.dimension_modular_forms(Integer(2), eps)
        32
        >>> G.dimension_modular_forms(Integer(2), eps, algorithm='Quer')
        32

  dimension_new_cusp_forms(k=2, eps=None, p=0, algorithm='CohenOesterle')

    Dimension of the new subspace (or \(p\)-new subspace) of cusp forms of weight \(k\) and character \(\varepsilon\).

    INPUT:

    - `k` – integer (default: 2)

    - `eps` – a Dirichlet character

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

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

    EXAMPLES:

    Sage

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

    Python

        >>> from sage.all import *
        >>> G = DirichletGroup(Integer(9))
        >>> eps = G.gen(0)**Integer(3)
        >>> eps.conductor()
        3
        >>> [Gamma1(Integer(9)).dimension_new_cusp_forms(k, eps) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))]
        [0, 0, 0, 2, 0, 2, 0, 2, 0]
        >>> [Gamma1(Integer(9)).dimension_cusp_forms(k, eps) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))]
        [0, 0, 0, 2, 0, 4, 0, 6, 0]
        >>> [Gamma1(Integer(9)).dimension_new_cusp_forms(k, eps, Integer(3)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))]
        [0, 0, 0, 2, 0, 2, 0, 2, 0]

    Double check using modular symbols (independent calculation):

    Sage

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

    [Python]

        >>> from sage.all import *
        >>> [ModularSymbols(eps,k,sign=Integer(1)).cuspidal_subspace().new_subspace().dimension()  for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))]
        [0, 0, 0, 2, 0, 2, 0, 2, 0]
        >>> [ModularSymbols(eps,k,sign=Integer(1)).cuspidal_subspace().new_subspace(Integer(3)).dimension()  for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))]
        [0, 0, 0, 2, 0, 2, 0, 2, 0]

    Another example at level 33:

    Sage

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

    Python

        >>> from sage.all import *
        >>> G = DirichletGroup(Integer(33))
        >>> eps = G.gen(1)
        >>> eps.conductor()
        11
        >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))]
        [0, 4, 0]
        >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1), algorithm='Quer') for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))]
        [0, 4, 0]
        >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1)**Integer(2)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))]
        [2, 0, 6]
        >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1)**Integer(2), p=Integer(3)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))]
        [2, 0, 6]

  generators(algorithm='farey')

    Return generators for this congruence subgroup. The result is cached.

    INPUT:

    - `algorithm` – string; either `'farey'` (default) or `'todd-coxeter'`

    If `algorithm` is set to `'farey'`, then the generators will be calculated using Farey symbols, which will always return a minimal generating set. See `farey_symbol` for more information.

    If `algorithm` is set to `'todd-coxeter'`, a simpler algorithm based on Todd-Coxeter enumeration will be used. This tends to return far larger sets of generators.

    EXAMPLES:

    Sage

        sage: Gamma1(3).generators()
        [
        [1 1]  [ 1 -1]
        [0 1], [ 3 -2]
        ]
        sage: Gamma1(3).generators(algorithm='todd-coxeter')
        [
        [1 1]  [-2  1]  [1 1]  [ 1 -1]  [1 0]  [1 1]  [-5  2]  [ 1  0]
        [0 1], [-3  1], [0 1], [ 0  1], [3 1], [0 1], [12 -5], [-3  1],

        [ 1 -1]  [ 1 -1]  [ 4 -1]  [ -5   3]
        [ 3 -2], [ 3 -2], [ 9 -2], [-12   7]
        ]

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(3)).generators()
        [
        [1 1]  [ 1 -1]
        [0 1], [ 3 -2]
        ]
        >>> Gamma1(Integer(3)).generators(algorithm='todd-coxeter')
        [
        [1 1]  [-2  1]  [1 1]  [ 1 -1]  [1 0]  [1 1]  [-5  2]  [ 1  0]
        [0 1], [-3  1], [0 1], [ 0  1], [3 1], [0 1], [12 -5], [-3  1],
        <BLANKLINE>
        [ 1 -1]  [ 1 -1]  [ 4 -1]  [ -5   3]
        [ 3 -2], [ 3 -2], [ 9 -2], [-12   7]
        ]

  index()

    Return the index of `self` in the full modular group. This is given by the formula

    \[\begin{split}N^2 \prod_{\substack{p \mid N \\ \text{$p$ prime}}} \left( 1 - \frac{1}{p^2}\right).\end{split}\]

    EXAMPLES:

    Sage

        sage: Gamma1(180).index()
        20736
        sage: [Gamma1(n).projective_index() for n in [1..16]]
        [1, 3, 4, 6, 12, 12, 24, 24, 36, 36, 60, 48, 84, 72, 96, 96]

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(180)).index()
        20736
        >>> [Gamma1(n).projective_index() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(16)))]
        [1, 3, 4, 6, 12, 12, 24, 24, 36, 36, 60, 48, 84, 72, 96, 96]

  is_even()

    Return `True` precisely if this subgroup contains the matrix -1.

    EXAMPLES:

    Sage

        sage: Gamma1(1).is_even()
        True
        sage: Gamma1(2).is_even()
        True
        sage: Gamma1(15).is_even()
        False

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(1)).is_even()
        True
        >>> Gamma1(Integer(2)).is_even()
        True
        >>> Gamma1(Integer(15)).is_even()
        False

  is_subgroup(right)

    Return `True` if `self` is a subgroup of `right`.

    EXAMPLES:

    Sage

        sage: Gamma1(3).is_subgroup(SL2Z)
        True
        sage: Gamma1(3).is_subgroup(Gamma1(5))
        False
        sage: Gamma1(3).is_subgroup(Gamma1(6))
        False
        sage: Gamma1(6).is_subgroup(Gamma1(3))
        True
        sage: Gamma1(6).is_subgroup(Gamma0(2))
        True
        sage: Gamma1(80).is_subgroup(GammaH(40, []))
        True
        sage: Gamma1(80).is_subgroup(GammaH(40, [21]))
        True

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(3)).is_subgroup(SL2Z)
        True
        >>> Gamma1(Integer(3)).is_subgroup(Gamma1(Integer(5)))
        False
        >>> Gamma1(Integer(3)).is_subgroup(Gamma1(Integer(6)))
        False
        >>> Gamma1(Integer(6)).is_subgroup(Gamma1(Integer(3)))
        True
        >>> Gamma1(Integer(6)).is_subgroup(Gamma0(Integer(2)))
        True
        >>> Gamma1(Integer(80)).is_subgroup(GammaH(Integer(40), []))
        True
        >>> Gamma1(Integer(80)).is_subgroup(GammaH(Integer(40), [Integer(21)]))
        True

  ncusps()

    Return the number of cusps of this subgroup \(\Gamma_1(N)\).

    EXAMPLES:

    Sage

        sage: [Gamma1(n).ncusps() for n in [1..15]]
        [1, 2, 2, 3, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 16]
        sage: [Gamma1(n).ncusps() for n in prime_range(2, 100)]
        [2, 2, 4, 6, 10, 12, 16, 18, 22, 28, 30, 36, 40, 42, 46, 52, 58, 60, 66, 70, 72, 78, 82, 88, 96]

    Python

        >>> from sage.all import *
        >>> [Gamma1(n).ncusps() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(15)))]
        [1, 2, 2, 3, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 16]
        >>> [Gamma1(n).ncusps() for n in prime_range(Integer(2), Integer(100))]
        [2, 2, 4, 6, 10, 12, 16, 18, 22, 28, 30, 36, 40, 42, 46, 52, 58, 60, 66, 70, 72, 78, 82, 88, 96]

  nu2()

    Calculate the number of orbits of elliptic points of order 2 for this subgroup \(\Gamma_1(N)\). This is known to be 0 if N > 2.

    EXAMPLES:

    Sage

        sage: Gamma1(2).nu2()
        1
        sage: Gamma1(457).nu2()
        0
        sage: [Gamma1(n).nu2() for n in [1..16]]
        [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(2)).nu2()
        1
        >>> Gamma1(Integer(457)).nu2()
        0
        >>> [Gamma1(n).nu2() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(16)))]
        [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

  nu3()

    Calculate the number of orbits of elliptic points of order 3 for this subgroup \(\Gamma_1(N)\). This is known to be 0 if N > 3.

    EXAMPLES:

    Sage

        sage: Gamma1(2).nu3()
        0
        sage: Gamma1(3).nu3()
        1
        sage: Gamma1(457).nu3()
        0
        sage: [Gamma1(n).nu3() for n in [1..10]]
        [1, 0, 1, 0, 0, 0, 0, 0, 0, 0]

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(2)).nu3()
        0
        >>> Gamma1(Integer(3)).nu3()
        1
        >>> Gamma1(Integer(457)).nu3()
        0
        >>> [Gamma1(n).nu3() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(10)))]
        [1, 0, 1, 0, 0, 0, 0, 0, 0, 0]

sage.modular.arithgroup.congroup_gamma1.Gamma1_constructor(N)

  Return the congruence subgroup \(\Gamma_1(N)\).

  EXAMPLES:

  Sage

      sage: Gamma1(5) # indirect doctest
      Congruence Subgroup Gamma1(5)
      sage: G = Gamma1(23)
      sage: G is Gamma1(23)
      True
      sage: G is GammaH(23, [1])
      True
      sage: TestSuite(G).run()
      sage: G is loads(dumps(G))
      True

  Python

      >>> from sage.all import *
      >>> Gamma1(Integer(5)) # indirect doctest
      Congruence Subgroup Gamma1(5)
      >>> G = Gamma1(Integer(23))
      >>> G is Gamma1(Integer(23))
      True
      >>> G is GammaH(Integer(23), [Integer(1)])
      True
      >>> TestSuite(G).run()
      >>> G is loads(dumps(G))
      True

sage.modular.arithgroup.congroup_gamma1.is_Gamma1(x)

  Return `True` if x is a congruence subgroup of type Gamma1.

  EXAMPLES:

  Sage

      sage: from sage.modular.arithgroup.congroup_gamma1 import is_Gamma1
      sage: is_Gamma1(SL2Z)
      doctest:warning...
      DeprecationWarning: The function is_Gamma1 is deprecated; use 'isinstance(..., Gamma1_class)' instead.
      See https://github.com/sagemath/sage/issues/38035 for details.
      False
      sage: is_Gamma1(Gamma1(13))
      True
      sage: is_Gamma1(Gamma0(6))
      False
      sage: is_Gamma1(GammaH(12, [])) # trick question!
      True
      sage: is_Gamma1(GammaH(12, [5]))
      False

  Python

      >>> from sage.all import *
      >>> from sage.modular.arithgroup.congroup_gamma1 import is_Gamma1
      >>> is_Gamma1(SL2Z)
      doctest:warning...
      DeprecationWarning: The function is_Gamma1 is deprecated; use 'isinstance(..., Gamma1_class)' instead.
      See https://github.com/sagemath/sage/issues/38035 for details.
      False
      >>> is_Gamma1(Gamma1(Integer(13)))
      True
      >>> is_Gamma1(Gamma0(Integer(6)))
      False
      >>> is_Gamma1(GammaH(Integer(12), [])) # trick question!
      True
      >>> is_Gamma1(GammaH(Integer(12), [Integer(5)]))
      False