## Structural Computations

Abelian groups support a wide range of structural operations such as

- enumeration of subgroups
- (outer) direct products
- tensor and
`hom`

constructions - free resolutions and general complexes
- (co)-homology and tensor and
`hom`

-functors

`snf`

— Method`snf(A::FinGenAbGroup) -> FinGenAbGroup, FinGenAbGroupHom`

Return a pair $(G, f)$, where $G$ is an abelian group in canonical Smith normal form isomorphic to $A$ and an isomorphism $f : G \to A$.

`find_isomorphism`

— Method`find_isomorphism(G, op, A::GrpAb) -> Dict, Dict`

Given an abelian group $A$ and a collection $G$ which is an abelian group with the operation `op`

, this functions returns isomorphisms $G \to A$ and $A \to G$ encoded as dictionaries.

It is assumed that $G$ and $A$ are isomorphic.

### Subgroups and Quotients

`torsion_subgroup`

— Method`torsion_subgroup(G::FinGenAbGroup) -> FinGenAbGroup, Map`

Return the torsion subgroup of `G`

.

`sub`

— Method`sub(G::FinGenAbGroup, s::Vector{FinGenAbGroupElem}) -> FinGenAbGroup, FinGenAbGroupHom`

Create the subgroup $H$ of $G$ generated by the elements in `s`

together with the injection $\iota : H \to G$.

`sub`

— Method`sub(A::SMat, r::AbstractUnitRange, c::AbstractUnitRange) -> SMat`

Return the submatrix of $A$, where the rows correspond to $r$ and the columns correspond to $c$.

`sub(s::Vector{FinGenAbGroupElem}) -> FinGenAbGroup, FinGenAbGroupHom`

Assuming that the non-empty array `s`

contains elements of an abelian group $G$, this functions returns the subgroup $H$ of $G$ generated by the elements in `s`

together with the injection $\iota : H \to G$.

`sub(F::FreeMod{T}, V::Vector{<:FreeModElem{T}}; cache_morphism::Bool=false) where {T}`

Given a vector `V`

of (homogeneous) elements of `F`

, return a pair `(I, inc)`

consisting of the (graded) submodule `I`

of `F`

generated by these elements and its inclusion map `inc : I ↪ F`

.

When `cache_morphism`

is set to true, then `inc`

will be cached and available for `transport`

and friends.

If only the submodule itself is desired, use `sub_object`

instead.

`sub(F::FreeMod{T}, A::MatElem{T}; cache_morphism::Bool=false) where {T}`

Given a (homogeneous) matrix `A`

interpret the rows of `A`

as elements of the free module `F`

and return a pair `(I, inc)`

consisting of the (graded) submodule `I`

of `F`

generated by these row vectors, together with its inclusion map `inc : I ↪ F`

.

When `cache_morphism`

is set to true, then `inc`

will be cached and available for `transport`

and friends.

If only the submodule itself is desired, use `sub_object`

instead.

`sub(F::FreeMod{T}, O::Vector{<:SubquoModuleElem{T}}; cache_morphism::Bool=false) where T`

Suppose the `ambient_free_module`

of the `parent`

`M`

of the elements `v_i`

in `O`

is `F`

and `M`

is a submodule (i.e. no relations are present). Then this returns a pair `(I, inc)`

consisting of the submodule `I`

generated by the elements in `O`

in `F`

, together with its inclusion morphism `inc : I ↪ F`

.

When `cache_morphism`

is set to true, then `inc`

will be cached and available for `transport`

and friends.

If only the submodule itself is desired, use `sub_object`

instead.

`sub(F::FreeMod{T}, M::SubquoModule{T}; cache_morphism::Bool=false) where T`

Return `M`

as a submodule of `F`

, together with its inclusion morphism `inc : M ↪ F`

.

When `cache_morphism`

is set to true, then `inc`

will be cached and available for `transport`

and friends.

The `ambient_free_module`

of `M`

needs to be `F`

and `M`

has to have no relations.

If only the submodule itself is desired, use `sub_object`

instead.

`sub(M::SubquoModule{T}, V::Vector{<:SubquoModuleElem{T}}; cache_morphism::Bool=false) where T`

