# Basics

## Elements of groups

Given a group `G`

, it is always possible to have access to some particular elements.

`GAPGroup`

— Type`GAPGroup <: AbstractAlgebra.Group`

Each object of the abstract type `GAPGroup`

stores a group object from the GAP system, and thus can delegate questions about this object to GAP.

For expert usage, you can extract the underlying GAP object via `GapObj`

, i.e., if `G`

is a `GAPGroup`

, then `GapObj(G)`

is the `GapObj`

underlying `G`

.

Concrete subtypes of `GAPGroup`

are `PermGroup`

, `FPGroup`

, `PcGroup`

, and `MatrixGroup`

.

`BasicGAPGroupElem`

— Type`BasicGAPGroupElem{T<:GAPGroup} <: GAPGroupElem{T}`

The type `BasicGAPGroupElem`

gathers all types of group elements described *only* by an underlying GAP object.

If $x$ is an element of the group `G`

of type `T`

, then the type of $x$ is `BasicGAPGroupElem{T}`

.

`elem_type`

— Method```
elem_type(::Type{T}) where T <: GAPGroup
elem_type(::T) where T <: GAPGroup
```

`elem_type`

maps (the type of) a group to the type of its elements. For now, a group of type `T`

has elements of type `BasicGAPGroupElem{T}`

. So we provide it mostly for consistency with other parts of OSCAR. In the future, a more elaborate setup for group element types might also be needed.

`one`

— Method`one(G::GAPGroup) -> elem_type(G)`

Return the identity of the group `G`

.

`one`

— Method`one(x::GAPGroupElem{T}) -> GAPGroupElem{T}`

Return the identity of the parent group of `x`

.

`is_finiteorder`

— Method`is_finiteorder(g::GAPGroupElem) -> Bool`

Return `true`

if `g`

has finite order, and `false`

otherwise.

**Examples**

```
julia> is_finiteorder(gen(symmetric_group(5), 1))
true
julia> is_finiteorder(gen(free_group(2), 1))
false
```

`gens`

— Method`gens(G::Group)`

Return a vector of generators of `G`

. To get the `i`

-th generator, use `G[i]`

or `gen(G,i)`

(see `gen`

) instead of `gens(G)[i]`

, as that is more efficient.

**Examples**

```
julia> g = symmetric_group(5); gens(g)
2-element Vector{PermGroupElem}:
(1,2,3,4,5)
(1,2)
julia> g[2]
(1,2)
```

The output of `gens(G)`

is not, in general, the minimal list of generators for `G`

.

`has_gens`

— Method`has_gens(G::Group)`

Return whether generators for the group `G`

are known.

**Examples**

```
julia> F = free_group(2)
<free group on the generators [ f1, f2 ]>
julia> has_gens(F)
true
julia> H = derived_subgroup(F)[1]
Group(<free, no generators known>)
julia> has_gens(H)
false
```

`ngens`

— Method`ngens(G::GAPGroup) -> Int`

Return the length of the vector `gens`

`(G)`

.

this is *NOT*, in general, the minimum number of generators for G.

`gen`

— Method`gen(G::GAPGroup, i::Int)`

Return the `i`

-th element of the vector `gens(G)`

. This is equivalent to `G[i]`

, and returns `gens(G)[i]`

but may be more efficient than the latter.

An exception is thrown if `i`

is larger than the length of `gens(G)`

.

`small_generating_set`

— Method`small_generating_set(G::GAPGroup)`

Return a reasonably short vector of elements in `G`

that generate `G`

; in general the length of this vector is not minimal.

**Examples**

```
julia> length(small_generating_set(abelian_group(PcGroup, [2,3,4])))
2
julia> length(small_generating_set(abelian_group(PermGroup, [2,3,4])))
3
```

`rand`

— Method`rand(rng::Random.AbstractRNG = Random.GLOBAL_RNG, G::Group)`

Return a random element of `G`

, using the random number generator `rng`

.

`rand_pseudo`

— Method`rand_pseudo(G::GAPGroup)`

Return a pseudo random element of `G`

. This works faster than `rand`

, but the returned elements are not necessarily uniformly distributed.

It is sometimes necessary to work with finite groups that we cannot effectively enumerate, e.g. matrix groups over finite fields. We may not even know the size of these groups. Yet many algorithms need to sample elements from the group "as randomly as possible", whatever that means; but also they need this *fast*.

The function `rand_pseudo`

returns elements that are cheap to compute and somehow random, but makes no guarantees about their distribution.

For finitely presented groups, it returns random words of bounded length.

