Arithmetic subgroups defined by permutations of cosets - Arithmetic Subgroups of $\SL_2(\ZZ)$

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

# Arithmetic subgroups defined by permutations of cosets

A subgroup of finite index \(H\) of a finitely generated group \(G\) is completely described by the action of a set of generators of \(G\) on the right cosets \(H \backslash G = \{Hg\}_{g \in G}\). After some arbitrary choice of numbering one can identify the action of generators as elements of a symmetric group acting transitively (and satisfying the relations of the relators in G). As \(\SL_2(\ZZ)\) has a very simple presentation as a central extension of a free product of cyclic groups, one can easily design algorithms from this point of view.

The generators of \(\SL_2(\ZZ)\) used in this module are named as follows \(s_2\), \(s_3\), \(l\), \(r\) which are defined by

\[\begin{split}s_2 = \begin{pmatrix} 0 & -1 \\ 1 & 0 \end{pmatrix},\quad s_3 = \begin{pmatrix} 0 & 1 \\ -1 & 1 \end{pmatrix},\quad l = \begin{pmatrix} 1 & 1 \\ 0 & 1 \end{pmatrix},\quad r = \begin{pmatrix} 1 & 0 \\ 1 & 1 \end{pmatrix}.\end{split}\]

Those generators satisfy the following relations

\[s_2^2 = s_3^3 = -1, \quad r = s_2^{-1}\ l^{-1}\ s_2.\]

In particular not all four are needed to generate the whole group \(\SL_2(\ZZ)\). Three couples which generate \(\SL_2(\ZZ)\) are of particular interest:

- \((l,r)\) as they are also semigroup generators for the semigroup of matrices in \(\SL_2(\ZZ)\) with nonnegative entries,

- \((l,s_2)\) as they are closely related to the continued fraction algorithm,

- \((s_2,s_3)\) as the group \(\PSL_2(\ZZ)\) is the free product of the finite cyclic groups generated by these two elements.

Part of these functions are based on Chris Kurth’s KFarey package [Kur2008]. For tests see the file `sage.modular.arithgroup.tests`.

REFERENCES:

- [ASD1971]

- [Gor2009]

- [HL2014]

- [Hsu1996]

- [Hsu1997]

- [KSV2011]

- [Kul1991]

- [Kur2008]

- [KL2008]

- [Ver]

Todo

- modular Farey symbols

- computation of generators of a modular subgroup with a standard surface group presentation. In other words, compute a presentation of the form

  \[\langle x_i,y_i,c_j |\ \prod_i [x_i,y_i] \prod_j c_j^{\nu_j} = 1\rangle\]

  where the elements \(x_i\) and \(y_i\) are hyperbolic and \(c_j\) are parabolic (\(\nu_j=\infty\)) or elliptic elements (\(\nu_j < \infty\)).

- computation of centralizer.

- generation of modular (even) subgroups of fixed index.

AUTHORS:

- Chris Kurth (2008): created KFarey package

- David Loeffler (2009): adapted functions from KFarey for inclusion into Sage

- Vincent Delecroix (2010): implementation for odd groups, new design, improvements, documentation

- David Loeffler (2011): congruence testing for odd subgroups, enumeration of liftings of projective subgroups

- David Loeffler & Thomas Hamilton (2012): generalised Hsu congruence test for odd subgroups

sage.modular.arithgroup.arithgroup_perm.ArithmeticSubgroup_Permutation(L=None, R=None, S2=None, S3=None, relabel=False, check=True)

  Construct a subgroup of \(\SL_2(\ZZ)\) from the action of generators on its right cosets.

  Return an arithmetic subgroup knowing the action, given by permutations, of at least two standard generators on the its cosets. The generators considered are the following matrices:

  \[\begin{split}s_2 = \begin{pmatrix} 0 & -1 \\ 1 & 0 \end{pmatrix},\quad s_3 = \begin{pmatrix} 0 & 1 \\ -1 & 1 \end{pmatrix},\quad l = \begin{pmatrix} 1 & 1 \\ 0 & 1\end{pmatrix},\quad r = \begin{pmatrix} 1 & 0 \\ 1 & 1 \end{pmatrix}.\end{split}\]

  An error will be raised if only one permutation is given. If no arguments are given at all, the full modular group \(\SL(2, \ZZ)\) is returned.

  INPUT:

  - `S2`, `S3`, `L`, `R` – permutations; action of matrices on the right cosets (each coset is identified to an element of \(\{1,\dots,n\}\) where \(1\) is reserved for the identity coset)

  - `relabel` – boolean (default: `False`); if `True`, renumber the cosets in a canonical way

  - `check` – boolean (default: `True`); check that the input is valid (it may be time efficient but less safe to set it to False)

  EXAMPLES:

  Sage

      sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)",S3="(1,2,3)")
      sage: G
      Arithmetic subgroup with permutations of right cosets
       S2=(1,2)(3,4)
       S3=(1,2,3)
       L=(1,4,3)
       R=(2,4,3)
      sage: G.index()
      4

      sage: G = ArithmeticSubgroup_Permutation(); G
      Arithmetic subgroup with permutations of right cosets
       S2=()
       S3=()
       L=()
       R=()
      sage: G == SL2Z
      True

  Python

      >>> from sage.all import *
      >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)",S3="(1,2,3)")
      >>> G
      Arithmetic subgroup with permutations of right cosets
       S2=(1,2)(3,4)
       S3=(1,2,3)
       L=(1,4,3)
       R=(2,4,3)
      >>> G.index()
      4

      >>> G = ArithmeticSubgroup_Permutation(); G
      Arithmetic subgroup with permutations of right cosets
       S2=()
       S3=()
       L=()
       R=()
      >>> G == SL2Z
      True

  Some invalid inputs:

  Sage

      sage: ArithmeticSubgroup_Permutation(S2="(1,2)")
      Traceback (most recent call last):
      ...
      ValueError: Need at least two generators
      sage: ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(3,4,5)")
      Traceback (most recent call last):
      ...
      ValueError: Permutations do not generate a transitive group
      sage: ArithmeticSubgroup_Permutation(L="(1,2)",R="(1,2,3)")
      Traceback (most recent call last):
      ...
      ValueError: Wrong relations between generators
      sage: ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="()")
      Traceback (most recent call last):
      ...
      ValueError: S2^2 does not equal to S3^3
      sage: ArithmeticSubgroup_Permutation(S2="(1,4,2,5,3)", S3="(1,3,5,2,4)")
      Traceback (most recent call last):
      ...
      ValueError: S2^2 = S3^3 must have order 1 or 2

  [Python]

      >>> from sage.all import *
      >>> ArithmeticSubgroup_Permutation(S2="(1,2)")
      Traceback (most recent call last):
      ...
      ValueError: Need at least two generators
      >>> ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(3,4,5)")
      Traceback (most recent call last):
      ...
      ValueError: Permutations do not generate a transitive group
      >>> ArithmeticSubgroup_Permutation(L="(1,2)",R="(1,2,3)")
      Traceback (most recent call last):
      ...
      ValueError: Wrong relations between generators
      >>> ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="()")
      Traceback (most recent call last):
      ...
      ValueError: S2^2 does not equal to S3^3
      >>> ArithmeticSubgroup_Permutation(S2="(1,4,2,5,3)", S3="(1,3,5,2,4)")
      Traceback (most recent call last):
      ...
      ValueError: S2^2 = S3^3 must have order 1 or 2

  The input checks can be disabled for speed:

  Sage

      sage: ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(3,4,5)", check=False) # don't do this!
      Arithmetic subgroup with permutations of right cosets
       S2=(1,2)
       S3=(3,4,5)
       L=(1,2)(3,5,4)
       R=(1,2)(3,4,5)

  Python

      >>> from sage.all import *
      >>> ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(3,4,5)", check=False) # don't do this!
      Arithmetic subgroup with permutations of right cosets
       S2=(1,2)
       S3=(3,4,5)
       L=(1,2)(3,5,4)
       R=(1,2)(3,4,5)