Given a vector `V`

of (homogeneous) elements of `M`

, return the (graded) submodule `I`

of `M`

generated by these elements together with its inclusion map `inc : I ↪ M.

When `cache_morphism`

is set to true, then `inc`

will be cached and available for `transport`

and friends.

If only the submodule itself is desired, use `sub_object`

instead.

`sub(M::ModuleFP{T}, V::Vector{<:ModuleFPElem{T}}; cache_morphism::Bool=false) where T`

Given a vector `V`

of (homogeneous) elements of `M`

, return the (graded) submodule `I`

of `M`

generated by these elements together with its inclusion map `inc : I ↪ M.

When `cache_morphism`

is set to true, then `inc`

will be cached and available for `transport`

and friends.

If only the submodule itself is desired, use `sub_object`

instead.

**Examples**

```
julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);
julia> F = free_module(R, 1);
julia> V = [x^2*F[1]; y^3*F[1]; z^4*F[1]];
julia> N, incl = sub(F, V);
julia> N
Submodule with 3 generators
1 -> x^2*e[1]
2 -> y^3*e[1]
3 -> z^4*e[1]
represented as subquotient with no relations.
julia> incl
Map with following data
Domain:
=======
Submodule with 3 generators
1 -> x^2*e[1]
2 -> y^3*e[1]
3 -> z^4*e[1]
represented as subquotient with no relations.
Codomain:
=========
Free module of rank 1 over R
```

`sub`

— Method`sub(G::FinGenAbGroup, M::ZZMatrix) -> FinGenAbGroup, FinGenAbGroupHom`

Create the subgroup $H$ of $G$ generated by the elements corresponding to the rows of $M$ together with the injection $\iota : H \to G$.

`sub`

— Method`sub(G::FinGenAbGroup, n::ZZRingElem) -> FinGenAbGroup, FinGenAbGroupHom`

Create the subgroup $n \cdot G$ of $G$ together with the injection $\iota : n\cdot G \to G$.

`sub`

— Method`sub(G::FinGenAbGroup, n::Integer) -> FinGenAbGroup, Map`

Create the subgroup $n \cdot G$ of $G$ together with the injection $\iota : n \cdot G \to G$.

`sylow_subgroup`

— Method`sylow_subgroup(G::FinGenAbGroup, p::IntegerUnion) -> FinGenAbGroup, FinGenAbGroupHom`

Return the Sylow $p-$subgroup of the finitely generated abelian group `G`

, for a prime `p`

. This is the subgroup of `p`

-power order in `G`

whose index in `G`

is coprime to `p`

.

**Examples**

```
julia> A = abelian_group(ZZRingElem[2, 6, 30])
Z/2 x Z/6 x Z/30
julia> H, j = sylow_subgroup(A, 2);
julia> H
(Z/2)^3
julia> divexact(order(A), order(H))
45
```

`has_quotient`

— Method`has_quotient(G::FinGenAbGroup, invariant::Vector{Int}) -> Bool`

Given an abelian group $G$, return true if it has a quotient with given elementary divisors and false otherwise.

`has_complement`

— Method```
has_complement(f::FinGenAbGroupHom) -> Bool, FinGenAbGroupHom
has_complement(U::FinGenAbGroup, G::FinGenAbGroup) -> Bool, FinGenAbGroupHom
```

Given a map representing a subgroup of a group $G$, or a subgroup `U`

of a group `G`

, return either true and an injection of a complement in $G$, or false.

See also: `is_pure`

`is_pure`

— Method`is_pure(U::FinGenAbGroup, G::FinGenAbGroup) -> Bool`

A subgroup `U`

of `G`

is called pure if for all `n`

an element in `U`

that is in the image of the multiplication by `n`

map of `G`

is also a multiple of an element in `U`

.

For finite abelian groups this is equivalent to `U`

having a complement in `G`

. They are also know as *isolated subgroups* and *serving subgroups*.

See also: `is_neat`

, `has_complement`

**EXAMPLES**

```
julia> G = abelian_group([2, 8]);
julia> U, _ = sub(G, [G[1]+2*G[2]]);
julia> is_pure(U, G)
false
julia> U, _ = sub(G, [G[1]+4*G[2]]);
julia> is_pure(U)
true
julia> has_complement(U, G)[1]
true
```

