mirror of
https://github.com/kalmarek/Groups.jl.git
synced 2024-11-28 08:45:27 +01:00
Merge pull request #24 from kalmarek/mk/update_to_KB_0.4
update to KnuthBendix-0.4
This commit is contained in:
commit
161c146642
13
.github/workflows/CompatHelper.yml
vendored
Normal file
13
.github/workflows/CompatHelper.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
name: CompatHelper
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: 0 0 * * *
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
CompatHelper:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: JuliaRegistries/compathelper-action@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
ssh: ${{ secrets.DOCUMENTER_KEY }}
|
5
.github/workflows/TagBot.yml
vendored
5
.github/workflows/TagBot.yml
vendored
@ -4,6 +4,11 @@ on:
|
|||||||
types:
|
types:
|
||||||
- created
|
- created
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
lookback:
|
||||||
|
default: 3
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
jobs:
|
jobs:
|
||||||
TagBot:
|
TagBot:
|
||||||
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
|
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
name: CI
|
name: CI
|
||||||
on:
|
on:
|
||||||
push:
|
- pull_request
|
||||||
branches:
|
- push
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
|
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
|
||||||
@ -22,21 +18,31 @@ jobs:
|
|||||||
- windows-latest
|
- windows-latest
|
||||||
arch:
|
arch:
|
||||||
- x64
|
- x64
|
||||||
|
allow_failures:
|
||||||
|
- julia: nightly
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: julia-actions/setup-julia@v1
|
- uses: julia-actions/setup-julia@v1
|
||||||
with:
|
with:
|
||||||
version: ${{ matrix.version }}
|
version: ${{ matrix.version }}
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
env:
|
||||||
|
cache-name: cache-artifacts
|
||||||
|
with:
|
||||||
|
path: ~/.julia/artifacts
|
||||||
|
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-test-${{ env.cache-name }}-
|
||||||
|
${{ runner.os }}-test-
|
||||||
|
${{ runner.os }}-
|
||||||
- uses: julia-actions/julia-buildpkg@latest
|
- uses: julia-actions/julia-buildpkg@latest
|
||||||
- uses: julia-actions/julia-runtest@latest
|
- uses: julia-actions/julia-runtest@latest
|
||||||
- uses: julia-actions/julia-processcoverage@v1
|
- uses: julia-actions/julia-processcoverage@v1
|
||||||
- uses: codecov/codecov-action@v1
|
- uses: codecov/codecov-action@v2
|
||||||
with:
|
with:
|
||||||
file: ./lcov.info
|
file: ./lcov.info
|
||||||
flags: unittests
|
flags: unittests
|
||||||
name: codecov-umbrella
|
name: codecov-umbrella
|
||||||
fail_ci_if_error: false
|
fail_ci_if_error: false
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@ -1,7 +1,7 @@
|
|||||||
name = "Groups"
|
name = "Groups"
|
||||||
uuid = "5d8bd718-bd84-11e8-3b40-ad14f4a32557"
|
uuid = "5d8bd718-bd84-11e8-3b40-ad14f4a32557"
|
||||||
authors = ["Marek Kaluba <kalmar@amu.edu.pl>"]
|
authors = ["Marek Kaluba <kalmar@amu.edu.pl>"]
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
Folds = "41a02a25-b8f0-4f67-bc48-60067656b558"
|
Folds = "41a02a25-b8f0-4f67-bc48-60067656b558"
|
||||||
@ -16,7 +16,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
|
|||||||
[compat]
|
[compat]
|
||||||
Folds = "0.2.7"
|
Folds = "0.2.7"
|
||||||
GroupsCore = "0.4"
|
GroupsCore = "0.4"
|
||||||
KnuthBendix = "0.3"
|
KnuthBendix = "0.4"
|
||||||
OrderedCollections = "1"
|
OrderedCollections = "1"
|
||||||
PermutationGroups = "0.3"
|
PermutationGroups = "0.3"
|
||||||
StaticArrays = "1"
|
StaticArrays = "1"
|
||||||
|
112
README.md
112
README.md
@ -10,25 +10,25 @@ The package implements `AbstractFPGroup` with three concrete types: `FreeGroup`,
|
|||||||
julia> using Groups, GroupsCore
|
julia> using Groups, GroupsCore
|
||||||
|
|
||||||
julia> A = Alphabet([:a, :A, :b, :B, :c, :C], [2, 1, 4, 3, 6, 5])
|
julia> A = Alphabet([:a, :A, :b, :B, :c, :C], [2, 1, 4, 3, 6, 5])
|
||||||
Alphabet of Symbol:
|
Alphabet of Symbol
|
||||||
1. :a = (:A)⁻¹
|
1. a (inverse of: A)
|
||||||
2. :A = (:a)⁻¹
|
2. A (inverse of: a)
|
||||||
3. :b = (:B)⁻¹
|
3. b (inverse of: B)
|
||||||
4. :B = (:b)⁻¹
|
4. B (inverse of: b)
|
||||||
5. :c = (:C)⁻¹
|
5. c (inverse of: C)
|
||||||
6. :C = (:c)⁻¹
|
6. C (inverse of: c)
|
||||||
|
|
||||||
julia> F = FreeGroup(A)
|
julia> F = FreeGroup(A)
|
||||||
free group on 3 generators
|
free group on 3 generators
|
||||||
|
|
||||||
julia> a,b,c = gens(F)
|
julia> a,b,c = gens(F)
|
||||||
3-element Vector{FPGroupElement{FreeGroup{Symbol}, KnuthBendix.Word{UInt8}}}:
|
3-element Vector{FPGroupElement{FreeGroup{Symbol, KnuthBendix.LenLex{Symbol}}, …}}:
|
||||||
a
|
a
|
||||||
b
|
b
|
||||||
c
|
c
|
||||||
|
|
||||||
julia> a*inv(a)
|
julia> a*inv(a)
|
||||||
(empty word)
|
(id)
|
||||||
|
|
||||||
julia> (a*b)^2
|
julia> (a*b)^2
|
||||||
a*b*a*b
|
a*b*a*b
|
||||||
@ -40,65 +40,75 @@ julia> x = a*b; y = inv(b)*a;
|
|||||||
|
|
||||||
julia> x*y
|
julia> x*y
|
||||||
a^2
|
a^2
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## FPGroup
|
||||||
Let's create a quotient of the free group above:
|
Let's create a quotient of the free group above:
|
||||||
```julia
|
```julia
|
||||||
julia> ε = one(F);
|
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) => ε ])
|
|
||||||
┌ Warning: Maximum number of rules (100) reached. The rewriting system may not be confluent.
|
|
||||||
│ You may retry `knuthbendix` with a larger `maxrules` kwarg.
|
|
||||||
└ @ KnuthBendix ~/.julia/packages/KnuthBendix/i93Np/src/kbs.jl:6
|
|
||||||
⟨a, b, c | a^2 => (empty word), b^3 => (empty word), a*b*a*b*a*b*a*b*a*b*a*b*a*b => (empty word), a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B => (empty word), A*C*a*c => (empty word), B*C*b*c => (empty word)⟩
|
|
||||||
|
|
||||||
|
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)
|
||||||
```
|
```
|
||||||
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.
|
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.
|
||||||
|
|
||||||
```julia
|
```julia
|
||||||
julia> G = FPGroup(F, [a^2 => ε, b^3=> ε, (a*b)^7=>ε, (a*b*a*inv(b))^6 => ε, commutator(a, c) => ε, commutator(b, c) => ε ], maxrules=500)
|
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)
|
||||||
⟨a, b, c | a^2 => (empty word), b^3 => (empty word), a*b*a*b*a*b*a*b*a*b*a*b*a*b => (empty word), a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B*a*b*a*B => (empty word), A*C*a*c => (empty word), B*C*b*c => (empty word)⟩
|
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)
|
||||||
|
|
||||||
```
|
```
|
||||||
This time there was no warning, i.e. Knuth-Bendix completion was successful and we may treat the equality (`==`) as 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`.
|
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`.
|
||||||
```julia
|
```julia
|
||||||
julia> using Random; Random.seed!(1); w = Groups.Word(rand(1:length(A), 16))
|
julia> using Random; Random.seed!(1); w = Groups.Word(rand(1:length(A), 16));
|
||||||
KnuthBendix.Word{UInt16}: 4·6·1·1·1·6·5·1·5·2·3·6·2·4·2·6
|
|
||||||
|
|
||||||
julia> F(w) # freely reduced w
|
julia> length(w), w # word of itself
|
||||||
B*C*a^4*c*A*b*C*A*B*A*C
|
(16, 1·3·5·4·6·2·5·5·5·2·4·3·2·1·4·4)
|
||||||
|
|
||||||
julia> G(w) # w as an element of G
|
julia> f = F(w) # freely reduced w
|
||||||
B*a*b*a*B*a*C^2
|
a*b*c*B*C*A*c^3*A*B^2
|
||||||
|
|
||||||
julia> F(w) # freely reduced w
|
julia> length(word(f)), word(f) # the underlying word in F
|
||||||
B*C*a^4*c*A*b*C*A*B*A*C
|
(12, 1·3·5·4·6·2·5·5·5·2·4·4)
|
||||||
|
|
||||||
julia> word(ans) # the underlying word in A
|
julia> g = G(w) # w as an element of G
|
||||||
KnuthBendix.Word{UInt8}: 4·6·1·1·1·1·5·2·3·6·2·4·2·6
|
a*b*c^3
|
||||||
|
|
||||||
julia> G(w) # w as an element of G
|
|
||||||
B*a*b*a*B*a*C^2
|
|
||||||
|
|
||||||
julia> word(ans) # the underlying word in A
|
|
||||||
KnuthBendix.Word{UInt8}: 4·1·3·1·4·1·6·6
|
|
||||||
|
|
||||||
|
julia> length(word(g)), word(g) # the underlying word in G
|
||||||
|
(5, 1·3·5·5·5)
|
||||||
```
|
```
|
||||||
As we can see the underlying words change according to where they are reduced.
|
As we can see the underlying words change according to where they are reduced.
|
||||||
Note that a word `w` (of type `Word <: AbstractWord`) is just a sequence of numbers -- pointers to letters of an `Alphabet`. Without the alphabet `w` has no meaning.
|
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.
|
||||||
|
|
||||||
### Automorphism Groups
|
## Automorphism Groups
|
||||||
|
|
||||||
Relatively complete is the support for the automorphisms of free groups, as given by Gersten presentation:
|
Relatively complete is the support for the automorphisms of free groups generated by transvections (or Nielsen generators):
|
||||||
```julia
|
```julia
|
||||||
julia> saut = SpecialAutomorphismGroup(F, maxrules=100)
|
julia> saut = SpecialAutomorphismGroup(F, max_rules=1000)
|
||||||
┌ Warning: Maximum number of rules (100) reached. The rewriting system may not be confluent.
|
|
||||||
│ You may retry `knuthbendix` with a larger `maxrules` kwarg.
|
|
||||||
└ @ KnuthBendix ~/.julia/packages/KnuthBendix/i93Np/src/kbs.jl:6
|
|
||||||
automorphism group of free group on 3 generators
|
automorphism group of free group on 3 generators
|
||||||
|
|
||||||
julia> S = gens(saut)
|
julia> S = gens(saut)
|
||||||
12-element Vector{Automorphism{FreeGroup{Symbol},…}}:
|
12-element Vector{Automorphism{FreeGroup{Symbol, KnuthBendix.LenLex{Symbol}}, …}}:
|
||||||
ϱ₁.₂
|
ϱ₁.₂
|
||||||
ϱ₁.₃
|
ϱ₁.₃
|
||||||
ϱ₂.₁
|
ϱ₂.₁
|
||||||
@ -114,17 +124,15 @@ julia> S = gens(saut)
|
|||||||
|
|
||||||
julia> x, y, z = S[1], S[12], S[6];
|
julia> x, y, z = S[1], S[12], S[6];
|
||||||
|
|
||||||
julia> f = x*y*inv(z)
|
julia> f = x*y*inv(z);
|
||||||
ϱ₁.₂*λ₃.₂*ϱ₃.₂^-1
|
|
||||||
|
|
||||||
julia> g = inv(z)*y*x
|
julia> g = inv(z)*y*x;
|
||||||
ϱ₃.₂^-1*ϱ₁.₂*λ₃.₂
|
|
||||||
|
|
||||||
julia> word(f), word(g)
|
julia> word(f), word(g)
|
||||||
(KnuthBendix.Word{UInt8}: 1·12·18, KnuthBendix.Word{UInt8}: 18·1·12)
|
(1·23·12, 12·23·1)
|
||||||
|
|
||||||
```
|
```
|
||||||
Even though Knuth-Bendix did not finish successfully in automorphism groups we have another ace in our sleeve to solve the word problem: evaluation.
|
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.
|
||||||
Lets have a look at the images of generators under those automorphisms:
|
Lets have a look at the images of generators under those automorphisms:
|
||||||
```julia
|
```julia
|
||||||
julia> evaluate(f) # or to be more verbose...
|
julia> evaluate(f) # or to be more verbose...
|
||||||
@ -147,7 +155,7 @@ This is what is happening behind the scenes:
|
|||||||
2. if resulting words are equal `true` is returned
|
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.
|
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.
|
||||||
|
|
||||||
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).
|
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).
|
||||||
|
|
||||||
----
|
----
|
||||||
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.
|
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.
|
||||||
|
@ -10,7 +10,7 @@ import OrderedCollections: OrderedSet
|
|||||||
|
|
||||||
import KnuthBendix
|
import KnuthBendix
|
||||||
import KnuthBendix: AbstractWord, Alphabet, Word
|
import KnuthBendix: AbstractWord, Alphabet, Word
|
||||||
import KnuthBendix: alphabet
|
import KnuthBendix: alphabet, ordering
|
||||||
|
|
||||||
export MatrixGroups
|
export MatrixGroups
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
function _abelianize(
|
function _abelianize(
|
||||||
i::Integer,
|
i::Integer,
|
||||||
source::AutomorphismGroup{<:FreeGroup},
|
source::AutomorphismGroup{<:FreeGroup},
|
||||||
target::MatrixGroups.SpecialLinearGroup{N, T}) where {N, T}
|
target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T}
|
||||||
n = ngens(object(source))
|
n = ngens(object(source))
|
||||||
@assert n == N
|
@assert n == N
|
||||||
aut = alphabet(source)[i]
|
aut = alphabet(source)[i]
|
||||||
@ -10,10 +10,10 @@ function _abelianize(
|
|||||||
# Automorphisms act on the right which corresponds to action on
|
# Automorphisms act on the right which corresponds to action on
|
||||||
# the columns in the matrix case
|
# the columns in the matrix case
|
||||||
eij = MatrixGroups.ElementaryMatrix{N}(
|
eij = MatrixGroups.ElementaryMatrix{N}(
|
||||||
aut.j,
|
aut.j,
|
||||||
aut.i,
|
aut.i,
|
||||||
ifelse(aut.inv, -one(T), one(T))
|
ifelse(aut.inv, -one(T), one(T))
|
||||||
)
|
)
|
||||||
k = alphabet(target)[eij]
|
k = alphabet(target)[eij]
|
||||||
return word_type(target)([k])
|
return word_type(target)([k])
|
||||||
else
|
else
|
||||||
@ -24,7 +24,7 @@ end
|
|||||||
function _abelianize(
|
function _abelianize(
|
||||||
i::Integer,
|
i::Integer,
|
||||||
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
||||||
target::MatrixGroups.SpecialLinearGroup{N, T}) where {N, T}
|
target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T}
|
||||||
n = ngens(Groups.object(source))
|
n = ngens(Groups.object(source))
|
||||||
@assert n == N
|
@assert n == N
|
||||||
g = alphabet(source)[i].autFn_word
|
g = alphabet(source)[i].autFn_word
|
||||||
@ -39,8 +39,8 @@ end
|
|||||||
function Groups._abelianize(
|
function Groups._abelianize(
|
||||||
i::Integer,
|
i::Integer,
|
||||||
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
||||||
target::MatrixGroups.SymplecticGroup{N, T}
|
target::MatrixGroups.SymplecticGroup{N,T}
|
||||||
) where {N, T}
|
) where {N,T}
|
||||||
@assert iseven(N)
|
@assert iseven(N)
|
||||||
As = alphabet(source)
|
As = alphabet(source)
|
||||||
At = alphabet(target)
|
At = alphabet(target)
|
||||||
@ -53,7 +53,7 @@ function Groups._abelianize(
|
|||||||
ab = Groups.Homomorphism(Groups._abelianize, source, SlN, check=false)
|
ab = Groups.Homomorphism(Groups._abelianize, source, SlN, check=false)
|
||||||
|
|
||||||
matrix_spn_map = let S = gens(target)
|
matrix_spn_map = let S = gens(target)
|
||||||
Dict(MatrixGroups.matrix_repr(g)=> word(g) for g in union(S, inv.(S)))
|
Dict(MatrixGroups.matrix_repr(g) => word(g) for g in union(S, inv.(S)))
|
||||||
end
|
end
|
||||||
|
|
||||||
# renumeration:
|
# renumeration:
|
||||||
@ -63,7 +63,7 @@ function Groups._abelianize(
|
|||||||
p = [reverse(2:2:N); reverse(1:2:N)]
|
p = [reverse(2:2:N); reverse(1:2:N)]
|
||||||
|
|
||||||
g = source([i])
|
g = source([i])
|
||||||
Mg = MatrixGroups.matrix_repr(ab(g))[p,p]
|
Mg = MatrixGroups.matrix_repr(ab(g))[p, p]
|
||||||
|
|
||||||
return matrix_spn_map[Mg]
|
return matrix_spn_map[Mg]
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
function gersten_alphabet(n::Integer; commutative::Bool = true)
|
function gersten_alphabet(n::Integer; commutative::Bool=true)
|
||||||
indexing = [(i, j) for i in 1:n for j in 1:n if i ≠ j]
|
indexing = [(i, j) for i in 1:n for j in 1:n if i ≠ j]
|
||||||
S = [ϱ(i, j) for (i, j) in indexing]
|
S = [ϱ(i, j) for (i, j) in indexing]
|
||||||
|
|
||||||
@ -6,7 +6,7 @@ function gersten_alphabet(n::Integer; commutative::Bool = true)
|
|||||||
append!(S, [λ(i, j) for (i, j) in indexing])
|
append!(S, [λ(i, j) for (i, j) in indexing])
|
||||||
end
|
end
|
||||||
|
|
||||||
return Alphabet(S)
|
return Alphabet(mapreduce(x -> [x, inv(x)], union, S))
|
||||||
end
|
end
|
||||||
|
|
||||||
function _commutation_rule(
|
function _commutation_rule(
|
||||||
@ -41,12 +41,12 @@ function _hexagonal_rule(
|
|||||||
end
|
end
|
||||||
|
|
||||||
gersten_relations(n::Integer; commutative) =
|
gersten_relations(n::Integer; commutative) =
|
||||||
gersten_relations(Word{UInt8}, n, commutative = commutative)
|
gersten_relations(Word{UInt8}, n, commutative=commutative)
|
||||||
|
|
||||||
function gersten_relations(::Type{W}, n::Integer; commutative) where {W<:AbstractWord}
|
function gersten_relations(::Type{W}, n::Integer; commutative) where {W<:AbstractWord}
|
||||||
@assert n > 1 "Gersten relations are defined only for n>1, got n=$n"
|
@assert n > 1 "Gersten relations are defined only for n>1, got n=$n"
|
||||||
A = gersten_alphabet(n, commutative = commutative)
|
A = gersten_alphabet(n, commutative=commutative)
|
||||||
@assert length(A) <= KnuthBendix._max_alphabet_length(W) "Type $W can not represent words over alphabet with $(length(A)) letters."
|
@assert length(A) <= typemax(eltype(W)) "Type $W can not represent words over alphabet with $(length(A)) letters."
|
||||||
|
|
||||||
rels = Pair{W,W}[]
|
rels = Pair{W,W}[]
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ function gersten_relations(::Type{W}, n::Integer; commutative) where {W<:Abstrac
|
|||||||
if i ≠ j
|
if i ≠ j
|
||||||
push!(rels, _hexagonal_rule(W, A, ϱ(i, j), ϱ(j, i), λ(i, j), λ(j, i)))
|
push!(rels, _hexagonal_rule(W, A, ϱ(i, j), ϱ(j, i), λ(i, j), λ(j, i)))
|
||||||
w = W([A[ϱ(i, j)], A[ϱ(j, i)^-1], A[λ(i, j)]])
|
w = W([A[ϱ(i, j)], A[ϱ(j, i)^-1], A[λ(i, j)]])
|
||||||
push!(rels, w^2 => inv(A, w)^2)
|
push!(rels, w^2 => inv(w, A)^2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
struct SurfaceGroup{T, S, R} <: AbstractFPGroup
|
struct SurfaceGroup{T,S,RW} <: AbstractFPGroup
|
||||||
genus::Int
|
genus::Int
|
||||||
boundaries::Int
|
boundaries::Int
|
||||||
gens::Vector{T}
|
gens::Vector{T}
|
||||||
relations::Vector{<:Pair{S,S}}
|
relations::Vector{<:Pair{S,S}}
|
||||||
rws::R
|
rw::RW
|
||||||
end
|
end
|
||||||
|
|
||||||
include("symplectic_twists.jl")
|
include("symplectic_twists.jl")
|
||||||
@ -17,7 +17,7 @@ function Base.show(io::IO, S::SurfaceGroup)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurfaceGroup(genus::Integer, boundaries::Integer)
|
function SurfaceGroup(genus::Integer, boundaries::Integer, W=Word{Int16})
|
||||||
@assert genus > 1
|
@assert genus > 1
|
||||||
|
|
||||||
# The (confluent) rewriting systems comes from
|
# The (confluent) rewriting systems comes from
|
||||||
@ -30,15 +30,15 @@ function SurfaceGroup(genus::Integer, boundaries::Integer)
|
|||||||
|
|
||||||
ltrs = String[]
|
ltrs = String[]
|
||||||
for i in 1:genus
|
for i in 1:genus
|
||||||
subscript = join('₀'+d for d in reverse(digits(i)))
|
subscript = join('₀' + d for d in reverse(digits(i)))
|
||||||
append!(ltrs, ["A" * subscript, "a" * subscript, "B" * subscript, "b" * subscript])
|
append!(ltrs, ["A" * subscript, "a" * subscript, "B" * subscript, "b" * subscript])
|
||||||
end
|
end
|
||||||
Al = Alphabet(reverse!(ltrs))
|
Al = Alphabet(reverse!(ltrs))
|
||||||
|
|
||||||
for i in 1:genus
|
for i in 1:genus
|
||||||
subscript = join('₀'+d for d in reverse(digits(i)))
|
subscript = join('₀' + d for d in reverse(digits(i)))
|
||||||
KnuthBendix.set_inversion!(Al, "a" * subscript, "A" * subscript)
|
KnuthBendix.setinverse!(Al, "a" * subscript, "A" * subscript)
|
||||||
KnuthBendix.set_inversion!(Al, "b" * subscript, "B" * subscript)
|
KnuthBendix.setinverse!(Al, "b" * subscript, "B" * subscript)
|
||||||
end
|
end
|
||||||
|
|
||||||
if boundaries == 0
|
if boundaries == 0
|
||||||
@ -46,43 +46,44 @@ function SurfaceGroup(genus::Integer, boundaries::Integer)
|
|||||||
|
|
||||||
for i in reverse(1:genus)
|
for i in reverse(1:genus)
|
||||||
x = 4 * i
|
x = 4 * i
|
||||||
append!(word, [x, x-2, x-1, x-3])
|
append!(word, [x, x - 2, x - 1, x - 3])
|
||||||
end
|
end
|
||||||
comms = Word(word)
|
comms = W(word)
|
||||||
word_rels = [ comms => one(comms) ]
|
word_rels = [comms => one(comms)]
|
||||||
|
|
||||||
rws = KnuthBendix.RewritingSystem(word_rels, KnuthBendix.RecursivePathOrder(Al))
|
rws = let R = KnuthBendix.RewritingSystem(word_rels, KnuthBendix.Recursive(Al))
|
||||||
KnuthBendix.knuthbendix!(rws)
|
KnuthBendix.IndexAutomaton(KnuthBendix.knuthbendix(R))
|
||||||
|
end
|
||||||
elseif boundaries == 1
|
elseif boundaries == 1
|
||||||
S = typeof(one(Word(Int[])))
|
word_rels = Pair{W,W}[]
|
||||||
word_rels = Pair{S, S}[]
|
rws = let R = RewritingSystem(word_rels, KnuthBendix.LenLex(Al))
|
||||||
rws = RewritingSystem(word_rels, KnuthBendix.LenLex(Al))
|
KnuthBendix.IndexAutomaton(KnuthBendix.knuthbendix(R))
|
||||||
|
end
|
||||||
else
|
else
|
||||||
throw("Not Implemented")
|
throw("Not Implemented for MCG with $boundaryies boundary components")
|
||||||
end
|
end
|
||||||
|
|
||||||
F = FreeGroup(alphabet(rws))
|
F = FreeGroup(Al)
|
||||||
rels = [F(lhs)=>F(rhs) for (lhs,rhs) in word_rels]
|
rels = [F(lhs) => F(rhs) for (lhs, rhs) in word_rels]
|
||||||
|
|
||||||
return SurfaceGroup(genus, boundaries, KnuthBendix.letters(Al)[2:2:end], rels, rws)
|
return SurfaceGroup(genus, boundaries, [Al[i] for i in 2:2:length(Al)], rels, rws)
|
||||||
end
|
end
|
||||||
|
|
||||||
rewriting(S::SurfaceGroup) = S.rws
|
rewriting(S::SurfaceGroup) = S.rw
|
||||||
KnuthBendix.alphabet(S::SurfaceGroup) = alphabet(rewriting(S))
|
|
||||||
relations(S::SurfaceGroup) = S.relations
|
relations(S::SurfaceGroup) = S.relations
|
||||||
|
|
||||||
function symplectic_twists(π₁Σ::SurfaceGroup)
|
function symplectic_twists(π₁Σ::SurfaceGroup)
|
||||||
g = genus(π₁Σ)
|
g = genus(π₁Σ)
|
||||||
|
|
||||||
saut = SpecialAutomorphismGroup(FreeGroup(2g), maxrules=100)
|
saut = SpecialAutomorphismGroup(FreeGroup(2g), max_rules=1000)
|
||||||
|
|
||||||
Aij = [SymplecticMappingClass(saut, :A, i, j) for i in 1:g for j in 1:g if i≠j]
|
Aij = [SymplecticMappingClass(saut, :A, i, j) for i in 1:g for j in 1:g if i ≠ j]
|
||||||
|
|
||||||
Bij = [SymplecticMappingClass(saut, :B, i, j) for i in 1:g for j in 1:g if i≠j]
|
Bij = [SymplecticMappingClass(saut, :B, i, j) for i in 1:g for j in 1:g if i ≠ j]
|
||||||
|
|
||||||
mBij = [SymplecticMappingClass(saut, :B, i, j, minus=true) for i in 1:g for j in 1:g if i≠j]
|
mBij = [SymplecticMappingClass(saut, :B, i, j, minus=true) for i in 1:g for j in 1:g if i ≠ j]
|
||||||
|
|
||||||
Bii = [SymplecticMappingClass(saut, :B, i, i) for i in 1:g]
|
Bii = [SymplecticMappingClass(saut, :B, i, i) for i in 1:g]
|
||||||
|
|
||||||
mBii = [SymplecticMappingClass(saut, :B, i, i, minus=true) for i in 1:g]
|
mBii = [SymplecticMappingClass(saut, :B, i, i, minus=true) for i in 1:g]
|
||||||
|
|
||||||
@ -98,6 +99,6 @@ function AutomorphismGroup(π₁Σ::SurfaceGroup; kwargs...)
|
|||||||
# this is to fix the definitions of symplectic twists:
|
# this is to fix the definitions of symplectic twists:
|
||||||
# with i->gens(π₁Σ, i) the corresponding automorphisms return
|
# with i->gens(π₁Σ, i) the corresponding automorphisms return
|
||||||
# reversed words
|
# reversed words
|
||||||
domain = ntuple(i->inv(gens(π₁Σ, i)), 2genus(π₁Σ))
|
domain = ntuple(i -> inv(gens(π₁Σ, i)), 2genus(π₁Σ))
|
||||||
return AutomorphismGroup(π₁Σ, S, A, domain)
|
return AutomorphismGroup(π₁Σ, S, A, domain)
|
||||||
end
|
end
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
include("transvections.jl")
|
include("transvections.jl")
|
||||||
include("gersten_relations.jl")
|
include("gersten_relations.jl")
|
||||||
|
|
||||||
function SpecialAutomorphismGroup(F::FreeGroup; ordering = KnuthBendix.LenLex, kwargs...)
|
function SpecialAutomorphismGroup(F::FreeGroup; ordering=KnuthBendix.LenLex, kwargs...)
|
||||||
|
|
||||||
n = length(alphabet(F)) ÷ 2
|
n = length(alphabet(F)) ÷ 2
|
||||||
A, rels = gersten_relations(n, commutative = false)
|
A, rels = gersten_relations(n, commutative=false)
|
||||||
S = KnuthBendix.letters(A)[1:2(n^2-n)]
|
S = [A[i] for i in 1:2:length(A)]
|
||||||
|
|
||||||
maxrules = 1000*n
|
max_rules = 1000 * n
|
||||||
|
|
||||||
rws = KnuthBendix.RewritingSystem(rels, ordering(A))
|
rws = Logging.with_logger(Logging.NullLogger()) do
|
||||||
Logging.with_logger(Logging.NullLogger()) do
|
rws = KnuthBendix.RewritingSystem(rels, ordering(A))
|
||||||
# the rws is not confluent, let's suppress warning about it
|
# the rws is not confluent, let's suppress warning about it
|
||||||
KnuthBendix.knuthbendix!(rws; maxrules=maxrules, kwargs...)
|
KnuthBendix.knuthbendix(rws, KnuthBendix.Settings(; max_rules=max_rules, kwargs...))
|
||||||
end
|
end
|
||||||
return AutomorphismGroup(F, S, rws, ntuple(i -> gens(F, i), n))
|
|
||||||
end
|
|
||||||
|
|
||||||
KnuthBendix.alphabet(G::AutomorphismGroup{<:FreeGroup}) = alphabet(rewriting(G))
|
idxA = KnuthBendix.IndexAutomaton(rws)
|
||||||
|
return AutomorphismGroup(F, S, idxA, ntuple(i -> gens(F, i), n))
|
||||||
|
end
|
||||||
|
|
||||||
function relations(G::AutomorphismGroup{<:FreeGroup})
|
function relations(G::AutomorphismGroup{<:FreeGroup})
|
||||||
n = length(alphabet(object(G))) ÷ 2
|
n = length(alphabet(object(G))) ÷ 2
|
||||||
return last(gersten_relations(n, commutative = false))
|
return last(gersten_relations(n, commutative=false))
|
||||||
end
|
end
|
||||||
|
@ -25,7 +25,7 @@ function Te_diagonal(λ::Groups.ΡΛ, ϱ::Groups.ΡΛ, i::Integer)
|
|||||||
|
|
||||||
if i == n
|
if i == n
|
||||||
τ = rotation_element(λ, ϱ)
|
τ = rotation_element(λ, ϱ)
|
||||||
return inv(A, τ) * Te_diagonal(λ, ϱ, 1) * τ
|
return inv(τ, A) * Te_diagonal(λ, ϱ, 1) * τ
|
||||||
end
|
end
|
||||||
|
|
||||||
@assert 1 <= i < n
|
@assert 1 <= i < n
|
||||||
@ -37,32 +37,32 @@ function Te_diagonal(λ::Groups.ΡΛ, ϱ::Groups.ΡΛ, i::Integer)
|
|||||||
|
|
||||||
g = one(Word(Int[]))
|
g = one(Word(Int[]))
|
||||||
g *= λ[NJ, NI] # β ↦ α*β
|
g *= λ[NJ, NI] # β ↦ α*β
|
||||||
g *= λ[NI, I] * inv(A, ϱ[NI, J]) # α ↦ a*α*b^-1
|
g *= λ[NI, I] * inv(ϱ[NI, J], A) # α ↦ a*α*b^-1
|
||||||
g *= inv(A, λ[NJ, NI]) # β ↦ b*α^-1*a^-1*α*β
|
g *= inv(λ[NJ, NI], A) # β ↦ b*α^-1*a^-1*α*β
|
||||||
g *= λ[J, NI] * inv(A, λ[J, I]) # b ↦ α
|
g *= λ[J, NI] * inv(λ[J, I], A) # b ↦ α
|
||||||
g *= inv(A, λ[J, NI]) # b ↦ b*α^-1*a^-1*α
|
g *= inv(λ[J, NI], A) # b ↦ b*α^-1*a^-1*α
|
||||||
g *= inv(A, ϱ[J, NI]) * ϱ[J, I] # b ↦ b*α^-1*a^-1*α*b*α^-1
|
g *= inv(ϱ[J, NI], A) * ϱ[J, I] # b ↦ b*α^-1*a^-1*α*b*α^-1
|
||||||
g *= ϱ[J, NI] # b ↦ b*α^-1*a^-1*α*b*α^-1*a*α*b^-1
|
g *= ϱ[J, NI] # b ↦ b*α^-1*a^-1*α*b*α^-1*a*α*b^-1
|
||||||
|
|
||||||
return g
|
return g
|
||||||
end
|
end
|
||||||
|
|
||||||
function Te_lantern(A::Alphabet, b₀::T, a₁::T, a₂::T, a₃::T, a₄::T, a₅::T) where {T}
|
function Te_lantern(A::Alphabet, b₀::T, a₁::T, a₂::T, a₃::T, a₄::T, a₅::T) where {T}
|
||||||
a₀ = (a₁ * a₂ * a₃)^4 * inv(A, b₀)
|
a₀ = (a₁ * a₂ * a₃)^4 * inv(b₀, A)
|
||||||
X = a₄ * a₅ * a₃ * a₄ # from Primer
|
X = a₄ * a₅ * a₃ * a₄ # from Primer
|
||||||
b₁ = inv(A, X) * a₀ * X # from Primer
|
b₁ = inv(X, A) * a₀ * X # from Primer
|
||||||
Y = a₂ * a₃ * a₁ * a₂
|
Y = a₂ * a₃ * a₁ * a₂
|
||||||
return inv(A, Y) * b₁ * Y # b₂ from Primer
|
return inv(Y, A) * b₁ * Y # b₂ from Primer
|
||||||
end
|
end
|
||||||
|
|
||||||
function Ta(λ::Groups.ΡΛ, i::Integer)
|
function Ta(λ::Groups.ΡΛ, i::Integer)
|
||||||
@assert λ.id == :λ;
|
@assert λ.id == :λ
|
||||||
return λ[mod1(λ.N-2i+1, λ.N), mod1(λ.N-2i+2, λ.N)]
|
return λ[mod1(λ.N - 2i + 1, λ.N), mod1(λ.N - 2i + 2, λ.N)]
|
||||||
end
|
end
|
||||||
|
|
||||||
function Tα(λ::Groups.ΡΛ, i::Integer)
|
function Tα(λ::Groups.ΡΛ, i::Integer)
|
||||||
@assert λ.id == :λ;
|
@assert λ.id == :λ
|
||||||
return inv(λ.A, λ[mod1(λ.N-2i+2, λ.N), mod1(λ.N-2i+1, λ.N)])
|
return inv(λ[mod1(λ.N - 2i + 2, λ.N), mod1(λ.N - 2i + 1, λ.N)], λ.A)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Te(λ::ΡΛ, ϱ::ΡΛ, i, j)
|
function Te(λ::ΡΛ, ϱ::ΡΛ, i, j)
|
||||||
@ -73,7 +73,7 @@ function Te(λ::ΡΛ, ϱ::ΡΛ, i, j)
|
|||||||
@assert λ.id == :λ && ϱ.id == :ϱ
|
@assert λ.id == :λ && ϱ.id == :ϱ
|
||||||
|
|
||||||
@assert iseven(λ.N)
|
@assert iseven(λ.N)
|
||||||
genus = λ.N÷2
|
genus = λ.N ÷ 2
|
||||||
i = mod1(i, genus)
|
i = mod1(i, genus)
|
||||||
j = mod1(j, genus)
|
j = mod1(j, genus)
|
||||||
|
|
||||||
@ -85,16 +85,16 @@ function Te(λ::ΡΛ, ϱ::ΡΛ, i, j)
|
|||||||
if mod(j - (i + 1), genus) == 0
|
if mod(j - (i + 1), genus) == 0
|
||||||
return Te_diagonal(λ, ϱ, i)
|
return Te_diagonal(λ, ϱ, i)
|
||||||
else
|
else
|
||||||
return inv(A, Te_lantern(
|
return inv(Te_lantern(
|
||||||
A,
|
A,
|
||||||
# Our notation: # Primer notation:
|
# Our notation: # Primer notation:
|
||||||
inv(A, Ta(λ, i + 1)), # b₀
|
inv(Ta(λ, i + 1), A), # b₀
|
||||||
inv(A, Ta(λ, i)), # a₁
|
inv(Ta(λ, i), A), # a₁
|
||||||
inv(A, Tα(λ, i)), # a₂
|
inv(Tα(λ, i), A), # a₂
|
||||||
inv(A, Te_diagonal(λ, ϱ, i)), # a₃
|
inv(Te_diagonal(λ, ϱ, i), A), # a₃
|
||||||
inv(A, Tα(λ, i + 1)), # a₄
|
inv(Tα(λ, i + 1), A), # a₄
|
||||||
inv(A, Te(λ, ϱ, i + 1, j)), # a₅
|
inv(Te(λ, ϱ, i + 1, j), A), # a₅
|
||||||
))
|
), A)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -118,29 +118,29 @@ end
|
|||||||
|
|
||||||
function rotation_element(λ::ΡΛ, ϱ::ΡΛ)
|
function rotation_element(λ::ΡΛ, ϱ::ΡΛ)
|
||||||
@assert iseven(λ.N)
|
@assert iseven(λ.N)
|
||||||
genus = λ.N÷2
|
genus = λ.N ÷ 2
|
||||||
A = λ.A
|
A = λ.A
|
||||||
|
|
||||||
halftwists = map(1:genus-1) do i
|
halftwists = map(1:genus-1) do i
|
||||||
j = i + 1
|
j = i + 1
|
||||||
x = Ta(λ, j) * inv(A, Ta(λ, i)) * Tα(λ, j) * Te_diagonal(λ, ϱ, i)
|
x = Ta(λ, j) * inv(Ta(λ, i), A) * Tα(λ, j) * Te_diagonal(λ, ϱ, i)
|
||||||
δ = x * Tα(λ, i) * inv(A, x)
|
δ = x * Tα(λ, i) * inv(x, A)
|
||||||
c =
|
c =
|
||||||
inv(A, Ta(λ, j)) *
|
inv(Ta(λ, j), A) *
|
||||||
Te(λ, ϱ, i, j) *
|
Te(λ, ϱ, i, j) *
|
||||||
Tα(λ, i)^2 *
|
Tα(λ, i)^2 *
|
||||||
inv(A, δ) *
|
inv(δ, A) *
|
||||||
inv(A, Ta(λ, j)) *
|
inv(Ta(λ, j), A) *
|
||||||
Ta(λ, i) *
|
Ta(λ, i) *
|
||||||
δ
|
δ
|
||||||
z =
|
z =
|
||||||
Te_diagonal(λ, ϱ, i) *
|
Te_diagonal(λ, ϱ, i) *
|
||||||
inv(A, Ta(λ, i)) *
|
inv(Ta(λ, i), A) *
|
||||||
Tα(λ, i) *
|
Tα(λ, i) *
|
||||||
Ta(λ, i) *
|
Ta(λ, i) *
|
||||||
inv(A, Te_diagonal(λ, ϱ, i))
|
inv(Te_diagonal(λ, ϱ, i), A)
|
||||||
|
|
||||||
Ta(λ, i) * inv(A, Ta(λ, j) * Tα(λ, j))^6 * (Ta(λ, j) * Tα(λ, j) * z)^4 * c
|
Ta(λ, i) * inv(Ta(λ, j) * Tα(λ, j), A)^6 * (Ta(λ, j) * Tα(λ, j) * z)^4 * c
|
||||||
end
|
end
|
||||||
|
|
||||||
τ = (Ta(λ, 1) * Tα(λ, 1))^6 * prod(halftwists)
|
τ = (Ta(λ, 1) * Tα(λ, 1))^6 * prod(halftwists)
|
||||||
@ -168,7 +168,7 @@ function mcg_twists(G::AutomorphismGroup{<:FreeGroup})
|
|||||||
return Tas, Tαs, Tes
|
return Tas, Tαs, Tes
|
||||||
end
|
end
|
||||||
|
|
||||||
struct SymplecticMappingClass{T, F} <: GSymbol
|
struct SymplecticMappingClass{T,F} <: GSymbol
|
||||||
id::Symbol # :A, :B
|
id::Symbol # :A, :B
|
||||||
i::UInt
|
i::UInt
|
||||||
j::UInt
|
j::UInt
|
||||||
@ -187,13 +187,13 @@ function SymplecticMappingClass(
|
|||||||
id::Symbol,
|
id::Symbol,
|
||||||
i::Integer,
|
i::Integer,
|
||||||
j::Integer;
|
j::Integer;
|
||||||
minus = false,
|
minus=false,
|
||||||
inverse = false,
|
inverse=false
|
||||||
)
|
)
|
||||||
@assert i > 0 && j > 0
|
@assert i > 0 && j > 0
|
||||||
id === :A && @assert i ≠ j
|
id === :A && @assert i ≠ j
|
||||||
@assert iseven(ngens(object(sautFn)))
|
@assert iseven(ngens(object(sautFn)))
|
||||||
genus = ngens(object(sautFn))÷2
|
genus = ngens(object(sautFn)) ÷ 2
|
||||||
|
|
||||||
A = alphabet(sautFn)
|
A = alphabet(sautFn)
|
||||||
λ = ΡΛ(:λ, A, 2genus)
|
λ = ΡΛ(:λ, A, 2genus)
|
||||||
@ -201,24 +201,24 @@ function SymplecticMappingClass(
|
|||||||
|
|
||||||
w = if id === :A
|
w = if id === :A
|
||||||
Te(λ, ϱ, i, j) *
|
Te(λ, ϱ, i, j) *
|
||||||
inv(A, Ta(λ, i)) *
|
inv(Ta(λ, i), A) *
|
||||||
Tα(λ, i) *
|
Tα(λ, i) *
|
||||||
Ta(λ, i) *
|
Ta(λ, i) *
|
||||||
inv(A, Te(λ, ϱ, i, j)) *
|
inv(Te(λ, ϱ, i, j), A) *
|
||||||
inv(A, Tα(λ, i)) *
|
inv(Tα(λ, i), A) *
|
||||||
inv(A, Ta(λ, j))
|
inv(Ta(λ, j), A)
|
||||||
elseif id === :B
|
elseif id === :B
|
||||||
if !minus
|
if !minus
|
||||||
if i ≠ j
|
if i ≠ j
|
||||||
x = Ta(λ, j) * inv(A, Ta(λ, i)) * Tα(λ, j) * Te(λ, ϱ, i, j)
|
x = Ta(λ, j) * inv(Ta(λ, i), A) * Tα(λ, j) * Te(λ, ϱ, i, j)
|
||||||
δ = x * Tα(λ, i) * inv(A, x)
|
δ = x * Tα(λ, i) * inv(x, A)
|
||||||
Tα(λ, i) * Tα(λ, j) * inv(A, δ)
|
Tα(λ, i) * Tα(λ, j) * inv(δ, A)
|
||||||
else
|
else
|
||||||
inv(A, Tα(λ, i))
|
inv(Tα(λ, i), A)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if i ≠ j
|
if i ≠ j
|
||||||
Ta(λ, i) * Ta(λ, j) * inv(A, Te(λ, ϱ, i, j))
|
Ta(λ, i) * Ta(λ, j) * inv(Te(λ, ϱ, i, j), A)
|
||||||
else
|
else
|
||||||
Ta(λ, i)
|
Ta(λ, i)
|
||||||
end
|
end
|
||||||
@ -241,7 +241,7 @@ end
|
|||||||
|
|
||||||
function Base.show(io::IO, smc::SymplecticMappingClass)
|
function Base.show(io::IO, smc::SymplecticMappingClass)
|
||||||
smc.minus && print(io, 'm')
|
smc.minus && print(io, 'm')
|
||||||
if smc.i < 10 && smc.j < 10
|
if smc.i < 10 && smc.j < 10
|
||||||
print(io, smc.id, subscriptify(smc.i), subscriptify(smc.j))
|
print(io, smc.id, subscriptify(smc.i), subscriptify(smc.j))
|
||||||
else
|
else
|
||||||
print(io, smc.id, subscriptify(smc.i), ".", subscriptify(smc.j))
|
print(io, smc.id, subscriptify(smc.i), ".", subscriptify(smc.j))
|
||||||
|
@ -4,7 +4,7 @@ struct Transvection <: GSymbol
|
|||||||
j::UInt16
|
j::UInt16
|
||||||
inv::Bool
|
inv::Bool
|
||||||
|
|
||||||
function Transvection(id::Symbol, i::Integer, j::Integer, inv = false)
|
function Transvection(id::Symbol, i::Integer, j::Integer, inv=false)
|
||||||
@assert id in (:ϱ, :λ)
|
@assert id in (:ϱ, :λ)
|
||||||
return new(id, i, j, inv)
|
return new(id, i, j, inv)
|
||||||
end
|
end
|
||||||
@ -33,7 +33,7 @@ Base.hash(t::Transvection, h::UInt) = hash(hash(t.id, hash(t.i)), hash(t.j, hash
|
|||||||
Base.@propagate_inbounds @inline function evaluate!(
|
Base.@propagate_inbounds @inline function evaluate!(
|
||||||
v::NTuple{T,N},
|
v::NTuple{T,N},
|
||||||
t::Transvection,
|
t::Transvection,
|
||||||
tmp = one(first(v)),
|
tmp=one(first(v)),
|
||||||
) where {T,N}
|
) where {T,N}
|
||||||
i, j = t.i, t.j
|
i, j = t.i, t.j
|
||||||
@assert 1 ≤ i ≤ length(v) && 1 ≤ j ≤ length(v)
|
@assert 1 ≤ i ≤ length(v) && 1 ≤ j ≤ length(v)
|
||||||
@ -45,9 +45,9 @@ Base.@propagate_inbounds @inline function evaluate!(
|
|||||||
if !t.inv
|
if !t.inv
|
||||||
append!(word(v[i]), word(v[j]))
|
append!(word(v[i]), word(v[j]))
|
||||||
else
|
else
|
||||||
# append!(word(v[i]), inv(A, word(v[j])))
|
# append!(word(v[i]), inv(word(v[j]), A))
|
||||||
for l in Iterators.reverse(word(v[j]))
|
for l in Iterators.reverse(word(v[j]))
|
||||||
push!(word(v[i]), inv(A, l))
|
push!(word(v[i]), inv(l, A))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else # if t.id === :λ
|
else # if t.id === :λ
|
||||||
@ -57,9 +57,9 @@ Base.@propagate_inbounds @inline function evaluate!(
|
|||||||
pushfirst!(word(v[i]), l)
|
pushfirst!(word(v[i]), l)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# prepend!(word(v[i]), inv(A, word(v[j])))
|
# prepend!(word(v[i]), inv(word(v[j]), A))
|
||||||
for l in word(v[j])
|
for l in word(v[j])
|
||||||
pushfirst!(word(v[i]), inv(A, l))
|
pushfirst!(word(v[i]), inv(l, A))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -92,4 +92,4 @@ Base.inv(p::PermRightAut) = PermRightAut(invperm(p.perm))
|
|||||||
Base.:(==)(p::PermRightAut, q::PermRightAut) = p.perm == q.perm
|
Base.:(==)(p::PermRightAut, q::PermRightAut) = p.perm == q.perm
|
||||||
Base.hash(p::PermRightAut, h::UInt) = hash(p.perm, hash(PermRightAut, h))
|
Base.hash(p::PermRightAut, h::UInt) = hash(p.perm, hash(PermRightAut, h))
|
||||||
|
|
||||||
evaluate!(v::NTuple{T,N}, p::PermRightAut, tmp = nothing) where {T,N} = v[p.perm]
|
evaluate!(v::NTuple{T,N}, p::PermRightAut, tmp=nothing) where {T,N} = v[p.perm]
|
||||||
|
@ -4,15 +4,15 @@ function KnuthBendix.Alphabet(S::AbstractVector{<:GSymbol})
|
|||||||
return Alphabet(S, inversions)
|
return Alphabet(S, inversions)
|
||||||
end
|
end
|
||||||
|
|
||||||
struct AutomorphismGroup{G<:Group,T,R,S} <: AbstractFPGroup
|
struct AutomorphismGroup{G<:Group,T,RW,S} <: AbstractFPGroup
|
||||||
group::G
|
group::G
|
||||||
gens::Vector{T}
|
gens::Vector{T}
|
||||||
rws::R
|
rw::RW
|
||||||
domain::S
|
domain::S
|
||||||
end
|
end
|
||||||
|
|
||||||
object(G::AutomorphismGroup) = G.group
|
object(G::AutomorphismGroup) = G.group
|
||||||
rewriting(G::AutomorphismGroup) = G.rws
|
rewriting(G::AutomorphismGroup) = G.rw
|
||||||
|
|
||||||
function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup})
|
function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup})
|
||||||
imf = evaluate(f)
|
imf = evaluate(f)
|
||||||
@ -104,8 +104,8 @@ evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f),
|
|||||||
function evaluate!(
|
function evaluate!(
|
||||||
t::NTuple{N,T},
|
t::NTuple{N,T},
|
||||||
f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}},
|
f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}},
|
||||||
tmp = one(first(t)),
|
tmp=one(first(t)),
|
||||||
) where {N, T<:FPGroupElement}
|
) where {N,T<:FPGroupElement}
|
||||||
A = alphabet(f)
|
A = alphabet(f)
|
||||||
for idx in word(f)
|
for idx in word(f)
|
||||||
t = @inbounds evaluate!(t, A[idx], tmp)::NTuple{N,T}
|
t = @inbounds evaluate!(t, A[idx], tmp)::NTuple{N,T}
|
||||||
@ -113,12 +113,12 @@ function evaluate!(
|
|||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
evaluate!(t::NTuple{N, T}, s::GSymbol, tmp=nothing) where {N, T} = throw("you need to implement `evaluate!(::$(typeof(t)), ::$(typeof(s)), ::Alphabet, tmp=one(first(t)))`")
|
evaluate!(t::NTuple{N,T}, s::GSymbol, tmp=nothing) where {N,T} = throw("you need to implement `evaluate!(::$(typeof(t)), ::$(typeof(s)), ::Alphabet, tmp=one(first(t)))`")
|
||||||
|
|
||||||
# forward evaluate by substitution
|
# forward evaluate by substitution
|
||||||
|
|
||||||
struct LettersMap{T, A}
|
struct LettersMap{T,A}
|
||||||
indices_map::Dict{Int, T}
|
indices_map::Dict{Int,T}
|
||||||
A::A
|
A::A
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -144,11 +144,11 @@ end
|
|||||||
|
|
||||||
function Base.getindex(lm::LettersMap, i::Integer)
|
function Base.getindex(lm::LettersMap, i::Integer)
|
||||||
# here i is an index of an alphabet
|
# here i is an index of an alphabet
|
||||||
@boundscheck 1 ≤ i ≤ length(KnuthBendix.letters(lm.A))
|
@boundscheck 1 ≤ i ≤ length(lm.A)
|
||||||
|
|
||||||
if !haskey(lm.indices_map, i)
|
if !haskey(lm.indices_map, i)
|
||||||
img = if haskey(lm.indices_map, inv(lm.A, i))
|
img = if haskey(lm.indices_map, inv(i, lm.A))
|
||||||
inv(lm.A, lm.indices_map[inv(lm.A, i)])
|
inv(lm.indices_map[inv(i, lm.A)], lm.A)
|
||||||
else
|
else
|
||||||
@warn "LetterMap: neither $i nor its inverse has assigned value"
|
@warn "LetterMap: neither $i nor its inverse has assigned value"
|
||||||
one(valtype(lm.indices_map))
|
one(valtype(lm.indices_map))
|
||||||
@ -193,7 +193,7 @@ function generated_evaluate(a::FPGroupElement{<:AutomorphismGroup})
|
|||||||
push!(args[idx].args, :(d[$k]))
|
push!(args[idx].args, :(d[$k]))
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
k = findfirst(==(inv(A, l)), first_ltrs)
|
k = findfirst(==(inv(l, A)), first_ltrs)
|
||||||
if k !== nothing
|
if k !== nothing
|
||||||
push!(args[idx].args, :(inv(d[$k])))
|
push!(args[idx].args, :(inv(d[$k])))
|
||||||
continue
|
continue
|
||||||
@ -201,13 +201,14 @@ function generated_evaluate(a::FPGroupElement{<:AutomorphismGroup})
|
|||||||
throw("Letter $l doesn't seem to be mapped anywhere!")
|
throw("Letter $l doesn't seem to be mapped anywhere!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
locals = Dict{Expr, Symbol}()
|
locals = Dict{Expr,Symbol}()
|
||||||
locals_counter = 0
|
locals_counter = 0
|
||||||
for (i,v) in enumerate(args)
|
for (i, v) in enumerate(args)
|
||||||
@assert length(v.args) >= 2
|
@assert length(v.args) >= 2
|
||||||
if length(v.args) > 2
|
if length(v.args) > 2
|
||||||
for (j, a) in pairs(v.args)
|
for (j, a) in pairs(v.args)
|
||||||
if a isa Expr && a.head == :call "$a"
|
if a isa Expr && a.head == :call
|
||||||
|
"$a"
|
||||||
@assert a.args[1] == :inv
|
@assert a.args[1] == :inv
|
||||||
if !(a in keys(locals))
|
if !(a in keys(locals))
|
||||||
locals[a] = Symbol("var_#$locals_counter")
|
locals[a] = Symbol("var_#$locals_counter")
|
||||||
@ -222,7 +223,7 @@ function generated_evaluate(a::FPGroupElement{<:AutomorphismGroup})
|
|||||||
end
|
end
|
||||||
|
|
||||||
q = quote
|
q = quote
|
||||||
$([:(local $v = $k) for (k,v) in locals]...)
|
$([:(local $v = $k) for (k, v) in locals]...)
|
||||||
end
|
end
|
||||||
|
|
||||||
# return args, locals
|
# return args, locals
|
||||||
|
@ -30,7 +30,7 @@ function Base.iterate(G::DirectPower)
|
|||||||
res = iterate(itr)
|
res = iterate(itr)
|
||||||
@assert res !== nothing
|
@assert res !== nothing
|
||||||
elt = DirectPowerElement(first(res), G)
|
elt = DirectPowerElement(first(res), G)
|
||||||
return elt, (iterator = itr, state = last(res))
|
return elt, (iterator=itr, state=last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.iterate(G::DirectPower, state)
|
function Base.iterate(G::DirectPower, state)
|
||||||
@ -38,7 +38,7 @@ function Base.iterate(G::DirectPower, state)
|
|||||||
res = iterate(itr, st)
|
res = iterate(itr, st)
|
||||||
res === nothing && return nothing
|
res === nothing && return nothing
|
||||||
elt = DirectPowerElement(first(res), G)
|
elt = DirectPowerElement(first(res), G)
|
||||||
return elt, (iterator = itr, state = last(res))
|
return elt, (iterator=itr, state=last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N}
|
function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N}
|
||||||
@ -52,7 +52,7 @@ Base.size(G::DirectPower) = ntuple(_ -> length(G.group), _nfold(G))
|
|||||||
GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} =
|
GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} =
|
||||||
convert(I, order(I, G.group)^_nfold(G))
|
convert(I, order(I, G.group)^_nfold(G))
|
||||||
|
|
||||||
GroupsCore.ngens(G::DirectPower) = _nfold(G)*ngens(G.group)
|
GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group)
|
||||||
|
|
||||||
function GroupsCore.gens(G::DirectPower, i::Integer)
|
function GroupsCore.gens(G::DirectPower, i::Integer)
|
||||||
k = ngens(G.group)
|
k = ngens(G.group)
|
||||||
@ -66,7 +66,7 @@ end
|
|||||||
function GroupsCore.gens(G::DirectPower)
|
function GroupsCore.gens(G::DirectPower)
|
||||||
N = _nfold(G)
|
N = _nfold(G)
|
||||||
S = gens(G.group)
|
S = gens(G.group)
|
||||||
tups = [ntuple(j->(i == j ? s : one(s)), N) for i in 1:N for s in S]
|
tups = [ntuple(j -> (i == j ? s : one(s)), N) for i in 1:N for s in S]
|
||||||
|
|
||||||
return [DirectPowerElement(elts, G) for elts in tups]
|
return [DirectPowerElement(elts, G) for elts in tups]
|
||||||
end
|
end
|
||||||
@ -99,7 +99,7 @@ function Base.:(*)(g::DirectPowerElement, h::DirectPowerElement)
|
|||||||
end
|
end
|
||||||
|
|
||||||
GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} =
|
GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} =
|
||||||
convert(I, reduce(lcm, (order(I, h) for h in g.elts), init = one(I)))
|
convert(I, reduce(lcm, (order(I, h) for h in g.elts), init=one(I)))
|
||||||
|
|
||||||
Base.isone(g::DirectPowerElement) = all(isone, g.elts)
|
Base.isone(g::DirectPowerElement) = all(isone, g.elts)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ function Base.iterate(G::DirectProduct)
|
|||||||
res = iterate(itr)
|
res = iterate(itr)
|
||||||
@assert res !== nothing
|
@assert res !== nothing
|
||||||
elt = DirectProductElement(first(res), G)
|
elt = DirectProductElement(first(res), G)
|
||||||
return elt, (iterator = itr, state = last(res))
|
return elt, (iterator=itr, state=last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.iterate(G::DirectProduct, state)
|
function Base.iterate(G::DirectProduct, state)
|
||||||
@ -33,7 +33,7 @@ function Base.iterate(G::DirectProduct, state)
|
|||||||
res = iterate(itr, st)
|
res = iterate(itr, st)
|
||||||
res === nothing && return nothing
|
res === nothing && return nothing
|
||||||
elt = DirectProductElement(first(res), G)
|
elt = DirectProductElement(first(res), G)
|
||||||
return elt, (iterator = itr, state = last(res))
|
return elt, (iterator=itr, state=last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.IteratorSize(::Type{<:DirectProduct{Gt,Ht}}) where {Gt,Ht}
|
function Base.IteratorSize(::Type{<:DirectProduct{Gt,Ht}}) where {Gt,Ht}
|
||||||
|
@ -52,7 +52,7 @@ function Base.iterate(G::WreathProduct)
|
|||||||
res = iterate(itr)
|
res = iterate(itr)
|
||||||
@assert res !== nothing
|
@assert res !== nothing
|
||||||
elt = WreathProductElement(first(res)..., G)
|
elt = WreathProductElement(first(res)..., G)
|
||||||
return elt, (iterator = itr, state = last(res))
|
return elt, (iterator=itr, state=last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.iterate(G::WreathProduct, state)
|
function Base.iterate(G::WreathProduct, state)
|
||||||
@ -60,7 +60,7 @@ function Base.iterate(G::WreathProduct, state)
|
|||||||
res = iterate(itr, st)
|
res = iterate(itr, st)
|
||||||
res === nothing && return nothing
|
res === nothing && return nothing
|
||||||
elt = WreathProductElement(first(res)..., G)
|
elt = WreathProductElement(first(res)..., G)
|
||||||
return elt, (iterator = itr, state = last(res))
|
return elt, (iterator=itr, state=last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.IteratorSize(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr}
|
function Base.IteratorSize(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr}
|
||||||
|
@ -58,8 +58,8 @@ true
|
|||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
struct Homomorphism{Gr1, Gr2, I, W}
|
struct Homomorphism{Gr1,Gr2,I,W}
|
||||||
gens_images::Dict{I, W}
|
gens_images::Dict{I,W}
|
||||||
source::Gr1
|
source::Gr1
|
||||||
target::Gr2
|
target::Gr2
|
||||||
|
|
||||||
@ -70,11 +70,11 @@ struct Homomorphism{Gr1, Gr2, I, W}
|
|||||||
check=true
|
check=true
|
||||||
)
|
)
|
||||||
A = alphabet(source)
|
A = alphabet(source)
|
||||||
dct = Dict(i=>convert(word_type(target), f(i, source, target))
|
dct = Dict(i => convert(word_type(target), f(i, source, target))
|
||||||
for i in 1:length(A))
|
for i in 1:length(A))
|
||||||
I = eltype(word_type(source))
|
I = eltype(word_type(source))
|
||||||
W = word_type(target)
|
W = word_type(target)
|
||||||
hom = new{typeof(source), typeof(target), I, W}(dct, source, target)
|
hom = new{typeof(source),typeof(target),I,W}(dct, source, target)
|
||||||
|
|
||||||
if check
|
if check
|
||||||
@assert hom(one(source)) == one(target)
|
@assert hom(one(source)) == one(target)
|
||||||
@ -83,12 +83,12 @@ struct Homomorphism{Gr1, Gr2, I, W}
|
|||||||
@assert hom(x^-1) == hom(x)^-1
|
@assert hom(x^-1) == hom(x)^-1
|
||||||
|
|
||||||
for y in gens(source)
|
for y in gens(source)
|
||||||
@assert hom(x*y) == hom(x)*hom(y)
|
@assert hom(x * y) == hom(x) * hom(y)
|
||||||
@assert hom(x*y)^-1 == hom(y^-1)*hom(x^-1)
|
@assert hom(x * y)^-1 == hom(y^-1) * hom(x^-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for (lhs, rhs) in relations(source)
|
for (lhs, rhs) in relations(source)
|
||||||
relator = lhs*inv(alphabet(source), rhs)
|
relator = lhs * inv(rhs, alphabet(source))
|
||||||
im_r = hom.target(hom(relator))
|
im_r = hom.target(hom(relator))
|
||||||
@assert isone(im_r) "Map does not define a homomorphism: h($relator) = $(im_r) ≠ $(one(target))."
|
@assert isone(im_r) "Map does not define a homomorphism: h($relator) = $(im_r) ≠ $(one(target))."
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
mutable struct FPGroupIter{S, T, GEl}
|
mutable struct FPGroupIter{S,T,GEl}
|
||||||
seen::S
|
seen::S
|
||||||
seen_iter_state::T
|
seen_iter_state::T
|
||||||
current::GEl
|
current::GEl
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
include("eltary_matrices.jl")
|
include("eltary_matrices.jl")
|
||||||
|
|
||||||
struct SpecialLinearGroup{N, T, R, A, S} <: MatrixGroup{N,T}
|
struct SpecialLinearGroup{N,T,R,A,S} <: MatrixGroup{N,T}
|
||||||
base_ring::R
|
base_ring::R
|
||||||
alphabet::A
|
alphabet::A
|
||||||
gens::S
|
gens::S
|
||||||
|
|
||||||
function SpecialLinearGroup{N}(base_ring) where N
|
function SpecialLinearGroup{N}(base_ring) where {N}
|
||||||
S = [ElementaryMatrix{N}(i,j, one(base_ring)) for i in 1:N for j in 1:N if i≠j]
|
S = [ElementaryMatrix{N}(i, j, one(base_ring)) for i in 1:N for j in 1:N if i ≠ j]
|
||||||
alphabet = Alphabet(S)
|
alphabet = Alphabet(S)
|
||||||
|
|
||||||
return new{
|
return new{
|
||||||
@ -19,16 +19,16 @@ struct SpecialLinearGroup{N, T, R, A, S} <: MatrixGroup{N,T}
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
GroupsCore.ngens(SL::SpecialLinearGroup{N}) where N = N^2 - N
|
GroupsCore.ngens(SL::SpecialLinearGroup{N}) where {N} = N^2 - N
|
||||||
|
|
||||||
Base.show(io::IO, SL::SpecialLinearGroup{N, T}) where {N, T} =
|
Base.show(io::IO, SL::SpecialLinearGroup{N,T}) where {N,T} =
|
||||||
print(io, "special linear group of $N×$N matrices over $T")
|
print(io, "special linear group of $N×$N matrices over $T")
|
||||||
|
|
||||||
function Base.show(
|
function Base.show(
|
||||||
io::IO,
|
io::IO,
|
||||||
::MIME"text/plain",
|
::MIME"text/plain",
|
||||||
sl::Groups.AbstractFPGroupElement{<:SpecialLinearGroup{N}}
|
sl::Groups.AbstractFPGroupElement{<:SpecialLinearGroup{N}}
|
||||||
) where N
|
) where {N}
|
||||||
|
|
||||||
Groups.normalform!(sl)
|
Groups.normalform!(sl)
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
include("eltary_symplectic.jl")
|
include("eltary_symplectic.jl")
|
||||||
|
|
||||||
struct SymplecticGroup{N, T, R, A, S} <: MatrixGroup{N,T}
|
struct SymplecticGroup{N,T,R,A,S} <: MatrixGroup{N,T}
|
||||||
base_ring::R
|
base_ring::R
|
||||||
alphabet::A
|
alphabet::A
|
||||||
gens::S
|
gens::S
|
||||||
|
|
||||||
function SymplecticGroup{N}(base_ring) where N
|
function SymplecticGroup{N}(base_ring) where {N}
|
||||||
S = symplectic_gens(N, eltype(base_ring))
|
S = symplectic_gens(N, eltype(base_ring))
|
||||||
alphabet = Alphabet(S)
|
alphabet = Alphabet(S)
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ end
|
|||||||
|
|
||||||
GroupsCore.ngens(Sp::SymplecticGroup) = length(Sp.gens)
|
GroupsCore.ngens(Sp::SymplecticGroup) = length(Sp.gens)
|
||||||
|
|
||||||
Base.show(io::IO, ::SymplecticGroup{N}) where N = print(io, "group of $N×$N symplectic matrices")
|
Base.show(io::IO, ::SymplecticGroup{N}) where {N} = print(io, "group of $N×$N symplectic matrices")
|
||||||
|
|
||||||
function Base.show(
|
function Base.show(
|
||||||
io::IO,
|
io::IO,
|
||||||
@ -35,15 +35,15 @@ function Base.show(
|
|||||||
Base.print_array(io, matrix_repr(sp))
|
Base.print_array(io, matrix_repr(sp))
|
||||||
end
|
end
|
||||||
|
|
||||||
_offdiag_idcs(n) = ((i,j) for i in 1:n for j in 1:n if i ≠ j)
|
_offdiag_idcs(n) = ((i, j) for i in 1:n for j in 1:n if i ≠ j)
|
||||||
|
|
||||||
function symplectic_gens(N, T=Int8)
|
function symplectic_gens(N, T=Int8)
|
||||||
iseven(N) || throw(ArgumentError("N needs to be even!"))
|
iseven(N) || throw(ArgumentError("N needs to be even!"))
|
||||||
n = N÷2
|
n = N ÷ 2
|
||||||
|
|
||||||
a_ijs = [ElementarySymplectic{N}(:A, i,j, one(T)) for (i,j) in _offdiag_idcs(n)]
|
a_ijs = [ElementarySymplectic{N}(:A, i, j, one(T)) for (i, j) in _offdiag_idcs(n)]
|
||||||
b_is = [ElementarySymplectic{N}(:B, n+i,i, one(T)) for i in 1:n]
|
b_is = [ElementarySymplectic{N}(:B, n + i, i, one(T)) for i in 1:n]
|
||||||
c_ijs = [ElementarySymplectic{N}(:B, n+i,j, one(T)) for (i,j) in _offdiag_idcs(n)]
|
c_ijs = [ElementarySymplectic{N}(:B, n + i, j, one(T)) for (i, j) in _offdiag_idcs(n)]
|
||||||
|
|
||||||
S = [a_ijs; b_is; c_ijs]
|
S = [a_ijs; b_is; c_ijs]
|
||||||
|
|
||||||
@ -53,18 +53,18 @@ function symplectic_gens(N, T=Int8)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function _std_symplectic_form(m::AbstractMatrix)
|
function _std_symplectic_form(m::AbstractMatrix)
|
||||||
r,c = size(m)
|
r, c = size(m)
|
||||||
r == c || return false
|
r == c || return false
|
||||||
iseven(r) || return false
|
iseven(r) || return false
|
||||||
|
|
||||||
n = r÷2
|
n = r ÷ 2
|
||||||
𝕆 = zeros(eltype(m), n, n)
|
𝕆 = zeros(eltype(m), n, n)
|
||||||
𝕀 = one(eltype(m))*LinearAlgebra.I
|
𝕀 = one(eltype(m)) * LinearAlgebra.I
|
||||||
Ω = [𝕆 -𝕀
|
Ω = [𝕆 -𝕀
|
||||||
𝕀 𝕆]
|
𝕀 𝕆]
|
||||||
return Ω
|
return Ω
|
||||||
end
|
end
|
||||||
|
|
||||||
function issymplectic(mat::M, Ω = _std_symplectic_form(mat)) where M <: AbstractMatrix
|
function issymplectic(mat::M, Ω=_std_symplectic_form(mat)) where {M<:AbstractMatrix}
|
||||||
return Ω == transpose(mat) * Ω * mat
|
return Ω == transpose(mat) * Ω * mat
|
||||||
end
|
end
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
abstract type MatrixGroup{N, T} <: Groups.AbstractFPGroup end
|
abstract type MatrixGroup{N,T} <: Groups.AbstractFPGroup end
|
||||||
const MatrixGroupElement{N, T} = Groups.AbstractFPGroupElement{<:MatrixGroup{N, T}}
|
const MatrixGroupElement{N,T} = Groups.AbstractFPGroupElement{<:MatrixGroup{N,T}}
|
||||||
|
|
||||||
Base.isone(g::MatrixGroupElement{N, T}) where {N, T} =
|
Base.isone(g::MatrixGroupElement{N,T}) where {N,T} =
|
||||||
isone(word(g)) || matrix_repr(g) == LinearAlgebra.I
|
isone(word(g)) || matrix_repr(g) == LinearAlgebra.I
|
||||||
|
|
||||||
function Base.:(==)(m1::M1, m2::M2) where {M1<:MatrixGroupElement, M2<:MatrixGroupElement}
|
function Base.:(==)(m1::M1, m2::M2) where {M1<:MatrixGroupElement,M2<:MatrixGroupElement}
|
||||||
parent(m1) === parent(m2) || return false
|
parent(m1) === parent(m2) || return false
|
||||||
word(m1) == word(m2) && return true
|
word(m1) == word(m2) && return true
|
||||||
return matrix_repr(m1) == matrix_repr(m2)
|
return matrix_repr(m1) == matrix_repr(m2)
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.size(m::MatrixGroupElement{N}) where N = (N, N)
|
Base.size(m::MatrixGroupElement{N}) where {N} = (N, N)
|
||||||
Base.eltype(m::MatrixGroupElement{N, T}) where {N, T} = T
|
Base.eltype(m::MatrixGroupElement{N,T}) where {N,T} = T
|
||||||
|
|
||||||
# three structural assumptions about matrix groups
|
# three structural assumptions about matrix groups
|
||||||
Groups.word(sl::MatrixGroupElement) = sl.word
|
Groups.word(sl::MatrixGroupElement) = sl.word
|
||||||
@ -22,9 +22,9 @@ Groups.rewriting(M::MatrixGroup) = alphabet(M)
|
|||||||
Base.hash(sl::MatrixGroupElement, h::UInt) =
|
Base.hash(sl::MatrixGroupElement, h::UInt) =
|
||||||
hash(matrix_repr(sl), hash(parent(sl), h))
|
hash(matrix_repr(sl), hash(parent(sl), h))
|
||||||
|
|
||||||
function matrix_repr(m::MatrixGroupElement{N, T}) where {N, T}
|
function matrix_repr(m::MatrixGroupElement{N,T}) where {N,T}
|
||||||
if isone(word(m))
|
if isone(word(m))
|
||||||
return StaticArrays.SMatrix{N, N, T}(LinearAlgebra.I)
|
return StaticArrays.SMatrix{N,N,T}(LinearAlgebra.I)
|
||||||
end
|
end
|
||||||
A = alphabet(parent(m))
|
A = alphabet(parent(m))
|
||||||
return prod(matrix_repr(A[l]) for l in word(m))
|
return prod(matrix_repr(A[l]) for l in word(m))
|
||||||
@ -33,7 +33,7 @@ end
|
|||||||
function Base.rand(
|
function Base.rand(
|
||||||
rng::Random.AbstractRNG,
|
rng::Random.AbstractRNG,
|
||||||
rs::Random.SamplerTrivial{<:MatrixGroup},
|
rs::Random.SamplerTrivial{<:MatrixGroup},
|
||||||
)
|
)
|
||||||
Mgroup = rs[]
|
Mgroup = rs[]
|
||||||
S = gens(Mgroup)
|
S = gens(Mgroup)
|
||||||
return prod(g -> rand(Bool) ? g : inv(g), rand(S, rand(1:30)))
|
return prod(g -> rand(Bool) ? g : inv(g), rand(S, rand(1:30)))
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
struct ElementaryMatrix{N, T} <: Groups.GSymbol
|
struct ElementaryMatrix{N,T} <: Groups.GSymbol
|
||||||
i::Int
|
i::Int
|
||||||
j::Int
|
j::Int
|
||||||
val::T
|
val::T
|
||||||
ElementaryMatrix{N}(i, j, val=1) where N =
|
ElementaryMatrix{N}(i, j, val=1) where {N} =
|
||||||
(@assert i≠j; new{N, typeof(val)}(i, j, val))
|
(@assert i ≠ j; new{N,typeof(val)}(i, j, val))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.show(io::IO, e::ElementaryMatrix)
|
function Base.show(io::IO, e::ElementaryMatrix)
|
||||||
@ -11,18 +11,18 @@ function Base.show(io::IO, e::ElementaryMatrix)
|
|||||||
!isone(e.val) && print(io, "^$(e.val)")
|
!isone(e.val) && print(io, "^$(e.val)")
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.:(==)(e::ElementaryMatrix{N}, f::ElementaryMatrix{N}) where N =
|
Base.:(==)(e::ElementaryMatrix{N}, f::ElementaryMatrix{N}) where {N} =
|
||||||
e.i == f.i && e.j == f.j && e.val == f.val
|
e.i == f.i && e.j == f.j && e.val == f.val
|
||||||
|
|
||||||
Base.hash(e::ElementaryMatrix, h::UInt) =
|
Base.hash(e::ElementaryMatrix, h::UInt) =
|
||||||
hash(typeof(e), hash((e.i, e.j, e.val), h))
|
hash(typeof(e), hash((e.i, e.j, e.val), h))
|
||||||
|
|
||||||
Base.inv(e::ElementaryMatrix{N}) where N =
|
Base.inv(e::ElementaryMatrix{N}) where {N} =
|
||||||
ElementaryMatrix{N}(e.i, e.j, -e.val)
|
ElementaryMatrix{N}(e.i, e.j, -e.val)
|
||||||
|
|
||||||
function matrix_repr(e::ElementaryMatrix{N, T}) where {N, T}
|
function matrix_repr(e::ElementaryMatrix{N,T}) where {N,T}
|
||||||
m = StaticArrays.MMatrix{N, N, T}(LinearAlgebra.I)
|
m = StaticArrays.MMatrix{N,N,T}(LinearAlgebra.I)
|
||||||
m[e.i, e.j] = e.val
|
m[e.i, e.j] = e.val
|
||||||
x = StaticArrays.SMatrix{N, N}(m)
|
x = StaticArrays.SMatrix{N,N}(m)
|
||||||
return x
|
return x
|
||||||
end
|
end
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
struct ElementarySymplectic{N, T} <: Groups.GSymbol
|
struct ElementarySymplectic{N,T} <: Groups.GSymbol
|
||||||
symbol::Symbol
|
symbol::Symbol
|
||||||
i::Int
|
i::Int
|
||||||
j::Int
|
j::Int
|
||||||
val::T
|
val::T
|
||||||
function ElementarySymplectic{N}(s::Symbol, i::Integer, j::Integer, val=1) where N
|
function ElementarySymplectic{N}(s::Symbol, i::Integer, j::Integer, val=1) where {N}
|
||||||
@assert s ∈ (:A, :B)
|
@assert s ∈ (:A, :B)
|
||||||
@assert iseven(N)
|
@assert iseven(N)
|
||||||
n = N÷2
|
n = N ÷ 2
|
||||||
if s === :A
|
if s === :A
|
||||||
@assert 1 ≤ i ≤ n && 1 ≤ j ≤ n && i ≠ j
|
@assert 1 ≤ i ≤ n && 1 ≤ j ≤ n && i ≠ j
|
||||||
elseif s === :B
|
elseif s === :B
|
||||||
@assert xor(1 ≤ i ≤ n, 1 ≤ j ≤ n) && xor(n < i ≤ N, n < j ≤ N)
|
@assert xor(1 ≤ i ≤ n, 1 ≤ j ≤ n) && xor(n < i ≤ N, n < j ≤ N)
|
||||||
end
|
end
|
||||||
return new{N, typeof(val)}(s, i, j, val)
|
return new{N,typeof(val)}(s, i, j, val)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -22,12 +22,12 @@ function Base.show(io::IO, s::ElementarySymplectic)
|
|||||||
!isone(s.val) && print(io, "^$(s.val)")
|
!isone(s.val) && print(io, "^$(s.val)")
|
||||||
end
|
end
|
||||||
|
|
||||||
_ind(s::ElementarySymplectic{N}) where N = (s.i, s.j)
|
_ind(s::ElementarySymplectic{N}) where {N} = (s.i, s.j)
|
||||||
_local_ind(N_half::Integer, i::Integer) = ifelse(i<=N_half, i, i-N_half)
|
_local_ind(N_half::Integer, i::Integer) = ifelse(i <= N_half, i, i - N_half)
|
||||||
function _dual_ind(s::ElementarySymplectic{N}) where N
|
function _dual_ind(s::ElementarySymplectic{N}) where {N}
|
||||||
if s.symbol === :A && return _ind(s)
|
if s.symbol === :A && return _ind(s)
|
||||||
else#if s.symbol === :B
|
else#if s.symbol === :B
|
||||||
return _dual_ind(N÷2, s.i, s.j)
|
return _dual_ind(N ÷ 2, s.i, s.j)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ function _dual_ind(N_half, i, j)
|
|||||||
return i, j
|
return i, j
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.:(==)(s::ElementarySymplectic{N}, t::ElementarySymplectic{M}) where {N, M}
|
function Base.:(==)(s::ElementarySymplectic{N}, t::ElementarySymplectic{M}) where {N,M}
|
||||||
N == M || return false
|
N == M || return false
|
||||||
s.symbol == t.symbol || return false
|
s.symbol == t.symbol || return false
|
||||||
s.val == t.val || return false
|
s.val == t.val || return false
|
||||||
@ -51,18 +51,18 @@ end
|
|||||||
Base.hash(s::ElementarySymplectic, h::UInt) =
|
Base.hash(s::ElementarySymplectic, h::UInt) =
|
||||||
hash(Set([_ind(s); _dual_ind(s)]), hash(s.symbol, hash(s.val, h)))
|
hash(Set([_ind(s); _dual_ind(s)]), hash(s.symbol, hash(s.val, h)))
|
||||||
|
|
||||||
LinearAlgebra.transpose(s::ElementarySymplectic{N}) where N =
|
LinearAlgebra.transpose(s::ElementarySymplectic{N}) where {N} =
|
||||||
ElementarySymplectic{N}(s.symbol, s.j, s.i, s.val)
|
ElementarySymplectic{N}(s.symbol, s.j, s.i, s.val)
|
||||||
|
|
||||||
Base.inv(s::ElementarySymplectic{N}) where N =
|
Base.inv(s::ElementarySymplectic{N}) where {N} =
|
||||||
ElementarySymplectic{N}(s.symbol, s.i, s.j, -s.val)
|
ElementarySymplectic{N}(s.symbol, s.i, s.j, -s.val)
|
||||||
|
|
||||||
function matrix_repr(s::ElementarySymplectic{N, T}) where {N, T}
|
function matrix_repr(s::ElementarySymplectic{N,T}) where {N,T}
|
||||||
@assert iseven(N)
|
@assert iseven(N)
|
||||||
n = div(N, 2)
|
n = div(N, 2)
|
||||||
m = StaticArrays.MMatrix{N, N, T}(LinearAlgebra.I)
|
m = StaticArrays.MMatrix{N,N,T}(LinearAlgebra.I)
|
||||||
i,j = _ind(s)
|
i, j = _ind(s)
|
||||||
m[i,j] = s.val
|
m[i, j] = s.val
|
||||||
if s.symbol === :A
|
if s.symbol === :A
|
||||||
m[n+j, n+i] = -s.val
|
m[n+j, n+i] = -s.val
|
||||||
else#if s.symbol === :B
|
else#if s.symbol === :B
|
||||||
@ -72,5 +72,5 @@ function matrix_repr(s::ElementarySymplectic{N, T}) where {N, T}
|
|||||||
m[j-n, i+n] = s.val
|
m[j-n, i+n] = s.val
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return StaticArrays.SMatrix{N, N}(m)
|
return StaticArrays.SMatrix{N,N}(m)
|
||||||
end
|
end
|
||||||
|
@ -42,5 +42,5 @@ Defaults to the rewriting in the free group.
|
|||||||
"""
|
"""
|
||||||
@inline function normalform!(res::AbstractWord, g::AbstractFPGroupElement)
|
@inline function normalform!(res::AbstractWord, g::AbstractFPGroupElement)
|
||||||
isone(res) && isnormalform(g) && return append!(res, word(g))
|
isone(res) && isnormalform(g) && return append!(res, word(g))
|
||||||
return KnuthBendix.rewrite_from_left!(res, word(g), rewriting(parent(g)))
|
return KnuthBendix.rewrite!(res, word(g), rewriting(parent(g)))
|
||||||
end
|
end
|
||||||
|
71
src/types.jl
71
src/types.jl
@ -3,15 +3,18 @@
|
|||||||
"""
|
"""
|
||||||
AbstractFPGroup
|
AbstractFPGroup
|
||||||
|
|
||||||
An Abstract type representing finitely presented groups. Every instance `` must implement
|
An Abstract type representing finitely presented groups. Every instance must implement
|
||||||
* `KnuthBendix.alphabet(G::MyFPGroup)`
|
* `KnuthBendix.alphabet(G::MyFPGroup)`
|
||||||
* `rewriting(G::MyFPGroup)` : return the rewriting object which must implement
|
* `rewriting(G::MyFPGroup)` : return the rewriting object which must implement
|
||||||
> `KnuthBendix.rewrite_from_left!(u, v, rewriting(G))`.
|
> `KnuthBendix.rewrite!(u, v, rewriting(G))`.
|
||||||
By default `alphabet(G)` is returned, which amounts to free rewriting in `G`.
|
E.g. for `G::FreeGroup` `alphabet(G)` is returned, which amounts to free rewriting.
|
||||||
|
* `ordering(G::MyFPGroup)[ = KnuthBendix.ordering(rewriting(G))]` : return the
|
||||||
|
(implicit) ordering for the alphabet of `G`.
|
||||||
* `relations(G::MyFPGroup)` : return a set of defining relations.
|
* `relations(G::MyFPGroup)` : return a set of defining relations.
|
||||||
|
|
||||||
AbstractFPGroup may also override `word_type(::Type{MyFPGroup}) = Word{UInt16}`,
|
AbstractFPGroup may also override `word_type(::Type{MyFPGroup}) = Word{UInt8}`,
|
||||||
which controls the word type used for group elements. If a group has more than `255` generators you need to define e.g.
|
which controls the word type used for group elements.
|
||||||
|
If a group has more than `255` generators you need to define e.g.
|
||||||
> `word_type(::Type{MyFPGroup}) = Word{UInt16}`
|
> `word_type(::Type{MyFPGroup}) = Word{UInt16}`
|
||||||
"""
|
"""
|
||||||
abstract type AbstractFPGroup <: GroupsCore.Group end
|
abstract type AbstractFPGroup <: GroupsCore.Group end
|
||||||
@ -22,22 +25,25 @@ word_type(::Type{<:AbstractFPGroup}) = Word{UInt8}
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
rewriting(G::AbstractFPGroup)
|
rewriting(G::AbstractFPGroup)
|
||||||
Return a "rewriting object" for elements of `G`. The rewriting object must must implement
|
Return a "rewriting object" for elements of `G`.
|
||||||
KnuthBendix.rewrite_from_left!(
|
|
||||||
u::AbstractWord,
|
|
||||||
v::AbstractWord,
|
|
||||||
rewriting(G)
|
|
||||||
)
|
|
||||||
|
|
||||||
For example if `G` is a `FreeGroup` then `alphabet(G)` is returned which results in free rewriting. For `FPGroup` a rewriting system is returned which may (or may not) rewrite word `v` to its normal form.
|
The rewriting object must must implement
|
||||||
|
KnuthBendix.rewrite!(u::AbstractWord, v::AbstractWord, rewriting(G))
|
||||||
|
|
||||||
|
For example if `G` is a `FreeGroup` then `alphabet(G)` is returned which results
|
||||||
|
in free rewriting. For `FPGroup` a rewriting system is returned which may
|
||||||
|
(or may not) rewrite word `v` to its normal form (depending on e.g. its confluence).
|
||||||
"""
|
"""
|
||||||
function rewriting end
|
function rewriting end
|
||||||
|
|
||||||
|
KnuthBendix.ordering(G::AbstractFPGroup) = ordering(rewriting(G))
|
||||||
|
KnuthBendix.alphabet(G::AbstractFPGroup) = alphabet(ordering(G))
|
||||||
|
|
||||||
Base.@propagate_inbounds function (G::AbstractFPGroup)(
|
Base.@propagate_inbounds function (G::AbstractFPGroup)(
|
||||||
word::AbstractVector{<:Integer},
|
word::AbstractVector{<:Integer},
|
||||||
)
|
)
|
||||||
@boundscheck @assert all(
|
@boundscheck @assert all(
|
||||||
l -> 1 <= l <= length(KnuthBendix.alphabet(G)),
|
l -> 1 <= l <= length(alphabet(G)),
|
||||||
word,
|
word,
|
||||||
)
|
)
|
||||||
return FPGroupElement(word_type(G)(word), G)
|
return FPGroupElement(word_type(G)(word), G)
|
||||||
@ -90,7 +96,7 @@ mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <:
|
|||||||
FPGroupElement(
|
FPGroupElement(
|
||||||
word::W,
|
word::W,
|
||||||
G::AbstractFPGroup,
|
G::AbstractFPGroup,
|
||||||
hash::UInt = UInt(0),
|
hash::UInt=UInt(0),
|
||||||
) where {W<:AbstractWord} = new{typeof(G),W}(word, hash, G)
|
) where {W<:AbstractWord} = new{typeof(G),W}(word, hash, G)
|
||||||
|
|
||||||
FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} =
|
FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} =
|
||||||
@ -128,7 +134,7 @@ end
|
|||||||
|
|
||||||
function Base.inv(g::GEl) where {GEl<:AbstractFPGroupElement}
|
function Base.inv(g::GEl) where {GEl<:AbstractFPGroupElement}
|
||||||
G = parent(g)
|
G = parent(g)
|
||||||
return GEl(inv(alphabet(G), word(g)), G)
|
return GEl(inv(word(g), alphabet(G)), G)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.:(*)(g::GEl, h::GEl) where {GEl<:AbstractFPGroupElement}
|
function Base.:(*)(g::GEl, h::GEl) where {GEl<:AbstractFPGroupElement}
|
||||||
@ -153,8 +159,7 @@ struct FreeGroup{T,O} <: AbstractFPGroup
|
|||||||
|
|
||||||
function FreeGroup(gens, ordering::KnuthBendix.WordOrdering)
|
function FreeGroup(gens, ordering::KnuthBendix.WordOrdering)
|
||||||
@assert length(gens) == length(unique(gens))
|
@assert length(gens) == length(unique(gens))
|
||||||
L = KnuthBendix.letters(alphabet(ordering))
|
@assert all(l -> l in alphabet(ordering), gens)
|
||||||
@assert all(l -> l in L, gens)
|
|
||||||
return new{eltype(gens),typeof(ordering)}(gens, ordering)
|
return new{eltype(gens),typeof(ordering)}(gens, ordering)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -163,15 +168,14 @@ FreeGroup(gens, A::Alphabet) = FreeGroup(gens, KnuthBendix.LenLex(A))
|
|||||||
|
|
||||||
function FreeGroup(A::Alphabet)
|
function FreeGroup(A::Alphabet)
|
||||||
@boundscheck @assert all(
|
@boundscheck @assert all(
|
||||||
KnuthBendix.hasinverse(l, A) for l in KnuthBendix.letters(A)
|
KnuthBendix.hasinverse(l, A) for l in A
|
||||||
)
|
)
|
||||||
ltrs = KnuthBendix.letters(A)
|
gens = Vector{eltype(A)}()
|
||||||
gens = Vector{eltype(ltrs)}()
|
invs = Vector{eltype(A)}()
|
||||||
invs = Vector{eltype(ltrs)}()
|
for l in A
|
||||||
for l in ltrs
|
|
||||||
l ∈ invs && continue
|
l ∈ invs && continue
|
||||||
push!(gens, l)
|
push!(gens, l)
|
||||||
push!(invs, inv(A, l))
|
push!(invs, inv(l, A))
|
||||||
end
|
end
|
||||||
|
|
||||||
return FreeGroup(gens, A)
|
return FreeGroup(gens, A)
|
||||||
@ -193,10 +197,9 @@ Base.show(io::IO, F::FreeGroup) =
|
|||||||
print(io, "free group on $(ngens(F)) generators")
|
print(io, "free group on $(ngens(F)) generators")
|
||||||
|
|
||||||
# mandatory methods:
|
# mandatory methods:
|
||||||
relations(F::FreeGroup) = Pair{eltype(F)}[]
|
|
||||||
KnuthBendix.ordering(F::FreeGroup) = F.ordering
|
KnuthBendix.ordering(F::FreeGroup) = F.ordering
|
||||||
KnuthBendix.alphabet(F::FreeGroup) = alphabet(KnuthBendix.ordering(F))
|
rewriting(F::FreeGroup) = alphabet(F) # alphabet(F) = alphabet(ordering(F))
|
||||||
rewriting(F::FreeGroup) = alphabet(F)
|
relations(F::FreeGroup) = Pair{eltype(F),eltype(F)}[]
|
||||||
|
|
||||||
# GroupsCore interface:
|
# GroupsCore interface:
|
||||||
# these are mathematically correct
|
# these are mathematically correct
|
||||||
@ -207,22 +210,20 @@ GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) =
|
|||||||
|
|
||||||
## FP Groups
|
## FP Groups
|
||||||
|
|
||||||
struct FPGroup{T,R,S} <: AbstractFPGroup
|
struct FPGroup{T,RW,S} <: AbstractFPGroup
|
||||||
gens::Vector{T}
|
gens::Vector{T}
|
||||||
relations::Vector{Pair{S,S}}
|
relations::Vector{Pair{S,S}}
|
||||||
rws::R
|
rw::RW
|
||||||
end
|
end
|
||||||
|
|
||||||
relations(G::FPGroup) = G.relations
|
relations(G::FPGroup) = G.relations
|
||||||
rewriting(G::FPGroup) = G.rws
|
rewriting(G::FPGroup) = G.rw
|
||||||
KnuthBendix.ordering(G::FPGroup) = KnuthBendix.ordering(rewriting(G))
|
|
||||||
KnuthBendix.alphabet(G::FPGroup) = alphabet(KnuthBendix.ordering(G))
|
|
||||||
|
|
||||||
function FPGroup(
|
function FPGroup(
|
||||||
G::AbstractFPGroup,
|
G::AbstractFPGroup,
|
||||||
rels::AbstractVector{<:Pair{GEl,GEl}};
|
rels::AbstractVector{<:Pair{GEl,GEl}};
|
||||||
ordering = KnuthBendix.ordering(G),
|
ordering=KnuthBendix.ordering(G),
|
||||||
kwargs...,
|
kwargs...
|
||||||
) where {GEl<:FPGroupElement}
|
) where {GEl<:FPGroupElement}
|
||||||
for (lhs, rhs) in rels
|
for (lhs, rhs) in rels
|
||||||
@assert parent(lhs) === parent(rhs) === G
|
@assert parent(lhs) === parent(rhs) === G
|
||||||
@ -230,9 +231,9 @@ function FPGroup(
|
|||||||
word_rels = [word(lhs) => word(rhs) for (lhs, rhs) in [relations(G); rels]]
|
word_rels = [word(lhs) => word(rhs) for (lhs, rhs) in [relations(G); rels]]
|
||||||
rws = KnuthBendix.RewritingSystem(word_rels, ordering)
|
rws = KnuthBendix.RewritingSystem(word_rels, ordering)
|
||||||
|
|
||||||
KnuthBendix.knuthbendix!(rws; kwargs...)
|
rws = KnuthBendix.knuthbendix(rws, KnuthBendix.Settings(; kwargs...))
|
||||||
|
|
||||||
return FPGroup(G.gens, rels, rws)
|
return FPGroup(G.gens, rels, KnuthBendix.IndexAutomaton(rws))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.show(io::IO, ::MIME"text/plain", G::FPGroup)
|
function Base.show(io::IO, ::MIME"text/plain", G::FPGroup)
|
||||||
|
@ -1,20 +1,31 @@
|
|||||||
"""
|
"""
|
||||||
wlmetric_ball(S::AbstractVector{<:GroupElem}
|
wlmetric_ball(S::AbstractVector{<:GroupElem}
|
||||||
[, center=one(first(S)); radius=2, op=*])
|
[, center=one(first(S)); radius=2, op=*, threading=true])
|
||||||
Compute metric ball as a list of elements of non-decreasing length, given the
|
Compute metric ball as a list of elements of non-decreasing length, given the
|
||||||
word-length metric on the group generated by `S`. The ball is centered at `center`
|
word-length metric on the group generated by `S`. The ball is centered at `center`
|
||||||
(by default: the identity element). `radius` and `op` keywords specify the
|
(by default: the identity element). `radius` and `op` keywords specify the
|
||||||
radius and multiplication operation to be used.
|
radius and multiplication operation to be used.
|
||||||
"""
|
"""
|
||||||
function wlmetric_ball_serial(S::AbstractVector{T}, center::T=one(first(S)); radius = 2, op = *) where {T}
|
function wlmetric_ball(
|
||||||
|
S::AbstractVector{T},
|
||||||
|
center::T=one(first(S));
|
||||||
|
radius=2,
|
||||||
|
op=*,
|
||||||
|
threading=true
|
||||||
|
) where {T}
|
||||||
|
threading && return wlmetric_ball_thr(S, center, radius=radius, op=op)
|
||||||
|
return wlmetric_ball_serial(S, center, radius=radius, op=op)
|
||||||
|
end
|
||||||
|
|
||||||
|
function wlmetric_ball_serial(S::AbstractVector{T}, center::T=one(first(S)); radius=2, op=*) where {T}
|
||||||
@assert radius >= 1
|
@assert radius >= 1
|
||||||
old = union!([center], [center*s for s in S])
|
old = union!([center], [center * s for s in S])
|
||||||
return _wlmetric_ball(S, old, radius, op, collect, unique!)
|
return _wlmetric_ball(S, old, radius, op, collect, unique!)
|
||||||
end
|
end
|
||||||
|
|
||||||
function wlmetric_ball_thr(S::AbstractVector{T}, center::T=one(first(S)); radius = 2, op = *) where {T}
|
function wlmetric_ball_thr(S::AbstractVector{T}, center::T=one(first(S)); radius=2, op=*) where {T}
|
||||||
@assert radius >= 1
|
@assert radius >= 1
|
||||||
old = union!([center], [center*s for s in S])
|
old = union!([center], [center * s for s in S])
|
||||||
return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique)
|
return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -26,6 +37,7 @@ function _wlmetric_ball(S, old, radius, op, collect, unique)
|
|||||||
(g = op(o, s); hash(g); g)
|
(g = op(o, s); hash(g); g)
|
||||||
for o in @view(old[sizes[end-1]:end]) for s in S
|
for o in @view(old[sizes[end-1]:end]) for s in S
|
||||||
)
|
)
|
||||||
|
|
||||||
append!(old, new)
|
append!(old, new)
|
||||||
unique(old)
|
unique(old)
|
||||||
end
|
end
|
||||||
@ -34,13 +46,3 @@ function _wlmetric_ball(S, old, radius, op, collect, unique)
|
|||||||
return old, sizes[2:end]
|
return old, sizes[2:end]
|
||||||
end
|
end
|
||||||
|
|
||||||
function wlmetric_ball(
|
|
||||||
S::AbstractVector{T},
|
|
||||||
center::T = one(first(S));
|
|
||||||
radius = 2,
|
|
||||||
op = *,
|
|
||||||
threading = true,
|
|
||||||
) where {T}
|
|
||||||
threading && return wlmetric_ball_thr(S, center, radius = radius, op = op)
|
|
||||||
return wlmetric_ball_serial(S, center, radius = radius, op = op)
|
|
||||||
end
|
|
||||||
|
104
test/AutFn.jl
104
test/AutFn.jl
@ -29,57 +29,57 @@
|
|||||||
end
|
end
|
||||||
|
|
||||||
A4 = Alphabet(
|
A4 = Alphabet(
|
||||||
[:a,:A,:b,:B,:c,:C,:d,:D],
|
[:a, :A, :b, :B, :c, :C, :d, :D],
|
||||||
[ 2, 1, 4, 3, 6, 5, 8, 7]
|
[2, 1, 4, 3, 6, 5, 8, 7]
|
||||||
)
|
)
|
||||||
|
|
||||||
A5 = Alphabet(
|
A5 = Alphabet(
|
||||||
[:a,:A,:b,:B,:c,:C,:d,:D,:e,:E],
|
[:a, :A, :b, :B, :c, :C, :d, :D, :e, :E],
|
||||||
[ 2, 1, 4, 3, 6, 5, 8, 7,10, 9]
|
[2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
|
||||||
)
|
)
|
||||||
|
|
||||||
F4 = FreeGroup([:a, :b, :c, :d], A4)
|
F4 = FreeGroup([:a, :b, :c, :d], A4)
|
||||||
a,b,c,d = gens(F4)
|
a, b, c, d = gens(F4)
|
||||||
D = ntuple(i->gens(F4, i), 4)
|
D = ntuple(i -> gens(F4, i), 4)
|
||||||
|
|
||||||
@testset "Transvection action correctness" begin
|
@testset "Transvection action correctness" begin
|
||||||
i,j = 1,2
|
i, j = 1, 2
|
||||||
r = Groups.Transvection(:ϱ,i,j)
|
r = Groups.Transvection(:ϱ, i, j)
|
||||||
l = Groups.Transvection(:λ,i,j)
|
l = Groups.Transvection(:λ, i, j)
|
||||||
|
|
||||||
(t::Groups.Transvection)(v::Tuple) = Groups.evaluate!(v, t)
|
(t::Groups.Transvection)(v::Tuple) = Groups.evaluate!(v, t)
|
||||||
|
|
||||||
@test r(deepcopy(D)) == (a*b, b, c, d)
|
@test r(deepcopy(D)) == (a * b, b, c, d)
|
||||||
@test inv(r)(deepcopy(D)) == (a*b^-1,b, c, d)
|
@test inv(r)(deepcopy(D)) == (a * b^-1, b, c, d)
|
||||||
@test l(deepcopy(D)) == (b*a, b, c, d)
|
@test l(deepcopy(D)) == (b * a, b, c, d)
|
||||||
@test inv(l)(deepcopy(D)) == (b^-1*a,b, c, d)
|
@test inv(l)(deepcopy(D)) == (b^-1 * a, b, c, d)
|
||||||
|
|
||||||
i,j = 3,1
|
i, j = 3, 1
|
||||||
r = Groups.Transvection(:ϱ,i,j)
|
r = Groups.Transvection(:ϱ, i, j)
|
||||||
l = Groups.Transvection(:λ,i,j)
|
l = Groups.Transvection(:λ, i, j)
|
||||||
@test r(deepcopy(D)) == (a, b, c*a, d)
|
@test r(deepcopy(D)) == (a, b, c * a, d)
|
||||||
@test inv(r)(deepcopy(D)) == (a, b, c*a^-1,d)
|
@test inv(r)(deepcopy(D)) == (a, b, c * a^-1, d)
|
||||||
@test l(deepcopy(D)) == (a, b, a*c, d)
|
@test l(deepcopy(D)) == (a, b, a * c, d)
|
||||||
@test inv(l)(deepcopy(D)) == (a, b, a^-1*c,d)
|
@test inv(l)(deepcopy(D)) == (a, b, a^-1 * c, d)
|
||||||
|
|
||||||
i,j = 4,3
|
i, j = 4, 3
|
||||||
r = Groups.Transvection(:ϱ,i,j)
|
r = Groups.Transvection(:ϱ, i, j)
|
||||||
l = Groups.Transvection(:λ,i,j)
|
l = Groups.Transvection(:λ, i, j)
|
||||||
@test r(deepcopy(D)) == (a, b, c, d*c)
|
@test r(deepcopy(D)) == (a, b, c, d * c)
|
||||||
@test inv(r)(deepcopy(D)) == (a, b, c, d*c^-1)
|
@test inv(r)(deepcopy(D)) == (a, b, c, d * c^-1)
|
||||||
@test l(deepcopy(D)) == (a, b, c, c*d)
|
@test l(deepcopy(D)) == (a, b, c, c * d)
|
||||||
@test inv(l)(deepcopy(D)) == (a, b, c, c^-1*d)
|
@test inv(l)(deepcopy(D)) == (a, b, c, c^-1 * d)
|
||||||
|
|
||||||
i,j = 2,4
|
i, j = 2, 4
|
||||||
r = Groups.Transvection(:ϱ,i,j)
|
r = Groups.Transvection(:ϱ, i, j)
|
||||||
l = Groups.Transvection(:λ,i,j)
|
l = Groups.Transvection(:λ, i, j)
|
||||||
@test r(deepcopy(D)) == (a, b*d, c, d)
|
@test r(deepcopy(D)) == (a, b * d, c, d)
|
||||||
@test inv(r)(deepcopy(D)) == (a, b*d^-1,c, d)
|
@test inv(r)(deepcopy(D)) == (a, b * d^-1, c, d)
|
||||||
@test l(deepcopy(D)) == (a, d*b, c, d)
|
@test l(deepcopy(D)) == (a, d * b, c, d)
|
||||||
@test inv(l)(deepcopy(D)) == (a, d^-1*b,c, d)
|
@test inv(l)(deepcopy(D)) == (a, d^-1 * b, c, d)
|
||||||
end
|
end
|
||||||
|
|
||||||
A = SpecialAutomorphismGroup(F4, maxrules=1000)
|
A = SpecialAutomorphismGroup(F4, max_rules=1000)
|
||||||
|
|
||||||
@testset "AutomorphismGroup constructors" begin
|
@testset "AutomorphismGroup constructors" begin
|
||||||
@test A isa Groups.AbstractFPGroup
|
@test A isa Groups.AbstractFPGroup
|
||||||
@ -91,33 +91,33 @@
|
|||||||
|
|
||||||
@testset "Automorphisms: hash and evaluate" begin
|
@testset "Automorphisms: hash and evaluate" begin
|
||||||
@test Groups.domain(gens(A, 1)) == D
|
@test Groups.domain(gens(A, 1)) == D
|
||||||
g, h = gens(A, 1), gens(A, 8)
|
g, h = gens(A, 1), gens(A, 8) # (ϱ₁.₂, ϱ₃.₂)
|
||||||
|
|
||||||
@test evaluate(g*h) == evaluate(h*g)
|
@test evaluate(g * h) == evaluate(h * g)
|
||||||
@test (g*h).savedhash == zero(UInt)
|
@test (g * h).savedhash == zero(UInt)
|
||||||
|
|
||||||
@test sprint(show, typeof(g)) == "Automorphism{FreeGroup{Symbol, KnuthBendix.LenLex{Symbol}}, …}"
|
@test contains(sprint(show, typeof(g)), "Automorphism{FreeGroup{Symbol")
|
||||||
|
|
||||||
a = g*h
|
a = g * h
|
||||||
b = h*g
|
b = h * g
|
||||||
@test hash(a) != zero(UInt)
|
@test hash(a) != zero(UInt)
|
||||||
@test hash(a) == hash(b)
|
@test hash(a) == hash(b)
|
||||||
@test a.savedhash == b.savedhash
|
@test a.savedhash == b.savedhash
|
||||||
|
|
||||||
@test length(unique([a,b])) == 1
|
@test length(unique([a, b])) == 1
|
||||||
@test length(unique([g*h, h*g])) == 1
|
@test length(unique([g * h, h * g])) == 1
|
||||||
|
|
||||||
# Not so simple arithmetic: applying starting on the left:
|
# Not so simple arithmetic: applying starting on the left:
|
||||||
# ϱ₁₂*ϱ₂₁⁻¹*λ₁₂*ε₂ == σ₂₁₃₄
|
# ϱ₁₂*ϱ₂₁⁻¹*λ₁₂*ε₂ == σ₂₁₃₄
|
||||||
|
|
||||||
g = gens(A, 1)
|
g = gens(A, 1)
|
||||||
x1, x2, x3, x4 = Groups.domain(g)
|
x1, x2, x3, x4 = Groups.domain(g)
|
||||||
@test evaluate(g) == (x1*x2, x2, x3, x4)
|
@test evaluate(g) == (x1 * x2, x2, x3, x4)
|
||||||
|
|
||||||
g = g*inv(gens(A, 4)) # ϱ₂₁
|
g = g * inv(gens(A, 4)) # ϱ₂₁
|
||||||
@test evaluate(g) == (x1*x2, x1^-1, x3, x4)
|
@test evaluate(g) == (x1 * x2, x1^-1, x3, x4)
|
||||||
|
|
||||||
g = g*gens(A, 13)
|
g = g * gens(A, 13)
|
||||||
@test evaluate(g) == (x2, x1^-1, x3, x4)
|
@test evaluate(g) == (x2, x1^-1, x3, x4)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -128,7 +128,7 @@
|
|||||||
S = gens(G)
|
S = gens(G)
|
||||||
@test S isa Vector{<:FPGroupElement{<:AutomorphismGroup{<:FreeGroup}}}
|
@test S isa Vector{<:FPGroupElement{<:AutomorphismGroup{<:FreeGroup}}}
|
||||||
|
|
||||||
@test length(S) == 2*N*(N-1)
|
@test length(S) == 2 * N * (N - 1)
|
||||||
@test length(unique(S)) == length(S)
|
@test length(unique(S)) == length(S)
|
||||||
|
|
||||||
S_sym = [S; inv.(S)]
|
S_sym = [S; inv.(S)]
|
||||||
@ -136,12 +136,12 @@
|
|||||||
|
|
||||||
pushfirst!(S_sym, one(G))
|
pushfirst!(S_sym, one(G))
|
||||||
|
|
||||||
B_2 = [i*j for (i,j) in Base.product(S_sym, S_sym)]
|
B_2 = [i * j for (i, j) in Base.product(S_sym, S_sym)]
|
||||||
@test length(B_2) == 2401
|
@test length(B_2) == 2401
|
||||||
@test length(unique(B_2)) == 1777
|
@test length(unique(B_2)) == 1777
|
||||||
|
|
||||||
@test all(g->isone(inv(g)*g), B_2)
|
@test all(g -> isone(inv(g) * g), B_2)
|
||||||
@test all(g->isone(g*inv(g)), B_2)
|
@test all(g -> isone(g * inv(g)), B_2)
|
||||||
end
|
end
|
||||||
|
|
||||||
@testset "Forward evaluate" begin
|
@testset "Forward evaluate" begin
|
||||||
@ -153,7 +153,7 @@
|
|||||||
|
|
||||||
f = gens(F)
|
f = gens(F)
|
||||||
|
|
||||||
@test a(f[1]) == f[1]*f[2]
|
@test a(f[1]) == f[1] * f[2]
|
||||||
@test all(a(f[i]) == f[i] for i in 2:length(f))
|
@test all(a(f[i]) == f[i] for i in 2:length(f))
|
||||||
|
|
||||||
S = let s = gens(G)
|
S = let s = gens(G)
|
||||||
|
@ -3,22 +3,24 @@
|
|||||||
|
|
||||||
π₁Σ = Groups.SurfaceGroup(genus, 0)
|
π₁Σ = Groups.SurfaceGroup(genus, 0)
|
||||||
|
|
||||||
|
@test contains(sprint(print, π₁Σ), "surface")
|
||||||
|
|
||||||
Groups.PermRightAut(p::Perm) = Groups.PermRightAut(p.d)
|
Groups.PermRightAut(p::Perm) = Groups.PermRightAut(p.d)
|
||||||
# Groups.PermLeftAut(p::Perm) = Groups.PermLeftAut(p.d)
|
# Groups.PermLeftAut(p::Perm) = Groups.PermLeftAut(p.d)
|
||||||
autπ₁Σ = let autπ₁Σ = AutomorphismGroup(π₁Σ)
|
autπ₁Σ = let autπ₁Σ = AutomorphismGroup(π₁Σ)
|
||||||
pauts = let p = perm"(1,3,5)(2,4,6)"
|
pauts = let p = perm"(1,3,5)(2,4,6)"
|
||||||
[Groups.PermRightAut(p^i) for i in 0:2]
|
[Groups.PermRightAut(p^i) for i in 0:2]
|
||||||
end
|
end
|
||||||
T = eltype(KnuthBendix.letters(alphabet(autπ₁Σ)))
|
T = eltype(alphabet(autπ₁Σ))
|
||||||
S = eltype(pauts)
|
S = eltype(pauts)
|
||||||
|
|
||||||
A = Alphabet(Union{T,S}[KnuthBendix.letters(alphabet(autπ₁Σ)); pauts])
|
A = Alphabet(Union{T,S}[alphabet(autπ₁Σ)...; pauts])
|
||||||
|
|
||||||
autG = AutomorphismGroup(
|
autG = AutomorphismGroup(
|
||||||
π₁Σ,
|
π₁Σ,
|
||||||
autπ₁Σ.gens,
|
autπ₁Σ.gens,
|
||||||
A,
|
A,
|
||||||
ntuple(i->inv(gens(π₁Σ, i)), 2Groups.genus(π₁Σ))
|
ntuple(i -> inv(gens(π₁Σ, i)), 2Groups.genus(π₁Σ))
|
||||||
)
|
)
|
||||||
|
|
||||||
autG
|
autG
|
||||||
@ -27,9 +29,7 @@
|
|||||||
Al = alphabet(autπ₁Σ)
|
Al = alphabet(autπ₁Σ)
|
||||||
S = [gens(autπ₁Σ); inv.(gens(autπ₁Σ))]
|
S = [gens(autπ₁Σ); inv.(gens(autπ₁Σ))]
|
||||||
|
|
||||||
sautFn = let ltrs = KnuthBendix.letters(Al)
|
sautFn = parent(Al[1].autFn_word)
|
||||||
parent(first(ltrs).autFn_word)
|
|
||||||
end
|
|
||||||
|
|
||||||
τ = Groups.rotation_element(sautFn)
|
τ = Groups.rotation_element(sautFn)
|
||||||
|
|
||||||
@ -38,7 +38,7 @@
|
|||||||
λ = Groups.ΡΛ(:λ, A, 2genus)
|
λ = Groups.ΡΛ(:λ, A, 2genus)
|
||||||
ϱ = Groups.ΡΛ(:ϱ, A, 2genus)
|
ϱ = Groups.ΡΛ(:ϱ, A, 2genus)
|
||||||
@test sautFn(Groups.Te_diagonal(λ, ϱ, 1)) ==
|
@test sautFn(Groups.Te_diagonal(λ, ϱ, 1)) ==
|
||||||
conj(sautFn(Groups.Te_diagonal(λ, ϱ, 2)), τ)
|
conj(sautFn(Groups.Te_diagonal(λ, ϱ, 2)), τ)
|
||||||
|
|
||||||
@test sautFn(Groups.Te_diagonal(λ, ϱ, 3)) == sautFn(Groups.Te(λ, ϱ, 3, 1))
|
@test sautFn(Groups.Te_diagonal(λ, ϱ, 3)) == sautFn(Groups.Te(λ, ϱ, 3, 1))
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@testset "FPGroups" begin
|
@testset "FPGroups" begin
|
||||||
A = Alphabet([:a, :A, :b, :B, :c, :C], [2,1,4,3,6,5])
|
A = Alphabet([:a, :A, :b, :B, :c, :C], [2, 1, 4, 3, 6, 5])
|
||||||
|
|
||||||
@test FreeGroup(A) isa FreeGroup
|
@test FreeGroup(A) isa FreeGroup
|
||||||
@test sprint(show, FreeGroup(A)) == "free group on 3 generators"
|
@test sprint(show, FreeGroup(A)) == "free group on 3 generators"
|
||||||
@ -7,26 +7,26 @@
|
|||||||
F = FreeGroup([:a, :b, :c], A)
|
F = FreeGroup([:a, :b, :c], A)
|
||||||
@test sprint(show, F) == "free group on 3 generators"
|
@test sprint(show, F) == "free group on 3 generators"
|
||||||
|
|
||||||
a,b,c = gens(F)
|
a, b, c = gens(F)
|
||||||
@test c*b*a isa FPGroupElement
|
@test c * b * a isa FPGroupElement
|
||||||
|
|
||||||
# quotient of F:
|
# quotient of F:
|
||||||
G = FPGroup(F, [a*b=>b*a, a*c=>c*a, b*c=>c*b])
|
G = FPGroup(F, [a * b => b * a, a * c => c * a, b * c => c * b])
|
||||||
|
|
||||||
@test G isa FPGroup
|
@test G isa FPGroup
|
||||||
@test sprint(show, G) == "⟨ a b c | \n\t a*b => b*a a*c => c*a b*c => c*b ⟩"
|
@test sprint(show, G) == "⟨ a b c | \n\t a*b => b*a a*c => c*a b*c => c*b ⟩"
|
||||||
@test rand(G) isa FPGroupElement
|
@test rand(G) isa FPGroupElement
|
||||||
|
|
||||||
f = a*c*b
|
f = a * c * b
|
||||||
@test word(f) isa Word{UInt8}
|
@test word(f) isa Word{UInt8}
|
||||||
|
|
||||||
aG,bG,cG = gens(G)
|
aG, bG, cG = gens(G)
|
||||||
|
|
||||||
@test aG isa FPGroupElement
|
@test aG isa FPGroupElement
|
||||||
@test_throws AssertionError aG == a
|
@test_throws AssertionError aG == a
|
||||||
@test word(aG) == word(a)
|
@test word(aG) == word(a)
|
||||||
|
|
||||||
g = aG*cG*bG
|
g = aG * cG * bG
|
||||||
|
|
||||||
@test_throws AssertionError f == g
|
@test_throws AssertionError f == g
|
||||||
@test word(f) == word(g)
|
@test word(f) == word(g)
|
||||||
@ -34,21 +34,21 @@
|
|||||||
Groups.normalform!(g)
|
Groups.normalform!(g)
|
||||||
@test word(g) == [1, 3, 5]
|
@test word(g) == [1, 3, 5]
|
||||||
|
|
||||||
let g = aG*cG*bG
|
let g = aG * cG * bG
|
||||||
# test that we normalize g before printing
|
# test that we normalize g before printing
|
||||||
@test sprint(show, g) == "a*b*c"
|
@test sprint(show, g) == "a*b*c"
|
||||||
end
|
end
|
||||||
|
|
||||||
# quotient of G
|
# quotient of G
|
||||||
H = FPGroup(G, [aG^2=>cG, bG*cG=>aG], maxrules=200)
|
H = FPGroup(G, [aG^2 => cG, bG * cG => aG], max_rules=200)
|
||||||
|
|
||||||
h = H(word(g))
|
h = H(word(g))
|
||||||
|
|
||||||
@test h isa FPGroupElement
|
@test h isa FPGroupElement
|
||||||
@test_throws AssertionError h == g
|
@test_throws AssertionError h == g
|
||||||
@test_throws MethodError h*g
|
@test_throws MethodError h * g
|
||||||
|
|
||||||
H′ = FPGroup(G, [aG^2=>cG, bG*cG=>aG], maxrules=200)
|
H′ = FPGroup(G, [aG^2 => cG, bG * cG => aG], max_rules=200)
|
||||||
@test_throws AssertionError one(H) == one(H′)
|
@test_throws AssertionError one(H) == one(H′)
|
||||||
|
|
||||||
Groups.normalform!(h)
|
Groups.normalform!(h)
|
||||||
|
@ -4,23 +4,25 @@ using Groups.MatrixGroups
|
|||||||
@testset "SL(n, ℤ)" begin
|
@testset "SL(n, ℤ)" begin
|
||||||
SL3Z = SpecialLinearGroup{3}(Int8)
|
SL3Z = SpecialLinearGroup{3}(Int8)
|
||||||
|
|
||||||
S = gens(SL3Z); union!(S, inv.(S))
|
S = gens(SL3Z)
|
||||||
|
union!(S, inv.(S))
|
||||||
|
|
||||||
E, sizes = Groups.wlmetric_ball(S, radius=4)
|
_, sizes = Groups.wlmetric_ball(S, radius=4)
|
||||||
|
|
||||||
@test sizes == [13, 121, 883, 5455]
|
@test sizes == [13, 121, 883, 5455]
|
||||||
|
|
||||||
E(i,j) = SL3Z([A[MatrixGroups.ElementaryMatrix{3}(i,j, Int8(1))]])
|
E(i, j) = SL3Z([A[MatrixGroups.ElementaryMatrix{3}(i, j, Int8(1))]])
|
||||||
|
|
||||||
A = alphabet(SL3Z)
|
A = alphabet(SL3Z)
|
||||||
w = E(1,2)
|
w = E(1, 2)
|
||||||
r = E(2,3)^-3
|
r = E(2, 3)^-3
|
||||||
s = E(1,3)^2*E(3,2)^-1
|
s = E(1, 3)^2 * E(3, 2)^-1
|
||||||
|
|
||||||
S = [w,r,s]; S = unique([S; inv.(S)]);
|
S = [w, r, s]
|
||||||
_, sizes = Groups.wlmetric_ball(S, radius=4);
|
S = unique([S; inv.(S)])
|
||||||
|
_, sizes = Groups.wlmetric_ball(S, radius=4)
|
||||||
@test sizes == [7, 33, 141, 561]
|
@test sizes == [7, 33, 141, 561]
|
||||||
_, sizes = Groups.wlmetric_ball_serial(S, radius=4);
|
_, sizes = Groups.wlmetric_ball_serial(S, radius=4)
|
||||||
@test sizes == [7, 33, 141, 561]
|
@test sizes == [7, 33, 141, 561]
|
||||||
|
|
||||||
Logging.with_logger(Logging.NullLogger()) do
|
Logging.with_logger(Logging.NullLogger()) do
|
||||||
@ -34,10 +36,10 @@ using Groups.MatrixGroups
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
x = w*inv(w)*r
|
x = w * inv(w) * r
|
||||||
|
|
||||||
@test length(word(x)) == 5
|
@test length(word(x)) == 5
|
||||||
@test size(x) == (3,3)
|
@test size(x) == (3, 3)
|
||||||
@test eltype(x) == Int8
|
@test eltype(x) == Int8
|
||||||
|
|
||||||
@test contains(sprint(print, SL3Z), "special linear group of 3×3")
|
@test contains(sprint(print, SL3Z), "special linear group of 3×3")
|
||||||
@ -50,12 +52,14 @@ using Groups.MatrixGroups
|
|||||||
@testset "Sp(6, ℤ)" begin
|
@testset "Sp(6, ℤ)" begin
|
||||||
Sp6 = MatrixGroups.SymplecticGroup{6}(Int8)
|
Sp6 = MatrixGroups.SymplecticGroup{6}(Int8)
|
||||||
|
|
||||||
@testset "GroupsCore conformance" begin
|
Logging.with_logger(Logging.NullLogger()) do
|
||||||
test_Group_interface(Sp6)
|
@testset "GroupsCore conformance" begin
|
||||||
g = Sp6(rand(1:length(alphabet(Sp6)), 10))
|
test_Group_interface(Sp6)
|
||||||
h = Sp6(rand(1:length(alphabet(Sp6)), 10))
|
g = Sp6(rand(1:length(alphabet(Sp6)), 10))
|
||||||
|
h = Sp6(rand(1:length(alphabet(Sp6)), 10))
|
||||||
|
|
||||||
test_GroupElement_interface(g, h)
|
test_GroupElement_interface(g, h)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@test contains(sprint(print, Sp6), "group of 6×6 symplectic matrices")
|
@test contains(sprint(print, Sp6), "group of 6×6 symplectic matrices")
|
||||||
@ -64,7 +68,7 @@ using Groups.MatrixGroups
|
|||||||
x *= inv(x) * gens(Sp6, 2)
|
x *= inv(x) * gens(Sp6, 2)
|
||||||
|
|
||||||
@test length(word(x)) == 3
|
@test length(word(x)) == 3
|
||||||
@test size(x) == (6,6)
|
@test size(x) == (6, 6)
|
||||||
@test eltype(x) == Int8
|
@test eltype(x) == Int8
|
||||||
|
|
||||||
@test contains(sprint(show, MIME"text/plain"(), x), "6×6 symplectic matrix:")
|
@test contains(sprint(show, MIME"text/plain"(), x), "6×6 symplectic matrix:")
|
||||||
|
@ -24,7 +24,7 @@ include(joinpath(pathof(GroupsCore), "..", "..", "test", "conformance_test.jl"))
|
|||||||
_, t = @timed include("homomorphisms.jl")
|
_, t = @timed include("homomorphisms.jl")
|
||||||
@info "homomorphisms.jl took $(round(t, digits=2))s"
|
@info "homomorphisms.jl took $(round(t, digits=2))s"
|
||||||
|
|
||||||
if haskey(ENV, "CI")
|
if !haskey(ENV, "CI")
|
||||||
_, t = @timed include("AutSigma_41.jl")
|
_, t = @timed include("AutSigma_41.jl")
|
||||||
@info "AutSigma_41 took $(round(t, digits=2))s"
|
@info "AutSigma_41 took $(round(t, digits=2))s"
|
||||||
_, t = @timed include("AutSigma3.jl")
|
_, t = @timed include("AutSigma3.jl")
|
||||||
@ -36,5 +36,5 @@ include(joinpath(pathof(GroupsCore), "..", "..", "test", "conformance_test.jl"))
|
|||||||
end
|
end
|
||||||
|
|
||||||
if !haskey(ENV, "CI")
|
if !haskey(ENV, "CI")
|
||||||
include("benchmarks.jl")
|
include("benchmarks.jl")
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user