class sage.modular.arithgroup.arithgroup_perm.ArithmeticSubgroup_Permutation_class

  Bases: `ArithmeticSubgroup`

  A subgroup of \(\SL_2(\ZZ)\) defined by the action of generators on its coset graph.

  The class stores the action of generators \(s_2, s_3, l, r\) on right cosets \(Hg\) of a finite index subgroup \(H < \SL_2(\ZZ)\). In particular the action of \(\SL_2(\ZZ)\) on the cosets is on right.

  \[\begin{split}s_2 = \begin{pmatrix} 0 & -1 \\ 1 & 0 \end{pmatrix},\quad s_3 = \begin{pmatrix} 0 & 1 \\ -1 & 1 \end{pmatrix},\quad l = \begin{pmatrix} 1 & 1 \\ 0 & 1\end{pmatrix},\quad r = \begin{pmatrix} 1 & 0 \\ 1 & 1 \end{pmatrix}.\end{split}\]
  L()

    Return the action of the matrix \(l\) as a permutation of cosets.

    \[\begin{split}l = \begin{pmatrix}1&1\\0&1\end{pmatrix}\end{split}\]

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        sage: G.L()
        (1,3)

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        >>> G.L()
        (1,3)

  R()

    Return the action of the matrix \(r\) as a permutation of cosets.

    \[\begin{split}r = \begin{pmatrix}1&0\\1&1\end{pmatrix}\end{split}\]

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        sage: G.R()
        (2,3)

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        >>> G.R()
        (2,3)

  S2()

    Return the action of the matrix \(s_2\) as a permutation of cosets.

    \[\begin{split}s_2 = \begin{pmatrix}0&-1\\1&0\end{pmatrix}\end{split}\]

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        sage: G.S2()
        (1,2)

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        >>> G.S2()
        (1,2)

  S3()

    Return the action of the matrix \(s_3\) as a permutation of cosets.

    \[\begin{split}s_3 = \begin{pmatrix} 0 & 1 \\ -1 & 1 \end{pmatrix},\quad\end{split}\]

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        sage: G.S3()
        (1,2,3)

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="(1,2,3)")
        >>> G.S3()
        (1,2,3)

  congruence_closure()

    Return the smallest congruence subgroup containing `self`. If `self` is congruence, this is just self, but represented as a congruence subgroup data type. If `self` is not congruence, then it may be larger.

    In practice, we use the following criterion: let \(m\) be the generalised level of `self`. If this subgroup is even, let \(n = m\), else let \(n = 2m\). Then any congruence subgroup containing `self` contains \(\Gamma(n)\) (a generalisation of Wohlfahrt’s theorem due to Kiming, Verrill and Schuett). So we compute the image of `self` modulo \(n\) and return the preimage of that.

    Note

    If you just want to know if the subgroup is congruence or not, it is much faster to use `is_congruence()`.

    EXAMPLES:

    Sage

        sage: Gamma1(3).as_permutation_group().congruence_closure()
        Congruence subgroup of SL(2,Z) of level 3, preimage of:
         Matrix group over Ring of integers modulo 3 with 2 generators (
        [1 1]  [1 2]
        [0 1], [0 1]
        )
        sage: sage.modular.arithgroup.arithgroup_perm.HsuExample10().congruence_closure()  # long time (11s on sage.math, 2012)
        Modular Group SL(2,Z)

    Python

        >>> from sage.all import *
        >>> Gamma1(Integer(3)).as_permutation_group().congruence_closure()
        Congruence subgroup of SL(2,Z) of level 3, preimage of:
         Matrix group over Ring of integers modulo 3 with 2 generators (
        [1 1]  [1 2]
        [0 1], [0 1]
        )
        >>> sage.modular.arithgroup.arithgroup_perm.HsuExample10().congruence_closure()  # long time (11s on sage.math, 2012)
        Modular Group SL(2,Z)

  coset_graph(right_cosets=False, s2_edges=True, s3_edges=True, l_edges=False, r_edges=False, s2_label='s2', s3_label='s3', l_label='l', r_label='r')

    Return the right (or left) coset graph.

    INPUT:

    - `right_cosets` – boolean (default: `False`); right or left coset graph

    - `s2_edges` – boolean (default: `True`); put edges associated to s2

    - `s3_edges` – boolean (default: `True`); put edges associated to s3

    - `l_edges` – boolean (default: `False`); put edges associated to l

    - `r_edges` – boolean (default: `False`); put edges associated to r

    - `s2_label`, `s3_label`, `l_label`, `r_label` – the labels to put on the edges corresponding to the generators action. Use `None` for no label.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="()")
        sage: G
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)
         S3=()
         L=(1,2)
         R=(1,2)
        sage: G.index()
        2
        sage: G.coset_graph()
        Looped multi-digraph on 2 vertices

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)",S3="()")
        >>> G
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)
         S3=()
         L=(1,2)
         R=(1,2)
        >>> G.index()
        2
        >>> G.coset_graph()
        Looped multi-digraph on 2 vertices

  generalised_level()

    Return the generalised level of this subgroup.

    The generalised level of a subgroup of the modular group is the least common multiple of the widths of the cusps. It was proven by Wohlfart that for even congruence subgroups, the (conventional) level coincides with the generalised level. For odd congruence subgroups the level is either the generalised level, or twice the generalised level [KSV2011].

    EXAMPLES:

    Sage

        sage: G = Gamma(2).as_permutation_group()
        sage: G.generalised_level()
        2
        sage: G = Gamma0(3).as_permutation_group()
        sage: G.generalised_level()
        3

    Python

        >>> from sage.all import *
        >>> G = Gamma(Integer(2)).as_permutation_group()
        >>> G.generalised_level()
        2
        >>> G = Gamma0(Integer(3)).as_permutation_group()
        >>> G.generalised_level()
        3

  index()

    Return the index of this modular subgroup in the full modular group.

    EXAMPLES:

    Sage

        sage: G = Gamma(2)
        sage: P = G.as_permutation_group()
        sage: P.index()
        6
        sage: G.index() == P.index()
        True

        sage: G = Gamma0(8)
        sage: P = G.as_permutation_group()
        sage: P.index()
        12
        sage: G.index() == P.index()
        True

        sage: G = Gamma1(6)
        sage: P = G.as_permutation_group()
        sage: P.index()
        24
        sage: G.index() == P.index()
        True

    Python

        >>> from sage.all import *
        >>> G = Gamma(Integer(2))
        >>> P = G.as_permutation_group()
        >>> P.index()
        6
        >>> G.index() == P.index()
        True

        >>> G = Gamma0(Integer(8))
        >>> P = G.as_permutation_group()
        >>> P.index()
        12
        >>> G.index() == P.index()
        True

        >>> G = Gamma1(Integer(6))
        >>> P = G.as_permutation_group()
        >>> P.index()
        24
        >>> G.index() == P.index()
        True

  is_congruence()

    Return `True` if this is a congruence subgroup, and `False` otherwise.

    ALGORITHM:

    Uses Hsu’s algorithm [Hsu1996]. Adapted from Chris Kurth’s implementation in KFarey [Kur2008].

    For odd subgroups, Hsu’s algorithm still works with minor modifications, using the extension of Wohlfarht’s theorem due to Kiming, Schuett and Verrill [KSV2011]. See [HL2014] for details.

    The algorithm is as follows. Let \(G\) be a finite-index subgroup of \(\SL(2, \ZZ)\), and let \(L\) and \(R\) be the permutations of the cosets of \(G\) given by the elements \(\begin{pmatrix} 1 & 1 \\ 0 & 1 \end{pmatrix}\) and \(\begin{pmatrix} 1 & 1 \\ 0 & 1 \end{pmatrix}\). Let \(N\) be the generalized level of \(G\) (if \(G\) is even) or twice the generalized level (if \(G\) is odd). Then:

    - if \(N\) is odd, \(G\) is congruence if and only if the relation

      \[(L R^{-1} L)^2 = (R^2 L^{1/2})^3\]

      holds, where \(1/2\) is understood as the multiplicative inverse of 2 modulo N.

    - if \(N\) is a power of 2, then \(G\) is congruence if and only if the relations

      \[\begin{split}\begin{array}{cc} (L R^{-1} L)^{-1} S (L R^{-1} L) S = 1 & (A1)\\ S^{-1} R S = R^{25} & (A2)\\ (L R^{-1} L)^2 = (S R^5 L R^{-1} L)^3 & (A3) \\ \end{array}\end{split}\]

      hold, where \(S = L^{20} R^{1/5} L^{-4} R^{-1}\), \(1/5\) being the inverse of 5 modulo N.

    - if \(N\) is neither odd nor a power of 2, seven relations (B1-7) hold, for which see [HL2014], or the source code of this function.

    If the Sage verbosity flag is set (using `set_verbose()`), then extra output will be produced indicating which of the relations (A1-3) or (B1-7) is not satisfied.

    EXAMPLES:

    Test if \(\SL_2(\ZZ)\) is congruence:

    Sage

        sage: a = ArithmeticSubgroup_Permutation(L='',R='')
        sage: a.index()
        1
        sage: a.is_congruence()
        True

    Python

        >>> from sage.all import *
        >>> a = ArithmeticSubgroup_Permutation(L='',R='')
        >>> a.index()
        1
        >>> a.is_congruence()
        True

    This example is congruence – it is \(\Gamma_0(3)\) in disguise:

    Sage

        sage: S2 = SymmetricGroup(4)
        sage: l = S2((2,3,4))
        sage: r = S2((1,3,4))
        sage: G = ArithmeticSubgroup_Permutation(L=l,R=r)
        sage: G
        Arithmetic subgroup with permutations of right cosets
        S2=(1,2)(3,4)
        S3=(1,4,2)
        L=(2,3,4)
        R=(1,3,4)
        sage: G.is_congruence()
        True

    [Python]

        >>> from sage.all import *
        >>> S2 = SymmetricGroup(Integer(4))
        >>> l = S2((Integer(2),Integer(3),Integer(4)))
        >>> r = S2((Integer(1),Integer(3),Integer(4)))
        >>> G = ArithmeticSubgroup_Permutation(L=l,R=r)
        >>> G
        Arithmetic subgroup with permutations of right cosets
        S2=(1,2)(3,4)
        S3=(1,4,2)
        L=(2,3,4)
        R=(1,3,4)
        >>> G.is_congruence()
        True

    This one is noncongruence:

    Sage

        sage: import sage.modular.arithgroup.arithgroup_perm as ap
        sage: ap.HsuExample10().is_congruence()
        False

    Python

        >>> from sage.all import *
        >>> import sage.modular.arithgroup.arithgroup_perm as ap
        >>> ap.HsuExample10().is_congruence()
        False

    The following example (taken from [KSV2011]) shows that a lifting of a congruence subgroup of \(\PSL(2,\ZZ)\) to a subgroup of \(\SL(2, \ZZ)\) need not necessarily be congruence:

    Sage

        sage: S2 = "(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23)"
        sage: S3 = "(1,14,15,13,2,3)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)"
        sage: G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        sage: G.is_congruence()
        False
        sage: G.to_even_subgroup().is_congruence()
        True

    [Python]

        >>> from sage.all import *
        >>> S2 = "(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23)"
        >>> S3 = "(1,14,15,13,2,3)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)"
        >>> G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        >>> G.is_congruence()
        False
        >>> G.to_even_subgroup().is_congruence()
        True

    In fact \(G\) is a lifting to \(\SL(2,\ZZ)\) of the group \(\bar{\Gamma}_0(6)\):

    Sage

        sage: G.to_even_subgroup() == Gamma0(6)
        True

    Python

        >>> from sage.all import *
        >>> G.to_even_subgroup() == Gamma0(Integer(6))
        True

  is_normal()

    Test whether the group is normal.

    EXAMPLES:

    Sage

        sage: G = Gamma(2).as_permutation_group()
        sage: G.is_normal()
        True

        sage: G = Gamma1(2).as_permutation_group()
        sage: G.is_normal()
        False

    Python

        >>> from sage.all import *
        >>> G = Gamma(Integer(2)).as_permutation_group()
        >>> G.is_normal()
        True

        >>> G = Gamma1(Integer(2)).as_permutation_group()
        >>> G.is_normal()
        False

  perm_group()

    Return the underlying permutation group.

    The permutation group returned is isomorphic to the action of the generators \(s_2\) (element of order two), \(s_3\) (element of order 3), \(l\) (parabolic element) and \(r\) (parabolic element) on right cosets (the action is on the right).

    EXAMPLES:

    Sage

        sage: import sage.modular.arithgroup.arithgroup_perm as ap
        sage: ap.HsuExample10().perm_group()
        Permutation Group with generators [(1,2)(3,4)(5,6)(7,8)(9,10), (1,8,3)(2,4,6)(5,7,10), (1,4)(2,5,9,10,8)(3,7,6), (1,7,9,10,6)(2,3)(4,5,8)]

    Python

        >>> from sage.all import *
        >>> import sage.modular.arithgroup.arithgroup_perm as ap
        >>> ap.HsuExample10().perm_group()
        Permutation Group with generators [(1,2)(3,4)(5,6)(7,8)(9,10), (1,8,3)(2,4,6)(5,7,10), (1,4)(2,5,9,10,8)(3,7,6), (1,7,9,10,6)(2,3)(4,5,8)]

  permutation_action(x)

    Given an element `x` of \(\SL_2(\ZZ)\), compute the permutation of the cosets of `self` given by right multiplication by `x`.

    EXAMPLES:

    Sage

        sage: import sage.modular.arithgroup.arithgroup_perm as ap
        sage: ap.HsuExample10().permutation_action(SL2Z([32, -21, -67, 44]))
        (1,4,6,2,10,5,3,7,8,9)

    Python

        >>> from sage.all import *
        >>> import sage.modular.arithgroup.arithgroup_perm as ap
        >>> ap.HsuExample10().permutation_action(SL2Z([Integer(32), -Integer(21), -Integer(67), Integer(44)]))
        (1,4,6,2,10,5,3,7,8,9)

  random_element(initial_steps=30)

    Return a random element in this subgroup.

    The algorithm uses a random walk on the Cayley graph of \(\SL_2(\ZZ)\) stopped at the first time it reaches the subgroup after at least `initial_steps` steps.

    INPUT:

    - `initial_steps` – positive integer (default: 30)

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2='(1,3)(4,5)',S3='(1,2,5)(3,4,6)')
        sage: all(G.random_element() in G for _ in range(10))
        True

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2='(1,3)(4,5)',S3='(1,2,5)(3,4,6)')
        >>> all(G.random_element() in G for _ in range(Integer(10)))
        True

  relabel(inplace=True)

    Relabel the cosets of this modular subgroup in a canonical way.

    The implementation of modular subgroup by action of generators on cosets depends on the choice of a numbering. This function provides canonical labels in the sense that two equal subgroups with different labels are relabeled the same way. The default implementation relabels the group itself. If you want to get a relabeled copy of your modular subgroup, put to `False` the option `inplace`.

    ALGORITHM:

    We give an overview of how the canonical labels for the modular subgroup are built. The procedure only uses the permutations \(S3\) and \(S2\) that define the modular subgroup and can be used to renumber any transitive action of the symmetric group. In other words, the algorithm construct a canonical representative of a transitive subgroup in its conjugacy class in the full symmetric group.

    1. The identity is still numbered \(0\) and set the current vertex to be the identity.

    2. Number the cycle of \(S3\) the current vertex belongs to: if the current vertex is labeled \(n\) then the numbering in such way that the cycle becomes \((n, n+1, \ldots, n+k)\)).

    3. Find a new current vertex using the permutation \(S2\). If all vertices are relabeled then it’s done, otherwise go to step 2.

    EXAMPLES:

    Sage

        sage: S2 = "(1,2)(3,4)(5,6)"; S3 = "(1,2,3)(4,5,6)"
        sage: G1 = ArithmeticSubgroup_Permutation(S2=S2,S3=S3); G1
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)
        sage: G1.relabel(); G1
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)

        sage: S2 = "(1,2)(3,5)(4,6)"; S3 = "(1,2,3)(4,5,6)"
        sage: G2 = ArithmeticSubgroup_Permutation(S2=S2,S3=S3); G2
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,5)(4,6)
         S3=(1,2,3)(4,5,6)
         L=(1,5,6,3)
         R=(2,5,4,3)
        sage: G2.relabel(); G2
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)

        sage: S2 = "(1,2)(3,6)(4,5)"; S3 = "(1,2,3)(4,5,6)"
        sage: G3 = ArithmeticSubgroup_Permutation(S2=S2,S3=S3); G3
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,6)(4,5)
         S3=(1,2,3)(4,5,6)
         L=(1,6,4,3)
         R=(2,6,5,3)
        sage: G4 = G3.relabel(inplace=False)
        sage: G4
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)
        sage: G3 is G4
        False

    Python

        >>> from sage.all import *
        >>> S2 = "(1,2)(3,4)(5,6)"; S3 = "(1,2,3)(4,5,6)"
        >>> G1 = ArithmeticSubgroup_Permutation(S2=S2,S3=S3); G1
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)
        >>> G1.relabel(); G1
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)

        >>> S2 = "(1,2)(3,5)(4,6)"; S3 = "(1,2,3)(4,5,6)"
        >>> G2 = ArithmeticSubgroup_Permutation(S2=S2,S3=S3); G2
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,5)(4,6)
         S3=(1,2,3)(4,5,6)
         L=(1,5,6,3)
         R=(2,5,4,3)
        >>> G2.relabel(); G2
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)

        >>> S2 = "(1,2)(3,6)(4,5)"; S3 = "(1,2,3)(4,5,6)"
        >>> G3 = ArithmeticSubgroup_Permutation(S2=S2,S3=S3); G3
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,6)(4,5)
         S3=(1,2,3)(4,5,6)
         L=(1,6,4,3)
         R=(2,6,5,3)
        >>> G4 = G3.relabel(inplace=False)
        >>> G4
        Arithmetic subgroup with permutations of right cosets
         S2=(1,2)(3,4)(5,6)
         S3=(1,2,3)(4,5,6)
         L=(1,4,5,3)
         R=(2,4,6,3)
        >>> G3 is G4
        False

  surgroups()

    Return an iterator through the non-trivial intermediate groups between \(SL(2,\ZZ)\) and this finite index group.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)(5,6)", S3="(1,2,3)(4,5,6)")
        sage: H = next(G.surgroups())
        sage: H
         Arithmetic subgroup with permutations of right cosets
         S2=(1,2)
         S3=(1,2,3)
         L=(1,3)
         R=(2,3)
        sage: G.is_subgroup(H)
        True

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)(5,6)", S3="(1,2,3)(4,5,6)")
        >>> H = next(G.surgroups())
        >>> H
         Arithmetic subgroup with permutations of right cosets
         S2=(1,2)
         S3=(1,2,3)
         L=(1,3)
         R=(2,3)
        >>> G.is_subgroup(H)
        True

    The principal congruence group \(\Gamma(3)\) has thirteen surgroups:

    Sage

        sage: G = Gamma(3).as_permutation_group()
        sage: G.index()
        24
        sage: l = []
        sage: for H in G.surgroups():
        ....:     l.append(H.index())
        ....:     assert G.is_subgroup(H) and H.is_congruence()
        sage: l
        [6, 3, 4, 8, 4, 8, 4, 12, 4, 6, 6, 8, 8]

    [Python]

        >>> from sage.all import *
        >>> G = Gamma(Integer(3)).as_permutation_group()
        >>> G.index()
        24
        >>> l = []
        >>> for H in G.surgroups():
        ...     l.append(H.index())
        ...     assert G.is_subgroup(H) and H.is_congruence()
        >>> l
        [6, 3, 4, 8, 4, 8, 4, 12, 4, 6, 6, 8, 8]