`is_neat`

— Method`is_neat(U::FinGenAbGroup, G::FinGenAbGroup) -> Bool`

A subgroup `U`

of `G`

is called neat if for all primes `p`

an element in `U`

that is in the image of the multiplication by `p`

map of `G`

is also a multiple of an element in `U`

.

See also: `is_pure`

**EXAMPLES**

```
julia> G = abelian_group([2, 8]);
julia> U, _ = sub(G, [G[1] + 2*G[2]]);
julia> is_neat(U, G)
true
julia> is_pure(U, G)
false
```

`saturate`

— Method`saturate(U::FinGenAbGroup, G::FinGenAbGroup) -> FinGenAbGroup`

For a subgroup `U`

of `G`

find a minimal overgroup that is pure, and thus has a complement.

See also: `is_pure`

, `has_complement`

A sophisticated algorithm for the enumeration of all (or selected) subgroups of a finite abelian group is available.

`psubgroups`

— Method```
psubgroups(g::FinGenAbGroup, p::Integer;
subtype = :all,
quotype = :all,
index = -1,
order = -1)
```

Return an iterator for the subgroups of $G$ of the specific form. Note that `subtype`

(and `quotype`

) is the type of the subgroup as an abelian $p$-group.

`julia> G = abelian_group([6, 12])`

`Z/6 x Z/12`

`julia> shapes = MSet{Vector{ZZRingElem}}()`

`MSet{Vector{ZZRingElem}}()`

`julia> for U = psubgroups(G, 2) push!(shapes, elementary_divisors(U[1])) end`

`julia> shapes`

`MSet{Vector{ZZRingElem}} with 8 elements: ZZRingElem[] ZZRingElem[4] : 2 ZZRingElem[2, 4] ZZRingElem[2] : 3 ZZRingElem[2, 2]`

So there are $2$ subgroups isomorphic to $C_4$ (`ZZRingElem[4] : 2`

), $1$ isomorphic to $C_2\times C_4$, 1 trivial and $3$ $C_2$ subgroups.

`subgroups`

— Method```
subgroups(g::FinGenAbGroup;
subtype = :all ,
quotype = :all,
index = -1,
order = -1)
```

Return an iterator for the subgroups of $G$ of the specific form.

`julia> for U = subgroups(G, subtype = [2]) @show U[1], map(U[2], gens(U[1])) end`

`(U[1], map(U[2], gens(U[1]))) = (Z/2, FinGenAbGroupElem[[0, 6]]) (U[1], map(U[2], gens(U[1]))) = (Z/2, FinGenAbGroupElem[[3, 6]]) (U[1], map(U[2], gens(U[1]))) = (Z/2, FinGenAbGroupElem[[3, 0]])`

`julia> for U = subgroups(G, quotype = [2]) @show U[1], map(U[2], gens(U[1])) end`

`(U[1], map(U[2], gens(U[1]))) = (Finitely generated abelian group with 3 generators and 3 relations, FinGenAbGroupElem[[3, 3], [0, 4], [2, 0]]) (U[1], map(U[2], gens(U[1]))) = (Finitely generated abelian group with 3 generators and 3 relations, FinGenAbGroupElem[[0, 3], [0, 4], [2, 0]]) (U[1], map(U[2], gens(U[1]))) = (Finitely generated abelian group with 4 generators and 4 relations, FinGenAbGroupElem[[3, 6], [0, 6], [0, 4], [2, 0]])`

`quo`

— Method`quo(G::FinGenAbGroup, s::Vector{FinGenAbGroupElem}) -> FinGenAbGroup, GrpAbfinGemMap`

Create the quotient $H$ of $G$ by the subgroup generated by the elements in $s$, together with the projection $p : G \to H$.

`quo`

— Method`quo(G::FinGenAbGroup, M::ZZMatrix) -> FinGenAbGroup, FinGenAbGroupHom`

Create the quotient $H$ of $G$ by the subgroup generated by the elements corresponding to the rows of $M$, together with the projection $p : G \to H$.

`quo`

