Groups.jl/README.md

162 lines
6.0 KiB
Markdown
Raw Permalink Normal View History

# Groups
2023-03-15 23:00:50 +01:00
[![CI](https://github.com/kalmarek/Groups.jl/actions/workflows/ci.yml/badge.svg)](https://github.com/kalmarek/Groups.jl/actions/workflows/ci.yml)
2019-03-16 23:36:43 +01:00
[![codecov](https://codecov.io/gh/kalmarek/Groups.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/kalmarek/Groups.jl)
2021-06-21 20:36:12 +02:00
An implementation of finitely-presented groups together with normalization (using Knuth-Bendix procedure).
2019-03-16 23:36:43 +01:00
2021-06-21 20:36:12 +02:00
The package implements `AbstractFPGroup` with three concrete types: `FreeGroup`, `FPGroup` and `AutomorphismGroup`. Here's an example usage:
```julia
julia> using Groups, GroupsCore
julia> A = Alphabet([:a, :A, :b, :B, :c, :C], [2, 1, 4, 3, 6, 5])
2022-10-14 14:05:01 +02:00
Alphabet of Symbol
1. a (inverse of: A)
2. A (inverse of: a)
3. b (inverse of: B)
4. B (inverse of: b)
5. c (inverse of: C)
6. C (inverse of: c)
2021-06-21 20:36:12 +02:00
julia> F = FreeGroup(A)
free group on 3 generators
julia> a,b,c = gens(F)
2022-10-14 14:05:01 +02:00
3-element Vector{FPGroupElement{FreeGroup{Symbol, KnuthBendix.LenLex{Symbol}}, …}}:
2021-06-21 20:36:12 +02:00
a
b
c
julia> a*inv(a)
2022-10-14 14:05:01 +02:00
(id)
2021-06-21 20:36:12 +02:00
julia> (a*b)^2
a*b*a*b
julia> commutator(a, b)
A*B*a*b
julia> x = a*b; y = inv(b)*a;
julia> x*y
a^2
```
2022-10-14 14:05:01 +02:00
## FPGroup
2021-06-21 20:36:12 +02:00
Let's create a quotient of the free group above:
```julia
2022-10-14 14:05:01 +02:00
julia> ε = one(F)
(id)
julia> G = FPGroup(F, [a^2 => ε, b^3=> ε, (a*b)^7=>ε, (a*b*a*inv(b))^6 => ε, commutator(a, c) => ε, commutator(b, c) => ε ], max_rules=100)
┌ Warning: Maximum number of rules (100) reached.
│ The rewriting system may not be confluent.
│ You may retry `knuthbendix` with a larger `max_rules` kwarg.
└ @ KnuthBendix ~/.julia/packages/KnuthBendix/6ME1b/src/knuthbendix_base.jl:8
Finitely presented group generated by:
{ a b c },
subject to relations:
a^2 => (id)
b^3 => (id)
a*b*a*b*a*b*a*b*a*b*a*b*a*b => (id)
a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B => (id)
A*C*a*c => (id)
B*C*b*c => (id)
2021-06-21 20:36:12 +02:00
```
2022-10-14 14:05:01 +02:00
As you can see from the warning, the Knuth-Bendix procedure has not completed successfully. This means that we only are able to **approximate the word problem** in `G`, i.e. if the equality (`==`) of two group elements may return `false` even if group elements are equal. Let us try with a larger maximal number of rules in the underlying rewriting system.
2021-06-21 20:36:12 +02:00
```julia
2022-10-14 14:05:01 +02:00
julia> G = FPGroup(F, [a^2 => ε, b^3=> ε, (a*b)^7=>ε, (a*b*a*inv(b))^6 => ε, commutator(a, c) => ε, commutator(b, c) => ε ], max_rules=500)
Finitely presented group generated by:
{ a b c },
subject to relations:
a^2 => (id)
b^3 => (id)
a*b*a*b*a*b*a*b*a*b*a*b*a*b => (id)
a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B => (id)
A*C*a*c => (id)
B*C*b*c => (id)
2021-06-21 20:36:12 +02:00
```
2022-10-14 14:05:01 +02:00
This time there was no warning, i.e. Knuth-Bendix completion was successful and we may treat the equality (`==`) as the **true mathematical equality**. Note that `G` is the direct product of ` = ⟨ c ⟩` and a quotient of van Dyck `(2,3,7)`-group. Let's create a random word and reduce it as an element of `G`.
2021-06-21 20:36:12 +02:00
```julia
2022-10-14 14:05:01 +02:00
julia> using Random; Random.seed!(1); w = Groups.Word(rand(1:length(A), 16));
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
julia> length(w), w # word of itself
(16, 1·3·5·4·6·2·5·5·5·2·4·3·2·1·4·4)
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
julia> f = F(w) # freely reduced w
a*b*c*B*C*A*c^3*A*B^2
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
julia> length(word(f)), word(f) # the underlying word in F
(12, 1·3·5·4·6·2·5·5·5·2·4·4)
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
julia> g = G(w) # w as an element of G
a*b*c^3
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
julia> length(word(g)), word(g) # the underlying word in G
(5, 1·3·5·5·5)
2021-06-21 20:36:12 +02:00
```
As we can see the underlying words change according to where they are reduced.
2022-10-14 14:05:01 +02:00
Note that a word `w` (of type `Word <: AbstractWord`) is just a sequence of numbers -- indices of letters of an `Alphabet`. Without the alphabet `w` has no intrinsic meaning.
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
## Automorphism Groups
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
Relatively complete is the support for the automorphisms of free groups generated by transvections (or Nielsen generators):
2021-06-21 20:36:12 +02:00
```julia
2022-10-14 14:05:01 +02:00
julia> saut = SpecialAutomorphismGroup(F, max_rules=1000)
2021-06-21 20:36:12 +02:00
automorphism group of free group on 3 generators
julia> S = gens(saut)
2022-10-14 14:05:01 +02:00
12-element Vector{Automorphism{FreeGroup{Symbol, KnuthBendix.LenLex{Symbol}}, …}}:
2021-06-21 20:36:12 +02:00
ϱ₁.₂
ϱ₁.₃
ϱ₂.₁
ϱ₂.₃
ϱ₃.₁
ϱ₃.₂
λ₁.₂
λ₁.₃
λ₂.₁
λ₂.₃
λ₃.₁
λ₃.₂
julia> x, y, z = S[1], S[12], S[6];
2022-10-14 14:05:01 +02:00
julia> f = x*y*inv(z);
2021-06-21 20:36:12 +02:00
2022-10-14 14:05:01 +02:00
julia> g = inv(z)*y*x;
2021-06-21 20:36:12 +02:00
julia> word(f), word(g)
2022-10-14 14:05:01 +02:00
(1·23·12, 12·23·1)
2021-06-21 20:36:12 +02:00
```
2022-10-14 14:05:01 +02:00
Even though there is no known finite, confluent rewriting system for automorphism groupsof the free group (so Knuth-Bendix did not finish successfully) we have another ace in our sleeve to solve the word problem: evaluation.
2021-06-21 20:36:12 +02:00
Lets have a look at the images of generators under those automorphisms:
```julia
julia> evaluate(f) # or to be more verbose...
(a*b, b, b*c*B)
julia> Groups.domain(g)
(a, b, c)
julia> Groups.evaluate!(Groups.domain(g), g)
(a*b, b, b*c*B)
```
Since these automorphism map the standard generating set to the same new generating set, they should be considered as equal! And indeed they are:
```julia
julia> f == g
true
```
This is what is happening behind the scenes:
1. words are reduced using a rewriting system
2. if resulting words are equal `true` is returned
3. if they are not equal `Groups.equality_data` is computed for each argument (here: the images of generators) and the result of comparison is returned.
2022-10-14 14:05:01 +02:00
Moreover we try to amortize the cost of computing those images. That is a hash of `equality_daata` is lazily stored in each group element and used as needed. Essentially only if `true` is returned, but comparison of words returns `false` recomputation of images is needed (to guard against hash collisions).
2021-06-21 20:36:12 +02:00
----
This package was developed for computations in [1712.07167](https://arxiv.org/abs/1712.07167) and in [1812.03456](https://arxiv.org/abs/1812.03456). If you happen to use this package please cite either of them.