Multiplicative Abelian Groups - Groups

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

# Multiplicative Abelian Groups

This module lets you compute with finitely generated Abelian groups of the form

\[G = \ZZ^r \oplus \ZZ_{k_1} \oplus \cdots \oplus \ZZ_{k_t}\]

It is customary to denote the infinite cyclic group \(\ZZ\) as having order \(0\), so the data defining the Abelian group can be written as an integer vector

\[\vec{k} = (0, \dots, 0, k_1, \dots, k_t)\]

where there are \(r\) zeroes and \(t\) nonzero values. To construct this Abelian group in Sage, you can either specify all entries of \(\vec{k}\) or only the nonzero entries together with the total number of generators:

Sage

    sage: AbelianGroup([0,0,0,2,3])
    Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3
    sage: AbelianGroup(5, [2,3])
    Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3

Python

    >>> from sage.all import *
    >>> AbelianGroup([Integer(0),Integer(0),Integer(0),Integer(2),Integer(3)])
    Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3
    >>> AbelianGroup(Integer(5), [Integer(2),Integer(3)])
    Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3

It is also legal to specify \(1\) as the order. The corresponding generator will be the neutral element, but it will still take up an index in the labelling of the generators:

Sage

    sage: G = AbelianGroup([2,1,3], names='g')
    sage: G.gens()
    (g0, 1, g2)

[Python]

    >>> from sage.all import *
    >>> G = AbelianGroup([Integer(2),Integer(1),Integer(3)], names='g')
    >>> G.gens()
    (g0, 1, g2)

Note that this presentation is not unique, for example \(\ZZ_6 \cong \ZZ_2 \times \ZZ_3\). The orders of the generators \(\vec{k}=(0,\dots,0,k_1,\dots, k_t)\) has previously been called invariants in Sage, even though they are not necessarily the (unique) invariant factors of the group. You should now use `gens_orders()` instead:

Sage

    sage: J = AbelianGroup([2,0,3,2,4]);  J
    Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4
    sage: J.gens_orders()            # use this instead
    (2, 0, 3, 2, 4)
    sage: J.invariants()             # deprecated
    (2, 0, 3, 2, 4)
    sage: J.elementary_divisors()    # these are the "invariant factors"
    (2, 2, 12, 0)
    sage: for i in range(J.ngens()):
    ....:     print((i, J.gen(i), J.gen(i).order()))     # or use this form
    (0, f0, 2)
    (1, f1, +Infinity)
    (2, f2, 3)
    (3, f3, 2)
    (4, f4, 4)

Python

    >>> from sage.all import *
    >>> J = AbelianGroup([Integer(2),Integer(0),Integer(3),Integer(2),Integer(4)]);  J
    Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4
    >>> J.gens_orders()            # use this instead
    (2, 0, 3, 2, 4)
    >>> J.invariants()             # deprecated
    (2, 0, 3, 2, 4)
    >>> J.elementary_divisors()    # these are the "invariant factors"
    (2, 2, 12, 0)
    >>> for i in range(J.ngens()):
    ...     print((i, J.gen(i), J.gen(i).order()))     # or use this form
    (0, f0, 2)
    (1, f1, +Infinity)
    (2, f2, 3)
    (3, f3, 2)
    (4, f4, 4)

Background on invariant factors and the Smith normal form (according to section 4.1 of [Cohen1]): An abelian group is a group \(A\) for which there exists an exact sequence \(\ZZ^k \rightarrow \ZZ^\ell \rightarrow A \rightarrow 1\), for some positive integers \(k,\ell\) with \(k\leq \ell\). For example, a finite abelian group has a decomposition

\[A = \langle a_1\rangle \times \dots \times \langle a_\ell\rangle ,\]

where \(\mathrm{ord}(a_i)=p_i^{c_i}\), for some primes \(p_i\) and some positive integers \(c_i\), \(i=1,...,\ell\). GAP calls the list (ordered by size) of the \(p_i^{c_i}\) the abelian invariants. In Sage they will be called invariants. In this situation, \(k=\ell\) and \(\phi: \ZZ^\ell \rightarrow A\) is the map \(\phi(x_1,...,x_\ell) = a_1^{x_1}...a_\ell^{x_\ell}\), for \((x_1,...,x_\ell)\in \ZZ^\ell\). The matrix of relations \(M:\ZZ^k \rightarrow \ZZ^\ell\) is the matrix whose rows generate the kernel of \(\phi\) as a \(\ZZ\)-module. In other words, \(M=(M_{ij})\) is a \(\ell\times \ell\) diagonal matrix with \(M_{ii}=p_i^{c_i}\). Consider now the subgroup \(B\subset A\) generated by \(b_1 = a_1^{f_{1,1}}...a_\ell^{f_{\ell,1}}\), …, \(b_m = a_1^{f_{1,m}}...a_\ell^{f_{\ell,m}}\). The kernel of the map \(\phi_B: \ZZ^m \rightarrow B\) defined by \(\phi_B(y_1,...,y_m) = b_1^{y_1}...b_m^{y_m}\), for \((y_1,...,y_m)\in \ZZ^m\), is the kernel of the matrix

\[\begin{split}F= \left( \begin{array}{cccc} f_{11} & f_{12} & \dots & f_{1m}\\ f_{21} & f_{22} & \dots & f_{2m}\\ \vdots & & \ddots & \vdots \\ f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m} \end{array} \right),\end{split}\]

regarded as a map \(\ZZ^m\rightarrow (\ZZ/p_1^{c_1}\ZZ)\times ...\times (\ZZ/p_\ell^{c_\ell}\ZZ)\). In particular, \(B\cong \ZZ^m/\ker(F)\). If \(B=A\) then the Smith normal form (SNF) of a generator matrix of \(\ker(F)\) and the SNF of \(M\) are the same. The diagonal entries \(s_i\) of the SNF \(S = \mathrm{diag}[s_1,s_2,s_3, ... s_r,0,0,...0]\), are called determinantal divisors of \(F\). where \(r\) is the rank. The invariant factors of \(A\) are:

\[s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}.\]

Sage supports multiplicative abelian groups on any prescribed finite number \(n \geq 0\) of generators. Use the `AbelianGroup()` function to create an abelian group, and the `gen()` and `gens()` methods to obtain the corresponding generators. You can print the generators as arbitrary strings using the optional `names` argument to the `AbelianGroup()` function.

EXAMPLE 1:

We create an abelian group in zero or more variables; the syntax `T(1)` creates the identity element even in the rank zero case:

Sage

    sage: T = AbelianGroup(0, [])
    sage: T
    Trivial Abelian group
    sage: T.gens()
    ()
    sage: T(1)
    1