— Method```
quo(G::FinGenAbGroup, n::Integer}) -> FinGenAbGroup, Map
quo(G::FinGenAbGroup, n::ZZRingElem}) -> FinGenAbGroup, Map
```

Returns the quotient $H = G/nG$ together with the projection $p : G \to H$.

`quo`

— Method```
quo(G::FinGenAbGroup, n::Integer}) -> FinGenAbGroup, Map
quo(G::FinGenAbGroup, n::ZZRingElem}) -> FinGenAbGroup, Map
```

Returns the quotient $H = G/nG$ together with the projection $p : G \to H$.

`quo`

— Method`quo(G::FinGenAbGroup, U::FinGenAbGroup) -> FinGenAbGroup, Map`

Create the quotient $H$ of $G$ by $U$, together with the projection $p : G \to H$.

For 2 subgroups `U`

and `V`

of the same group `G`

, `U+V`

returns the smallest subgroup of `G`

containing both. Similarly, $U\cap V$ computes the intersection and $U \subset V$ tests for inclusion. The difference between `issubset =`

$\subset$ and `is_subgroup`

is that the inclusion map is also returned in the 2nd call.

`intersect`

— Method`intersect(mG::FinGenAbGroupHom, mH::FinGenAbGroupHom) -> FinGenAbGroup, Map`

Given two injective maps of abelian groups with the same codomain $G$, return the intersection of the images as a subgroup of $G$.

### Direct Products

`direct_product`

— Method`direct_product(G::FinGenAbGroup...) -> FinGenAbGroup, Vector{FinGenAbGroupHom}`

Return the direct product $D$ of the (finitely many) abelian groups $G_i$, together with the projections $D \to G_i$.

For finite abelian groups, finite direct sums and finite direct products agree and they are therefore called biproducts. If one wants to obtain $D$ as a direct sum together with the injections $D \to G_i$, one should call `direct_sum(G...)`

. If one wants to obtain $D$ as a biproduct together with the projections and the injections, one should call `biproduct(G...)`

.

Otherwise, one could also call `canonical_injections(D)`

or `canonical_projections(D)`

later on.

`canonical_injection`

— Method`canonical_injection(G::FinGenAbGroup, i::Int) -> FinGenAbGroupHom`

Given a group $G$ that was created as a direct product, return the injection from the $i$th component.

`canonical_projection`

— Method`canonical_projection(G::FinGenAbGroup, i::Int) -> FinGenAbGroupHom`

Given a group $G$ that was created as a direct product, return the projection onto the $i$th component.

`flat`

— Method`flat(G::FinGenAbGroup) -> FinGenAbGroupHom`

Given a group $G$ that is created using (iterated) direct products, or (iterated) tensor products, return a group isomorphism into a flat product: for $G := (A \oplus B) \oplus C$, it returns the isomorphism $G \to A \oplus B \oplus C$ (resp. $\otimes$).

### Tensor Producs

`tensor_product`

— Method`tensor_product(G::FinGenAbGroup...; task::Symbol = :map) -> FinGenAbGroup, Map`

Given groups $G_i$, compute the tensor product $G_1\otimes \cdots \otimes G_n$. If `task`

is set to ":map", a map $\phi$ is returned that maps tuples in $G_1 \times \cdots \times G_n$ to pure tensors $g_1 \otimes \cdots \otimes g_n$. The map admits a preimage as well.

`hom_tensor`

— Method`hom_tensor(G::FinGenAbGroup, H::FinGenAbGroup, A::Vector{ <: Map{FinGenAbGroup, FinGenAbGroup}}) -> Map`

Given groups $G = G_1 \otimes \cdots \otimes G_n$ and $H = H_1 \otimes \cdot \otimes H_n$ as well as maps $\phi_i: G_i\to H_i$, compute the tensor product of the maps.

### Hom-Group

`hom`

— Method`hom(G::FinGenAbGroup, H::FinGenAbGroup; task::Symbol = :map) -> FinGenAbGroup, Map`

Computes the group of all homomorpisms from $G$ to $H$ as an abstract group. If `task`

is ":map", then a map $\phi$ is computed that can be used to obtain actual homomorphisms. This map also allows preimages. Set `task`

to ":none" to not compute the map.