For finite permutation and matrix groups, it uses a variant of the product replacement algorithm. For most inputs, the resulting stream of elements relatively quickly converges to a uniform distribution.

It is also possible to obtain the generators of `G`

by typing

`f1,f2,f3 = gens(G)`

This is equivalent to

`f1=G[1]; f2=G[2]; f3=G[3];`

For a group `G`

that has been created as a subgroup of another group, generated by a list `L`

of elements, `gens(G)`

is equal to `L`

.

## Operations on group elements

OSCAR supports the following operations and functions on group elements.

`*`

, multiplication between two elements in a group.`inv(x)`

and`x^-1`

, the inverse of`x`

.`x/y`

, the element`x y^-1`

.`x^n`

, the`n`

-th power of`x`

; if`n == 0`

, the identity of the group is returned; if`n < 0`

, the`-n`

-th power of the inverse of`x`

is returned.`isone(x)`

returns whether`x`

is the identity of the group.`conj(x,y)`

and`x^y`

, the conjugate of`x`

by`y`

, i.e., the element`y^-1 x y`

.`comm(x,y)`

, the commutator of`x`

and`y`

, i.e., the element`x^-1 y^-1 x y`

.

In OSCAR, the expression `x^y^z`

is equivalent to `x^(y^z)`

. In other words, conjugations are evaluated from the right to the left.

`comm`

— Method`comm(x::GAPGroupElem, y::GAPGroupElem)`

Return the commutator of `x`

and `y`

, which is defined as `x^-1*y^-1*x*y`

, and usually denoted as `[x,y]`

in the literature.

## Properties of groups

`is_finite`

— Method`is_finite(G::GAPGroup) -> Bool`

Return `true`

if `G`

is finite, and `false`

otherwise.

**Examples**

```
julia> is_finite(symmetric_group(5))
true
julia> is_finite(free_group(2))
false
```

`is_trivial`

— Method`is_trivial(G::GAPGroup)`

Return `true`

if `G`

has order `1`

, and `false`

otherwise.

**Examples**

```
julia> is_trivial(symmetric_group(1))
true
julia> is_trivial(symmetric_group(2))
false
```

`is_cyclic`

— Method`is_cyclic(G::GAPGroup)`

Return `true`

if `G`

is cyclic, i.e., if `G`

can be generated by one element.

`is_abelian`

— Method`is_abelian(G::Group)`

Return `true`

if `G`

is abelian (commutative), that is, $x*y = y*x$ holds for all elements $x, y$ in `G`

.

`is_elementary_abelian`

— Function`is_elementary_abelian(G::Group)`

Return `true`

if `G`

is a abelian (see `is_abelian`

) and if there is a prime `p`

such that the order of each element in `G`

divides `p`

.

**Examples**

```
julia> g = alternating_group(5);
julia> is_elementary_abelian(sylow_subgroup(g, 2)[1])
true
julia> g = alternating_group(6);
julia> is_elementary_abelian(sylow_subgroup(g, 2)[1])
false
```

`is_pgroup`

— Function`is_pgroup(G)`

Return `true`

if `G`

is a $p$-group for some prime $p$, that is, if the order of every element in `G`

is a power of $p$.

Note that a finite group is a $p$-group if and only if its order is a prime power. In particular, the trivial group is a $p$-group for every prime.

**Examples**

```
julia> is_pgroup(symmetric_group(1))
true
julia> is_pgroup(symmetric_group(2))
true
julia> is_pgroup(symmetric_group(3))
false
```

`is_pgroup_with_prime`

— Function`is_pgroup_with_prime(::Type{T} = ZZRingElem, G::GAPGroup) where T <: IntegerUnion`

Return `(true, nothing)`

if `G`

is the trivial group, `(true, p)`

if the order of every element in `G`

is a power of a prime `p`

, and `(false, nothing)`

otherwise.

For finite groups `G`

, the first return value is `true`

if and only if the order of `G`

is a prime power.

**Examples**

```
julia> is_pgroup_with_prime(symmetric_group(1))
(true, nothing)
julia> is_pgroup_with_prime(symmetric_group(2))
(true, 2)
julia> is_pgroup_with_prime(symmetric_group(3))
(false, nothing)
```

`is_nilpotent`

— Function`is_nilpotent(G::GAPGroup)`

Return whether `G`

is nilpotent, i.e., whether the lower central series of `G`

reaches the trivial subgroup in a finite number of steps.

`is_nilpotent(L::LieAlgebra) -> Bool`

Return `true`

if `L`