[Python]

    >>> from sage.all import *
    >>> T = AbelianGroup(Integer(0), [])
    >>> T
    Trivial Abelian group
    >>> T.gens()
    ()
    >>> T(Integer(1))
    1

EXAMPLE 2:

An Abelian group uses a multiplicative representation of elements, but the underlying representation is lists of integer exponents:

Sage

    sage: F = AbelianGroup(5, [3,4,5,5,7], names = list("abcde"))
    sage: F
    Multiplicative Abelian group isomorphic to C3 x C4 x C5 x C5 x C7
    sage: (a,b,c,d,e) = F.gens()
    sage: a*b^2*e*d
    a*b^2*d*e
    sage: x = b^2*e*d*a^7
    sage: x
    a*b^2*d*e
    sage: x.list()
    [1, 2, 0, 1, 1]

Python

    >>> from sage.all import *
    >>> F = AbelianGroup(Integer(5), [Integer(3),Integer(4),Integer(5),Integer(5),Integer(7)], names = list("abcde"))
    >>> F
    Multiplicative Abelian group isomorphic to C3 x C4 x C5 x C5 x C7
    >>> (a,b,c,d,e) = F.gens()
    >>> a*b**Integer(2)*e*d
    a*b^2*d*e
    >>> x = b**Integer(2)*e*d*a**Integer(7)
    >>> x
    a*b^2*d*e
    >>> x.list()
    [1, 2, 0, 1, 1]

REFERENCES:

[Cohen1]

H. Cohen, Advanced topics in computational number theory, Springer, 2000.

[Cohen2]

H. Cohen, A course in computational algebraic number theory, Springer, 1996.

[Rotman]

J. Rotman, An introduction to the theory of groups, 4th ed, Springer, 1995.

Warning

Many basic properties for infinite abelian groups are not implemented.

AUTHORS:

- William Stein, David Joyner (2008-12): added (user requested) is_cyclic, fixed elementary_divisors.

- David Joyner (2006-03): (based on free abelian monoids by David Kohel)

- David Joyner (2006-05) several significant bug fixes

- David Joyner (2006-08) trivial changes to docs, added random, fixed bug in how invariants are recorded

- David Joyner (2006-10) added dual_group method

- David Joyner (2008-02) fixed serious bug in word_problem

- David Joyner (2008-03) fixed bug in trivial group case

- David Loeffler (2009-05) added subgroups method

- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables. Rename invariants to gens_orders.

sage.groups.abelian_gps.abelian_group.AbelianGroup(n, gens_orders=None, names='f')

  Create the multiplicative abelian group in \(n\) generators with given orders of generators (which need not be prime powers).

  INPUT:

  - `n` – integer (optional); if not specified, will be derived from `gens_orders`

  - `gens_orders` – list of nonnegative integers in the form

      \([a_0, a_1, \dots, a_{n-1}]\), typically written in increasing order. This list is padded with zeros if it has length less than \(n\). The orders of the commuting generators, with \(0\) denoting an infinite cyclic factor.

  - `names` – (optional) names of generators

  Alternatively, you can also give input in the form `AbelianGroup(gens_orders, names='f')`, where the names keyword argument must be explicitly named.

  OUTPUT:

  Abelian group with generators and invariant type. The default name for generator `A.i` is `fi`, as in GAP.

  EXAMPLES:

  Sage

      sage: F = AbelianGroup(5, [5,5,7,8,9], names='abcde')
      sage: F(1)
      1
      sage: (a, b, c, d, e) = F.gens()
      sage: mul([ a, b, a, c, b, d, c, d ], F(1))
      a^2*b^2*c^2*d^2
      sage: d * b**2 * c**3
      b^2*c^3*d
      sage: F = AbelianGroup(3, [2]*3); F
      Multiplicative Abelian group isomorphic to C2 x C2 x C2
      sage: H = AbelianGroup([2,3], names='xy'); H
      Multiplicative Abelian group isomorphic to C2 x C3
      sage: AbelianGroup(5)
      Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
      sage: AbelianGroup(5).order()
      +Infinity

  Python

      >>> from sage.all import *
      >>> F = AbelianGroup(Integer(5), [Integer(5),Integer(5),Integer(7),Integer(8),Integer(9)], names='abcde')
      >>> F(Integer(1))
      1
      >>> (a, b, c, d, e) = F.gens()
      >>> mul([ a, b, a, c, b, d, c, d ], F(Integer(1)))
      a^2*b^2*c^2*d^2
      >>> d * b**Integer(2) * c**Integer(3)
      b^2*c^3*d
      >>> F = AbelianGroup(Integer(3), [Integer(2)]*Integer(3)); F
      Multiplicative Abelian group isomorphic to C2 x C2 x C2
      >>> H = AbelianGroup([Integer(2),Integer(3)], names='xy'); H
      Multiplicative Abelian group isomorphic to C2 x C3
      >>> AbelianGroup(Integer(5))
      Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
      >>> AbelianGroup(Integer(5)).order()
      +Infinity

  Notice that \(0\)’s are prepended if necessary:

  Sage

      sage: G = AbelianGroup(5, [2,3,4]);  G
      Multiplicative Abelian group isomorphic to Z x Z x C2 x C3 x C4
      sage: G.gens_orders()
      (0, 0, 2, 3, 4)

  [Python]

      >>> from sage.all import *
      >>> G = AbelianGroup(Integer(5), [Integer(2),Integer(3),Integer(4)]);  G
      Multiplicative Abelian group isomorphic to Z x Z x C2 x C3 x C4
      >>> G.gens_orders()
      (0, 0, 2, 3, 4)

  The invariant list must not be longer than the number of generators:

  Sage

      sage: AbelianGroup(2, [2,3,4])
      Traceback (most recent call last):
      ...
      ValueError: gens_orders (=(2, 3, 4)) must have length n (=2)

  Python

      >>> from sage.all import *
      >>> AbelianGroup(Integer(2), [Integer(2),Integer(3),Integer(4)])
      Traceback (most recent call last):
      ...
      ValueError: gens_orders (=(2, 3, 4)) must have length n (=2)