class sage.modular.arithgroup.arithgroup_perm.EvenArithmeticSubgroup_Permutation(S2, S3, L, R, canonical_labels=False)

  Bases: `ArithmeticSubgroup_Permutation_class`

  An arithmetic subgroup of \(\SL(2, \ZZ)\) containing \(-1\), represented in terms of the right action of \(\SL(2, \ZZ)\) on its cosets.

  EXAMPLES:

  Construct a noncongruence subgroup of index 7 (the smallest possible):

  Sage

      sage: a2 = SymmetricGroup(7)([(1,2),(3,4),(6,7)]); a3 = SymmetricGroup(7)([(1,2,3),(4,5,6)])
      sage: G = ArithmeticSubgroup_Permutation(S2=a2, S3=a3); G
      Arithmetic subgroup with permutations of right cosets
      S2=(1,2)(3,4)(6,7)
      S3=(1,2,3)(4,5,6)
      L=(1,4,7,6,5,3)
      R=(2,4,5,7,6,3)
      sage: G.index()
      7
      sage: G.dimension_cusp_forms(4)
      1
      sage: G.is_congruence()
      False

  Python

      >>> from sage.all import *
      >>> a2 = SymmetricGroup(Integer(7))([(Integer(1),Integer(2)),(Integer(3),Integer(4)),(Integer(6),Integer(7))]); a3 = SymmetricGroup(Integer(7))([(Integer(1),Integer(2),Integer(3)),(Integer(4),Integer(5),Integer(6))])
      >>> G = ArithmeticSubgroup_Permutation(S2=a2, S3=a3); G
      Arithmetic subgroup with permutations of right cosets
      S2=(1,2)(3,4)(6,7)
      S3=(1,2,3)(4,5,6)
      L=(1,4,7,6,5,3)
      R=(2,4,5,7,6,3)
      >>> G.index()
      7
      >>> G.dimension_cusp_forms(Integer(4))
      1
      >>> G.is_congruence()
      False

  Convert some standard congruence subgroups into permutation form:

  Sage

      sage: G = Gamma0(8).as_permutation_group()
      sage: G.index()
      12
      sage: G.is_congruence()
      True

      sage: G = Gamma0(12).as_permutation_group()
      sage: G
      Arithmetic subgroup of index 24
      sage: G.is_congruence()
      True

  [Python]

      >>> from sage.all import *
      >>> G = Gamma0(Integer(8)).as_permutation_group()
      >>> G.index()
      12
      >>> G.is_congruence()
      True

      >>> G = Gamma0(Integer(12)).as_permutation_group()
      >>> G
      Arithmetic subgroup of index 24
      >>> G.is_congruence()
      True

  The following is the unique index 2 even subgroup of \(\SL_2(\ZZ)\):

  Sage

      sage: w = SymmetricGroup(2)([2,1])
      sage: G = ArithmeticSubgroup_Permutation(L=w, R=w)
      sage: G.dimension_cusp_forms(6)
      1
      sage: G.genus()
      0

  Python

      >>> from sage.all import *
      >>> w = SymmetricGroup(Integer(2))([Integer(2),Integer(1)])
      >>> G = ArithmeticSubgroup_Permutation(L=w, R=w)
      >>> G.dimension_cusp_forms(Integer(6))
      1
      >>> G.genus()
      0

  coset_reps()

    Return coset representatives.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)",S3="(1,2,3)")
        sage: c = G.coset_reps()
        sage: len(c)
        4
        sage: [g in G for g in c]
        [True, False, False, False]

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)",S3="(1,2,3)")
        >>> c = G.coset_reps()
        >>> len(c)
        4
        >>> [g in G for g in c]
        [True, False, False, False]

  cusp_widths(exp=False)

    Return the list of cusp widths of the group.

    EXAMPLES:

    Sage

        sage: G = Gamma(2).as_permutation_group()
        sage: G.cusp_widths()
        [2, 2, 2]
        sage: G.cusp_widths(exp=True)
        {2: 3}

        sage: S2 = "(1,2)(3,4)(5,6)"
        sage: S3 = "(1,2,3)(4,5,6)"
        sage: G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        sage: G.cusp_widths()
        [1, 1, 4]
        sage: G.cusp_widths(exp=True)
        {1: 2, 4: 1}

        sage: S2 = "(1,2)(3,4)(5,6)"
        sage: S3 = "(1,3,5)(2,4,6)"
        sage: G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        sage: G.cusp_widths()
        [6]
        sage: G.cusp_widths(exp=True)
        {6: 1}

    Python

        >>> from sage.all import *
        >>> G = Gamma(Integer(2)).as_permutation_group()
        >>> G.cusp_widths()
        [2, 2, 2]
        >>> G.cusp_widths(exp=True)
        {2: 3}

        >>> S2 = "(1,2)(3,4)(5,6)"
        >>> S3 = "(1,2,3)(4,5,6)"
        >>> G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        >>> G.cusp_widths()
        [1, 1, 4]
        >>> G.cusp_widths(exp=True)
        {1: 2, 4: 1}

        >>> S2 = "(1,2)(3,4)(5,6)"
        >>> S3 = "(1,3,5)(2,4,6)"
        >>> G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        >>> G.cusp_widths()
        [6]
        >>> G.cusp_widths(exp=True)
        {6: 1}

  is_even()

    Return `True` if this subgroup contains the matrix \(-Id\).

    EXAMPLES:

    Sage

        sage: G = Gamma(2).as_permutation_group()
        sage: G.is_even()
        True

    Python

        >>> from sage.all import *
        >>> G = Gamma(Integer(2)).as_permutation_group()
        >>> G.is_even()
        True

  is_odd()

    Return `True` if this subgroup does not contain the matrix \(-Id\).

    EXAMPLES:

    Sage

        sage: G = Gamma(2).as_permutation_group()
        sage: G.is_odd()
        False

    Python

        >>> from sage.all import *
        >>> G = Gamma(Integer(2)).as_permutation_group()
        >>> G.is_odd()
        False

  ncusps()

    Return the number of cusps of this arithmetic subgroup.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)(5,6)",S3="(1,2,3)(4,5,6)")
        sage: G.ncusps()
        3

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)(5,6)",S3="(1,2,3)(4,5,6)")
        >>> G.ncusps()
        3

  nu2()

    Return the number of orbits of elliptic points of order 2 for this arithmetic subgroup.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,4)(2)(3)",S3="(1,2,3)(4)")
        sage: G.nu2()
        2

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,4)(2)(3)",S3="(1,2,3)(4)")
        >>> G.nu2()
        2

  nu3()

    Return the number of orbits of elliptic points of order 3 for this arithmetic subgroup.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,4)(2)(3)",S3="(1,2,3)(4)")
        sage: G.nu3()
        1

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,4)(2)(3)",S3="(1,2,3)(4)")
        >>> G.nu3()
        1

  odd_subgroups()

    Return a list of the odd subgroups of index 2 in \(\Gamma\), where \(\Gamma\) is this subgroup. (Equivalently, return the liftings of \(\bar{\Gamma} \le \PSL(2, \ZZ)\) to \(\SL(2, \ZZ)\).) This can take rather a long time if the index of this subgroup is large.

    See also

    `one_odd_subgroup()`, which returns just one of the odd subgroups (which is much quicker than enumerating them all).

    ALGORITHM:

    - If \(\Gamma\) has an element of order 4, then there are no index 2 odd subgroups, so return the empty set.

    - If \(\Gamma\) has no elements of order 4, then the permutation \(S_2\) is a combination of 2-cycles with no fixed points on \(\{1, \dots, N\}\). We construct the permutation \(\tilde{S}_2\) of \(\{1, \dots, 2N\}\) which has a 4-cycle \((a, b, a+N, b+N)\) for each 2-cycle \((a,b)\) in `S2`. Similarly, we construct a permutation \(\tilde{S}_3\) which has a 6-cycle \((a,b,c,a+N,b+N,c+N)\) for each 3-cycle \((a,b,c)\) in \(S_3\), and a 2-cycle \((a,a+N)\) for each fixed point \(a\) of \(S_3\).

      Then the permutations \(\tilde{S}_2\) and \(\tilde{S}_3\) satisfy \(\tilde{S}_2^2 = \tilde{S}_3^3 = \iota\) where \(\iota\) is the order 2 permutation interchanging \(a\) and \(a+N\) for each \(a\). So the subgroup corresponding to these permutations is an index 2 odd subgroup of \(\Gamma\).

    - The other index 2 odd subgroups of \(\Gamma\) are obtained from the pairs \(\tilde{S}_2, \tilde{S}_3^\sigma\) where \(\sigma\) is an element of the group generated by the 2-cycles \((a, a+N)\).

    Studying the permutations in the first example below gives a good illustration of the algorithm.

    EXAMPLES:

    Sage

        sage: G = sage.modular.arithgroup.arithgroup_perm.HsuExample10()
        sage: [G.S2(), G.S3()]
        [(1,2)(3,4)(5,6)(7,8)(9,10), (1,8,3)(2,4,6)(5,7,10)]
        sage: X = G.odd_subgroups()
        sage: for u in X: print([u.S2(), u.S3()])
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,8,3,11,18,13)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,18,13,11,8,3)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,8,13,11,18,3)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,18,3,11,8,13)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]

    Python

        >>> from sage.all import *
        >>> G = sage.modular.arithgroup.arithgroup_perm.HsuExample10()
        >>> [G.S2(), G.S3()]
        [(1,2)(3,4)(5,6)(7,8)(9,10), (1,8,3)(2,4,6)(5,7,10)]
        >>> X = G.odd_subgroups()
        >>> for u in X: print([u.S2(), u.S3()])
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,8,3,11,18,13)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,18,13,11,8,3)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,8,13,11,18,3)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]
        [(1,2,11,12)(3,4,13,14)(5,6,15,16)(7,8,17,18)(9,10,19,20), (1,18,3,11,8,13)(2,4,6,12,14,16)(5,7,10,15,17,20)(9,19)]

    A projective congruence subgroup may have noncongruence liftings, as the example of \(\bar{\Gamma}_0(6)\) illustrates (see [KSV2011]):

    Sage

        sage: X = Gamma0(6).as_permutation_group().odd_subgroups(); Sequence([[u.S2(), u.S3()] for u in X],cr=True)
        [[(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)]]
        sage: [u.is_congruence() for u in X]
        [True, False, False, True, True, False, False, True]

    [Python]

        >>> from sage.all import *
        >>> X = Gamma0(Integer(6)).as_permutation_group().odd_subgroups(); Sequence([[u.S2(), u.S3()] for u in X],cr=True)
        [[(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,2,3,13,14,15)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)],
         [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23),
          (1,14,15,13,2,3)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)]]
        >>> [u.is_congruence() for u in X]
        [True, False, False, True, True, False, False, True]

  one_odd_subgroup(random=False)

    Return an odd subgroup of index 2 in \(\Gamma\), where \(\Gamma\) is this subgroup. If the optional argument `random` is False (the default), this returns an arbitrary but consistent choice from the set of index 2 odd subgroups. If `random` is True, then it will choose one of these at random.

    For details of the algorithm used, see the docstring for the related function `odd_subgroups()`, which returns a list of all the index 2 odd subgroups.

    EXAMPLES:

    Starting from \(\Gamma(4)\) we get back \(\Gamma(4)\):

    Sage

        sage: G = Gamma(4).as_permutation_group()
        sage: G.is_odd(), G.index()
        (True, 48)
        sage: Ge = G.to_even_subgroup()
        sage: Go = Ge.one_odd_subgroup()
        sage: Go.is_odd(), Go.index()
        (True, 48)
        sage: Go == G
        True

    Python

        >>> from sage.all import *
        >>> G = Gamma(Integer(4)).as_permutation_group()
        >>> G.is_odd(), G.index()
        (True, 48)
        >>> Ge = G.to_even_subgroup()
        >>> Go = Ge.one_odd_subgroup()
        >>> Go.is_odd(), Go.index()
        (True, 48)
        >>> Go == G
        True

    Starting from \(\Gamma(6)\) we get a different group:

    Sage

        sage: G = Gamma(6).as_permutation_group()
        sage: G.is_odd(), G.index()
        (True, 144)
        sage: Ge = G.to_even_subgroup()
        sage: Go = Ge.one_odd_subgroup()
        sage: Go.is_odd(), Go.index()
        (True, 144)
        sage: Go == G
        False

    [Python]

        >>> from sage.all import *
        >>> G = Gamma(Integer(6)).as_permutation_group()
        >>> G.is_odd(), G.index()
        (True, 144)
        >>> Ge = G.to_even_subgroup()
        >>> Go = Ge.one_odd_subgroup()
        >>> Go.is_odd(), Go.index()
        (True, 144)
        >>> Go == G
        False

    An error will be raised if there are no such subgroups, which occurs if and only if the group contains an element of order 4:

    Sage

        sage: Gamma0(10).as_permutation_group().one_odd_subgroup()
        Traceback (most recent call last):
        ...
        ValueError: Group contains an element of order 4, hence no index 2 odd subgroups

    Python

        >>> from sage.all import *
        >>> Gamma0(Integer(10)).as_permutation_group().one_odd_subgroup()
        Traceback (most recent call last):
        ...
        ValueError: Group contains an element of order 4, hence no index 2 odd subgroups

    Testing randomness:

    Sage

        sage: G = Gamma(6).as_permutation_group().to_even_subgroup()
        sage: G1 = G.one_odd_subgroup(random=True) # random
        sage: G1.is_subgroup(G)
        True

    [Python]

        >>> from sage.all import *
        >>> G = Gamma(Integer(6)).as_permutation_group().to_even_subgroup()
        >>> G1 = G.one_odd_subgroup(random=True) # random
        >>> G1.is_subgroup(G)
        True

  to_even_subgroup(relabel=True)

    Return the subgroup generated by `self` and `-Id`. Since `self` is even, this is just `self`. Provided for compatibility.

    EXAMPLES:

    Sage

        sage: G = Gamma0(4).as_permutation_group()
        sage: H = G.to_even_subgroup()
        sage: H == G
        True

    Python

        >>> from sage.all import *
        >>> G = Gamma0(Integer(4)).as_permutation_group()
        >>> H = G.to_even_subgroup()
        >>> H == G
        True

  todd_coxeter()

    alias of `todd_coxeter_l_s2()`.

  todd_coxeter_l_s2()

    Return a 4-tuple `(coset_reps, gens, l, s2)` where `coset_reps` is a list of coset representatives of the subgroup, `gens` a list of generators, `l` and `s2` are list that corresponds to the action of the matrix \(S2\) and \(L\) on the cosets.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2='(1,2)(3,4)',S3='(1,2,3)')
        sage: reps,gens,l,s=G.todd_coxeter_l_s2()
        sage: reps
        [
        [1 0]  [ 0 -1]  [1 2]  [1 1]
        [0 1], [ 1  0], [0 1], [0 1]
        ]
        sage: len(gens)
        3
        sage: Matrix(2, 2, [1, 3, 0, 1]) in gens
        True
        sage: Matrix(2, 2, [1, 0, -1, 1]) in gens
        True
        sage: Matrix(2, 2, [1, -3, 1, -2]) in gens or Matrix(2, 2, [2, -3, 1, -1]) in gens
        True
        sage: l
        [3, 1, 0, 2]
        sage: s
        [1, 0, 3, 2]
        sage: S2 = SL2Z([0,-1,1,0])
        sage: L = SL2Z([1,1,0,1])
        sage: reps[0] == SL2Z([1,0,0,1])
        True
        sage: all(reps[i]*S2*~reps[s[i]] in G for i in range(4))
        True
        sage: all(reps[i]*L*~reps[l[i]] in G for i in range(4))
        True

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2='(1,2)(3,4)',S3='(1,2,3)')
        >>> reps,gens,l,s=G.todd_coxeter_l_s2()
        >>> reps
        [
        [1 0]  [ 0 -1]  [1 2]  [1 1]
        [0 1], [ 1  0], [0 1], [0 1]
        ]
        >>> len(gens)
        3
        >>> Matrix(Integer(2), Integer(2), [Integer(1), Integer(3), Integer(0), Integer(1)]) in gens
        True
        >>> Matrix(Integer(2), Integer(2), [Integer(1), Integer(0), -Integer(1), Integer(1)]) in gens
        True
        >>> Matrix(Integer(2), Integer(2), [Integer(1), -Integer(3), Integer(1), -Integer(2)]) in gens or Matrix(Integer(2), Integer(2), [Integer(2), -Integer(3), Integer(1), -Integer(1)]) in gens
        True
        >>> l
        [3, 1, 0, 2]
        >>> s
        [1, 0, 3, 2]
        >>> S2 = SL2Z([Integer(0),-Integer(1),Integer(1),Integer(0)])
        >>> L = SL2Z([Integer(1),Integer(1),Integer(0),Integer(1)])
        >>> reps[Integer(0)] == SL2Z([Integer(1),Integer(0),Integer(0),Integer(1)])
        True
        >>> all(reps[i]*S2*~reps[s[i]] in G for i in range(Integer(4)))
        True
        >>> all(reps[i]*L*~reps[l[i]] in G for i in range(Integer(4)))
        True

  todd_coxeter_s2_s3()

    Return a 4-tuple `(coset_reps, gens, s2, s3)` where `coset_reps` are coset representatives of the subgroup, `gens` is a list of generators, `s2` and `s3` are the action of the matrices \(S2\) and \(S3\) on the list of cosets.

    The so called Todd-Coxeter algorithm is a general method for coset enumeration for a subgroup of a group given by generators and relations.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2='(1,2)(3,4)',S3='(1,2,3)')
        sage: G.genus()
        0
        sage: reps,gens,s2,s3=G.todd_coxeter_s2_s3()
        sage: g1,g2 = gens
        sage: g1 in G and g2 in G
        True
        sage: Matrix(2, 2, [-1, 3, -1, 2]) in gens
        True
        sage: Matrix(2, 2, [-1, 0, 1, -1]) in gens or Matrix(2, 2, [1, 0, 1, 1]) in gens
        True
        sage: S2 = SL2Z([0,-1,1,0])
        sage: S3 = SL2Z([0,1,-1,1])
        sage: reps[0] == SL2Z([1,0,0,1])
        True
        sage: all(reps[i]*S2*~reps[s2[i]] in G for i in range(4))
        True
        sage: all(reps[i]*S3*~reps[s3[i]] in G for i in range(4))
        True

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2='(1,2)(3,4)',S3='(1,2,3)')
        >>> G.genus()
        0
        >>> reps,gens,s2,s3=G.todd_coxeter_s2_s3()
        >>> g1,g2 = gens
        >>> g1 in G and g2 in G
        True
        >>> Matrix(Integer(2), Integer(2), [-Integer(1), Integer(3), -Integer(1), Integer(2)]) in gens
        True
        >>> Matrix(Integer(2), Integer(2), [-Integer(1), Integer(0), Integer(1), -Integer(1)]) in gens or Matrix(Integer(2), Integer(2), [Integer(1), Integer(0), Integer(1), Integer(1)]) in gens
        True
        >>> S2 = SL2Z([Integer(0),-Integer(1),Integer(1),Integer(0)])
        >>> S3 = SL2Z([Integer(0),Integer(1),-Integer(1),Integer(1)])
        >>> reps[Integer(0)] == SL2Z([Integer(1),Integer(0),Integer(0),Integer(1)])
        True
        >>> all(reps[i]*S2*~reps[s2[i]] in G for i in range(Integer(4)))
        True
        >>> all(reps[i]*S3*~reps[s3[i]] in G for i in range(Integer(4)))
        True