is nilpotent, i.e. the lower central series of `L`

terminates in $0$.

```
is_nilpotent(a::ResElem{ZZRingElem}) -> Bool
is_nilpotent(a::ResElem{Integer}) -> Bool
```

Tests if $a$ is nilpotent.

`is_supersolvable`

— Function`is_supersolvable(G::GAPGroup)`

Return whether `G`

is supersolvable, i.e., `G`

is finite and has a normal series with cyclic factors.

`is_solvable`

— Function`is_solvable(G::GAPGroup)`

Return whether `G`

is solvable, i.e., whether `derived_series`

(`G`

) reaches the trivial subgroup in a finite number of steps.

`is_solvable(L::LieAlgebra) -> Bool`

Return `true`

if `L`

is solvable, i.e. the derived series of `L`

terminates in $0$.

`is_perfect`

— Function`is_perfect(G::GAPGroup)`

Return whether `G`

is a perfect group, i.e., equal to its derived subgroup.

**Examples**

```
julia> is_perfect(special_linear_group(2, 5))
true
julia> is_perfect(symmetric_group(5))
false
```

`is_perfect(L::LieAlgebra) -> Bool`

Return `true`

if `L`

is perfect, i.e. $[L, L] = L$.

`is_simple`

— Method`is_simple(G::GAPGroup)`

Return whether `G`

is a simple group, i.e., `G`

is not trivial and has no non-trivial normal subgroups.

**Examples**

```
julia> is_simple(alternating_group(5))
true
julia> is_simple(symmetric_group(5))
false
```

`is_almostsimple`

— Function`is_almostsimple(G::GAPGroup)`

Return whether `G`

is an almost simple group, i.e., `G`

is isomorphic to a group $H$ with the property $S \leq H \leq Aut(S)$, for some non-abelian simple group $S$.

**Examples**

```
julia> is_almostsimple(symmetric_group(5))
true
julia> is_almostsimple(special_linear_group(2, 5))
false
```

`is_quasisimple`

— Function`is_quasisimple(G::GAPGroup)`

Return whether `G`

is a quasisimple group, i.e., `G`

is perfect such that the factor group modulo its centre is a non-abelian simple group.

**Examples**

```
julia> is_quasisimple(special_linear_group(2, 5))
true
julia> is_quasisimple(symmetric_group(5))
false
```

`is_sporadic_simple`

— Function`is_sporadic_simple(G::GAPGroup)`

Return whether `G`

is a sporadic simple group.

**Examples**

```
julia> is_sporadic_simple(mathieu_group(11))
true
julia> is_sporadic_simple(mathieu_group(10))
false
```

`is_finitelygenerated`

— Function`is_finitelygenerated(G)`

Return whether `G`

is a finitely generated group.

**Examples**

```
julia> F = free_group(2)
<free group on the generators [ f1, f2 ]>
julia> is_finitelygenerated(F)
true
julia> H = derived_subgroup(F)[1]
Group(<free, no generators known>)
julia> is_finitelygenerated(H)
false
```

## Attributes of groups

`order`

— Method`order(::Type{T} = ZZRingElem, x::Union{GAPGroupElem, GAPGroup}) where T <: IntegerUnion`

Return the order of `x`

, as an instance of `T`

.

For a group element `x`

in the group `G`

, the order of `x`

is the smallest positive integer `n`

such that `x^n`

is the identity of `G`

. For a group `x`

, the order of `x`

is the number of elements in `x`

.

An exception is thrown if the order of `x`

is infinite, use `is_finite`

for checking the finiteness of a group, and `is_finiteorder`

for checking whether a group element has finite order.

**Examples**

```
julia> g = symmetric_group(3);
julia> order(g)
6
julia> order(gen(g, 1))
3
julia> g = free_group(1);
julia> is_finite(g)
false
julia> is_finiteorder(gen(g, 1))
false
```

`cyclic_generator`

— Method`cyclic_generator(G::GAPGroup)`

Return an element of `G`

that generates `G`

if `G`

is cyclic, and throw an error otherwise.

**Examples**

```
julia> g = permutation_group(5, [cperm(1:3), cperm(4:5)])
Group([ (1,2,3), (4,5) ])
julia> cyclic_generator(g)
(1,2,3)(4,5)
```

`exponent`

— Method`exponent(::Type{T} = ZZRingElem, G::GAPGroup) where T <: IntegerUnion`

Return the exponent of `G`

, as an instance of `T`

, i.e., the smallest positive integer $e$ such that $g^e$ is the identity of `G`

for every $g$ in `G`