class sage.groups.abelian_gps.abelian_group.AbelianGroup_class(generator_orders, names, category=None)

  Bases: `UniqueRepresentation`, `AbelianGroup`

  The parent for Abelian groups with chosen generator orders.

  Warning

  You should use `AbelianGroup()` to construct Abelian groups and not instantiate this class directly.

  INPUT:

  - `generator_orders` – list of integers. The orders of the (commuting) generators. Zero denotes an infinite cyclic generator.

  - `names` – names of the group generators (optional)

  EXAMPLES:

  Sage

      sage: Z2xZ3 = AbelianGroup([2,3])
      sage: Z6 = AbelianGroup([6])
      sage: Z2xZ3 is Z2xZ3, Z6 is Z6
      (True, True)
      sage: Z2xZ3 is Z6
      False
      sage: Z2xZ3 == Z6
      False
      sage: Z2xZ3.is_isomorphic(Z6)
      True

      sage: F = AbelianGroup(5,[5,5,7,8,9], names=list("abcde")); F
      Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9
      sage: F = AbelianGroup(5,[2, 4, 12, 24, 120], names=list("abcde")); F
      Multiplicative Abelian group isomorphic to C2 x C4 x C12 x C24 x C120
      sage: F.elementary_divisors()
      (2, 4, 12, 24, 120)

      sage: F.category()
      Category of finite enumerated commutative groups

  Python

      >>> from sage.all import *
      >>> Z2xZ3 = AbelianGroup([Integer(2),Integer(3)])
      >>> Z6 = AbelianGroup([Integer(6)])
      >>> Z2xZ3 is Z2xZ3, Z6 is Z6
      (True, True)
      >>> Z2xZ3 is Z6
      False
      >>> Z2xZ3 == Z6
      False
      >>> Z2xZ3.is_isomorphic(Z6)
      True

      >>> F = AbelianGroup(Integer(5),[Integer(5),Integer(5),Integer(7),Integer(8),Integer(9)], names=list("abcde")); F
      Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9
      >>> F = AbelianGroup(Integer(5),[Integer(2), Integer(4), Integer(12), Integer(24), Integer(120)], names=list("abcde")); F
      Multiplicative Abelian group isomorphic to C2 x C4 x C12 x C24 x C120
      >>> F.elementary_divisors()
      (2, 4, 12, 24, 120)

      >>> F.category()
      Category of finite enumerated commutative groups

  Element

    alias of `AbelianGroupElement`

  Subgroup

    alias of `AbelianGroup_subgroup`

  cardinality()

    alias of `order()`.

  dual_group(names='X', base_ring=None)

    Return the dual group.

    INPUT:

    - `names` – string or list of strings. The generator names for the dual group

    - `base_ring` – the base ring; if `None` (default), then a suitable cyclotomic field is picked automatically

    OUTPUT: the `dual abelian group`

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([2])
        sage: G.dual_group()                                                        # needs sage.rings.number_field
        Dual of Abelian Group isomorphic to Z/2Z over Cyclotomic Field of order 2 and degree 1
        sage: G.dual_group().gens()                                                 # needs sage.rings.number_field
        (X,)
        sage: G.dual_group(names='Z').gens()                                        # needs sage.rings.number_field
        (Z,)

        sage: G.dual_group(base_ring=QQ)
        Dual of Abelian Group isomorphic to Z/2Z over Rational Field

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2)])
        >>> G.dual_group()                                                        # needs sage.rings.number_field
        Dual of Abelian Group isomorphic to Z/2Z over Cyclotomic Field of order 2 and degree 1
        >>> G.dual_group().gens()                                                 # needs sage.rings.number_field
        (X,)
        >>> G.dual_group(names='Z').gens()                                        # needs sage.rings.number_field
        (Z,)

        >>> G.dual_group(base_ring=QQ)
        Dual of Abelian Group isomorphic to Z/2Z over Rational Field

  elementary_divisors()

    Return the elementary divisors of the group, using Pari.

    Note

    Here is another algorithm for computing the elementary divisors \(d_1, d_2, d_3, \ldots\), of a finite abelian group (where \(d_1 | d_2 | d_3 | \ldots\) are composed of prime powers dividing the invariants of the group in a way described below). Just factor the invariants \(a_i\) that define the abelian group. Then the biggest \(d_i\) is the product of the maximum prime powers dividing some \(a_j\). In other words, the largest \(d_i\) is the product of \(p^v\), where \(v = \max(\mathrm{ord}_p(a_j) \text{ for all } j\)). Now divide out all those \(p^v\)’s into the list of invariants \(a_i\), and get a new list of “smaller invariants”. Repeat the above procedure on these “smaller invariants” to compute \(d_{i-1}\), and so on. (Thanks to Robert Miller for communicating this algorithm.)

    OUTPUT: tuple of integers

    EXAMPLES:

    Sage

        sage: G = AbelianGroup(2, [2,3])
        sage: G.elementary_divisors()
        (6,)
        sage: G = AbelianGroup(1, [6])
        sage: G.elementary_divisors()
        (6,)
        sage: G = AbelianGroup(2, [2,6])
        sage: G
        Multiplicative Abelian group isomorphic to C2 x C6
        sage: G.gens_orders()
        (2, 6)
        sage: G.elementary_divisors()
        (2, 6)
        sage: J = AbelianGroup([1,3,5,12])
        sage: J.elementary_divisors()
        (3, 60)
        sage: G = AbelianGroup(2, [0,6])
        sage: G.elementary_divisors()
        (6, 0)
        sage: AbelianGroup([3,4,5]).elementary_divisors()
        (60,)

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup(Integer(2), [Integer(2),Integer(3)])
        >>> G.elementary_divisors()
        (6,)
        >>> G = AbelianGroup(Integer(1), [Integer(6)])
        >>> G.elementary_divisors()
        (6,)
        >>> G = AbelianGroup(Integer(2), [Integer(2),Integer(6)])
        >>> G
        Multiplicative Abelian group isomorphic to C2 x C6
        >>> G.gens_orders()
        (2, 6)
        >>> G.elementary_divisors()
        (2, 6)
        >>> J = AbelianGroup([Integer(1),Integer(3),Integer(5),Integer(12)])
        >>> J.elementary_divisors()
        (3, 60)
        >>> G = AbelianGroup(Integer(2), [Integer(0),Integer(6)])
        >>> G.elementary_divisors()
        (6, 0)
        >>> AbelianGroup([Integer(3),Integer(4),Integer(5)]).elementary_divisors()
        (60,)

  exponent()

    Return the exponent of this abelian group.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([2,3,7]); G
        Multiplicative Abelian group isomorphic to C2 x C3 x C7
        sage: G.exponent()
        42
        sage: G = AbelianGroup([2,4,6]); G
        Multiplicative Abelian group isomorphic to C2 x C4 x C6
        sage: G.exponent()
        12

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2),Integer(3),Integer(7)]); G
        Multiplicative Abelian group isomorphic to C2 x C3 x C7
        >>> G.exponent()
        42
        >>> G = AbelianGroup([Integer(2),Integer(4),Integer(6)]); G
        Multiplicative Abelian group isomorphic to C2 x C4 x C6
        >>> G.exponent()
        12

  gen(i=0)

    The \(i\)-th generator of the abelian group.

    EXAMPLES:

    Sage

        sage: F = AbelianGroup(5,[],names='a')
        sage: F.0
        a0
        sage: F.2
        a2
        sage: F.gens_orders()
        (0, 0, 0, 0, 0)

        sage: G = AbelianGroup([2,1,3])
        sage: G.gens()
        (f0, 1, f2)

    Python

        >>> from sage.all import *
        >>> F = AbelianGroup(Integer(5),[],names='a')
        >>> F.gen(0)
        a0
        >>> F.gen(2)
        a2
        >>> F.gens_orders()
        (0, 0, 0, 0, 0)

        >>> G = AbelianGroup([Integer(2),Integer(1),Integer(3)])
        >>> G.gens()
        (f0, 1, f2)

  gens()

    Return the generators of the group.

    OUTPUT:

    A tuple of group elements. The generators according to the chosen `gens_orders()`.

    EXAMPLES:

    Sage

        sage: F = AbelianGroup(5, [3,2], names='abcde')
        sage: F.gens()
        (a, b, c, d, e)
        sage: [g.order() for g in F.gens()]
        [+Infinity, +Infinity, +Infinity, 3, 2]

    Python

        >>> from sage.all import *
        >>> F = AbelianGroup(Integer(5), [Integer(3),Integer(2)], names='abcde')
        >>> F.gens()
        (a, b, c, d, e)
        >>> [g.order() for g in F.gens()]
        [+Infinity, +Infinity, +Infinity, 3, 2]

  gens_orders()

    Return the orders of the cyclic factors that this group has been defined with.

    Use `elementary_divisors()` if you are looking for an invariant of the group.

    OUTPUT: tuple of integers

    EXAMPLES:

    Sage

        sage: Z2xZ3 = AbelianGroup([2,3])
        sage: Z2xZ3.gens_orders()
        (2, 3)
        sage: Z2xZ3.elementary_divisors()
        (6,)

        sage: Z6 = AbelianGroup([6])
        sage: Z6.gens_orders()
        (6,)
        sage: Z6.elementary_divisors()
        (6,)

        sage: Z2xZ3.is_isomorphic(Z6)
        True
        sage: Z2xZ3 is Z6
        False

    Python

        >>> from sage.all import *
        >>> Z2xZ3 = AbelianGroup([Integer(2),Integer(3)])
        >>> Z2xZ3.gens_orders()
        (2, 3)
        >>> Z2xZ3.elementary_divisors()
        (6,)

        >>> Z6 = AbelianGroup([Integer(6)])
        >>> Z6.gens_orders()
        (6,)
        >>> Z6.elementary_divisors()
        (6,)

        >>> Z2xZ3.is_isomorphic(Z6)
        True
        >>> Z2xZ3 is Z6
        False

  identity()

    Return the identity element of this group.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([2,2])
        sage: e = G.identity()
        sage: e
        1
        sage: g = G.gen(0)
        sage: g*e
        f0
        sage: e*g
        f0

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2),Integer(2)])
        >>> e = G.identity()
        >>> e
        1
        >>> g = G.gen(Integer(0))
        >>> g*e
        f0
        >>> e*g
        f0

  invariants()

    Return the orders of the cyclic factors that this group has been defined with.

    For historical reasons this has been called invariants in Sage, even though they are not necessarily the invariant factors of the group. Use `gens_orders()` instead:

    Sage

        sage: J = AbelianGroup([2,0,3,2,4]);  J
        Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4
        sage: J.invariants()    # deprecated
        (2, 0, 3, 2, 4)
        sage: J.gens_orders()   # use this instead
        (2, 0, 3, 2, 4)
        sage: for i in range(J.ngens()):
        ....:     print((i, J.gen(i), J.gen(i).order()))     # or this
        (0, f0, 2)
        (1, f1, +Infinity)
        (2, f2, 3)
        (3, f3, 2)
        (4, f4, 4)

    Python

        >>> from sage.all import *
        >>> J = AbelianGroup([Integer(2),Integer(0),Integer(3),Integer(2),Integer(4)]);  J
        Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4
        >>> J.invariants()    # deprecated
        (2, 0, 3, 2, 4)
        >>> J.gens_orders()   # use this instead
        (2, 0, 3, 2, 4)
        >>> for i in range(J.ngens()):
        ...     print((i, J.gen(i), J.gen(i).order()))     # or this
        (0, f0, 2)
        (1, f1, +Infinity)
        (2, f2, 3)
        (3, f3, 2)
        (4, f4, 4)

    Use `elementary_divisors()` if you are looking for an invariant of the group.

    OUTPUT: tuple of integers; zero means infinite cyclic factor

    EXAMPLES:

    Sage

        sage: J = AbelianGroup([2,3])
        sage: J.invariants()
        (2, 3)
        sage: J.elementary_divisors()
        (6,)

    [Python]

        >>> from sage.all import *
        >>> J = AbelianGroup([Integer(2),Integer(3)])
        >>> J.invariants()
        (2, 3)
        >>> J.elementary_divisors()
        (6,)

  is_commutative()

    Return `True` since this group is commutative.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([2,3,9, 0])
        sage: G.is_commutative()
        True
        sage: G.is_abelian()
        True

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2),Integer(3),Integer(9), Integer(0)])
        >>> G.is_commutative()
        True
        >>> G.is_abelian()
        True

  is_cyclic()

    Return `True` if the group is a cyclic group.

    EXAMPLES:

    Sage

        sage: J = AbelianGroup([2,3])
        sage: J.gens_orders()
        (2, 3)
        sage: J.elementary_divisors()
        (6,)
        sage: J.is_cyclic()
        True
        sage: G = AbelianGroup([6])
        sage: G.gens_orders()
        (6,)
        sage: G.is_cyclic()
        True
        sage: H = AbelianGroup([2,2])
        sage: H.gens_orders()
        (2, 2)
        sage: H.is_cyclic()
        False
        sage: H = AbelianGroup([2,4])
        sage: H.elementary_divisors()
        (2, 4)
        sage: H.is_cyclic()
        False
        sage: H.permutation_group().is_cyclic()                                     # needs sage.groups
        False
        sage: T = AbelianGroup([])
        sage: T.is_cyclic()
        True
        sage: T = AbelianGroup(1, [0]); T
        Multiplicative Abelian group isomorphic to Z
        sage: T.is_cyclic()
        True
        sage: B = AbelianGroup([3,4,5])
        sage: B.is_cyclic()
        True

    Python

        >>> from sage.all import *
        >>> J = AbelianGroup([Integer(2),Integer(3)])
        >>> J.gens_orders()
        (2, 3)
        >>> J.elementary_divisors()
        (6,)
        >>> J.is_cyclic()
        True
        >>> G = AbelianGroup([Integer(6)])
        >>> G.gens_orders()
        (6,)
        >>> G.is_cyclic()
        True
        >>> H = AbelianGroup([Integer(2),Integer(2)])
        >>> H.gens_orders()
        (2, 2)
        >>> H.is_cyclic()
        False
        >>> H = AbelianGroup([Integer(2),Integer(4)])
        >>> H.elementary_divisors()
        (2, 4)
        >>> H.is_cyclic()
        False
        >>> H.permutation_group().is_cyclic()                                     # needs sage.groups
        False
        >>> T = AbelianGroup([])
        >>> T.is_cyclic()
        True
        >>> T = AbelianGroup(Integer(1), [Integer(0)]); T
        Multiplicative Abelian group isomorphic to Z
        >>> T.is_cyclic()
        True
        >>> B = AbelianGroup([Integer(3),Integer(4),Integer(5)])
        >>> B.is_cyclic()
        True

  is_isomorphic(left, right)

    Check whether `left` and `right` are isomorphic.

    INPUT:

    - `right` – anything

    OUTPUT: boolean; whether `left` and `right` are isomorphic as abelian groups

    EXAMPLES:

    Sage

        sage: G1 = AbelianGroup([2,3,4,5])
        sage: G2 = AbelianGroup([2,3,4,5,1])
        sage: G1.is_isomorphic(G2)
        True

    Python

        >>> from sage.all import *
        >>> G1 = AbelianGroup([Integer(2),Integer(3),Integer(4),Integer(5)])
        >>> G2 = AbelianGroup([Integer(2),Integer(3),Integer(4),Integer(5),Integer(1)])
        >>> G1.is_isomorphic(G2)
        True

  is_subgroup(left, right)

    Test whether `left` is a subgroup of `right`.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([2,3,4,5])
        sage: G.is_subgroup(G)
        True

        sage: H = G.subgroup([G.1])                                                 # needs sage.libs.gap  # optional - gap_package_polycyclic
        sage: H.is_subgroup(G)                                                      # needs sage.libs.gap  # optional - gap_package_polycyclic
        True

        sage: G.<a, b> = AbelianGroup(2)
        sage: H.<c> = AbelianGroup(1)
        sage: H < G
        False

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2),Integer(3),Integer(4),Integer(5)])
        >>> G.is_subgroup(G)
        True

        >>> H = G.subgroup([G.gen(1)])                                                 # needs sage.libs.gap  # optional - gap_package_polycyclic
        >>> H.is_subgroup(G)                                                      # needs sage.libs.gap  # optional - gap_package_polycyclic
        True

        >>> G = AbelianGroup(Integer(2), names=('a', 'b',)); (a, b,) = G._first_ngens(2)
        >>> H = AbelianGroup(Integer(1), names=('c',)); (c,) = H._first_ngens(1)
        >>> H < G
        False

  is_trivial()

    Return whether the group is trivial.

    A group is trivial if it has precisely one element.

    EXAMPLES:

    Sage

        sage: AbelianGroup([2, 3]).is_trivial()
        False
        sage: AbelianGroup([1, 1]).is_trivial()
        True

    Python

        >>> from sage.all import *
        >>> AbelianGroup([Integer(2), Integer(3)]).is_trivial()
        False
        >>> AbelianGroup([Integer(1), Integer(1)]).is_trivial()
        True

  list()

    Return tuple of all elements of this group.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([2,3], names = "ab")
        sage: G.list()
        (1, b, b^2, a, a*b, a*b^2)

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2),Integer(3)], names = "ab")
        >>> G.list()
        (1, b, b^2, a, a*b, a*b^2)

    Sage

        sage: G = AbelianGroup([]); G
        Trivial Abelian group
        sage: G.list()
        (1,)

    [Python]

        >>> from sage.all import *
        >>> G = AbelianGroup([]); G
        Trivial Abelian group
        >>> G.list()
        (1,)

  ngens()

    The number of free generators of the abelian group.

    EXAMPLES:

    Sage

        sage: F = AbelianGroup(10000)
        sage: F.ngens()
        10000

    Python

        >>> from sage.all import *
        >>> F = AbelianGroup(Integer(10000))
        >>> F.ngens()
        10000

  number_of_subgroups(order=None)

    Return the number of subgroups of this group, possibly only of a specific order.

    INPUT:

    - `order` – (default: `None`) find the number of subgroups of this order; if `None`, this defaults to counting all subgroups

    ALGORITHM:

    An infinite group has infinitely many subgroups. All finite subgroups of any group are contained in the torsion subgroup, which for finitely generated abelian group is itself finite. Hence, we can assume the group is finite. A finite abelian group is isomorphic to a direct product of its Sylow subgroups, and so we can reduce the problem further to counting subgroups of finite abelian \(p\)-groups.

    Assume a Sylow subgroup is a \(p\)-group of type \(\lambda\), and using `q_subgroups_of_abelian_group()` sum the number of subgroups of type \(\mu\) in an abelian \(p\)-group of type \(\lambda\) for all \(\mu\) contained in \(\lambda\).

    EXAMPLES:

    Sage

        sage: AbelianGroup([2,0,0,3,0]).number_of_subgroups()
        +Infinity

        sage: # needs sage.combinat
        sage: AbelianGroup([2,3]).number_of_subgroups()
        4
        sage: AbelianGroup([2,4,8]).number_of_subgroups()
        81
        sage: AbelianGroup([2,4,8]).number_of_subgroups(order=4)
        19
        sage: AbelianGroup([10,15,25,12]).number_of_subgroups()
        5760
        sage: AbelianGroup([10,15,25,12]).number_of_subgroups(order=45000)
        1
        sage: AbelianGroup([10,15,25,12]).number_of_subgroups(order=14)
        0

    Python

        >>> from sage.all import *
        >>> AbelianGroup([Integer(2),Integer(0),Integer(0),Integer(3),Integer(0)]).number_of_subgroups()
        +Infinity

        >>> # needs sage.combinat
        >>> AbelianGroup([Integer(2),Integer(3)]).number_of_subgroups()
        4
        >>> AbelianGroup([Integer(2),Integer(4),Integer(8)]).number_of_subgroups()
        81
        >>> AbelianGroup([Integer(2),Integer(4),Integer(8)]).number_of_subgroups(order=Integer(4))
        19
        >>> AbelianGroup([Integer(10),Integer(15),Integer(25),Integer(12)]).number_of_subgroups()
        5760
        >>> AbelianGroup([Integer(10),Integer(15),Integer(25),Integer(12)]).number_of_subgroups(order=Integer(45000))
        1
        >>> AbelianGroup([Integer(10),Integer(15),Integer(25),Integer(12)]).number_of_subgroups(order=Integer(14))
        0

  order()

    Return the order of this group.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup(2, [2,3])
        sage: G.order()
        6
        sage: G = AbelianGroup(3, [2,3,0])
        sage: G.order()
        +Infinity

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup(Integer(2), [Integer(2),Integer(3)])
        >>> G.order()
        6
        >>> G = AbelianGroup(Integer(3), [Integer(2),Integer(3),Integer(0)])
        >>> G.order()
        +Infinity

  permutation_group()

    Return the permutation group isomorphic to this abelian group.

    If the invariants are \(q_1, \ldots, q_n\) then the generators of the permutation will be of order \(q_1, \ldots, q_n\), respectively.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup(2,[2,3]); G
        Multiplicative Abelian group isomorphic to C2 x C3
        sage: G.permutation_group()                                                 # needs sage.groups
        Permutation Group with generators [(1,2), (3,4,5)]

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup(Integer(2),[Integer(2),Integer(3)]); G
        Multiplicative Abelian group isomorphic to C2 x C3
        >>> G.permutation_group()                                                 # needs sage.groups
        Permutation Group with generators [(1,2), (3,4,5)]

  random_element()

    Return a random element of this group.

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([2,3,9])
        sage: G.random_element().parent() is G
        True

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2),Integer(3),Integer(9)])
        >>> G.random_element().parent() is G
        True

  subgroup(gensH, names='f')

    Create a subgroup of this group.

    The “big” group must be defined using “named” generators.

    INPUT:

    - `gensH` – list of elements which are products of the generators of the ambient abelian group \(G\) = `self`

    EXAMPLES:

    Sage

        sage: # needs sage.libs.gap  # optional - gap_package_polycyclic
        sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G
        Multiplicative Abelian group isomorphic to C2 x C3 x C4
        sage: H = G.subgroup([a*b,a]); H
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a*b, a}
        sage: H < G
        True
        sage: F = G.subgroup([a,b^2])
        sage: F
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}
        sage: F.gens()
        (a, b^2)
        sage: F = AbelianGroup(5, [30,64,729], names=list("abcde"))
        sage: a,b,c,d,e = F.gens()
        sage: F.subgroup([a,b])
        Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b}
        sage: F.subgroup([c,e])
        Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x C729
        generated by {c, e}

    Python

        >>> from sage.all import *
        >>> # needs sage.libs.gap  # optional - gap_package_polycyclic
        >>> G = AbelianGroup(Integer(3), [Integer(2),Integer(3),Integer(4)], names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3); G
        Multiplicative Abelian group isomorphic to C2 x C3 x C4
        >>> H = G.subgroup([a*b,a]); H
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a*b, a}
        >>> H < G
        True
        >>> F = G.subgroup([a,b**Integer(2)])
        >>> F
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}
        >>> F.gens()
        (a, b^2)
        >>> F = AbelianGroup(Integer(5), [Integer(30),Integer(64),Integer(729)], names=list("abcde"))
        >>> a,b,c,d,e = F.gens()
        >>> F.subgroup([a,b])
        Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b}
        >>> F.subgroup([c,e])
        Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x C729
        generated by {c, e}

  subgroup_reduced(elts, verbose=False)

    Given a list of lists of integers (corresponding to elements of `self`), find a set of independent generators for the subgroup generated by these elements, and return the subgroup with these as generators, forgetting the original generators.

    This is used by the `subgroups` routine.

    An error will be raised if the elements given are not linearly independent over \(\QQ\).

    EXAMPLES:

    Sage

        sage: G = AbelianGroup([4,4])
        sage: G.subgroup( [ G([1,0]), G([1,2]) ])                                   # needs sage.libs.gap  # optional - gap_package_polycyclic
        Multiplicative Abelian subgroup isomorphic to C2 x C4
        generated by {f0, f0*f1^2}
        sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ])               # needs sage.libs.gap  # optional - gap_package_polycyclic
        Multiplicative Abelian subgroup isomorphic to C2 x C4
        generated by {f0^2*f1^2, f0^3}

    Python

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(4),Integer(4)])
        >>> G.subgroup( [ G([Integer(1),Integer(0)]), G([Integer(1),Integer(2)]) ])                                   # needs sage.libs.gap  # optional - gap_package_polycyclic
        Multiplicative Abelian subgroup isomorphic to C2 x C4
        generated by {f0, f0*f1^2}
        >>> AbelianGroup([Integer(4),Integer(4)]).subgroup_reduced( [ [Integer(1),Integer(0)], [Integer(1),Integer(2)] ])               # needs sage.libs.gap  # optional - gap_package_polycyclic
        Multiplicative Abelian subgroup isomorphic to C2 x C4
        generated by {f0^2*f1^2, f0^3}

  subgroups(check=False)

    Compute all the subgroups of this abelian group (which must be finite).

    INPUT:

    - `check` – boolean; if `True`, performs the same computation in GAP and checks that the number of subgroups generated is the same. (I don’t know how to convert GAP’s output back into Sage, so we don’t actually compare the subgroups).

    ALGORITHM:

    If the group is cyclic, the problem is easy. Otherwise, write it as a direct product A x B, where B is cyclic. Compute the subgroups of A (by recursion).

    Now, for every subgroup C of A x B, let G be its projection onto A and H its intersection with B. Then there is a well-defined homomorphism f: G -> B/H that sends a in G to the class mod H of b, where (a,b) is any element of C lifting a; and every subgroup C arises from a unique triple (G, H, f).

    Todo

    This is many orders of magnitude slower than Magma. Consider using the much faster method `number_of_subgroups()` in case you only need the number of subgroups, possibly of a specific order.

    EXAMPLES:

    Sage

        sage: AbelianGroup([2,3]).subgroups()                                       # needs sage.libs.gap  # optional - gap_package_polycyclic
        [Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {f0*f1^2},
         Multiplicative Abelian subgroup isomorphic to C2 generated by {f0},
         Multiplicative Abelian subgroup isomorphic to C3 generated by {f1},
         Trivial Abelian subgroup]
        sage: len(AbelianGroup([2,4,8]).subgroups())                                # needs sage.libs.gap  # optional - gap_package_polycyclic
        81

    Python

        >>> from sage.all import *
        >>> AbelianGroup([Integer(2),Integer(3)]).subgroups()                                       # needs sage.libs.gap  # optional - gap_package_polycyclic
        [Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {f0*f1^2},
         Multiplicative Abelian subgroup isomorphic to C2 generated by {f0},
         Multiplicative Abelian subgroup isomorphic to C3 generated by {f1},
         Trivial Abelian subgroup]
        >>> len(AbelianGroup([Integer(2),Integer(4),Integer(8)]).subgroups())                                # needs sage.libs.gap  # optional - gap_package_polycyclic
        81

  torsion_subgroup(n=None)

    Return the \(n\)-torsion subgroup of this abelian group when \(n\) is given, and the torsion subgroup otherwise.

    The [\(n\)-]torsion subgroup consists of all elements whose order is finite [and divides \(n\)].

    EXAMPLES:

    Sage

        sage: # needs sage.libs.gap  # optional - gap_package_polycyclic
        sage: G = AbelianGroup([2, 3])
        sage: G.torsion_subgroup()
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated
        by {f0, f1}
        sage: G = AbelianGroup([2, 0, 0, 3, 0])
        sage: G.torsion_subgroup()
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated
        by {f0, f3}
        sage: G = AbelianGroup([])
        sage: G.torsion_subgroup()
        Trivial Abelian subgroup
        sage: G = AbelianGroup([0, 0])
        sage: G.torsion_subgroup()
        Trivial Abelian subgroup

    Python

        >>> from sage.all import *
        >>> # needs sage.libs.gap  # optional - gap_package_polycyclic
        >>> G = AbelianGroup([Integer(2), Integer(3)])
        >>> G.torsion_subgroup()
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated
        by {f0, f1}
        >>> G = AbelianGroup([Integer(2), Integer(0), Integer(0), Integer(3), Integer(0)])
        >>> G.torsion_subgroup()
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated
        by {f0, f3}
        >>> G = AbelianGroup([])
        >>> G.torsion_subgroup()
        Trivial Abelian subgroup
        >>> G = AbelianGroup([Integer(0), Integer(0)])
        >>> G.torsion_subgroup()
        Trivial Abelian subgroup

    Sage

        sage: G = AbelianGroup([2, 2*3, 2*3*5, 0, 2*3*5*7, 2*3*5*7*11])
        sage: G.torsion_subgroup(5)                                                 # needs sage.libs.gap  # optional - gap_package_polycyclic
        Multiplicative Abelian subgroup isomorphic to C5 x C5 x C5
         generated by {f2^6, f4^42, f5^462}

    [Python]

        >>> from sage.all import *
        >>> G = AbelianGroup([Integer(2), Integer(2)*Integer(3), Integer(2)*Integer(3)*Integer(5), Integer(0), Integer(2)*Integer(3)*Integer(5)*Integer(7), Integer(2)*Integer(3)*Integer(5)*Integer(7)*Integer(11)])
        >>> G.torsion_subgroup(Integer(5))                                                 # needs sage.libs.gap  # optional - gap_package_polycyclic
        Multiplicative Abelian subgroup isomorphic to C5 x C5 x C5
         generated by {f2^6, f4^42, f5^462}