sage.modular.arithgroup.arithgroup_perm.HsuExample10()

  An example of an index 10 arithmetic subgroup studied by Tim Hsu.

  EXAMPLES:

  Sage

      sage: import sage.modular.arithgroup.arithgroup_perm as ap
      sage: ap.HsuExample10()
      Arithmetic subgroup with permutations of right cosets
       S2=(1,2)(3,4)(5,6)(7,8)(9,10)
       S3=(1,8,3)(2,4,6)(5,7,10)
       L=(1,4)(2,5,9,10,8)(3,7,6)
       R=(1,7,9,10,6)(2,3)(4,5,8)

  Python

      >>> from sage.all import *
      >>> import sage.modular.arithgroup.arithgroup_perm as ap
      >>> ap.HsuExample10()
      Arithmetic subgroup with permutations of right cosets
       S2=(1,2)(3,4)(5,6)(7,8)(9,10)
       S3=(1,8,3)(2,4,6)(5,7,10)
       L=(1,4)(2,5,9,10,8)(3,7,6)
       R=(1,7,9,10,6)(2,3)(4,5,8)

sage.modular.arithgroup.arithgroup_perm.HsuExample18()

  An example of an index 18 arithmetic subgroup studied by Tim Hsu.

  EXAMPLES:

  Sage

      sage: import sage.modular.arithgroup.arithgroup_perm as ap
      sage: ap.HsuExample18()
      Arithmetic subgroup with permutations of right cosets
       S2=(1,5)(2,11)(3,10)(4,15)(6,18)(7,12)(8,14)(9,16)(13,17)
       S3=(1,7,11)(2,18,5)(3,9,15)(4,14,10)(6,17,12)(8,13,16)
       L=(1,2)(3,4)(5,6,7)(8,9,10)(11,12,13,14,15,16,17,18)
       R=(1,12,18)(2,6,13,9,4,8,17,7)(3,16,14)(5,11)(10,15)

  Python

      >>> from sage.all import *
      >>> import sage.modular.arithgroup.arithgroup_perm as ap
      >>> ap.HsuExample18()
      Arithmetic subgroup with permutations of right cosets
       S2=(1,5)(2,11)(3,10)(4,15)(6,18)(7,12)(8,14)(9,16)(13,17)
       S3=(1,7,11)(2,18,5)(3,9,15)(4,14,10)(6,17,12)(8,13,16)
       L=(1,2)(3,4)(5,6,7)(8,9,10)(11,12,13,14,15,16,17,18)
       R=(1,12,18)(2,6,13,9,4,8,17,7)(3,16,14)(5,11)(10,15)

