# Group homomorphisms

In OSCAR, a group homomorphism from `G`

to `H`

is an object of parametric type `GAPGroupHomomorphism{S,T}`

, where `S`

and `T`

are the types of `G`

and `H`

respectively.

A homomorphism from `G`

to `H`

can be defined in two ways.

- Writing explicitly the images of the generators of
`G`

:

`f = hom(G,H,[x1,x2,...],[y1,y2,...])`

Here, `[x1,x2,...]`

must be a generating set for `G`

(not necessarily minimal) and `[y1,y2,...]`

is a vector of elements of `H`

of the same length of `[x1,x2,...]`

. This assigns to `f`

the value of the group homomorphism sending `x_i`

into `y_i`

.

An exception is thrown if such a homomorphism does not exist.

- Taking an existing function
`g`

satisfying the group homomorphism properties:

`f = hom(G,H,g)`

An exception is thrown if the function `g`

does not define a group homomorphism.

**Example:** The following procedures define the same homomorphism (conjugation by `x`

) in the two ways explained above.

```
julia> S=symmetric_group(4);
julia> x=S[1];
julia> f=hom(S,S,gens(S),[S[1]^x,S[2]^x]);
julia> g=hom(S,S,y->y^x);
julia> f==g
true
```

`hom`

— Method`hom(G::GAPGroup, H::GAPGroup, f::Function)`

Return the group homomorphism defined by the function `f`

.

`hom`

— Method`hom(G::GAPGroup, H::GAPGroup, gensG::Vector = gens(G), imgs::Vector; check::Bool = true)`

Return the group homomorphism defined by `gensG`

[`i`

] -> `imgs`

[`i`

] for every `i`

. In order to work, the elements of `gensG`

must generate `G`

.

If `check`

is set to `false`

then it is not checked whether the mapping defines a group homomorphism.

`image`

— Method```
image(f::GAPGroupHomomorphism, x::GAPGroupElem)
(f::GAPGroupHomomorphism)(x::GAPGroupElem)
```

Return `f`

(`x`

).

`preimage`

— Method`preimage(f::GAPGroupHomomorphism, x::GAPGroupElem)`

Return an element `y`

in the domain of `f`

with the property `f(y) == x`

. See `has_preimage_with_preimage(f::GAPGroupHomomorphism, x::GAPGroupElem; check::Bool = true)`

for a check whether `x`

has such a preimage.

`restrict_homomorphism`

— Method```
restrict_homomorphism(f::GAPGroupHomomorphism, H::Group)
restrict_homomorphism(f::GAPGroupElem{AutomorphismGroup{T}}, H::T) where T <: Group
```

Return the restriction of `f`

to `H`

. An exception is thrown if `H`

is not a subgroup of `domain(f)`

.

OSCAR has also the following standard homomorphism.

`id_hom`

— Function`id_hom(T::TorQuadModule) -> TorQuadModuleMap`

Alias for `identity_map`

.

`id_hom(G::GAPGroup)`

Return the identity homomorphism on the group `G`

.

`trivial_morphism`

— Function`trivial_morphism(T::TorQuadModule, U::TorQuadModule) -> TorQuadModuleMap`

Return the abelian group homomorphism between `T`

and `U`

sending every elements of `T`

to the zero element of `U`

.

`trivial_morphism(T::TorQuadModule) -> TorQuadModuleMap`

Return the abelian group endomorphism of `T`

sending every elements of `T`

to the zero element of `T`

.

`trivial_morphism(G::GAPGroup, H::GAPGroup = G)`

Return the homomorphism from `G`

to `H`

sending every element of `G`

into the identity of `H`

.

To evaluate the homomorphism `f`

in the element `x`

of `G`

, it is possible to use the instruction

`image(f,x)`

or the more compact notations `f(x)`

and `x^f`

.

**Example:**