class sage.groups.abelian_gps.abelian_group.AbelianGroup_subgroup(ambient, gens, names='f', category=None)

  Bases: `AbelianGroup_class`

  Subgroup subclass of `AbelianGroup_class`, so instance methods are inherited.

  Todo

  There should be a way to coerce an element of a subgroup into the ambient group.

  ambient_group()

    Return the ambient group related to `self`.

    OUTPUT: a multiplicative Abelian group

    EXAMPLES:

    Sage

        sage: # needs sage.libs.gap  # optional - gap_package_polycyclic
        sage: G.<a,b,c> = AbelianGroup([2,3,4])
        sage: H = G.subgroup([a, b^2])
        sage: H.ambient_group() is G
        True

    Python

        >>> from sage.all import *
        >>> # needs sage.libs.gap  # optional - gap_package_polycyclic
        >>> G = AbelianGroup([Integer(2),Integer(3),Integer(4)], names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3)
        >>> H = G.subgroup([a, b**Integer(2)])
        >>> H.ambient_group() is G
        True

  equals(left, right)

    Check whether `left` and `right` are the same (sub)group.

    INPUT:

    - `right` – anything

    OUTPUT:

    boolean; if `right` is a subgroup, test whether `left` and `right` are the same subset of the ambient group. If `right` is not a subgroup, test whether they are isomorphic groups, see `is_isomorphic()`.

    EXAMPLES:

    Sage

        sage: # needs sage.libs.gap  # optional - gap_package_polycyclic
        sage: G = AbelianGroup(3, [2,3,4], names='abc'); G
        Multiplicative Abelian group isomorphic to C2 x C3 x C4
        sage: a,b,c = G.gens()
        sage: F = G.subgroup([a,b^2]); F
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}
        sage: F<G
        True
        sage: A = AbelianGroup(1, [6])
        sage: A.subgroup(list(A.gens())) == A
        True
        sage: G.<a,b> = AbelianGroup(2)
        sage: A = G.subgroup([a])
        sage: B = G.subgroup([b])
        sage: A.equals(B)
        False
        sage: A == B        # sames as A.equals(B)
        False
        sage: A.is_isomorphic(B)
        True

    Python

        >>> from sage.all import *
        >>> # needs sage.libs.gap  # optional - gap_package_polycyclic
        >>> G = AbelianGroup(Integer(3), [Integer(2),Integer(3),Integer(4)], names='abc'); G
        Multiplicative Abelian group isomorphic to C2 x C3 x C4
        >>> a,b,c = G.gens()
        >>> F = G.subgroup([a,b**Integer(2)]); F
        Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}
        >>> F<G
        True
        >>> A = AbelianGroup(Integer(1), [Integer(6)])
        >>> A.subgroup(list(A.gens())) == A
        True
        >>> G = AbelianGroup(Integer(2), names=('a', 'b',)); (a, b,) = G._first_ngens(2)
        >>> A = G.subgroup([a])
        >>> B = G.subgroup([b])
        >>> A.equals(B)
        False
        >>> A == B        # sames as A.equals(B)
        False
        >>> A.is_isomorphic(B)
        True

  gen(n)

    Return the \(n\)-th generator of this subgroup.

    EXAMPLES:

    Sage

        sage: # needs sage.libs.gap  # optional - gap_package_polycyclic
        sage: G.<a,b> = AbelianGroup(2)
        sage: A = G.subgroup([a])
        sage: A.gen(0)
        a

    Python

        >>> from sage.all import *
        >>> # needs sage.libs.gap  # optional - gap_package_polycyclic
        >>> G = AbelianGroup(Integer(2), names=('a', 'b',)); (a, b,) = G._first_ngens(2)
        >>> A = G.subgroup([a])
        >>> A.gen(Integer(0))
        a

  gens()

    Return the generators for this subgroup.

    OUTPUT: tuple of group elements generating the subgroup

    EXAMPLES:

    Sage

        sage: # needs sage.libs.gap  # optional - gap_package_polycyclic
        sage: G.<a,b> = AbelianGroup(2)
        sage: A = G.subgroup([a])
        sage: G.gens()
        (a, b)
        sage: A.gens()
        (a,)

    Python

        >>> from sage.all import *
        >>> # needs sage.libs.gap  # optional - gap_package_polycyclic
        >>> G = AbelianGroup(Integer(2), names=('a', 'b',)); (a, b,) = G._first_ngens(2)
        >>> A = G.subgroup([a])
        >>> G.gens()
        (a, b)
        >>> A.gens()
        (a,)