class sage.modular.arithgroup.arithgroup_perm.OddArithmeticSubgroup_Permutation(S2, S3, L, R, canonical_labels=False)

  Bases: `ArithmeticSubgroup_Permutation_class`

  An arithmetic subgroup of \(\SL(2, \ZZ)\) not containing \(-1\), represented in terms of the right action of \(\SL(2, \ZZ)\) on its cosets.

  EXAMPLES:

  Sage

      sage: G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
      sage: G
      Arithmetic subgroup with permutations of right cosets
      S2=(1,2,3,4)
      S3=(1,3)(2,4)
      L=(1,2,3,4)
      R=(1,4,3,2)
      sage: type(G)
      <class 'sage.modular.arithgroup.arithgroup_perm.OddArithmeticSubgroup_Permutation_with_category'>

  Python

      >>> from sage.all import *
      >>> G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
      >>> G
      Arithmetic subgroup with permutations of right cosets
      S2=(1,2,3,4)
      S3=(1,3)(2,4)
      L=(1,2,3,4)
      R=(1,4,3,2)
      >>> type(G)
      <class 'sage.modular.arithgroup.arithgroup_perm.OddArithmeticSubgroup_Permutation_with_category'>

  cusp_widths(exp=False)

    Return the list of cusp widths.

    INPUT:

    - `exp` – boolean (default: `False`); if `True`, return a dictionary with keys the possible widths and with values the number of cusp with that width

    EXAMPLES:

    Sage

        sage: G = Gamma1(5).as_permutation_group()
        sage: G.cusp_widths()
        [1, 1, 5, 5]
        sage: G.cusp_widths(exp=True)
        {1: 2, 5: 2}

    Python

        >>> from sage.all import *
        >>> G = Gamma1(Integer(5)).as_permutation_group()
        >>> G.cusp_widths()
        [1, 1, 5, 5]
        >>> G.cusp_widths(exp=True)
        {1: 2, 5: 2}

  is_even()

    Test whether the group is even.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,6,4,3)(2,7,5,8)",S3="(1,2,3,4,5,6)(7,8)")
        sage: G.is_even()
        False

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,6,4,3)(2,7,5,8)",S3="(1,2,3,4,5,6)(7,8)")
        >>> G.is_even()
        False

  is_odd()

    Test whether the group is odd.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,6,4,3)(2,7,5,8)",S3="(1,2,3,4,5,6)(7,8)")
        sage: G.is_odd()
        True

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,6,4,3)(2,7,5,8)",S3="(1,2,3,4,5,6)(7,8)")
        >>> G.is_odd()
        True

  ncusps()

    Return the number of cusps.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
        sage: G.ncusps()
        1

        sage: G = Gamma1(3).as_permutation_group()
        sage: G.ncusps()
        2

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
        >>> G.ncusps()
        1

        >>> G = Gamma1(Integer(3)).as_permutation_group()
        >>> G.ncusps()
        2

  nirregcusps()

    Return the number of irregular cusps.

    The cusps are associated to cycles of the permutations \(L\) or \(R\). The irregular cusps are the one which are stabilised by \(-Id\).

    EXAMPLES:

    Sage

        sage: S2 = "(1,3,2,4)(5,7,6,8)(9,11,10,12)"
        sage: S3 = "(1,3,5,2,4,6)(7,9,11,8,10,12)"
        sage: G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        sage: G.nirregcusps()
        3

    Python

        >>> from sage.all import *
        >>> S2 = "(1,3,2,4)(5,7,6,8)(9,11,10,12)"
        >>> S3 = "(1,3,5,2,4,6)(7,9,11,8,10,12)"
        >>> G = ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
        >>> G.nirregcusps()
        3

  nregcusps()

    Return the number of regular cusps of the group.

    The cusps are associated to cycles of \(L\) or \(R\). The irregular cusps correspond to the ones which are not stabilised by \(-Id\).

    EXAMPLES:

    Sage

        sage: G = Gamma1(3).as_permutation_group()
        sage: G.nregcusps()
        2

    Python

        >>> from sage.all import *
        >>> G = Gamma1(Integer(3)).as_permutation_group()
        >>> G.nregcusps()
        2

  nu2()

    Return the number of elliptic points of order 2.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
        sage: G.nu2()
        0

        sage: G = Gamma1(2).as_permutation_group()
        sage: G.nu2()
        1

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
        >>> G.nu2()
        0

        >>> G = Gamma1(Integer(2)).as_permutation_group()
        >>> G.nu2()
        1

  nu3()

    Return the number of elliptic points of order 3.

    EXAMPLES:

    Sage

        sage: G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
        sage: G.nu3()
        2

        sage: G = Gamma1(3).as_permutation_group()
        sage: G.nu3()
        1

    Python

        >>> from sage.all import *
        >>> G = ArithmeticSubgroup_Permutation(S2="(1,2,3,4)",S3="(1,3)(2,4)")
        >>> G.nu3()
        2

        >>> G = Gamma1(Integer(3)).as_permutation_group()
        >>> G.nu3()
        1

  to_even_subgroup(relabel=True)

    Return the group with \(-Id\) added in it.

    EXAMPLES:

    Sage

        sage: G = Gamma1(3).as_permutation_group()
        sage: G.to_even_subgroup()
        Arithmetic subgroup with permutations of right cosets
         S2=(1,3)(2,4)
         S3=(1,2,3)
         L=(2,3,4)
         R=(1,4,2)

        sage: H = ArithmeticSubgroup_Permutation(S2 = '(1,4,11,14)(2,7,12,17)(3,5,13,15)(6,9,16,19)(8,10,18,20)', S3 = '(1,2,3,11,12,13)(4,5,6,14,15,16)(7,8,9,17,18,19)(10,20)')
        sage: G = H.to_even_subgroup(relabel=False); G
        Arithmetic subgroup with permutations of right cosets
         S2=(1,4)(2,7)(3,5)(6,9)(8,10)
         S3=(1,2,3)(4,5,6)(7,8,9)
         L=(1,5)(2,4,9,10,8)(3,7,6)
         R=(1,7,10,8,6)(2,5,9)(3,4)
        sage: H.is_subgroup(G)
        True

    Python

        >>> from sage.all import *
        >>> G = Gamma1(Integer(3)).as_permutation_group()
        >>> G.to_even_subgroup()
        Arithmetic subgroup with permutations of right cosets
         S2=(1,3)(2,4)
         S3=(1,2,3)
         L=(2,3,4)
         R=(1,4,2)

        >>> H = ArithmeticSubgroup_Permutation(S2 = '(1,4,11,14)(2,7,12,17)(3,5,13,15)(6,9,16,19)(8,10,18,20)', S3 = '(1,2,3,11,12,13)(4,5,6,14,15,16)(7,8,9,17,18,19)(10,20)')
        >>> G = H.to_even_subgroup(relabel=False); G
        Arithmetic subgroup with permutations of right cosets
         S2=(1,4)(2,7)(3,5)(6,9)(8,10)
         S3=(1,2,3)(4,5,6)(7,8,9)
         L=(1,5)(2,4,9,10,8)(3,7,6)
         R=(1,7,10,8,6)(2,5,9)(3,4)
        >>> H.is_subgroup(G)
        True