```
julia> S=symmetric_group(4);
julia> f=hom(S,S,x->x^S[1]);
julia> x=cperm(S,[1,2]);
julia> image(f,x)
(2,3)
julia> f(x)
(2,3)
julia> x^f
(2,3)
```

A sort of "inverse" of the evaluation is the following

`has_preimage_with_preimage`

— Method`has_preimage_with_preimage(f::GAPGroupHomomorphism, x::GAPGroupElem; check::Bool = true)`

Return (`true`

, `y`

) if there exists `y`

in `domain(f)`

such that `f`

(`y`

) = `x`

holds; otherwise, return (`false`

, `o`

) where `o`

is the identity of `domain(f)`

.

If `check`

is set to `false`

then the test whether `x`

is an element of `image(f)`

is omitted.

**Example:**

```
julia> S=symmetric_group(4);
julia> f=hom(S,S,x->x^S[1]);
julia> x=cperm(S,[1,2]);
julia> has_preimage_with_preimage(f,x)
(true, (1,4))
```

## Operations on homomorphisms

OSCAR supports the following operations on homomorphisms.

`inv(f)`

= the inverse of`f`

. An exception is thrown if`f`

is not bijective.`f^n`

= the homomorphism`f`

composed`n`

times with itself. An exception is thrown if the domain and the codomain of`f`

do not coincide (unless`n=1`

). If`n`

is negative, the result is the inverse of`f`

composed`n`

times with itself.`compose(f, g)`

= composition of`f`

and`g`

. This works only if the codomain of`f`

coincides with the domain of`g`

. Shorter equivalent expressions are`f*g`

and`g(f)`

.**Example:**

```
julia> S=symmetric_group(4);
julia> f=hom(S,S,x->x^S[1]);
julia> g=hom(S,S,x->x^S[2]);
julia> f*g==hom(S,S,x->x^(S[1]*S[2]))
true
julia> f==f^-3
true
```

The composition operation `*`

has to be read from the right to the left. So, `(f*g)(x)`

is equivalent to `g(f(x))`

.

## Properties of homomorphisms

OSCAR implements the following attributes of homomorphisms, in addition to the usual `domain`

and `codomain`

.

`is_injective`

— Method`is_injective(f::GAPGroupHomomorphism)`

Return whether `f`

is injective.

`is_surjective`

— Method`is_surjective(f::GAPGroupHomomorphism)`

Return whether `f`

is surjective.

`is_bijective`

— Method`is_bijective(f::GAPGroupHomomorphism)`

Return whether `f`

is bijective.

`is_invertible`

— Method`is_invertible(f::GAPGroupHomomorphism)`

Return whether `f`

is invertible.

`is_invariant`

— Method```
is_invariant(f::GAPGroupHomomorphism, H::Group)
is_invariant(f::GAPGroupElem{AutomorphismGroup{T}}, H::T)
```

Return whether `f(H) == H`

holds. An exception is thrown if `domain(f)`

and `codomain(f)`

are not equal or if `H`

is not contained in `domain(f)`

.

## Subgroups described by homomorphisms

The following functions compute subgroups or quotients of either the domain or the codomain. Analogously to the functions described in Sections Subgroups and Quotients, the output consists of a pair (`H`

, `g`

), where `H`

is a subgroup (resp. quotient) and `g`

is its embedding (resp. projection) homomorphism.

`kernel`

— Method`kernel(f::GAPGroupHomomorphism)`

Return the kernel of `f`

, together with its embedding into `domain`

(`f`

).

`image`

— Method`image(f::GAPGroupHomomorphism)`

Return the image of `f`

as subgroup of `codomain`

(`f`

), together with the embedding homomorphism.

`image`

— Method```
image(f::GAPGroupHomomorphism{S, T}, H::S) where S <: GAPGroup where T <: GAPGroup
(f::GAPGroupHomomorphism{S, T})(H::S)
```

Return `f`

(`H`

), together with the embedding homomorphism into `codomain`

(`f`

).

`cokernel`

— Method`cokernel(f::GAPGroupHomomorphism)`

