Finitely Presented Groups - Groups

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

# Finitely Presented Groups

Finitely presented groups are constructed as quotients of `free_group`:

Sage

    sage: F.<a,b,c> = FreeGroup()
    sage: G = F / [a^2, b^2, c^2, a*b*c*a*b*c]
    sage: G
    Finitely presented group < a, b, c | a^2, b^2, c^2, (a*b*c)^2 >

Python

    >>> from sage.all import *
    >>> F = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = F._first_ngens(3)
    >>> G = F / [a**Integer(2), b**Integer(2), c**Integer(2), a*b*c*a*b*c]
    >>> G
    Finitely presented group < a, b, c | a^2, b^2, c^2, (a*b*c)^2 >

One can create their elements by multiplying the generators or by specifying a Tietze list (see `Tietze()`) as in the case of free groups:

Sage

    sage: G.gen(0) * G.gen(1)
    a*b
    sage: G([1,2,-1])
    a*b*a^-1
    sage: a.parent()
    Free Group on generators {a, b, c}
    sage: G.inject_variables()
    Defining a, b, c
    sage: a.parent()
    Finitely presented group < a, b, c | a^2, b^2, c^2, (a*b*c)^2 >

[Python]

    >>> from sage.all import *
    >>> G.gen(Integer(0)) * G.gen(Integer(1))
    a*b
    >>> G([Integer(1),Integer(2),-Integer(1)])
    a*b*a^-1
    >>> a.parent()
    Free Group on generators {a, b, c}
    >>> G.inject_variables()
    Defining a, b, c
    >>> a.parent()
    Finitely presented group < a, b, c | a^2, b^2, c^2, (a*b*c)^2 >

Notice that, even if they are represented in the same way, the elements of a finitely presented group and the elements of the corresponding free group are not the same thing. However, they can be converted from one parent to the other:

Sage

    sage: F.<a,b,c> = FreeGroup()
    sage: G = F / [a^2,b^2,c^2,a*b*c*a*b*c]
    sage: F([1])
    a
    sage: G([1])
    a
    sage: F([1]) is G([1])
    False
    sage: F([1]) == G([1])
    False
    sage: G(a*b/c)
    a*b*c^-1
    sage: F(G(a*b/c))
    a*b*c^-1

Python

    >>> from sage.all import *
    >>> F = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = F._first_ngens(3)
    >>> G = F / [a**Integer(2),b**Integer(2),c**Integer(2),a*b*c*a*b*c]
    >>> F([Integer(1)])
    a
    >>> G([Integer(1)])
    a
    >>> F([Integer(1)]) is G([Integer(1)])
    False
    >>> F([Integer(1)]) == G([Integer(1)])
    False
    >>> G(a*b/c)
    a*b*c^-1
    >>> F(G(a*b/c))
    a*b*c^-1

Finitely presented groups are implemented via GAP. You can use the `gap()` method to access the underlying LibGAP object:

Sage

    sage: G = FreeGroup(2)
    sage: G.inject_variables()
    Defining x0, x1
    sage: H = G / (x0^2, (x0*x1)^2, x1^2)
    sage: H.gap()
    <fp group on the generators [ x0, x1 ]>

[Python]

    >>> from sage.all import *
    >>> G = FreeGroup(Integer(2))
    >>> G.inject_variables()
    Defining x0, x1
    >>> H = G / (x0**Integer(2), (x0*x1)**Integer(2), x1**Integer(2))
    >>> H.gap()
    <fp group on the generators [ x0, x1 ]>

This can be useful, for example, to use GAP functions that are not yet wrapped in Sage:

Sage

    sage: H.gap().LowerCentralSeries()
    [ Group(<fp, no generators known>), Group(<fp, no generators known>) ]

Python

    >>> from sage.all import *
    >>> H.gap().LowerCentralSeries()
    [ Group(<fp, no generators known>), Group(<fp, no generators known>) ]

The same holds for the group elements:

Sage

    sage: G = FreeGroup(2)
    sage: H = G / (G([1, 1]), G([2, 2, 2]), G([1, 2, -1, -2]));  H
    Finitely presented group < x0, x1 | x0^2, x1^3, x0*x1*x0^-1*x1^-1 >
    sage: a = H([1])
    sage: a
    x0
    sage: a.gap()
    x0
    sage: a.gap().Order()
    2
    sage: type(_)    # note that the above output is not a Sage integer
    <class 'sage.libs.gap.element.GapElement_Integer'>

[Python]

    >>> from sage.all import *
    >>> G = FreeGroup(Integer(2))
    >>> H = G / (G([Integer(1), Integer(1)]), G([Integer(2), Integer(2), Integer(2)]), G([Integer(1), Integer(2), -Integer(1), -Integer(2)]));  H
    Finitely presented group < x0, x1 | x0^2, x1^3, x0*x1*x0^-1*x1^-1 >
    >>> a = H([Integer(1)])
    >>> a
    x0
    >>> a.gap()
    x0
    >>> a.gap().Order()
    2
    >>> type(_)    # note that the above output is not a Sage integer
    <class 'sage.libs.gap.element.GapElement_Integer'>

You can use call syntax to replace the generators with a set of arbitrary ring elements. For example, take the free abelian group obtained by modding out the commutator subgroup of the free group:

Sage

    sage: G = FreeGroup(2)
    sage: G_ab = G / [G([1, 2, -1, -2])];  G_ab
    Finitely presented group < x0, x1 | x0*x1*x0^-1*x1^-1 >
    sage: a,b = G_ab.gens()
    sage: g =  a * b
    sage: M1 = matrix([[1,0],[0,2]])
    sage: M2 = matrix([[0,1],[1,0]])
    sage: g(3, 5)
    15
    sage: g(M1, M1)
    [1 0]
    [0 4]
    sage: M1*M2 == M2*M1   # matrices do not commute
    False
    sage: g(M1, M2)
    Traceback (most recent call last):
    ...
    ValueError: the values do not satisfy all relations of the group

Python

    >>> from sage.all import *
    >>> G = FreeGroup(Integer(2))
    >>> G_ab = G / [G([Integer(1), Integer(2), -Integer(1), -Integer(2)])];  G_ab
    Finitely presented group < x0, x1 | x0*x1*x0^-1*x1^-1 >
    >>> a,b = G_ab.gens()
    >>> g =  a * b
    >>> M1 = matrix([[Integer(1),Integer(0)],[Integer(0),Integer(2)]])
    >>> M2 = matrix([[Integer(0),Integer(1)],[Integer(1),Integer(0)]])
    >>> g(Integer(3), Integer(5))
    15
    >>> g(M1, M1)
    [1 0]
    [0 4]
    >>> M1*M2 == M2*M1   # matrices do not commute
    False
    >>> g(M1, M2)
    Traceback (most recent call last):
    ...
    ValueError: the values do not satisfy all relations of the group

Warning

Some methods are not guaranteed to finish since the word problem for finitely presented groups is, in general, undecidable. In those cases the process may run until the available memory is exhausted.

REFERENCES:

- Wikipedia article Presentation_of_a_group

- Wikipedia article Word_problem_for_groups

AUTHOR:

- Miguel Angel Marco Buzunariz