sage.groups.abelian_gps.abelian_group.word_problem(words, g, verbose=False)

  \(G\) and \(H\) are abelian, \(g\) in \(G\), \(H\) is a subgroup of \(G\) generated by a list (words) of elements of \(G\). If \(g\) is in \(H\), return the expression for \(g\) as a word in the elements of (words).

  The ‘word problem’ for a finite abelian group \(G\) boils down to the following matrix-vector analog of the Chinese remainder theorem.

  Problem: Fix integers \(1<n_1\leq n_2\leq ...\leq n_k\) (indeed, these \(n_i\) will all be prime powers), fix a generating set \(g_i=(a_{i1},...,a_{ik})\) (with \(a_{ij}\in \mathrm{Z}/n_j\mathrm{Z}\)), for \(1\leq i\leq \ell\), for the group \(G\), and let \(d = (d_1,...,d_k)\) be an element of the direct product \(\mathrm{Z}/n_1\mathrm{Z} \times ...\times \mathrm{Z}/n_k\mathrm{Z}\). Find, if they exist, integers \(c_1,...,c_\ell\) such that \(c_1g_1+...+c_\ell g_\ell = d\). In other words, solve the equation \(cA=d\) for \(c\in \mathrm{Z}^\ell\), where \(A\) is the matrix whose rows are the \(g_i\)’s. Of course, it suffices to restrict the \(c_i\)’s to the range \(0\leq c_i\leq N-1\), where \(N\) denotes the least common multiple of the integers \(n_1,...,n_k\).

  This function does not solve this directly, as perhaps it should. Rather (for both speed and as a model for a similar function valid for more general groups), it pushes it over to GAP, which has optimized (non-deterministic) algorithms for the word problem. Essentially, this function is a wrapper for the GAP function ‘Factorization’.

  EXAMPLES:

  Sage

      sage: # needs sage.libs.gap
      sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G
      Multiplicative Abelian group isomorphic to C2 x C3 x C4
      sage: w = word_problem([a*b,a*c], b*c); w       # random
      [[a*b, 1], [a*c, 1]]
      sage: prod([x^i for x,i in w]) == b*c
      True
      sage: w = word_problem([a*c,c], a); w           # random
      [[a*c, 1], [c, -1]]
      sage: prod([x^i for x,i in w]) == a
      True
      sage: word_problem([a*c,c], a, verbose=True)    # random
      a = (a*c)^1*(c)^-1
      [[a*c, 1], [c, -1]]

  Python

      >>> from sage.all import *
      >>> # needs sage.libs.gap
      >>> G = AbelianGroup(Integer(3), [Integer(2),Integer(3),Integer(4)], names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3); G
      Multiplicative Abelian group isomorphic to C2 x C3 x C4
      >>> w = word_problem([a*b,a*c], b*c); w       # random
      [[a*b, 1], [a*c, 1]]
      >>> prod([x**i for x,i in w]) == b*c
      True
      >>> w = word_problem([a*c,c], a); w           # random
      [[a*c, 1], [c, -1]]
      >>> prod([x**i for x,i in w]) == a
      True
      >>> word_problem([a*c,c], a, verbose=True)    # random
      a = (a*c)^1*(c)^-1
      [[a*c, 1], [c, -1]]

  Sage

      sage: # needs sage.libs.gap
      sage: A.<a,b,c,d,e> = AbelianGroup(5, [4, 5, 5, 7, 8])
      sage: b1 = a^3*b*c*d^2*e^5
      sage: b2 = a^2*b*c^2*d^3*e^3
      sage: b3 = a^7*b^3*c^5*d^4*e^4
      sage: b4 = a^3*b^2*c^2*d^3*e^5
      sage: b5 = a^2*b^4*c^2*d^4*e^5
      sage: w = word_problem([b1,b2,b3,b4,b5], e); w  # random
      [[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1],
       [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]]
      sage: prod([x^i for x,i in w]) == e
      True
      sage: word_problem([a,b,c,d,e], e)
      [[e, 1]]
      sage: word_problem([a,b,c,d,e], b)
      [[b, 1]]

  [Python]

      >>> from sage.all import *
      >>> # needs sage.libs.gap
      >>> A = AbelianGroup(Integer(5), [Integer(4), Integer(5), Integer(5), Integer(7), Integer(8)], names=('a', 'b', 'c', 'd', 'e',)); (a, b, c, d, e,) = A._first_ngens(5)
      >>> b1 = a**Integer(3)*b*c*d**Integer(2)*e**Integer(5)
      >>> b2 = a**Integer(2)*b*c**Integer(2)*d**Integer(3)*e**Integer(3)
      >>> b3 = a**Integer(7)*b**Integer(3)*c**Integer(5)*d**Integer(4)*e**Integer(4)
      >>> b4 = a**Integer(3)*b**Integer(2)*c**Integer(2)*d**Integer(3)*e**Integer(5)
      >>> b5 = a**Integer(2)*b**Integer(4)*c**Integer(2)*d**Integer(4)*e**Integer(5)
      >>> w = word_problem([b1,b2,b3,b4,b5], e); w  # random
      [[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1],
       [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]]
      >>> prod([x**i for x,i in w]) == e
      True
      >>> word_problem([a,b,c,d,e], e)
      [[e, 1]]
      >>> word_problem([a,b,c,d,e], b)
      [[b, 1]]

  Warning

  1. Might have unpleasant effect when the word problem cannot be solved.

  2. Uses permutation groups, so may be slow when group is large. The instance method word_problem of the class AbelianGroupElement is implemented differently (wrapping GAP’s ‘EpimorphismFromFreeGroup’ and ‘PreImagesRepresentative’) and may be faster.