.

**Examples**

```
julia> exponent(symmetric_group(3))
6
julia> exponent(symmetric_group(13))
360360
```

`describe`

— Method`describe(G::GAPGroup)`

Return a string that describes some aspects of the structure of `G`

.

For finite groups, the function works well if `G`

is an abelian group or a finite simple group or a group in one of the following series: symmetric, dihedral, quasidihedral, generalized quaternion, general linear, special linear.

For other finite groups, the function tries to decompose `G`

as a direct product or a semidirect product, and if this is not possible as a non-splitting extension of a normal subgroup $N$ with the factor group `G`

$/N$, where $N$ is the center or the derived subgroup or the Frattini subgroup of `G`

.

For infinite groups, if the group is known to be finitely generated and abelian or free, a reasonable description is printed.

For general infinite groups, or groups for which finiteness is not (yet) known, not much if anything can be done. In particular we avoid potentially expensive checks such as computing the size of the group or whether it is abelian. While we do attempt a few limited fast checks for finiteness and commutativity, these will not detect all finite or commutative groups.

Thus calling `describe`

again on the same group after additional information about it becomes known to Oscar may yield different outputs.

- for finitely presented groups, even deciding if the group is trivial is impossible in general; the same holds for most other properties, like whether the group is finite, abelian, etc.,
- there is in general no "nice" decomposition of
`G`

, - there may be several decompositions of
`G`

, - nonisomorphic groups may yield the same
`describe`

result, - isomorphic groups may yield different
`describe`

results, - the computations can take a long time (for example in the case of large $p$-groups), and the results are still often not very helpful.

The following notation is used in the returned string.

Description | Syntax |
---|---|

trivial group | 1 |

finite cyclic group | C<size> |

infinite cyclic group | Z |

alternating group | A<degree> |

symmetric group | S<degree> |

dihedral group | D<size> |

quaternion group | Q<size> |

quasidihedral group | QD<size> |

projective special linear group | PSL(<n>,<q>) |

special linear group | SL(<n>,<q>) |

general linear group | GL(<n>,<q>) |

proj. special unitary group | PSU(<n>,<q>) |

orthogonal group, type B | O(2<n>+1,<q>) |

orthogonal group, type D | O+(2<n>,<q>) |

orthogonal group, type 2D | O-(2<n>,<q>) |

proj. special symplectic group | PSp(2<n>,<q>) |

Suzuki group (type 2B) | Sz(<q>) |

Ree group (type 2F or 2G) | Ree(<q>) |

Lie group of exceptional type | E(6,<q>), E(7,<q>), E(8,<q>), 2E(6,<q>), F(4,<q>), G(2,<q>) |

Steinberg triality group | 3D(4,<q>) |

sporadic simple group | M11, M12, M22, M23, M24, J1, J2, J3, J4, Co1, Co2, Co3, Fi22, Fi23, Fi24', Suz, HS, McL, He, HN, Th, B, M, ON, Ly, Ru |

Tits group | 2F(4,2)' |

the indicated group from the library of perfect groups | PerfectGroup(<size>,<id>) |

direct product | A x B |

semidirect product | N : H |

non-split extension | Z(G) . G/Z(G) = G' . G/G', Phi(G) . G/Phi(G) |

**Examples**

```
julia> g = symmetric_group(6);
julia> describe(g)
"S6"
julia> describe(sylow_subgroup(g,2)[1])
"C2 x D8"
julia> describe(sylow_subgroup(g, 3)[1])
"C3 x C3"
julia> describe(free_group(3))
"a free group of rank 3"
```

`nilpotency_class`

— Method`nilpotency_class(G::GAPGroup) -> Int`

Return the nilpotency class of `G`

, i.e., the smallest integer $n$ such that `G`

has a central series of length $n$.

An exception is thrown if `G`

is not nilpotent.

`prime_of_pgroup`

— Function`prime_of_pgroup(::Type{T} = ZZRingElem, G::GAPGroup) where T <: IntegerUnion`

Return the prime $p$ if `G`

is a non-trivial $p$-group.

An exception is thrown if `G`

is not a $p$-group or is a trivial group.

**Examples**

```
julia> prime_of_pgroup(quaternion_group(8))
2
julia> prime_of_pgroup(UInt16, quaternion_group(8))
0x0002
julia> prime_of_pgroup(symmetric_group(1))
ERROR: ArgumentError: only supported for non-trivial p-groups
julia> prime_of_pgroup(symmetric_group(3))
ERROR: ArgumentError: only supported for non-trivial p-groups
```