# Group homomorphisms for groups with a GAP backend#

EXAMPLES:

```sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([2, 4])
sage: F.<a,b> = FreeGroup()
sage: f = F.hom([g for g in A.gens()])
sage: K = f.kernel()
sage: K
Group(<free, no generators known>)
```
```>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(2), Integer(4)])
>>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
>>> f = F.hom([g for g in A.gens()])
>>> K = f.kernel()
>>> K
Group(<free, no generators known>)
```

AUTHORS:

• Simon Brandhorst (2018-02-08): initial version

• Sebastian Oehms (2018-11-15): have this functionality work for permutation groups (Issue #26750) and implement `section()` and `natural_map()`

class sage.groups.libgap_morphism.GroupHomset_libgap(G, H, category=None, check=True)[source]#

Bases: `HomsetWithBase`

Homsets of groups with a libgap backend.

Do not call this directly instead use `Hom()`.

INPUT:

• `G` – a libgap group

• `H` – a libgap group

• `category` – a category

OUTPUT: the homset of two libgap groups

EXAMPLES:

```sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([2,4])
sage: H = A.Hom(A)
sage: H
Set of Morphisms from Abelian group with gap, generator orders (2, 4)
to Abelian group with gap, generator orders (2, 4)
in Category of finite enumerated commutative groups
```
```>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(2),Integer(4)])
>>> H = A.Hom(A)
>>> H
Set of Morphisms from Abelian group with gap, generator orders (2, 4)
to Abelian group with gap, generator orders (2, 4)
in Category of finite enumerated commutative groups
```
Element[source]#

alias of `GroupMorphism_libgap`

natural_map()[source]#

This method from `HomsetWithBase` is overloaded here for cases in which both groups have corresponding lists of generators.

OUTPUT:

An instance of the element class of `self` if there exists a group homomorphism mapping the generators of the domain of `self` to the according generators of the codomain. Otherwise, the method falls back to the default.

EXAMPLES:

```sage: G = GL(3,2)
sage: P = PGL(3,2)
sage: nat = Hom(G, P).natural_map()
sage: type(nat)
<class 'sage.groups.libgap_morphism.GroupHomset_libgap_with_category.element_class'>
sage: g1, g2 = G.gens()
sage: nat(g1*g2)
(1,2,4,5,7,3,6)
```
```>>> from sage.all import *
>>> G = GL(Integer(3),Integer(2))
>>> P = PGL(Integer(3),Integer(2))
>>> nat = Hom(G, P).natural_map()
>>> type(nat)
<class 'sage.groups.libgap_morphism.GroupHomset_libgap_with_category.element_class'>
>>> g1, g2 = G.gens()
>>> nat(g1*g2)
(1,2,4,5,7,3,6)
```
class sage.groups.libgap_morphism.GroupMorphism_libgap(homset, gap_hom, check=True)[source]#

Bases: `Morphism`

This wraps GAP group homomorphisms.

Checking if the input defines a group homomorphism can be expensive if the group is large.

INPUT:

• `homset` – the parent

• `gap_hom` – a `sage.libs.gap.element.GapElement` consisting of a group homomorphism

• `check` – (default: `True`) check if the `gap_hom` is a group homomorphism; this can be expensive

EXAMPLES:

```sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([2, 4])
sage: A.hom([g^2 for g in A.gens()])
Group endomorphism of Abelian group with gap, generator orders (2, 4)
```
```>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(2), Integer(4)])
>>> A.hom([g**Integer(2) for g in A.gens()])
Group endomorphism of Abelian group with gap, generator orders (2, 4)
```

Homomorphisms can be defined between different kinds of GAP groups:

```sage: G = MatrixGroup([Matrix(ZZ, 2, [0,1,1,0])])
sage: f = A.hom([G.0, G(1)])
sage: f
Group morphism:
From: Abelian group with gap, generator orders (2, 4)
To:   Matrix group over Integer Ring with 1 generators (
[0 1]
[1 0]
)
sage: G.<a,b> = FreeGroup()
sage: H = G / (G([1]), G([2])^3)
sage: f = G.hom(H.gens())
sage: f
Group morphism:
From: Free Group on generators {a, b}
To:   Finitely presented group < a, b | a, b^3 >
```
```>>> from sage.all import *
>>> G = MatrixGroup([Matrix(ZZ, Integer(2), [Integer(0),Integer(1),Integer(1),Integer(0)])])
>>> f = A.hom([G.gen(0), G(Integer(1))])
>>> f
Group morphism:
From: Abelian group with gap, generator orders (2, 4)
To:   Matrix group over Integer Ring with 1 generators (
[0 1]
[1 0]
)
>>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
>>> H = G / (G([Integer(1)]), G([Integer(2)])**Integer(3))
>>> f = G.hom(H.gens())
>>> f
Group morphism:
From: Free Group on generators {a, b}
To:   Finitely presented group < a, b | a, b^3 >
```

Homomorphisms can be defined between GAP groups and permutation groups:

```sage: S = Sp(4,3)
sage: P = PSp(4,3)
sage: pr = S.hom(P.gens())
sage: E = copy(S.one().matrix())
sage: E[3,0] = 2; e = S(E)
sage: pr(e)
(1,16,15)(3,22,18)(4,19,21)(6,34,24)(7,25,33)(9,40,27)(10,28,39)(12,37,30)(13,31,36)
```
```>>> from sage.all import *
>>> S = Sp(Integer(4),Integer(3))
>>> P = PSp(Integer(4),Integer(3))
>>> pr = S.hom(P.gens())
>>> E = copy(S.one().matrix())
>>> E[Integer(3),Integer(0)] = Integer(2); e = S(E)
>>> pr(e)
(1,16,15)(3,22,18)(4,19,21)(6,34,24)(7,25,33)(9,40,27)(10,28,39)(12,37,30)(13,31,36)
```
gap()[source]#

Return the underlying LibGAP group homomorphism.

EXAMPLES:

```sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([2,4])
sage: f = A.hom([g^2 for g in A.gens()])
sage: f.gap()
[ f1, f2 ] -> [ <identity> of ..., f3 ]
```
```>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(2),Integer(4)])
>>> f = A.hom([g**Integer(2) for g in A.gens()])
>>> f.gap()
[ f1, f2 ] -> [ <identity> of ..., f3 ]
```
image(J, *args, **kwds)[source]#

The image of an element or a subgroup.

INPUT:

• `J` – a subgroup or an element of the domain of `self`

OUTPUT: the image of `J` under `self`

Note

`pushforward` is the method that is used when a map is called on anything that is not an element of its domain. For historical reasons, we keep the alias `image()` for this method.

EXAMPLES:

```sage: G.<a,b> = FreeGroup()
sage: H = G / (G([1]), G([2])^3)
sage: f = G.hom(H.gens())
sage: S = G.subgroup([a.gap()])
sage: f.pushforward(S)
Group([ a ])
sage: x = f.image(a)
sage: x
a
sage: x.parent()
Finitely presented group < a, b | a, b^3 >

sage: # needs sage.rings.finite_rings
sage: G = GU(3,2)
sage: P = PGU(3,2)
sage: pr = Hom(G, P).natural_map()
sage: GS = G.subgroup([G.gen(0)])
sage: pr.pushforward(GS)
Subgroup generated by [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] of
(The projective general unitary group of degree 3 over Finite Field of size 2)
```
```>>> from sage.all import *
>>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
>>> H = G / (G([Integer(1)]), G([Integer(2)])**Integer(3))
>>> f = G.hom(H.gens())
>>> S = G.subgroup([a.gap()])
>>> f.pushforward(S)
Group([ a ])
>>> x = f.image(a)
>>> x
a
>>> x.parent()
Finitely presented group < a, b | a, b^3 >

>>> # needs sage.rings.finite_rings
>>> G = GU(Integer(3),Integer(2))
>>> P = PGU(Integer(3),Integer(2))
>>> pr = Hom(G, P).natural_map()
>>> GS = G.subgroup([G.gen(Integer(0))])
>>> pr.pushforward(GS)
Subgroup generated by [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] of
(The projective general unitary group of degree 3 over Finite Field of size 2)
```
kernel()[source]#

Return the kernel of `self`.

EXAMPLES:

```sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A1 = AbelianGroupGap([6, 6])
sage: A2 = AbelianGroupGap([3, 3])
sage: f = A1.hom(A2.gens())
sage: f.kernel()
Subgroup of Abelian group with gap, generator orders (6, 6)
generated by (f1*f2, f3*f4)
sage: f.kernel().order()
4
sage: S = Sp(6,3)
sage: P = PSp(6,3)
sage: pr = Hom(S, P).natural_map()
sage: pr.kernel()
Subgroup with 1 generators (
[2 0 0 0 0 0]
[0 2 0 0 0 0]
[0 0 2 0 0 0]
[0 0 0 2 0 0]
[0 0 0 0 2 0]
[0 0 0 0 0 2]
) of Symplectic Group of degree 6 over Finite Field of size 3
```
```>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A1 = AbelianGroupGap([Integer(6), Integer(6)])
>>> A2 = AbelianGroupGap([Integer(3), Integer(3)])
>>> f = A1.hom(A2.gens())
>>> f.kernel()
Subgroup of Abelian group with gap, generator orders (6, 6)
generated by (f1*f2, f3*f4)
>>> f.kernel().order()
4
>>> S = Sp(Integer(6),Integer(3))
>>> P = PSp(Integer(6),Integer(3))
>>> pr = Hom(S, P).natural_map()
>>> pr.kernel()
Subgroup with 1 generators (
[2 0 0 0 0 0]
[0 2 0 0 0 0]
[0 0 2 0 0 0]
[0 0 0 2 0 0]
[0 0 0 0 2 0]
[0 0 0 0 0 2]
) of Symplectic Group of degree 6 over Finite Field of size 3
```
lift(h)[source]#

Return an element of the domain that maps to `h`.

EXAMPLES:

```sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([2,4])
sage: f = A.hom([g^2 for g in A.gens()])
sage: a = A.gens()[1]
sage: f.lift(a^2)
f2
```
```>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(2),Integer(4)])
>>> f = A.hom([g**Integer(2) for g in A.gens()])
>>> a = A.gens()[Integer(1)]
>>> f.lift(a**Integer(2))
f2
```

If the element is not in the image, we raise an error:

```sage: f.lift(a)
Traceback (most recent call last):
...
ValueError: f2 is not an element of the image of Group endomorphism
of Abelian group with gap, generator orders (2, 4)
```
```>>> from sage.all import *
>>> f.lift(a)
Traceback (most recent call last):
...
ValueError: f2 is not an element of the image of Group endomorphism
of Abelian group with gap, generator orders (2, 4)
```
preimage(S)[source]#

Return the preimage of the subgroup `S`.

INPUT:

• `S` – a subgroup of this group

EXAMPLES:

```sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
sage: A = AbelianGroupGap([2,4])
sage: B = AbelianGroupGap([4])
sage: f = A.hom([B.one(), B.gen(0)^2])
sage: S = B.subgroup([B.one()])
sage: f.preimage(S) == f.kernel()
True
sage: S = Sp(4,3)
sage: P = PSp(4,3)
sage: pr = Hom(S, P).natural_map()
sage: PS = P.subgroup([P.gen(0)])
sage: pr.preimage(PS)
Subgroup with 2 generators (
[2 0 0 0]  [1 0 0 0]
[0 2 0 0]  [0 2 0 0]
[0 0 2 0]  [0 0 2 0]
[0 0 0 2], [0 0 0 1]
) of Symplectic Group of degree 4 over Finite Field of size 3
```
```>>> from sage.all import *
>>> from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
>>> A = AbelianGroupGap([Integer(2),Integer(4)])
>>> B = AbelianGroupGap([Integer(4)])
>>> f = A.hom([B.one(), B.gen(Integer(0))**Integer(2)])
>>> S = B.subgroup([B.one()])
>>> f.preimage(S) == f.kernel()
True
>>> S = Sp(Integer(4),Integer(3))
>>> P = PSp(Integer(4),Integer(3))
>>> pr = Hom(S, P).natural_map()
>>> PS = P.subgroup([P.gen(Integer(0))])
>>> pr.preimage(PS)
Subgroup with 2 generators (
[2 0 0 0]  [1 0 0 0]
[0 2 0 0]  [0 2 0 0]
[0 0 2 0]  [0 0 2 0]
[0 0 0 2], [0 0 0 1]
) of Symplectic Group of degree 4 over Finite Field of size 3
```
pushforward(J, *args, **kwds)[source]#

The image of an element or a subgroup.

INPUT:

• `J` – a subgroup or an element of the domain of `self`

OUTPUT: the image of `J` under `self`

Note

`pushforward` is the method that is used when a map is called on anything that is not an element of its domain. For historical reasons, we keep the alias `image()` for this method.

EXAMPLES:

```sage: G.<a,b> = FreeGroup()
sage: H = G / (G([1]), G([2])^3)
sage: f = G.hom(H.gens())
sage: S = G.subgroup([a.gap()])
sage: f.pushforward(S)
Group([ a ])
sage: x = f.image(a)
sage: x
a
sage: x.parent()
Finitely presented group < a, b | a, b^3 >

sage: # needs sage.rings.finite_rings
sage: G = GU(3,2)
sage: P = PGU(3,2)
sage: pr = Hom(G, P).natural_map()
sage: GS = G.subgroup([G.gen(0)])
sage: pr.pushforward(GS)
Subgroup generated by [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] of
(The projective general unitary group of degree 3 over Finite Field of size 2)
```
```>>> from sage.all import *
>>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
>>> H = G / (G([Integer(1)]), G([Integer(2)])**Integer(3))
>>> f = G.hom(H.gens())
>>> S = G.subgroup([a.gap()])
>>> f.pushforward(S)
Group([ a ])
>>> x = f.image(a)
>>> x
a
>>> x.parent()
Finitely presented group < a, b | a, b^3 >

>>> # needs sage.rings.finite_rings
>>> G = GU(Integer(3),Integer(2))
>>> P = PGU(Integer(3),Integer(2))
>>> pr = Hom(G, P).natural_map()
>>> GS = G.subgroup([G.gen(Integer(0))])
>>> pr.pushforward(GS)
Subgroup generated by [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] of
(The projective general unitary group of degree 3 over Finite Field of size 2)
```
section()[source]#

Return a section map of `self` by use of `lift()`.

See `section()` of `sage.categories.map.Map`, as well.

OUTPUT: an instance of `sage.categories.morphism.SetMorphism` mapping an element of the codomain of `self` to one of its preimages

EXAMPLES:

```sage: # needs sage.rings.finite_rings
sage: G = GU(3,2)
sage: P = PGU(3,2)
sage: pr = Hom(G, P).natural_map()
sage: sect = pr.section()
sage: sect(P.an_element())
[a + 1     a     a]
[    1     1     0]
[    a     0     0]
```
```>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> G = GU(Integer(3),Integer(2))
>>> P = PGU(Integer(3),Integer(2))
>>> pr = Hom(G, P).natural_map()
>>> sect = pr.section()
>>> sect(P.an_element())
[a + 1     a     a]
[    1     1     0]
[    a     0     0]
```