Return the cokernel of `f`

, that is, the quotient of the codomain of `f`

by the normal closure of the image.

`preimage`

— Method`preimage(f::GAPGroupHomomorphism{S, T}, H::T) where S <: GAPGroup where T <: GAPGroup`

If `H`

is a subgroup of the codomain of `f`

, return the subgroup `f^-1(H)`

, together with its embedding homomorphism into the domain of `f`

.

## Group isomorphisms

`is_isomorphic`

— Method`is_isomorphic(G::Group, H::Group)`

Return `true`

if `G`

and `H`

are isomorphic groups, and `false`

otherwise.

**Examples**

```
julia> is_isomorphic(symmetric_group(3), dihedral_group(6))
true
```

`is_isomorphic_with_map`

— Method`is_isomorphic_with_map(G::Group, H::Group)`

Return (`true`

,`f`

) if `G`

and `H`

are isomorphic groups, where `f`

is a group isomorphism. Otherwise, return (`false`

,`f`

), where `f`

is the trivial homomorphism.

**Examples**

```
julia> is_isomorphic_with_map(symmetric_group(3), dihedral_group(6))
(true, Hom: Sym(3) -> pc group)
```

`isomorphism`

— Method`isomorphism(G::Group, H::Group)`

Return a group isomorphism between `G`

and `H`

if they are isomorphic groups. Otherwise throw an exception.

**Examples**

```
julia> isomorphism(symmetric_group(3), dihedral_group(6))
Group homomorphism
from Sym(3)
to pc group of order 6
```

`isomorphism`

— Method`isomorphism(::Type{T}, G::GAPGroup) where T <: Union{FPGroup, PcGroup, PermGroup}`

Return an isomorphism from `G`

to a group of type `T`

. An exception is thrown if no such isomorphism exists.

Isomorphisms are cached in `G`

, subsequent calls of `isomorphism`

with the same `T`

yield identical results.

If only the image of such an isomorphism is needed, use `T(G)`

.

**Examples**

```
julia> G = dihedral_group(6)
Pc group of order 6
julia> iso = isomorphism(PermGroup, G)
Group homomorphism
from pc group of order 6
to permutation group of degree 6 and order 6
julia> permutation_group(G)
Permutation group of degree 6 and order 6
julia> codomain(iso) === ans
true
```

`isomorphism`

— Method`isomorphism(::Type{FinGenAbGroup}, G::GAPGroup)`

Return a map from `G`

to an isomorphic (additive) group of type `FinGenAbGroup`

. An exception is thrown if `G`

is not abelian or not finite.

`simplified_fp_group`

— Method`simplified_fp_group(G::FPGroup)`

Return a group `H`

of type `FPGroup`

and an isomorphism `f`

from `G`

to `H`

, where the presentation of `H`

was obtained from the presentation of `G`

by applying Tietze transformations in order to reduce it with respect to the number of generators, the number of relators, and the relator lengths.

**Examples**

```
julia> F = free_group(3)
Free group of rank 3
julia> G = quo(F, [gen(F,1)])[1]
Finitely presented group of infinite order
julia> simplified_fp_group(G)[1]
Finitely presented group of infinite order
```

## Other homomorphisms

`epimorphism_from_free_group`

— Method`epimorphism_from_free_group(G::GAPGroup)`

Return an epimorphism `epi`

from a free group `F == domain(epi)`

onto `G`

, where `F`

has the same number of generators as `G`

and such that for each `i`

it maps `gen(F,i)`

to `gen(G,i)`

.

A useful application of this function is expressing an element of `G`

as a word in its generators.

**Examples**

```
julia> G = symmetric_group(4);
julia> epi = epimorphism_from_free_group(G)
Group homomorphism
from free group of rank 2
to Sym(4)
julia> pi = G([2,4,3,1])
(1,2,4)
julia> w = preimage(epi, pi);
julia> map_word(w, gens(G))
(1,2,4)
```