Finitely generated abelian groups with GAP.#

This module provides a python wrapper for abelian groups in GAP.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: AbelianGroupGap([3,5])
Abelian group with gap, generator orders (3, 5)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> AbelianGroupGap([Integer(3),Integer(5)])
Abelian group with gap, generator orders (3, 5)


For infinite abelian groups we use the GAP package Polycyclic:

sage: AbelianGroupGap([3,0])   # optional - gap_package_polycyclic
Abelian group with gap, generator orders (3, 0)

>>> from sage.all import *
>>> AbelianGroupGap([Integer(3),Integer(0)])   # optional - gap_package_polycyclic
Abelian group with gap, generator orders (3, 0)


AUTHORS:

• Simon Brandhorst (2018-01-17): initial version

class sage.groups.abelian_gps.abelian_group_gap.AbelianGroupElement_gap(parent, x, check=True)[source]#

Bases: ElementLibGAP

An element of an abelian group via libgap.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([3,6])
sage: G.gens()
(f1, f2)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(3),Integer(6)])
>>> G.gens()
(f1, f2)

exponents()[source]#

Return the tuple of exponents of this element.

OUTPUT: tuple of integers

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([4,7,9])
sage: gens = G.gens()
sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8
sage: g.exponents()
(2, 4, 8)
sage: S = G.subgroup(G.gens()[:1])
sage: s = S.gens()[0]
sage: s
f1
sage: s.exponents()
(1,)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(4),Integer(7),Integer(9)])
>>> gens = G.gens()
>>> g = gens[Integer(0)]**Integer(2) * gens[Integer(1)]**Integer(4) * gens[Integer(2)]**Integer(8)
>>> g.exponents()
(2, 4, 8)
>>> S = G.subgroup(G.gens()[:Integer(1)])
>>> s = S.gens()[Integer(0)]
>>> s
f1
>>> s.exponents()
(1,)


It can handle quite large groups too:

sage: G = AbelianGroupGap([2^10, 5^10])
sage: f1, f2 = G.gens()
sage: g = f1^123*f2^789
sage: g.exponents()
(123, 789)

>>> from sage.all import *
>>> G = AbelianGroupGap([Integer(2)**Integer(10), Integer(5)**Integer(10)])
>>> f1, f2 = G.gens()
>>> g = f1**Integer(123)*f2**Integer(789)
>>> g.exponents()
(123, 789)


Warning

Crashes for very large groups.

Todo

Make exponents work for very large groups. This could be done by using Pcgs in gap.

order()[source]#

Return the order of this element.

OUTPUT: integer or infinity

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([4])
sage: g = G.gens()[0]
sage: g.order()
4
sage: G = AbelianGroupGap([0])          # optional - gap_package_polycyclic
sage: g = G.gens()[0]                   # optional - gap_package_polycyclic
sage: g.order()                         # optional - gap_package_polycyclic
+Infinity

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(4)])
>>> g = G.gens()[Integer(0)]
>>> g.order()
4
>>> G = AbelianGroupGap([Integer(0)])          # optional - gap_package_polycyclic
>>> g = G.gens()[Integer(0)]                   # optional - gap_package_polycyclic
>>> g.order()                         # optional - gap_package_polycyclic
+Infinity

class sage.groups.abelian_gps.abelian_group_gap.AbelianGroupElement_polycyclic(parent, x, check=True)[source]#

An element of an abelian group using the GAP package Polycyclic.

exponents()[source]#

Return the tuple of exponents of self.

OUTPUT: tuple of integers

EXAMPLES:

sage: # optional - gap_package_polycyclic
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([4,7,0])
sage: gens = G.gens()
sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8
sage: g.exponents()
(2, 4, 8)

>>> from sage.all import *
>>> # optional - gap_package_polycyclic
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(4),Integer(7),Integer(0)])
>>> gens = G.gens()
>>> g = gens[Integer(0)]**Integer(2) * gens[Integer(1)]**Integer(4) * gens[Integer(2)]**Integer(8)
>>> g.exponents()
(2, 4, 8)


Efficiently handles very large groups:

sage: # optional - gap_package_polycyclic
sage: G = AbelianGroupGap([2^30,5^30,0])
sage: f1, f2, f3 = G.gens()
sage: (f1^12345*f2^123456789).exponents()
(12345, 123456789, 0)

>>> from sage.all import *
>>> # optional - gap_package_polycyclic
>>> G = AbelianGroupGap([Integer(2)**Integer(30),Integer(5)**Integer(30),Integer(0)])
>>> f1, f2, f3 = G.gens()
>>> (f1**Integer(12345)*f2**Integer(123456789)).exponents()
(12345, 123456789, 0)