sage.modular.arithgroup.arithgroup_perm.eval_sl2z_word(w)

  Given a word in the format output by `sl2z_word_problem()`, convert it back into an element of \(\SL_2(\ZZ)\).

  EXAMPLES:

  Sage

      sage: from sage.modular.arithgroup.arithgroup_perm import eval_sl2z_word
      sage: eval_sl2z_word([(0, 1), (1, -1), (0, 0), (1, 3), (0, 2), (1, 9), (0, -1)])
      [ 66 -59]
      [ 47 -42]

  Python

      >>> from sage.all import *
      >>> from sage.modular.arithgroup.arithgroup_perm import eval_sl2z_word
      >>> eval_sl2z_word([(Integer(0), Integer(1)), (Integer(1), -Integer(1)), (Integer(0), Integer(0)), (Integer(1), Integer(3)), (Integer(0), Integer(2)), (Integer(1), Integer(9)), (Integer(0), -Integer(1))])
      [ 66 -59]
      [ 47 -42]

sage.modular.arithgroup.arithgroup_perm.sl2z_word_problem(A)

  Given an element of \(\SL_2(\ZZ)\), express it as a word in the generators L = [1,1,0,1] and R = [1,0,1,1].

  The return format is a list of pairs `(a,b)`, where `a = 0` or `1` denoting `L` or `R` respectively, and `b` is an integer exponent.

  See also the function `eval_sl2z_word()`.

  EXAMPLES:

  Sage

      sage: from sage.modular.arithgroup.arithgroup_perm import eval_sl2z_word, sl2z_word_problem
      sage: m = SL2Z([1,0,0,1])
      sage: eval_sl2z_word(sl2z_word_problem(m)) == m
      True
      sage: m = SL2Z([0,-1,1,0])
      sage: eval_sl2z_word(sl2z_word_problem(m)) == m
      True
      sage: m = SL2Z([7,8,-50,-57])
      sage: eval_sl2z_word(sl2z_word_problem(m)) == m
      True

  Python

      >>> from sage.all import *
      >>> from sage.modular.arithgroup.arithgroup_perm import eval_sl2z_word, sl2z_word_problem
      >>> m = SL2Z([Integer(1),Integer(0),Integer(0),Integer(1)])
      >>> eval_sl2z_word(sl2z_word_problem(m)) == m
      True
      >>> m = SL2Z([Integer(0),-Integer(1),Integer(1),Integer(0)])
      >>> eval_sl2z_word(sl2z_word_problem(m)) == m
      True
      >>> m = SL2Z([Integer(7),Integer(8),-Integer(50),-Integer(57)])
      >>> eval_sl2z_word(sl2z_word_problem(m)) == m
      True