class sage.groups.finitely_presented.FinitelyPresentedGroup(free_group, relations, category=None, libgap_fpgroup=None)

  Bases: `GroupMixinLibGAP`, `CachedRepresentation`, `Group`, `ParentLibGAP`

  A class that wraps GAP’s Finitely Presented Groups.

  Warning

  You should use `quotient()` to construct finitely presented groups as quotients of free groups. Any class inheriting this one should define `__reduce__ = CachedRepresentation.__reduce__` after importing `CachedRepresentation`.

  EXAMPLES:

  Sage

      sage: G.<a,b> = FreeGroup()
      sage: H = G / [a, b^3]
      sage: H
      Finitely presented group < a, b | a, b^3 >
      sage: H.gens()
      (a, b)

      sage: F.<a,b> = FreeGroup('a, b')
      sage: J = F / (F([1]), F([2, 2, 2]))
      sage: J is H
      True

      sage: G = FreeGroup(2)
      sage: H = G / (G([1, 1]), G([2, 2, 2]))
      sage: H.gens()
      (x0, x1)
      sage: H.gen(0)
      x0
      sage: H.ngens()
      2
      sage: H.gap()
      <fp group on the generators [ x0, x1 ]>
      sage: type(_)
      <class 'sage.libs.gap.element.GapElement'>

  Python

      >>> from sage.all import *
      >>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
      >>> H = G / [a, b**Integer(3)]
      >>> H
      Finitely presented group < a, b | a, b^3 >
      >>> H.gens()
      (a, b)

      >>> F = FreeGroup('a, b', names=('a', 'b',)); (a, b,) = F._first_ngens(2)
      >>> J = F / (F([Integer(1)]), F([Integer(2), Integer(2), Integer(2)]))
      >>> J is H
      True

      >>> G = FreeGroup(Integer(2))
      >>> H = G / (G([Integer(1), Integer(1)]), G([Integer(2), Integer(2), Integer(2)]))
      >>> H.gens()
      (x0, x1)
      >>> H.gen(Integer(0))
      x0
      >>> H.ngens()
      2
      >>> H.gap()
      <fp group on the generators [ x0, x1 ]>
      >>> type(_)
      <class 'sage.libs.gap.element.GapElement'>

  Element

    alias of `FinitelyPresentedGroupElement`

  abelian_alexander_matrix(ring=Rational Field, simplified=True)

    Return the Alexander matrix of the group with values in the group algebra of the abelianized.

    INPUT:

    - `ring` – (default: `QQ`) the base ring of the group algebra

    - `simplified` – boolean (default: `False`); if set to `True` use Gauss elimination and erase rows and columns

    OUTPUT:

    - `A` – a matrix with coefficients in `R`

    - `ideal` – an list of generators of an ideal `I` of `R = A.base_ring()` such that `R/I` is the group algebra of the abelianization of `self`

    EXAMPLES:

    Sage

        sage: G.<a,b,c> = FreeGroup()
        sage: H = G.quotient([a*b/a/b, a*c/a/c, c*b/c/b])
        sage: A, ideal = H.abelian_alexander_matrix()
        sage: A
        [-f2 + 1  f1 - 1       0]
        [-f3 + 1       0  f1 - 1]
        [      0  f3 - 1 -f2 + 1]
        sage: A.base_ring()
        Multivariate Laurent Polynomial Ring in f1, f2, f3 over Rational Field
        sage: ideal
        []
        sage: G = FreeGroup(3)/[(2, 1, 1), (1, 2, 2, 3, 3)]
        sage: A, ideal = G.abelian_alexander_matrix(simplified=True); A
        [-f1^2 - f1^4 - f1^6         f1^3 + f1^6]
        sage: g = FreeGroup(1) / []
        sage: g.abelian_alexander_matrix()
        ([], [])
        sage: g.abelian_alexander_matrix()[0].base_ring()
        Univariate Laurent Polynomial Ring in f1 over Rational Field
        sage: g = FreeGroup(0) / []
        sage: A, ideal = g.abelian_alexander_matrix(); A
        []
        sage: A.base_ring()
        Rational Field

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3)
        >>> H = G.quotient([a*b/a/b, a*c/a/c, c*b/c/b])
        >>> A, ideal = H.abelian_alexander_matrix()
        >>> A
        [-f2 + 1  f1 - 1       0]
        [-f3 + 1       0  f1 - 1]
        [      0  f3 - 1 -f2 + 1]
        >>> A.base_ring()
        Multivariate Laurent Polynomial Ring in f1, f2, f3 over Rational Field
        >>> ideal
        []
        >>> G = FreeGroup(Integer(3))/[(Integer(2), Integer(1), Integer(1)), (Integer(1), Integer(2), Integer(2), Integer(3), Integer(3))]
        >>> A, ideal = G.abelian_alexander_matrix(simplified=True); A
        [-f1^2 - f1^4 - f1^6         f1^3 + f1^6]
        >>> g = FreeGroup(Integer(1)) / []
        >>> g.abelian_alexander_matrix()
        ([], [])
        >>> g.abelian_alexander_matrix()[Integer(0)].base_ring()
        Univariate Laurent Polynomial Ring in f1 over Rational Field
        >>> g = FreeGroup(Integer(0)) / []
        >>> A, ideal = g.abelian_alexander_matrix(); A
        []
        >>> A.base_ring()
        Rational Field

  abelian_invariants()

    Return the abelian invariants of `self`.

    The abelian invariants are given by a list of integers \((i_1, \ldots, i_j)\), such that the abelianization of the group is isomorphic to \(\ZZ / (i_1) \times \cdots \times \ZZ / (i_j)\).

    EXAMPLES:

    Sage

        sage: G = FreeGroup(4, 'g')
        sage: G.inject_variables()
        Defining g0, g1, g2, g3
        sage: H = G.quotient([g1^2, g2*g1*g2^(-1)*g1^(-1), g1*g3^(-2), g0^4])
        sage: H.abelian_invariants()
        (0, 4, 4)

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(Integer(4), 'g')
        >>> G.inject_variables()
        Defining g0, g1, g2, g3
        >>> H = G.quotient([g1**Integer(2), g2*g1*g2**(-Integer(1))*g1**(-Integer(1)), g1*g3**(-Integer(2)), g0**Integer(4)])
        >>> H.abelian_invariants()
        (0, 4, 4)

    ALGORITHM:

    Uses GAP.

  abelianization_map()

    Return the abelianization map of `self`.

    OUTPUT: the abelianization map of `self` as a homomorphism of finitely presented groups

    EXAMPLES:

    Sage

        sage: G = FreeGroup(4, 'g')
        sage: G.inject_variables(verbose=False)
        sage: H = G.quotient([g1^2, g2*g1*g2^(-1)*g1^(-1), g1*g3^(-2), g0^4])
        sage: H.abelianization_map()
        Group morphism:
          From: Finitely presented group < g0, g1, g2, g3 | g1^2, g2*g1*g2^-1*g1^-1, g1*g3^-2, g0^4 >
          To:   Finitely presented group < f1, f2, f3 | f1^4, f2^-1*f1^-1*f2*f1, f2^4, f3^-1*f1^-1*f3*f1, f3^-1*f2^-1*f3*f2 >
        sage: g = FreeGroup(0) / []
        sage: g.abelianization_map()
        Group endomorphism of Finitely presented group  <  |  >

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(Integer(4), 'g')
        >>> G.inject_variables(verbose=False)
        >>> H = G.quotient([g1**Integer(2), g2*g1*g2**(-Integer(1))*g1**(-Integer(1)), g1*g3**(-Integer(2)), g0**Integer(4)])
        >>> H.abelianization_map()
        Group morphism:
          From: Finitely presented group < g0, g1, g2, g3 | g1^2, g2*g1*g2^-1*g1^-1, g1*g3^-2, g0^4 >
          To:   Finitely presented group < f1, f2, f3 | f1^4, f2^-1*f1^-1*f2*f1, f2^4, f3^-1*f1^-1*f3*f1, f3^-1*f2^-1*f3*f2 >
        >>> g = FreeGroup(Integer(0)) / []
        >>> g.abelianization_map()
        Group endomorphism of Finitely presented group  <  |  >

  abelianization_to_algebra(ring=Rational Field)

    Return the group algebra of the abelianization of `self` together with the monomials representing the generators of `self`.

    INPUT:

    - `ring` – (default: `QQ`) the base ring for the group algebra of `self`

    OUTPUT:

    - `ab` – the abelianization of `self` as a finitely presented group with a minimal number \(n\) of generators

    - `R` – a Laurent polynomial ring with \(n\) variables with base ring `ring`

    - `ideal` – list of generators of an ideal `I` in `R` such that `R/I` is the group algebra of the abelianization over `ring`

    - `image` – list with the images of the generators of `self` in `R/I`

    EXAMPLES:

    Sage

        sage: G = FreeGroup(4, 'g')
        sage: G.inject_variables()
        Defining g0, g1, g2, g3
        sage: H = G.quotient([g1^2, g2*g1*g2^(-1)*g1^(-1), g1*g3^(-2), g0^4])
        sage: H.abelianization_to_algebra()
        (Finitely presented group < f1, f2, f3 | f1^4, f2^-1*f1^-1*f2*f1, f2^4, f3^-1*f1^-1*f3*f1, f3^-1*f2^-1*f3*f2 >,
         Multivariate Laurent Polynomial Ring in f1, f2, f3 over Rational Field,
         [f1^4 - 1, f2^4 - 1],
         [f1^3*f2^2, f2^2, f3, f2])
        sage: g=FreeGroup(0) / []
        sage: g.abelianization_to_algebra()
        (Finitely presented group  <  |  >, Rational Field, [], [])

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(Integer(4), 'g')
        >>> G.inject_variables()
        Defining g0, g1, g2, g3
        >>> H = G.quotient([g1**Integer(2), g2*g1*g2**(-Integer(1))*g1**(-Integer(1)), g1*g3**(-Integer(2)), g0**Integer(4)])
        >>> H.abelianization_to_algebra()
        (Finitely presented group < f1, f2, f3 | f1^4, f2^-1*f1^-1*f2*f1, f2^4, f3^-1*f1^-1*f3*f1, f3^-1*f2^-1*f3*f2 >,
         Multivariate Laurent Polynomial Ring in f1, f2, f3 over Rational Field,
         [f1^4 - 1, f2^4 - 1],
         [f1^3*f2^2, f2^2, f3, f2])
        >>> g=FreeGroup(Integer(0)) / []
        >>> g.abelianization_to_algebra()
        (Finitely presented group  <  |  >, Rational Field, [], [])

  alexander_matrix(im_gens=None)

    Return the Alexander matrix of the group.

    This matrix is given by the Fox derivatives of the relations with respect to the generators.

    - `im_gens` – (optional) the images of the generators

    OUTPUT:

    A matrix with coefficients in the group algebra. If `im_gens` is given, the coefficients will live in the same algebra as the given values. The result depends on the (fixed) choice of presentation.

    EXAMPLES:

    Sage

        sage: G.<a,b,c> = FreeGroup()
        sage: H = G.quotient([a*b/a/b, a*c/a/c, c*b/c/b])
        sage: H.alexander_matrix()
        [     1 - a*b*a^-1 a - a*b*a^-1*b^-1                 0]
        [     1 - a*c*a^-1                 0 a - a*c*a^-1*c^-1]
        [                0 c - c*b*c^-1*b^-1      1 - c*b*c^-1]

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3)
        >>> H = G.quotient([a*b/a/b, a*c/a/c, c*b/c/b])
        >>> H.alexander_matrix()
        [     1 - a*b*a^-1 a - a*b*a^-1*b^-1                 0]
        [     1 - a*c*a^-1                 0 a - a*c*a^-1*c^-1]
        [                0 c - c*b*c^-1*b^-1      1 - c*b*c^-1]

    If we introduce the images of the generators, we obtain the result in the corresponding algebra.

    Sage

        sage: G.<a,b,c,d,e> = FreeGroup()
        sage: H = G.quotient([a*b/a/b, a*c/a/c, a*d/a/d, b*c*d/(c*d*b), b*c*d/(d*b*c)])
        sage: H.alexander_matrix()
        [              1 - a*b*a^-1          a - a*b*a^-1*b^-1                          0                          0                          0]
        [              1 - a*c*a^-1                          0          a - a*c*a^-1*c^-1                          0                          0]
        [              1 - a*d*a^-1                          0                          0          a - a*d*a^-1*d^-1                          0]
        [                         0             1 - b*c*d*b^-1   b - b*c*d*b^-1*d^-1*c^-1      b*c - b*c*d*b^-1*d^-1                          0]
        [                         0        1 - b*c*d*c^-1*b^-1             b - b*c*d*c^-1 b*c - b*c*d*c^-1*b^-1*d^-1                          0]
        sage: R.<t1,t2,t3,t4> = LaurentPolynomialRing(ZZ)
        sage: H.alexander_matrix([t1,t2,t3,t4])
        [    -t2 + 1      t1 - 1           0           0           0]
        [    -t3 + 1           0      t1 - 1           0           0]
        [    -t4 + 1           0           0      t1 - 1           0]
        [          0  -t3*t4 + 1      t2 - 1  t2*t3 - t3           0]
        [          0     -t4 + 1 -t2*t4 + t2   t2*t3 - 1           0]

    [Python]

        >>> from sage.all import *
        >>> G = FreeGroup(names=('a', 'b', 'c', 'd', 'e',)); (a, b, c, d, e,) = G._first_ngens(5)
        >>> H = G.quotient([a*b/a/b, a*c/a/c, a*d/a/d, b*c*d/(c*d*b), b*c*d/(d*b*c)])
        >>> H.alexander_matrix()
        [              1 - a*b*a^-1          a - a*b*a^-1*b^-1                          0                          0                          0]
        [              1 - a*c*a^-1                          0          a - a*c*a^-1*c^-1                          0                          0]
        [              1 - a*d*a^-1                          0                          0          a - a*d*a^-1*d^-1                          0]
        [                         0             1 - b*c*d*b^-1   b - b*c*d*b^-1*d^-1*c^-1      b*c - b*c*d*b^-1*d^-1                          0]
        [                         0        1 - b*c*d*c^-1*b^-1             b - b*c*d*c^-1 b*c - b*c*d*c^-1*b^-1*d^-1                          0]
        >>> R = LaurentPolynomialRing(ZZ, names=('t1', 't2', 't3', 't4',)); (t1, t2, t3, t4,) = R._first_ngens(4)
        >>> H.alexander_matrix([t1,t2,t3,t4])
        [    -t2 + 1      t1 - 1           0           0           0]
        [    -t3 + 1           0      t1 - 1           0           0]
        [    -t4 + 1           0           0      t1 - 1           0]
        [          0  -t3*t4 + 1      t2 - 1  t2*t3 - t3           0]
        [          0     -t4 + 1 -t2*t4 + t2   t2*t3 - 1           0]

  as_permutation_group(limit=4096000)

    Return an isomorphic permutation group.

    The generators of the resulting group correspond to the images by the isomorphism of the generators of the given group.

    INPUT:

    - `limit` – integer (default: 4096000); the maximal number of cosets before the computation is aborted

    OUTPUT:

    A Sage `PermutationGroup()`. If the number of cosets exceeds the given `limit`, a `ValueError` is returned.

    EXAMPLES:

    Sage

        sage: G.<a,b> = FreeGroup()
        sage: H = G / (a^2, b^3, a*b*~a*~b)
        sage: H.as_permutation_group()
        Permutation Group with generators [(1,2)(3,5)(4,6), (1,3,4)(2,5,6)]

        sage: G.<a,b> = FreeGroup()
        sage: H = G / [a^3*b]
        sage: H.as_permutation_group(limit=1000)
        Traceback (most recent call last):
        ...
        ValueError: Coset enumeration exceeded limit, is the group finite?

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
        >>> H = G / (a**Integer(2), b**Integer(3), a*b*~a*~b)
        >>> H.as_permutation_group()
        Permutation Group with generators [(1,2)(3,5)(4,6), (1,3,4)(2,5,6)]

        >>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
        >>> H = G / [a**Integer(3)*b]
        >>> H.as_permutation_group(limit=Integer(1000))
        Traceback (most recent call last):
        ...
        ValueError: Coset enumeration exceeded limit, is the group finite?

    ALGORITHM:

    Uses GAP’s coset enumeration on the trivial subgroup.

    Warning

    This is in general not a decidable problem (in fact, it is not even possible to check if the group is finite or not). If the group is infinite, or too big, you should be prepared for a long computation that consumes all the memory without finishing if you do not set a sensible `limit`.

  cardinality(limit=4096000)

    Compute the cardinality of `self`.

    INPUT:

    - `limit` – integer (default: 4096000); the maximal number of cosets before the computation is aborted

    OUTPUT: integer or `Infinity`; the number of elements in the group

    EXAMPLES:

    Sage

        sage: G.<a,b> = FreeGroup('a, b')
        sage: H = G / (a^2, b^3, a*b*~a*~b)
        sage: H.cardinality()
        6

        sage: F.<a,b,c> = FreeGroup()
        sage: J = F / (F([1]), F([2, 2, 2]))
        sage: J.cardinality()
        +Infinity

    Python

        >>> from sage.all import *
        >>> G = FreeGroup('a, b', names=('a', 'b',)); (a, b,) = G._first_ngens(2)
        >>> H = G / (a**Integer(2), b**Integer(3), a*b*~a*~b)
        >>> H.cardinality()
        6

        >>> F = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = F._first_ngens(3)
        >>> J = F / (F([Integer(1)]), F([Integer(2), Integer(2), Integer(2)]))
        >>> J.cardinality()
        +Infinity

    ALGORITHM:

    > Uses GAP.

    Warning

    This is in general not a decidable problem, so it is not guaranteed to give an answer. If the group is infinite, or too big, you should be prepared for a long computation that consumes all the memory without finishing if you do not set a sensible `limit`.

  characteristic_varieties(ring=Rational Field, matrix_ideal=None, groebner=False)

    Return the characteristic varieties of the group `self`.

    There are several definitions of the characteristic varieties of a group \(G\), see e.g. [CS1999a]. Let \(\Lambda\) be the group algebra of \(G/G'\) and \(\mathbb{T}\) its associated algebraic variety (a torus). Each element \(\xi\in\mathbb{T}\) defines a local system of coefficients and the \(k\)-th characteristic variety is

    \[V_k(G) = \{\xi\in\mathbb{T}\mid \dim H^1(G;\xi)\geq k\}.\]

    These varieties are defined by ideals in \(\Lambda\).

    INPUT:

    - `ring` – (default: `QQ`) the base ring of the group algebra

    - `groebner` – boolean (default: `False`); if set to `True` the minimal associated primes of the ideals and their groebner bases are computed; ignored if the base ring is not a field

    OUTPUT:

    A dictionary with keys the indices of the varieties. If `groebner` is `False` the values are the ideals defining the characteristic varieties. If it is `True`, lists for Gröbner bases for the ideal of each irreducible component, stopping when the first time a characteristic variety is empty.

    EXAMPLES:

    Sage

        sage: L = [2*(i, j) + 2* (-i, -j) for i, j in ((1, 2), (2, 3), (3, 1))]
        sage: G = FreeGroup(3) / L
        sage: G.characteristic_varieties(groebner=True)
        {0: [(0,)],
         1: [(f1 - 1, f2 - 1, f3 - 1), (f1*f3 + 1, f2 - 1), (f1*f2 + 1, f3 - 1), (f2*f3 + 1, f1 - 1),
             (f2*f3 + 1, f1 - f2), (f2*f3 + 1, f1 - f3), (f1*f3 + 1, f2 - f3)],
         2: [(f1 - 1, f2 - 1, f3 - 1), (f1 + 1, f2 - 1, f3 - 1), (f1 - 1, f2 - 1, f3 + 1),
             (f3^2 + 1, f1 - f3, f2 - f3), (f1 - 1, f2 + 1, f3 - 1)],
         3: [(f1 - 1, f2 - 1, f3 - 1)],
         4: []}
        sage: G = FreeGroup(2)/[2*(1,2,-1,-2)]
        sage: G.characteristic_varieties()
        {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
         1: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
         2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
         3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field}
        sage: G.characteristic_varieties(ring=ZZ)
        {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
         1: Ideal (2*f2 - 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
         2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
         3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring}
        sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)]
        sage: G.characteristic_varieties()
        {0: Ideal (0) of Univariate Laurent Polynomial Ring in f1 over Rational Field,
         1: Ideal (-1 + 2*f1 - 2*f1^2 + f1^3) of Univariate Laurent Polynomial Ring in f1 over Rational Field,
         2: Ideal (1) of Univariate Laurent Polynomial Ring in f1 over Rational Field}
        sage: G.characteristic_varieties(groebner=True)
        {0: [0], 1: [-1 + f1, 1 - f1 + f1^2], 2: []}
        sage: G = FreeGroup(2)/[3 * (1, ), 2 * (2, )]
        sage: G.characteristic_varieties(groebner=True)
        {0: [-1 + F1, 1 + F1, 1 - F1 + F1^2, 1 + F1 + F1^2], 1: [1 - F1 + F1^2],  2: []}
        sage: G = FreeGroup(2)/[2 * (2, )]
        sage: G.characteristic_varieties(groebner=True)
        {0: [(f1 + 1,), (f1 - 1,)], 1: [(f1 + 1,), (f1 - 1, f2 - 1)], 2: []}
        sage: G = (FreeGroup(0) / [])
        sage: G.characteristic_varieties()
        {0: Principal ideal (0) of Rational Field,
         1: Principal ideal (1) of Rational Field}
        sage: G.characteristic_varieties(groebner=True)
        {0: [(0,)], 1: [(1,)]}

    Python

        >>> from sage.all import *
        >>> L = [Integer(2)*(i, j) + Integer(2)* (-i, -j) for i, j in ((Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(3), Integer(1)))]
        >>> G = FreeGroup(Integer(3)) / L
        >>> G.characteristic_varieties(groebner=True)
        {0: [(0,)],
         1: [(f1 - 1, f2 - 1, f3 - 1), (f1*f3 + 1, f2 - 1), (f1*f2 + 1, f3 - 1), (f2*f3 + 1, f1 - 1),
             (f2*f3 + 1, f1 - f2), (f2*f3 + 1, f1 - f3), (f1*f3 + 1, f2 - f3)],
         2: [(f1 - 1, f2 - 1, f3 - 1), (f1 + 1, f2 - 1, f3 - 1), (f1 - 1, f2 - 1, f3 + 1),
             (f3^2 + 1, f1 - f3, f2 - f3), (f1 - 1, f2 + 1, f3 - 1)],
         3: [(f1 - 1, f2 - 1, f3 - 1)],
         4: []}
        >>> G = FreeGroup(Integer(2))/[Integer(2)*(Integer(1),Integer(2),-Integer(1),-Integer(2))]
        >>> G.characteristic_varieties()
        {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
         1: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
         2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
         3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field}
        >>> G.characteristic_varieties(ring=ZZ)
        {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
         1: Ideal (2*f2 - 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
         2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
         3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring}
        >>> G = FreeGroup(Integer(2))/[(Integer(1),Integer(2),Integer(1),-Integer(2),-Integer(1),-Integer(2))]
        >>> G.characteristic_varieties()
        {0: Ideal (0) of Univariate Laurent Polynomial Ring in f1 over Rational Field,
         1: Ideal (-1 + 2*f1 - 2*f1^2 + f1^3) of Univariate Laurent Polynomial Ring in f1 over Rational Field,
         2: Ideal (1) of Univariate Laurent Polynomial Ring in f1 over Rational Field}
        >>> G.characteristic_varieties(groebner=True)
        {0: [0], 1: [-1 + f1, 1 - f1 + f1^2], 2: []}
        >>> G = FreeGroup(Integer(2))/[Integer(3) * (Integer(1), ), Integer(2) * (Integer(2), )]
        >>> G.characteristic_varieties(groebner=True)
        {0: [-1 + F1, 1 + F1, 1 - F1 + F1^2, 1 + F1 + F1^2], 1: [1 - F1 + F1^2],  2: []}
        >>> G = FreeGroup(Integer(2))/[Integer(2) * (Integer(2), )]
        >>> G.characteristic_varieties(groebner=True)
        {0: [(f1 + 1,), (f1 - 1,)], 1: [(f1 + 1,), (f1 - 1, f2 - 1)], 2: []}
        >>> G = (FreeGroup(Integer(0)) / [])
        >>> G.characteristic_varieties()
        {0: Principal ideal (0) of Rational Field,
         1: Principal ideal (1) of Rational Field}
        >>> G.characteristic_varieties(groebner=True)
        {0: [(0,)], 1: [(1,)]}

  direct_product(H, reduced=False, new_names=True)

    Return the direct product of `self` with finitely presented group `H`.

    Calls GAP function `DirectProduct`, which returns the direct product of a list of groups of any representation.

    From [Joh1990] (p. 45, proposition 4): If \(G\), \(H\) are groups presented by \(\langle X \mid R \rangle\) and \(\langle Y \mid S \rangle\) respectively, then their direct product has the presentation \(\langle X, Y \mid R, S, [X, Y] \rangle\) where \([X, Y]\) denotes the set of commutators \(\{ x^{-1} y^{-1} x y \mid x \in X, y \in Y \}\).

    INPUT:

    - `H` – a finitely presented group

    - `reduced` – boolean (default: `False`); if `True`, then attempt to reduce the presentation of the product group

    - `new_names` – boolean (default: `True`); if `True`, then lexicographical variable names are assigned to the generators of the group to be returned. If `False`, the group to be returned keeps the generator names of the two groups forming the direct product. Note that one cannot ask to reduce the output and ask to keep the old variable names, as they may change meaning in the output group if its presentation is reduced.

    OUTPUT: the direct product of `self` with `H` as a finitely presented group

    EXAMPLES:

    Sage

        sage: G = FreeGroup()
        sage: C12 =  ( G / [G([1,1,1,1])] ).direct_product( G / [G([1,1,1])]); C12
        Finitely presented group < a, b | a^4, b^3, a^-1*b^-1*a*b >
        sage: C12.order(), C12.as_permutation_group().is_cyclic()
        (12, True)
        sage: klein = ( G / [G([1,1])] ).direct_product( G / [G([1,1])]); klein
        Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
        sage: klein.order(), klein.as_permutation_group().is_cyclic()
        (4, False)

    Python

        >>> from sage.all import *
        >>> G = FreeGroup()
        >>> C12 =  ( G / [G([Integer(1),Integer(1),Integer(1),Integer(1)])] ).direct_product( G / [G([Integer(1),Integer(1),Integer(1)])]); C12
        Finitely presented group < a, b | a^4, b^3, a^-1*b^-1*a*b >
        >>> C12.order(), C12.as_permutation_group().is_cyclic()
        (12, True)
        >>> klein = ( G / [G([Integer(1),Integer(1)])] ).direct_product( G / [G([Integer(1),Integer(1)])]); klein
        Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
        >>> klein.order(), klein.as_permutation_group().is_cyclic()
        (4, False)

    We can keep the variable names from `self` and `H` to examine how new relations are formed:

    Sage

        sage: F = FreeGroup("a"); G = FreeGroup("g")
        sage: X = G / [G.0^12]; A = F / [F.0^6]
        sage: X.direct_product(A, new_names=False)
        Finitely presented group < g, a | g^12, a^6, g^-1*a^-1*g*a >
        sage: A.direct_product(X, new_names=False)
        Finitely presented group < a, g | a^6, g^12, a^-1*g^-1*a*g >

    [Python]

        >>> from sage.all import *
        >>> F = FreeGroup("a"); G = FreeGroup("g")
        >>> X = G / [G.gen(0)**Integer(12)]; A = F / [F.gen(0)**Integer(6)]
        >>> X.direct_product(A, new_names=False)
        Finitely presented group < g, a | g^12, a^6, g^-1*a^-1*g*a >
        >>> A.direct_product(X, new_names=False)
        Finitely presented group < a, g | a^6, g^12, a^-1*g^-1*a*g >

    Or we can attempt to reduce the output group presentation:

    Sage

        sage: F = FreeGroup("a"); G = FreeGroup("g")
        sage: X = G / [G.0]; A = F / [F.0]
        sage: X.direct_product(A, new_names=True)
        Finitely presented group < a, b | a, b, a^-1*b^-1*a*b >
        sage: X.direct_product(A, reduced=True, new_names=True)
        Finitely presented group <  |  >

    Python

        >>> from sage.all import *
        >>> F = FreeGroup("a"); G = FreeGroup("g")
        >>> X = G / [G.gen(0)]; A = F / [F.gen(0)]
        >>> X.direct_product(A, new_names=True)
        Finitely presented group < a, b | a, b, a^-1*b^-1*a*b >
        >>> X.direct_product(A, reduced=True, new_names=True)
        Finitely presented group <  |  >

    But we cannot do both:

    Sage

        sage: K = FreeGroup(['a','b'])
        sage: D = K / [K.0^5, K.1^8]
        sage: D.direct_product(D, reduced=True, new_names=False)
        Traceback (most recent call last):
        ...
        ValueError: cannot reduce output and keep old variable names

    [Python]

        >>> from sage.all import *
        >>> K = FreeGroup(['a','b'])
        >>> D = K / [K.gen(0)**Integer(5), K.gen(1)**Integer(8)]
        >>> D.direct_product(D, reduced=True, new_names=False)
        Traceback (most recent call last):
        ...
        ValueError: cannot reduce output and keep old variable names

    AUTHORS:

    - Davis Shurbert (2013-07-20): initial version

  epimorphisms(H)

    Return the epimorphisms from `self` to \(H\), up to automorphism of \(H\).

    INPUT:

    - `H` – another group

    EXAMPLES:

    Sage

        sage: F = FreeGroup(3)
        sage: G = F / [F([1, 2, 3, 1, 2, 3]), F([1, 1, 1])]
        sage: H = AlternatingGroup(3)
        sage: for quo in G.epimorphisms(H):
        ....:   for a in G.gens():
        ....:       print(a, "|-->", quo(a))
        ....:   print("-----")
        x0 |--> ()
        x1 |--> (1,3,2)
        x2 |--> (1,2,3)
        -----
        x0 |--> (1,3,2)
        x1 |--> ()
        x2 |--> (1,2,3)
        -----
        x0 |--> (1,3,2)
        x1 |--> (1,2,3)
        x2 |--> ()
        -----
        x0 |--> (1,2,3)
        x1 |--> (1,2,3)
        x2 |--> (1,2,3)
        -----

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(Integer(3))
        >>> G = F / [F([Integer(1), Integer(2), Integer(3), Integer(1), Integer(2), Integer(3)]), F([Integer(1), Integer(1), Integer(1)])]
        >>> H = AlternatingGroup(Integer(3))
        >>> for quo in G.epimorphisms(H):
        ...   for a in G.gens():
        ...       print(a, "|-->", quo(a))
        ...   print("-----")
        x0 |--> ()
        x1 |--> (1,3,2)
        x2 |--> (1,2,3)
        -----
        x0 |--> (1,3,2)
        x1 |--> ()
        x2 |--> (1,2,3)
        -----
        x0 |--> (1,3,2)
        x1 |--> (1,2,3)
        x2 |--> ()
        -----
        x0 |--> (1,2,3)
        x1 |--> (1,2,3)
        x2 |--> (1,2,3)
        -----

    ALGORITHM:

    Uses libgap’s GQuotients function.

  free_group()

    Return the free group (without relations).

    OUTPUT: a `FreeGroup()`

    EXAMPLES:

    Sage

        sage: G.<a,b,c> = FreeGroup()
        sage: H = G / (a^2, b^3, a*b*~a*~b)
        sage: H.free_group()
        Free Group on generators {a, b, c}
        sage: H.free_group() is G
        True

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3)
        >>> H = G / (a**Integer(2), b**Integer(3), a*b*~a*~b)
        >>> H.free_group()
        Free Group on generators {a, b, c}
        >>> H.free_group() is G
        True

  order(limit=4096000)

    alias of `cardinality()`.

  relations()

    Return the relations of the group.

    OUTPUT: the relations as a tuple of elements of `free_group()`

    EXAMPLES:

    Sage

        sage: F = FreeGroup(5, 'x')
        sage: F.inject_variables()
        Defining x0, x1, x2, x3, x4
        sage: G = F.quotient([x0*x2, x3*x1*x3, x2*x1*x2])
        sage: G.relations()
        (x0*x2, x3*x1*x3, x2*x1*x2)
        sage: all(rel in F for rel in G.relations())
        True

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(Integer(5), 'x')
        >>> F.inject_variables()
        Defining x0, x1, x2, x3, x4
        >>> G = F.quotient([x0*x2, x3*x1*x3, x2*x1*x2])
        >>> G.relations()
        (x0*x2, x3*x1*x3, x2*x1*x2)
        >>> all(rel in F for rel in G.relations())
        True

  rewriting_system()

    Return the rewriting system corresponding to the finitely presented group. This rewriting system can be used to reduce words with respect to the relations.

    If the rewriting system is transformed into a confluent one, the reduction process will give as a result the (unique) reduced form of an element.

    EXAMPLES:

    Sage

        sage: F.<a,b> = FreeGroup()
        sage: G = F / [a^2,b^3,(a*b/a)^3,b*a*b*a]
        sage: k = G.rewriting_system()
        sage: k
        Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, b*a*b*a >
        with rules:
            a^2    --->    1
            b^3    --->    1
            b*a*b*a    --->    1
            a*b^3*a^-1    --->    1

        sage: G([1,1,2,2,2])
        a^2*b^3
        sage: k.reduce(G([1,1,2,2,2]))
        1
        sage: k.reduce(G([2,2,1]))
        b^2*a
        sage: k.make_confluent()
        sage: k.reduce(G([2,2,1]))
        a*b

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
        >>> G = F / [a**Integer(2),b**Integer(3),(a*b/a)**Integer(3),b*a*b*a]
        >>> k = G.rewriting_system()
        >>> k
        Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, b*a*b*a >
        with rules:
            a^2    --->    1
            b^3    --->    1
            b*a*b*a    --->    1
            a*b^3*a^-1    --->    1

        >>> G([Integer(1),Integer(1),Integer(2),Integer(2),Integer(2)])
        a^2*b^3
        >>> k.reduce(G([Integer(1),Integer(1),Integer(2),Integer(2),Integer(2)]))
        1
        >>> k.reduce(G([Integer(2),Integer(2),Integer(1)]))
        b^2*a
        >>> k.make_confluent()
        >>> k.reduce(G([Integer(2),Integer(2),Integer(1)]))
        a*b

  semidirect_product(H, hom, check=True, reduced=False)

    The semidirect product of `self` with `H` via `hom`.

    If there exists a homomorphism \(\phi\) from a group \(G\) to the automorphism group of a group \(H\), then we can define the semidirect product of \(G\) with \(H\) via \(\phi\) as the Cartesian product of \(G\) and \(H\) with the operation

    \[(g_1, h_1)(g_2, h_2) = (g_1 g_2, \phi(g_2)(h_1) h_2).\]

    INPUT:

    - `H` – finitely presented group which is implicitly acted on by `self` and can be naturally embedded as a normal subgroup of the semidirect product

    - `hom` – homomorphism from `self` to the automorphism group of `H`. Given as a pair, with generators of `self` in the first slot and the images of the corresponding generators in the second. These images must be automorphisms of `H`, given again as a pair of generators and images.

    - `check` – boolean (default: `True`); if `False` the defining homomorphism and automorphism images are not tested for validity. This test can be costly with large groups, so it can be bypassed if the user is confident that his morphisms are valid.

    - `reduced` – boolean (default: `False`); if `True` then the method attempts to reduce the presentation of the output group

    OUTPUT:

    The semidirect product of `self` with `H` via `hom` as a finitely presented group. See `PermutationGroup_generic.semidirect_product` for a more in depth explanation of a semidirect product.

    AUTHORS:

    - Davis Shurbert (8-1-2013)

    EXAMPLES:

    Group of order 12 as two isomorphic semidirect products:

    Sage

        sage: D4 = groups.presentation.Dihedral(4)
        sage: C3 = groups.presentation.Cyclic(3)
        sage: alpha1 = ([C3.gen(0)],[C3.gen(0)])
        sage: alpha2 = ([C3.gen(0)],[C3([1,1])])
        sage: S1 = D4.semidirect_product(C3, ([D4.gen(1), D4.gen(0)],[alpha1,alpha2]))
        sage: C2 = groups.presentation.Cyclic(2)
        sage: Q = groups.presentation.DiCyclic(3)
        sage: a = Q([1]); b = Q([-2])
        sage: alpha = (Q.gens(), [a,b])
        sage: S2 = C2.semidirect_product(Q, ([C2.0],[alpha]))
        sage: S1.is_isomorphic(S2)
        True

    Python

        >>> from sage.all import *
        >>> D4 = groups.presentation.Dihedral(Integer(4))
        >>> C3 = groups.presentation.Cyclic(Integer(3))
        >>> alpha1 = ([C3.gen(Integer(0))],[C3.gen(Integer(0))])
        >>> alpha2 = ([C3.gen(Integer(0))],[C3([Integer(1),Integer(1)])])
        >>> S1 = D4.semidirect_product(C3, ([D4.gen(Integer(1)), D4.gen(Integer(0))],[alpha1,alpha2]))
        >>> C2 = groups.presentation.Cyclic(Integer(2))
        >>> Q = groups.presentation.DiCyclic(Integer(3))
        >>> a = Q([Integer(1)]); b = Q([-Integer(2)])
        >>> alpha = (Q.gens(), [a,b])
        >>> S2 = C2.semidirect_product(Q, ([C2.gen(0)],[alpha]))
        >>> S1.is_isomorphic(S2)
        True

    Dihedral groups can be constructed as semidirect products of cyclic groups:

    Sage

        sage: C2 = groups.presentation.Cyclic(2)
        sage: C8 = groups.presentation.Cyclic(8)
        sage: hom = (C2.gens(), [ ([C8([1])], [C8([-1])]) ])
        sage: D = C2.semidirect_product(C8, hom)
        sage: D.as_permutation_group().is_isomorphic(DihedralGroup(8))
        True

    [Python]

        >>> from sage.all import *
        >>> C2 = groups.presentation.Cyclic(Integer(2))
        >>> C8 = groups.presentation.Cyclic(Integer(8))
        >>> hom = (C2.gens(), [ ([C8([Integer(1)])], [C8([-Integer(1)])]) ])
        >>> D = C2.semidirect_product(C8, hom)
        >>> D.as_permutation_group().is_isomorphic(DihedralGroup(Integer(8)))
        True

    You can attempt to reduce the presentation of the output group:

    Sage

        sage: D = C2.semidirect_product(C8, hom); D
        Finitely presented group < a, b | a^2, b^8, a^-1*b*a*b >
        sage: D = C2.semidirect_product(C8, hom, reduced=True); D
        Finitely presented group < a, b | a^2, a*b*a*b, b^8 >

        sage: C3 = groups.presentation.Cyclic(3)
        sage: C4 = groups.presentation.Cyclic(4)
        sage: hom = (C3.gens(), [(C4.gens(), C4.gens())])
        sage: C3.semidirect_product(C4, hom)
        Finitely presented group < a, b | a^3, b^4, a^-1*b*a*b^-1 >
        sage: D = C3.semidirect_product(C4, hom, reduced=True); D
        Finitely presented group < a, b | a^3, b^4, a^-1*b*a*b^-1 >
        sage: D.as_permutation_group().is_cyclic()
        True

    Python

        >>> from sage.all import *
        >>> D = C2.semidirect_product(C8, hom); D
        Finitely presented group < a, b | a^2, b^8, a^-1*b*a*b >
        >>> D = C2.semidirect_product(C8, hom, reduced=True); D
        Finitely presented group < a, b | a^2, a*b*a*b, b^8 >

        >>> C3 = groups.presentation.Cyclic(Integer(3))
        >>> C4 = groups.presentation.Cyclic(Integer(4))
        >>> hom = (C3.gens(), [(C4.gens(), C4.gens())])
        >>> C3.semidirect_product(C4, hom)
        Finitely presented group < a, b | a^3, b^4, a^-1*b*a*b^-1 >
        >>> D = C3.semidirect_product(C4, hom, reduced=True); D
        Finitely presented group < a, b | a^3, b^4, a^-1*b*a*b^-1 >
        >>> D.as_permutation_group().is_cyclic()
        True

    You can turn off the checks for the validity of the input morphisms. This check is expensive but behavior is unpredictable if inputs are invalid and are not caught by these tests:

    Sage

        sage: C5 = groups.presentation.Cyclic(5)
        sage: C12 = groups.presentation.Cyclic(12)
        sage: hom = (C5.gens(), [(C12.gens(), C12.gens())])
        sage: sp = C5.semidirect_product(C12, hom, check=False); sp
        Finitely presented group < a, b | a^5, b^12, a^-1*b*a*b^-1 >
        sage: sp.as_permutation_group().is_cyclic(), sp.order()
        (True, 60)

    [Python]

        >>> from sage.all import *
        >>> C5 = groups.presentation.Cyclic(Integer(5))
        >>> C12 = groups.presentation.Cyclic(Integer(12))
        >>> hom = (C5.gens(), [(C12.gens(), C12.gens())])
        >>> sp = C5.semidirect_product(C12, hom, check=False); sp
        Finitely presented group < a, b | a^5, b^12, a^-1*b*a*b^-1 >
        >>> sp.as_permutation_group().is_cyclic(), sp.order()
        (True, 60)

  simplification_isomorphism()

    Return an isomorphism from `self` to a finitely presented group with a (hopefully) simpler presentation.

    EXAMPLES:

    Sage

        sage: G.<a,b,c> = FreeGroup()
        sage: H = G / [a*b*c, a*b^2, c*b/c^2]
        sage: I = H.simplification_isomorphism()
        sage: I
        Group morphism:
          From: Finitely presented group < a, b, c | a*b*c, a*b^2, c*b*c^-2 >
          To:   Finitely presented group < b |  >
        sage: I(a)
        b^-2
        sage: I(b)
        b
        sage: I(c)
        b

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3)
        >>> H = G / [a*b*c, a*b**Integer(2), c*b/c**Integer(2)]
        >>> I = H.simplification_isomorphism()
        >>> I
        Group morphism:
          From: Finitely presented group < a, b, c | a*b*c, a*b^2, c*b*c^-2 >
          To:   Finitely presented group < b |  >
        >>> I(a)
        b^-2
        >>> I(b)
        b
        >>> I(c)
        b

    ALGORITHM:

    Uses GAP.

  simplified()

    Return an isomorphic group with a (hopefully) simpler presentation.

    OUTPUT:

    A new finitely presented group. Use `simplification_isomorphism()` if you want to know the isomorphism.

    EXAMPLES:

    Sage

        sage: G.<x,y> = FreeGroup()
        sage: H = G /  [x ^5, y ^4, y*x*y^3*x ^3]
        sage: H
        Finitely presented group < x, y | x^5, y^4, y*x*y^3*x^3 >
        sage: H.simplified()
        Finitely presented group < x, y | y^4, y*x*y^-1*x^-2, x^5 >

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(names=('x', 'y',)); (x, y,) = G._first_ngens(2)
        >>> H = G /  [x **Integer(5), y **Integer(4), y*x*y**Integer(3)*x **Integer(3)]
        >>> H
        Finitely presented group < x, y | x^5, y^4, y*x*y^3*x^3 >
        >>> H.simplified()
        Finitely presented group < x, y | y^4, y*x*y^-1*x^-2, x^5 >

    A more complicate example:

    Sage

        sage: G.<e0, e1, e2, e3, e4, e5, e6, e7, e8, e9> = FreeGroup()
        sage: rels = [e6, e5, e3, e9, e4*e7^-1*e6, e9*e7^-1*e0,
        ....:         e0*e1^-1*e2, e5*e1^-1*e8, e4*e3^-1*e8, e2]
        sage: H = G.quotient(rels);  H
        Finitely presented group < e0, e1, e2, e3, e4, e5, e6, e7, e8, e9 |
        e6, e5, e3, e9, e4*e7^-1*e6, e9*e7^-1*e0, e0*e1^-1*e2, e5*e1^-1*e8, e4*e3^-1*e8, e2 >
        sage: H.simplified()
        Finitely presented group < e0 | e0^2 >

    [Python]

        >>> from sage.all import *
        >>> G = FreeGroup(names=('e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9',)); (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,) = G._first_ngens(10)
        >>> rels = [e6, e5, e3, e9, e4*e7**-Integer(1)*e6, e9*e7**-Integer(1)*e0,
        ...         e0*e1**-Integer(1)*e2, e5*e1**-Integer(1)*e8, e4*e3**-Integer(1)*e8, e2]
        >>> H = G.quotient(rels);  H
        Finitely presented group < e0, e1, e2, e3, e4, e5, e6, e7, e8, e9 |
        e6, e5, e3, e9, e4*e7^-1*e6, e9*e7^-1*e0, e0*e1^-1*e2, e5*e1^-1*e8, e4*e3^-1*e8, e2 >
        >>> H.simplified()
        Finitely presented group < e0 | e0^2 >

  sorted_presentation()

    Return the same presentation with the relations sorted to ensure equality.

    OUTPUT: a new finitely presented group with the relations sorted

    EXAMPLES:

    Sage

        sage: G = FreeGroup(2) / [(1, 2, -1, -2), ()]; G
        Finitely presented group < x0, x1 | x0*x1*x0^-1*x1^-1, 1 >
        sage: G.sorted_presentation()
        Finitely presented group < x0, x1 | 1, x1^-1*x0^-1*x1*x0 >

    Python

        >>> from sage.all import *
        >>> G = FreeGroup(Integer(2)) / [(Integer(1), Integer(2), -Integer(1), -Integer(2)), ()]; G
        Finitely presented group < x0, x1 | x0*x1*x0^-1*x1^-1, 1 >
        >>> G.sorted_presentation()
        Finitely presented group < x0, x1 | 1, x1^-1*x0^-1*x1*x0 >

  structure_description(G, latex=False)

    Return a string that tries to describe the structure of `G`.

    This methods wraps GAP’s `StructureDescription` method.

    For full details, including the form of the returned string and the algorithm to build it, see GAP’s documentation.

    INPUT:

    - `latex` – boolean (default: `False`); if `True`, return a LaTeX formatted string

    OUTPUT: string

    Warning

    From GAP’s documentation: The string returned by `StructureDescription` is not an isomorphism invariant: non-isomorphic groups can have the same string value, and two isomorphic groups in different representations can produce different strings.

    EXAMPLES:

    Sage

        sage: # needs sage.groups
        sage: G = CyclicPermutationGroup(6)
        sage: G.structure_description()
        'C6'
        sage: G.structure_description(latex=True)
        'C_{6}'
        sage: G2 = G.direct_product(G, maps=False)
        sage: LatexExpr(G2.structure_description(latex=True))
        C_{6} \times C_{6}

    Python

        >>> from sage.all import *
        >>> # needs sage.groups
        >>> G = CyclicPermutationGroup(Integer(6))
        >>> G.structure_description()
        'C6'
        >>> G.structure_description(latex=True)
        'C_{6}'
        >>> G2 = G.direct_product(G, maps=False)
        >>> LatexExpr(G2.structure_description(latex=True))
        C_{6} \times C_{6}

    This method is mainly intended for small groups or groups with few normal subgroups. Even then there are some surprises:

    Sage

        sage: D3 = DihedralGroup(3)                                                     # needs sage.groups
        sage: D3.structure_description()                                                # needs sage.groups
        'S3'

    [Python]

        >>> from sage.all import *
        >>> D3 = DihedralGroup(Integer(3))                                                     # needs sage.groups
        >>> D3.structure_description()                                                # needs sage.groups
        'S3'

    We use the Sage notation for the degree of dihedral groups:

    Sage

        sage: D4 = DihedralGroup(4)                                                     # needs sage.groups
        sage: D4.structure_description()                                                # needs sage.groups
        'D4'

    Python

        >>> from sage.all import *
        >>> D4 = DihedralGroup(Integer(4))                                                     # needs sage.groups
        >>> D4.structure_description()                                                # needs sage.groups
        'D4'

    Works for finitely presented groups (Issue #17573):

    Sage

        sage: F.<x, y> = FreeGroup()                                                    # needs sage.groups
        sage: G = F / [x^2*y^-1, x^3*y^2, x*y*x^-1*y^-1]                                # needs sage.groups
        sage: G.structure_description()                                                 # needs sage.groups
        'C7'

    [Python]

        >>> from sage.all import *
        >>> F = FreeGroup(names=('x', 'y',)); (x, y,) = F._first_ngens(2)# needs sage.groups
        >>> G = F / [x**Integer(2)*y**-Integer(1), x**Integer(3)*y**Integer(2), x*y*x**-Integer(1)*y**-Integer(1)]                                # needs sage.groups
        >>> G.structure_description()                                                 # needs sage.groups
        'C7'

    And matrix groups (Issue #17573):

    Sage

        sage: groups.matrix.GL(4,2).structure_description()                             # needs sage.libs.gap sage.modules
        'A8'

    Python

        >>> from sage.all import *
        >>> groups.matrix.GL(Integer(4),Integer(2)).structure_description()                             # needs sage.libs.gap sage.modules
        'A8'

class sage.groups.finitely_presented.FinitelyPresentedGroupElement(parent, x, check=True)

  Bases: `FreeGroupElement`

  A wrapper of GAP’s Finitely Presented Group elements.

  The elements are created by passing the Tietze list that determines them.

  EXAMPLES:

  Sage

      sage: G = FreeGroup('a, b')
      sage: H = G / [G([1]), G([2, 2, 2])]
      sage: H([1, 2, 1, -1])
      a*b
      sage: H([1, 2, 1, -2])
      a*b*a*b^-1
      sage: x = H([1, 2, -1, -2])
      sage: x
      a*b*a^-1*b^-1
      sage: y = H([2, 2, 2, 1, -2, -2, -2])
      sage: y
      b^3*a*b^-3
      sage: x*y
      a*b*a^-1*b^2*a*b^-3
      sage: x^(-1)
      b*a*b^-1*a^-1

  Python

      >>> from sage.all import *
      >>> G = FreeGroup('a, b')
      >>> H = G / [G([Integer(1)]), G([Integer(2), Integer(2), Integer(2)])]
      >>> H([Integer(1), Integer(2), Integer(1), -Integer(1)])
      a*b
      >>> H([Integer(1), Integer(2), Integer(1), -Integer(2)])
      a*b*a*b^-1
      >>> x = H([Integer(1), Integer(2), -Integer(1), -Integer(2)])
      >>> x
      a*b*a^-1*b^-1
      >>> y = H([Integer(2), Integer(2), Integer(2), Integer(1), -Integer(2), -Integer(2), -Integer(2)])
      >>> y
      b^3*a*b^-3
      >>> x*y
      a*b*a^-1*b^2*a*b^-3
      >>> x**(-Integer(1))
      b*a*b^-1*a^-1

  Tietze()

    Return the Tietze list of the element.

    The Tietze list of a word is a list of integers that represent the letters in the word. A positive integer \(i\) represents the letter corresponding to the \(i\)-th generator of the group. Negative integers represent the inverses of generators.

    OUTPUT: tuple of integers

    EXAMPLES:

    Sage

        sage: G = FreeGroup('a, b')
        sage: H = G / (G([1]), G([2, 2, 2]))
        sage: H.inject_variables()
        Defining a, b
        sage: a.Tietze()
        (1,)
        sage: x = a^2*b^(-3)*a^(-2)
        sage: x.Tietze()
        (1, 1, -2, -2, -2, -1, -1)

    Python

        >>> from sage.all import *
        >>> G = FreeGroup('a, b')
        >>> H = G / (G([Integer(1)]), G([Integer(2), Integer(2), Integer(2)]))
        >>> H.inject_variables()
        Defining a, b
        >>> a.Tietze()
        (1,)
        >>> x = a**Integer(2)*b**(-Integer(3))*a**(-Integer(2))
        >>> x.Tietze()
        (1, 1, -2, -2, -2, -1, -1)

class sage.groups.finitely_presented.GroupMorphismWithGensImages

  Bases: `SetMorphism`

  Class used for morphisms from finitely presented groups to other groups. It just adds the images of the generators at the end of the representation.

  EXAMPLES:

  Sage

      sage: F = FreeGroup(3)
      sage: G = F / [F([1, 2, 3, 1, 2, 3]), F([1, 1, 1])]
      sage: H = AlternatingGroup(3)
      sage: HS = G.Hom(H)
      sage: from sage.groups.finitely_presented import GroupMorphismWithGensImages
      sage: GroupMorphismWithGensImages(HS, lambda a: H.one())
      Generic morphism:
      From: Finitely presented group < x0, x1, x2 | (x0*x1*x2)^2, x0^3 >
      To:   Alternating group of order 3!/2 as a permutation group
      Defn: x0 |--> ()
            x1 |--> ()
            x2 |--> ()

  Python

      >>> from sage.all import *
      >>> F = FreeGroup(Integer(3))
      >>> G = F / [F([Integer(1), Integer(2), Integer(3), Integer(1), Integer(2), Integer(3)]), F([Integer(1), Integer(1), Integer(1)])]
      >>> H = AlternatingGroup(Integer(3))
      >>> HS = G.Hom(H)
      >>> from sage.groups.finitely_presented import GroupMorphismWithGensImages
      >>> GroupMorphismWithGensImages(HS, lambda a: H.one())
      Generic morphism:
      From: Finitely presented group < x0, x1, x2 | (x0*x1*x2)^2, x0^3 >
      To:   Alternating group of order 3!/2 as a permutation group
      Defn: x0 |--> ()
            x1 |--> ()
            x2 |--> ()

class sage.groups.finitely_presented.RewritingSystem(G)

  Bases: `object`

  A class that wraps GAP’s rewriting systems.

  A rewriting system is a set of rules that allow to transform one word in the group to an equivalent one.

  If the rewriting system is confluent, then the transformed word is a unique reduced form of the element of the group.

  Warning

  Note that the process of making a rewriting system confluent might not end.

  INPUT:

  - `G` – a group

  REFERENCES:

  - Wikipedia article Knuth-Bendix_completion_algorithm

  EXAMPLES:

  Sage

      sage: F.<a,b> = FreeGroup()
      sage: G = F / [a*b/a/b]
      sage: k = G.rewriting_system()
      sage: k
      Rewriting system of Finitely presented group < a, b | a*b*a^-1*b^-1 >
      with rules:
          a*b*a^-1*b^-1    --->    1

      sage: k.reduce(a*b*a*b)
      (a*b)^2
      sage: k.make_confluent()
      sage: k
      Rewriting system of Finitely presented group < a, b | a*b*a^-1*b^-1 >
      with rules:
          b^-1*a^-1    --->    a^-1*b^-1
          b^-1*a    --->    a*b^-1
          b*a^-1    --->    a^-1*b
          b*a    --->    a*b

      sage: k.reduce(a*b*a*b)
      a^2*b^2

  Python

      >>> from sage.all import *
      >>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
      >>> G = F / [a*b/a/b]
      >>> k = G.rewriting_system()
      >>> k
      Rewriting system of Finitely presented group < a, b | a*b*a^-1*b^-1 >
      with rules:
          a*b*a^-1*b^-1    --->    1

      >>> k.reduce(a*b*a*b)
      (a*b)^2
      >>> k.make_confluent()
      >>> k
      Rewriting system of Finitely presented group < a, b | a*b*a^-1*b^-1 >
      with rules:
          b^-1*a^-1    --->    a^-1*b^-1
          b^-1*a    --->    a*b^-1
          b*a^-1    --->    a^-1*b
          b*a    --->    a*b

      >>> k.reduce(a*b*a*b)
      a^2*b^2

  Todo

  - Include support for different orderings (currently only shortlex is used).

  - Include the GAP package kbmag for more functionalities, including automatic structures and faster compiled functions.

  AUTHORS:

  - Miguel Angel Marco Buzunariz (2013-12-16)

  finitely_presented_group()

    The finitely presented group where the rewriting system is defined.

    EXAMPLES:

    Sage

        sage: F = FreeGroup(3)
        sage: G = F / [ [1,2,3], [-1,-2,-3], [1,1], [2,2] ]
        sage: k = G.rewriting_system()
        sage: k.make_confluent()
        sage: k
        Rewriting system of Finitely presented group < x0, x1, x2 | x0*x1*x2, x0^-1*x1^-1*x2^-1, x0^2, x1^2 >
        with rules:
            x0^-1    --->    x0
            x1^-1    --->    x1
            x2^-1    --->    x2
            x0^2    --->    1
            x0*x1    --->    x2
            x0*x2    --->    x1
            x1*x0    --->    x2
            x1^2    --->    1
            x1*x2    --->    x0
            x2*x0    --->    x1
            x2*x1    --->    x0
            x2^2    --->    1
        sage: k.finitely_presented_group()
        Finitely presented group < x0, x1, x2 | x0*x1*x2, x0^-1*x1^-1*x2^-1, x0^2, x1^2 >

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(Integer(3))
        >>> G = F / [ [Integer(1),Integer(2),Integer(3)], [-Integer(1),-Integer(2),-Integer(3)], [Integer(1),Integer(1)], [Integer(2),Integer(2)] ]
        >>> k = G.rewriting_system()
        >>> k.make_confluent()
        >>> k
        Rewriting system of Finitely presented group < x0, x1, x2 | x0*x1*x2, x0^-1*x1^-1*x2^-1, x0^2, x1^2 >
        with rules:
            x0^-1    --->    x0
            x1^-1    --->    x1
            x2^-1    --->    x2
            x0^2    --->    1
            x0*x1    --->    x2
            x0*x2    --->    x1
            x1*x0    --->    x2
            x1^2    --->    1
            x1*x2    --->    x0
            x2*x0    --->    x1
            x2*x1    --->    x0
            x2^2    --->    1
        >>> k.finitely_presented_group()
        Finitely presented group < x0, x1, x2 | x0*x1*x2, x0^-1*x1^-1*x2^-1, x0^2, x1^2 >

  free_group()

    The free group after which the rewriting system is defined.

    EXAMPLES:

    Sage

        sage: F = FreeGroup(3)
        sage: G = F / [ [1,2,3], [-1,-2,-3] ]
        sage: k = G.rewriting_system()
        sage: k.free_group()
        Free Group on generators {x0, x1, x2}

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(Integer(3))
        >>> G = F / [ [Integer(1),Integer(2),Integer(3)], [-Integer(1),-Integer(2),-Integer(3)] ]
        >>> k = G.rewriting_system()
        >>> k.free_group()
        Free Group on generators {x0, x1, x2}

  gap()

    The gap representation of the rewriting system.

    EXAMPLES:

    Sage

        sage: F.<a,b> = FreeGroup()
        sage: G = F/[a*a,b*b]
        sage: k = G.rewriting_system()
        sage: k.gap()
        Knuth Bendix Rewriting System for Monoid( [ a, A, b, B ] ) with rules
        [ [ a*A, <identity ...> ], [ A*a, <identity ...> ],
          [ b*B, <identity ...> ], [ B*b, <identity ...> ],
          [ a^2, <identity ...> ], [ b^2, <identity ...> ] ]

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
        >>> G = F/[a*a,b*b]
        >>> k = G.rewriting_system()
        >>> k.gap()
        Knuth Bendix Rewriting System for Monoid( [ a, A, b, B ] ) with rules
        [ [ a*A, <identity ...> ], [ A*a, <identity ...> ],
          [ b*B, <identity ...> ], [ B*b, <identity ...> ],
          [ a^2, <identity ...> ], [ b^2, <identity ...> ] ]

  is_confluent()

    Return `True` if the system is confluent and `False` otherwise.

    EXAMPLES:

    Sage

        sage: F = FreeGroup(3)
        sage: G = F / [F([1,2,1,2,1,3,-1]),F([2,2,2,1,1,2]),F([1,2,3])]
        sage: k = G.rewriting_system()
        sage: k.is_confluent()
        False
        sage: k
        Rewriting system of Finitely presented group < x0, x1, x2 | (x0*x1)^2*x0*x2*x0^-1, x1^3*x0^2*x1, x0*x1*x2 >
        with rules:
            x0*x1*x2    --->    1
            x1^3*x0^2*x1    --->    1
            (x0*x1)^2*x0*x2*x0^-1    --->    1

        sage: k.make_confluent()
        sage: k.is_confluent()
        True
        sage: k
        Rewriting system of Finitely presented group < x0, x1, x2 | (x0*x1)^2*x0*x2*x0^-1, x1^3*x0^2*x1, x0*x1*x2 >
        with rules:
            x0^-1    --->    x0
            x1^-1    --->    x1
            x0^2    --->    1
            x0*x1    --->    x2^-1
            x0*x2^-1    --->    x1
            x1*x0    --->    x2
            x1^2    --->    1
            x1*x2^-1    --->    x0*x2
            x1*x2    --->    x0
            x2^-1*x0    --->    x0*x2
            x2^-1*x1    --->    x0
            x2^-2    --->    x2
            x2*x0    --->    x1
            x2*x1    --->    x0*x2
            x2^2    --->    x2^-1

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(Integer(3))
        >>> G = F / [F([Integer(1),Integer(2),Integer(1),Integer(2),Integer(1),Integer(3),-Integer(1)]),F([Integer(2),Integer(2),Integer(2),Integer(1),Integer(1),Integer(2)]),F([Integer(1),Integer(2),Integer(3)])]
        >>> k = G.rewriting_system()
        >>> k.is_confluent()
        False
        >>> k
        Rewriting system of Finitely presented group < x0, x1, x2 | (x0*x1)^2*x0*x2*x0^-1, x1^3*x0^2*x1, x0*x1*x2 >
        with rules:
            x0*x1*x2    --->    1
            x1^3*x0^2*x1    --->    1
            (x0*x1)^2*x0*x2*x0^-1    --->    1

        >>> k.make_confluent()
        >>> k.is_confluent()
        True
        >>> k
        Rewriting system of Finitely presented group < x0, x1, x2 | (x0*x1)^2*x0*x2*x0^-1, x1^3*x0^2*x1, x0*x1*x2 >
        with rules:
            x0^-1    --->    x0
            x1^-1    --->    x1
            x0^2    --->    1
            x0*x1    --->    x2^-1
            x0*x2^-1    --->    x1
            x1*x0    --->    x2
            x1^2    --->    1
            x1*x2^-1    --->    x0*x2
            x1*x2    --->    x0
            x2^-1*x0    --->    x0*x2
            x2^-1*x1    --->    x0
            x2^-2    --->    x2
            x2*x0    --->    x1
            x2*x1    --->    x0*x2
            x2^2    --->    x2^-1

  make_confluent()

    Apply the Knuth-Bendix algorithm to try to transform the rewriting system into a confluent one.

    Note that this method does not return any object, just changes the rewriting system internally.

    Warning

    This algorithm is not granted to finish. Although it may be useful in some occasions to run it, interrupt it manually after some time and use then the transformed rewriting system. Even if it is not confluent, it could be used to reduce some words.

    ALGORITHM:

    Uses GAP’s `MakeConfluent`.

    EXAMPLES:

    Sage

        sage: F.<a,b> = FreeGroup()
        sage: G = F / [a^2,b^3,(a*b/a)^3,b*a*b*a]
        sage: k = G.rewriting_system()
        sage: k
        Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, (b*a)^2 >
        with rules:
            a^2    --->    1
            b^3    --->    1
            (b*a)^2    --->    1
            a*b^3*a^-1    --->    1

        sage: k.make_confluent()
        sage: k
        Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, (b*a)^2 >
        with rules:
            a^-1    --->    a
            a^2    --->    1
            b^-1*a    --->    a*b
            b^-2    --->    b
            b*a    --->    a*b^-1
            b^2    --->    b^-1

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
        >>> G = F / [a**Integer(2),b**Integer(3),(a*b/a)**Integer(3),b*a*b*a]
        >>> k = G.rewriting_system()
        >>> k
        Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, (b*a)^2 >
        with rules:
            a^2    --->    1
            b^3    --->    1
            (b*a)^2    --->    1
            a*b^3*a^-1    --->    1

        >>> k.make_confluent()
        >>> k
        Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, (b*a)^2 >
        with rules:
            a^-1    --->    a
            a^2    --->    1
            b^-1*a    --->    a*b
            b^-2    --->    b
            b*a    --->    a*b^-1
            b^2    --->    b^-1

  reduce(element)

    Apply the rules in the rewriting system to the element, to obtain a reduced form.

    If the rewriting system is confluent, this reduced form is unique for all words representing the same element.

    EXAMPLES:

    Sage

        sage: F.<a,b> = FreeGroup()
        sage: G = F/[a^2, b^3, (a*b/a)^3, b*a*b*a]
        sage: k = G.rewriting_system()
        sage: k.reduce(b^4)
        b
        sage: k.reduce(a*b*a)
        a*b*a

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
        >>> G = F/[a**Integer(2), b**Integer(3), (a*b/a)**Integer(3), b*a*b*a]
        >>> k = G.rewriting_system()
        >>> k.reduce(b**Integer(4))
        b
        >>> k.reduce(a*b*a)
        a*b*a

  rules()

    Return the rules that form the rewriting system.

    OUTPUT:

    A dictionary containing the rules of the rewriting system. Each key is a word in the free group, and its corresponding value is the word to which it is reduced.

    EXAMPLES:

    Sage

        sage: F.<a,b> = FreeGroup()
        sage: G = F / [a*a*a,b*b*a*a]
        sage: k = G.rewriting_system()
        sage: k
        Rewriting system of Finitely presented group < a, b | a^3, b^2*a^2 >
        with rules:
            a^3    --->    1
            b^2*a^2    --->    1

        sage: k.rules()
        {a^3: 1, b^2*a^2: 1}
        sage: k.make_confluent()
        sage: sorted(k.rules().items())
        [(a^-2, a), (a^-1*b^-1, a*b), (a^-1*b, b^-1), (a^2, a^-1),
         (a*b^-1, b), (b^-1*a^-1, a*b), (b^-1*a, b), (b^-2, a^-1),
         (b*a^-1, b^-1), (b*a, a*b), (b^2, a)]

    Python

        >>> from sage.all import *
        >>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
        >>> G = F / [a*a*a,b*b*a*a]
        >>> k = G.rewriting_system()
        >>> k
        Rewriting system of Finitely presented group < a, b | a^3, b^2*a^2 >
        with rules:
            a^3    --->    1
            b^2*a^2    --->    1

        >>> k.rules()
        {a^3: 1, b^2*a^2: 1}
        >>> k.make_confluent()
        >>> sorted(k.rules().items())
        [(a^-2, a), (a^-1*b^-1, a*b), (a^-1*b, b^-1), (a^2, a^-1),
         (a*b^-1, b), (b^-1*a^-1, a*b), (b^-1*a, b), (b^-2, a^-1),
         (b*a^-1, b^-1), (b*a, a*b), (b^2, a)]