class sage.groups.abelian_gps.abelian_group_gap.AbelianGroupGap(generator_orders)[source]#

Abelian groups implemented using GAP.

INPUT:

• generator_orders – a list of nonnegative integers where $$0$$ gives a factor isomorphic to $$\ZZ$$

OUTPUT: an abelian group

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: AbelianGroupGap([3,6])
Abelian group with gap, generator orders (3, 6)
sage: AbelianGroupGap([3,6,5])
Abelian group with gap, generator orders (3, 6, 5)
sage: AbelianGroupGap([3,6,0])      # optional - gap_package_polycyclic
Abelian group with gap, generator orders (3, 6, 0)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> AbelianGroupGap([Integer(3),Integer(6)])
Abelian group with gap, generator orders (3, 6)
>>> AbelianGroupGap([Integer(3),Integer(6),Integer(5)])
Abelian group with gap, generator orders (3, 6, 5)
>>> AbelianGroupGap([Integer(3),Integer(6),Integer(0)])      # optional - gap_package_polycyclic
Abelian group with gap, generator orders (3, 6, 0)


Warning

Needs the GAP package Polycyclic in case the group is infinite.

class sage.groups.abelian_gps.abelian_group_gap.AbelianGroupQuotient_gap(G, N)[source]#

Quotients of abelian groups by a subgroup.

Note

Do not call this directly. Instead use quotient().

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([4,3])
sage: N = A.subgroup([A.gen(0)^2])
sage: Q1 = A.quotient(N)
sage: Q1
Quotient abelian group with generator orders (2, 3)
sage: Q2 = Q1.quotient(Q1.subgroup(Q1.gens()[:1]))
sage: Q2
Quotient abelian group with generator orders (1, 3)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(4),Integer(3)])
>>> N = A.subgroup([A.gen(Integer(0))**Integer(2)])
>>> Q1 = A.quotient(N)
>>> Q1
Quotient abelian group with generator orders (2, 3)
>>> Q2 = Q1.quotient(Q1.subgroup(Q1.gens()[:Integer(1)]))
>>> Q2
Quotient abelian group with generator orders (1, 3)

cover()[source]#

Return the covering group of this quotient group.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2,3,4,5])
sage: gen = G.gens()[:2]
sage: S = G.subgroup(gen)
sage: Q = G.quotient(S)
sage: Q.cover() is G
True

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2),Integer(3),Integer(4),Integer(5)])
>>> gen = G.gens()[:Integer(2)]
>>> S = G.subgroup(gen)
>>> Q = G.quotient(S)
>>> Q.cover() is G
True

lift(x)[source]#

Lift an element to the cover.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([4])
sage: N = A.subgroup([A.gen(0)^2])
sage: Q = A.quotient(N)
sage: Q.lift(Q.0)
f1

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(4)])
>>> N = A.subgroup([A.gen(Integer(0))**Integer(2)])
>>> Q = A.quotient(N)
>>> Q.lift(Q.gen(0))
f1

natural_homomorphism()[source]#

Return the defining homomorphism into self.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([4])
sage: N = A.subgroup([A.gen(0)^2])
sage: Q = A.quotient(N)
sage: Q.natural_homomorphism()
Group morphism:
From: Abelian group with gap, generator orders (4,)
To:   Quotient abelian group with generator orders (2,)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(4)])
>>> N = A.subgroup([A.gen(Integer(0))**Integer(2)])
>>> Q = A.quotient(N)
>>> Q.natural_homomorphism()
Group morphism:
From: Abelian group with gap, generator orders (4,)
To:   Quotient abelian group with generator orders (2,)

relations()[source]#

Return the relations of this quotient group.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2,3,4,5])
sage: gen = G.gens()[:2]
sage: S = G.subgroup(gen)
sage: Q = G.quotient(S)
sage: Q.relations() is S
True

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2),Integer(3),Integer(4),Integer(5)])
>>> gen = G.gens()[:Integer(2)]
>>> S = G.subgroup(gen)
>>> Q = G.quotient(S)
>>> Q.relations() is S
True

class sage.groups.abelian_gps.abelian_group_gap.AbelianGroupSubgroup_gap(ambient, gens)[source]#

Subgroups of abelian groups with GAP.

INPUT:

• ambient – the ambient group

• gens – generators of the subgroup

Note

Do not construct this class directly. Instead use subgroup().

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2,3,4,5])
sage: gen = G.gens()[:2]
sage: S = G.subgroup(gen)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2),Integer(3),Integer(4),Integer(5)])
>>> gen = G.gens()[:Integer(2)]
>>> S = G.subgroup(gen)