sage.modular.arithgroup.arithgroup_perm.word_of_perms(w, p1, p2)

  Given a word \(w\) as a list of 2-tuples `(index,power)` and permutations `p1` and `p2` return the product of `p1` and `p2` that corresponds to `w`.

  EXAMPLES:

  Sage

      sage: import sage.modular.arithgroup.arithgroup_perm as ap
      sage: S2 = SymmetricGroup(4)
      sage: p1 = S2('(1,2)(3,4)')
      sage: p2 = S2('(1,2,3,4)')
      sage: ap.word_of_perms([(1,1),(0,1)], p1, p2) ==  p2 * p1
      True
      sage: ap.word_of_perms([(0,1),(1,1)], p1, p2) == p1 * p2
      True

  Python

      >>> from sage.all import *
      >>> import sage.modular.arithgroup.arithgroup_perm as ap
      >>> S2 = SymmetricGroup(Integer(4))
      >>> p1 = S2('(1,2)(3,4)')
      >>> p2 = S2('(1,2,3,4)')
      >>> ap.word_of_perms([(Integer(1),Integer(1)),(Integer(0),Integer(1))], p1, p2) ==  p2 * p1
      True
      >>> ap.word_of_perms([(Integer(0),Integer(1)),(Integer(1),Integer(1))], p1, p2) == p1 * p2
      True