lift(x)[source]#

Coerce to the ambient group.

The terminology comes from the category framework and the more general notion of a subquotient.

INPUT:

• x – an element of this subgroup

OUTPUT: the corresponding element of the ambient group

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([4])
sage: g = G.gen(0)
sage: H = G.subgroup([g^2])
sage: h = H.gen(0); h
f2
sage: h.parent()
Subgroup of Abelian group with gap, generator orders (4,) generated by (f2,)
sage: H.lift(h)
f2
sage: H.lift(h).parent()
Abelian group with gap, generator orders (4,)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(4)])
>>> g = G.gen(Integer(0))
>>> H = G.subgroup([g**Integer(2)])
>>> h = H.gen(Integer(0)); h
f2
>>> h.parent()
Subgroup of Abelian group with gap, generator orders (4,) generated by (f2,)
>>> H.lift(h)
f2
>>> H.lift(h).parent()
Abelian group with gap, generator orders (4,)

retract(x)[source]#

Convert an element of the ambient group into this subgroup.

The terminology comes from the category framework and the more general notion of a subquotient.

INPUT:

• x – an element of the ambient group that actually lies in this subgroup.

OUTPUT: the corresponding element of this subgroup

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([4])
sage: g = G.gen(0)
sage: H = G.subgroup([g^2])
sage: H.retract(g^2)
f2
sage: H.retract(g^2).parent()
Subgroup of Abelian group with gap, generator orders (4,) generated by (f2,)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(4)])
>>> g = G.gen(Integer(0))
>>> H = G.subgroup([g**Integer(2)])
>>> H.retract(g**Integer(2))
f2
>>> H.retract(g**Integer(2)).parent()
Subgroup of Abelian group with gap, generator orders (4,) generated by (f2,)

class sage.groups.abelian_gps.abelian_group_gap.AbelianGroup_gap(G, category, ambient=None)[source]#

Finitely generated abelian groups implemented in GAP.

Needs the gap package Polycyclic in case the group is infinite.

INPUT:

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([3, 2, 5])
sage: G
Abelian group with gap, generator orders (3, 2, 5)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(3), Integer(2), Integer(5)])
>>> G
Abelian group with gap, generator orders (3, 2, 5)

Element[source]#
all_subgroups()[source]#

Return the list of all subgroups of this group.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2, 3])
sage: G.all_subgroups()
[Subgroup of Abelian group with gap, generator orders (2, 3) generated by (),
Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f1,),
Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f2,),
Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f2, f1)]

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2), Integer(3)])
>>> G.all_subgroups()
[Subgroup of Abelian group with gap, generator orders (2, 3) generated by (),
Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f1,),
Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f2,),
Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f2, f1)]

aut()[source]#

Return the group of automorphisms of self.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2, 3])
sage: G.aut()
Full group of automorphisms of Abelian group with gap, generator orders (2, 3)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2), Integer(3)])
>>> G.aut()
Full group of automorphisms of Abelian group with gap, generator orders (2, 3)

automorphism_group()[source]#

Return the group of automorphisms of self.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2, 3])
sage: G.aut()
Full group of automorphisms of Abelian group with gap, generator orders (2, 3)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2), Integer(3)])
>>> G.aut()
Full group of automorphisms of Abelian group with gap, generator orders (2, 3)

elementary_divisors()[source]#

Return the elementary divisors of this group.

See sage.groups.abelian_gps.abelian_group_gap.elementary_divisors().

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2,3,4,5])
sage: G.elementary_divisors()
(2, 60)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2),Integer(3),Integer(4),Integer(5)])
>>> G.elementary_divisors()
(2, 60)

exponent()[source]#

Return the exponent of this abelian group.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2,3,7])
sage: G
Abelian group with gap, generator orders (2, 3, 7)
sage: G = AbelianGroupGap([2,4,6])
sage: G
Abelian group with gap, generator orders (2, 4, 6)
sage: G.exponent()
12

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2),Integer(3),Integer(7)])
>>> G
Abelian group with gap, generator orders (2, 3, 7)
>>> G = AbelianGroupGap([Integer(2),Integer(4),Integer(6)])
>>> G
Abelian group with gap, generator orders (2, 4, 6)
>>> G.exponent()
12

gens_orders()[source]#

Return the orders of the generators.

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

OUTPUT: tuple of integers

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: Z2xZ3 = AbelianGroupGap([2,3])
sage: Z2xZ3.gens_orders()
(2, 3)
sage: Z2xZ3.elementary_divisors()
(6,)
sage: Z6 = AbelianGroupGap([6])
sage: Z6.gens_orders()
(6,)
sage: Z6.elementary_divisors()
(6,)
sage: Z2xZ3.is_isomorphic(Z6)
True
sage: Z2xZ3 is Z6
False

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> Z2xZ3 = AbelianGroupGap([Integer(2),Integer(3)])
>>> Z2xZ3.gens_orders()
(2, 3)
>>> Z2xZ3.elementary_divisors()
(6,)
>>> Z6 = AbelianGroupGap([Integer(6)])
>>> Z6.gens_orders()
(6,)
>>> Z6.elementary_divisors()
(6,)
>>> Z2xZ3.is_isomorphic(Z6)
True
>>> Z2xZ3 is Z6
False

identity()[source]#

Return the identity element of this group.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([4,10])
sage: G.identity()
1

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(4),Integer(10)])
>>> G.identity()
1

is_subgroup_of(G)[source]#

Return if self is a subgroup of G considered in the same ambient group.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2,3,4,5])
sage: gen = G.gens()[:2]
sage: S1 = G.subgroup(gen)
sage: S1.is_subgroup_of(G)
True
sage: S2 = G.subgroup(G.gens()[1:])
sage: S2.is_subgroup_of(S1)
False

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2),Integer(3),Integer(4),Integer(5)])
>>> gen = G.gens()[:Integer(2)]
>>> S1 = G.subgroup(gen)
>>> S1.is_subgroup_of(G)
True
>>> S2 = G.subgroup(G.gens()[Integer(1):])
>>> S2.is_subgroup_of(S1)
False

is_trivial()[source]#

Return True if this group is the trivial group.

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([])
sage: G
Abelian group with gap, generator orders ()
sage: G.is_trivial()
True
sage: AbelianGroupGap([1]).is_trivial()
True
sage: AbelianGroupGap([1,1,1]).is_trivial()
True
sage: AbelianGroupGap([2]).is_trivial()
False
sage: AbelianGroupGap([2,1]).is_trivial()
False

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([])
>>> G
Abelian group with gap, generator orders ()
>>> G.is_trivial()
True
>>> AbelianGroupGap([Integer(1)]).is_trivial()
True
>>> AbelianGroupGap([Integer(1),Integer(1),Integer(1)]).is_trivial()
True
>>> AbelianGroupGap([Integer(2)]).is_trivial()
False
>>> AbelianGroupGap([Integer(2),Integer(1)]).is_trivial()
False

quotient(N)[source]#

Return the quotient of this group by the normal subgroup $$N$$.

INPUT:

• N – a subgroup

• check – bool (default: True) check if $$N$$ is normal

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([2,3,4,5])
sage: S = A.subgroup(A.gens()[:1])
sage: A.quotient(S)
Quotient abelian group with generator orders (1, 3, 4, 5)

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(2),Integer(3),Integer(4),Integer(5)])
>>> S = A.subgroup(A.gens()[:Integer(1)])
>>> A.quotient(S)
Quotient abelian group with generator orders (1, 3, 4, 5)

subgroup(gens)[source]#

Return the subgroup of this group generated by gens.

INPUT:

• gens – a list of elements coercible into this group

OUTPUT: a subgroup

EXAMPLES:

sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: G = AbelianGroupGap([2,3,4,5])
sage: gen = G.gens()[:2]
sage: S = G.subgroup(gen)
sage: S
Subgroup of Abelian group with gap, generator orders (2, 3, 4, 5)
generated by (f1, f2)
sage: g = G.an_element()
sage: s = S.an_element()
sage: g * s
f2^2*f3*f5

sage: # optional - gap_package_polycyclic
sage: G = AbelianGroupGap([3,4,0,2])
sage: gen = G.gens()[:2]
sage: S = G.subgroup(gen)
sage: g = G.an_element()
sage: s = S.an_element()
sage: g * s
g1^2*g2^2*g3*g4

>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> G = AbelianGroupGap([Integer(2),Integer(3),Integer(4),Integer(5)])
>>> gen = G.gens()[:Integer(2)]
>>> S = G.subgroup(gen)
>>> S
Subgroup of Abelian group with gap, generator orders (2, 3, 4, 5)
generated by (f1, f2)
>>> g = G.an_element()
>>> s = S.an_element()
>>> g * s
f2^2*f3*f5

>>> # optional - gap_package_polycyclic
>>> G = AbelianGroupGap([Integer(3),Integer(4),Integer(0),Integer(2)])
>>> gen = G.gens()[:Integer(2)]
>>> S = G.subgroup(gen)
>>> g = G.an_element()
>>> s = S.an_element()
>>> g * s
g1^2*g2^2*g3*g4