From 9006f8a4a1b583175a2fb420865a1f653beeaec0 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Tue, 15 Nov 2022 19:52:40 +0100 Subject: [PATCH 01/12] make wl_ball thread safe: pre-compute normalforms! --- src/wl_ball.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wl_ball.jl b/src/wl_ball.jl index 18645cb..0c52080 100644 --- a/src/wl_ball.jl +++ b/src/wl_ball.jl @@ -34,7 +34,8 @@ function _wlmetric_ball(S, old, radius, op, collect, unique) for r in 2:radius old = let old = old, S = S, new = collect( - (g = op(o, s); hash(g); g) + (g = op(o, s); normalform!(g); hash(g); g) + # normalform! and hash are to make assure thread-safety of produced elts for o in @view(old[sizes[end-1]:end]) for s in S ) From b7a6f4e9529c3e13dda3c86622e69932b72fd2a8 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Tue, 15 Nov 2022 19:53:52 +0100 Subject: [PATCH 02/12] bump version 0.7.5 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d9251fa..6b177eb 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Groups" uuid = "5d8bd718-bd84-11e8-3b40-ad14f4a32557" authors = ["Marek Kaluba "] -version = "0.7.4" +version = "0.7.5" [deps] Folds = "41a02a25-b8f0-4f67-bc48-60067656b558" From f096a869b8cf4438e07437608a54c5029bdde298 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 16:51:22 +0100 Subject: [PATCH 03/12] rename matrix_repr to simply matrix --- src/abelianize.jl | 4 ++-- src/matrix_groups/abstract.jl | 12 ++++++------ src/matrix_groups/eltary_matrices.jl | 2 +- src/matrix_groups/eltary_symplectic.jl | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/abelianize.jl b/src/abelianize.jl index 4f47f0f..1ab92ee 100644 --- a/src/abelianize.jl +++ b/src/abelianize.jl @@ -53,7 +53,7 @@ function Groups._abelianize( ab = Groups.Homomorphism(Groups._abelianize, source, SlN, check=false) matrix_spn_map = let S = gens(target) - Dict(MatrixGroups.matrix_repr(g) => word(g) for g in union(S, inv.(S))) + Dict(MatrixGroups.matrix(g) => word(g) for g in union(S, inv.(S))) end # renumeration: @@ -63,7 +63,7 @@ function Groups._abelianize( p = [reverse(2:2:N); reverse(1:2:N)] g = source([i]) - Mg = MatrixGroups.matrix_repr(ab(g))[p, p] + Mg = MatrixGroups.matrix(ab(g))[p, p] return matrix_spn_map[Mg] end diff --git a/src/matrix_groups/abstract.jl b/src/matrix_groups/abstract.jl index 1da2228..5e022f7 100644 --- a/src/matrix_groups/abstract.jl +++ b/src/matrix_groups/abstract.jl @@ -2,12 +2,12 @@ abstract type MatrixGroup{N,T} <: Groups.AbstractFPGroup end const MatrixGroupElement{N,T} = Groups.AbstractFPGroupElement{<:MatrixGroup{N,T}} Base.isone(g::MatrixGroupElement{N,T}) where {N,T} = - isone(word(g)) || matrix_repr(g) == LinearAlgebra.I + isone(word(g)) || isone(matrix(g)) function Base.:(==)(m1::M1, m2::M2) where {M1<:MatrixGroupElement,M2<:MatrixGroupElement} parent(m1) === parent(m2) || return false word(m1) == word(m2) && return true - return matrix_repr(m1) == matrix_repr(m2) + return matrix(m1) == matrix(m2) end Base.size(m::MatrixGroupElement{N}) where {N} = (N, N) @@ -19,15 +19,15 @@ Base.parent(sl::MatrixGroupElement) = sl.parent Groups.alphabet(M::MatrixGroup) = M.alphabet Groups.rewriting(M::MatrixGroup) = alphabet(M) -Base.hash(sl::MatrixGroupElement, h::UInt) = - hash(matrix_repr(sl), hash(parent(sl), h)) +Base.hash(m::MatrixGroupElement, h::UInt) = + hash(matrix(m), hash(parent(m), h)) -function matrix_repr(m::MatrixGroupElement{N,T}) where {N,T} +function matrix(m::MatrixGroupElement{N,T}) where {N,T} if isone(word(m)) return StaticArrays.SMatrix{N,N,T}(LinearAlgebra.I) end A = alphabet(parent(m)) - return prod(matrix_repr(A[l]) for l in word(m)) + return prod(matrix(A[l]) for l in word(m)) end function Base.rand( diff --git a/src/matrix_groups/eltary_matrices.jl b/src/matrix_groups/eltary_matrices.jl index 6e3ed48..42b582d 100644 --- a/src/matrix_groups/eltary_matrices.jl +++ b/src/matrix_groups/eltary_matrices.jl @@ -20,7 +20,7 @@ Base.hash(e::ElementaryMatrix, h::UInt) = Base.inv(e::ElementaryMatrix{N}) where {N} = ElementaryMatrix{N}(e.i, e.j, -e.val) -function matrix_repr(e::ElementaryMatrix{N,T}) where {N,T} +function matrix(e::ElementaryMatrix{N,T}) where {N,T} m = StaticArrays.MMatrix{N,N,T}(LinearAlgebra.I) m[e.i, e.j] = e.val x = StaticArrays.SMatrix{N,N}(m) diff --git a/src/matrix_groups/eltary_symplectic.jl b/src/matrix_groups/eltary_symplectic.jl index 0640e6b..91ab941 100644 --- a/src/matrix_groups/eltary_symplectic.jl +++ b/src/matrix_groups/eltary_symplectic.jl @@ -57,7 +57,7 @@ LinearAlgebra.transpose(s::ElementarySymplectic{N}) where {N} = Base.inv(s::ElementarySymplectic{N}) where {N} = ElementarySymplectic{N}(s.symbol, s.i, s.j, -s.val) -function matrix_repr(s::ElementarySymplectic{N,T}) where {N,T} +function matrix(s::ElementarySymplectic{N,T}) where {N,T} @assert iseven(N) n = div(N, 2) m = StaticArrays.MMatrix{N,N,T}(LinearAlgebra.I) From a3809596144af510b47703e275a7b10eb5631f0b Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 17:11:22 +0100 Subject: [PATCH 04/12] add AbstractMatrixGroup --- src/matrix_groups/SLn.jl | 2 +- src/matrix_groups/Spn.jl | 2 +- src/matrix_groups/abstract.jl | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/matrix_groups/SLn.jl b/src/matrix_groups/SLn.jl index 5a783fa..72b9504 100644 --- a/src/matrix_groups/SLn.jl +++ b/src/matrix_groups/SLn.jl @@ -1,6 +1,6 @@ include("eltary_matrices.jl") -struct SpecialLinearGroup{N,T,R,A,S} <: MatrixGroup{N,T} +struct SpecialLinearGroup{N,T,R,A,S} <: AbstractMatrixGroup{N,T} base_ring::R alphabet::A gens::S diff --git a/src/matrix_groups/Spn.jl b/src/matrix_groups/Spn.jl index 6d98bae..98f556a 100644 --- a/src/matrix_groups/Spn.jl +++ b/src/matrix_groups/Spn.jl @@ -1,6 +1,6 @@ include("eltary_symplectic.jl") -struct SymplecticGroup{N,T,R,A,S} <: MatrixGroup{N,T} +struct SymplecticGroup{N,T,R,A,S} <: AbstractMatrixGroup{N,T} base_ring::R alphabet::A gens::S diff --git a/src/matrix_groups/abstract.jl b/src/matrix_groups/abstract.jl index 5e022f7..d90613b 100644 --- a/src/matrix_groups/abstract.jl +++ b/src/matrix_groups/abstract.jl @@ -1,5 +1,5 @@ -abstract type MatrixGroup{N,T} <: Groups.AbstractFPGroup end -const MatrixGroupElement{N,T} = Groups.AbstractFPGroupElement{<:MatrixGroup{N,T}} +abstract type AbstractMatrixGroup{N,T} <: Groups.AbstractFPGroup end +const MatrixGroupElement{N,T} = Groups.AbstractFPGroupElement{<:AbstractMatrixGroup{N,T}} Base.isone(g::MatrixGroupElement{N,T}) where {N,T} = isone(word(g)) || isone(matrix(g)) @@ -32,9 +32,9 @@ end function Base.rand( rng::Random.AbstractRNG, - rs::Random.SamplerTrivial{<:MatrixGroup}, + rs::Random.SamplerTrivial{<:AbstractMatrixGroup}, ) Mgroup = rs[] S = gens(Mgroup) - return prod(g -> rand(Bool) ? g : inv(g), rand(S, rand(1:30))) + return prod(g -> rand(rng, Bool) ? g : inv(g), rand(rng, S, rand(rng, 1:30))) end From 116439d074914ae5ddef5341fe0cf80ca12564d7 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 17:20:52 +0100 Subject: [PATCH 05/12] move show functions to abstract.jl --- src/matrix_groups/SLn.jl | 20 ++++++-------------- src/matrix_groups/Spn.jl | 15 +++------------ src/matrix_groups/abstract.jl | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/matrix_groups/SLn.jl b/src/matrix_groups/SLn.jl index 72b9504..d95107e 100644 --- a/src/matrix_groups/SLn.jl +++ b/src/matrix_groups/SLn.jl @@ -21,22 +21,14 @@ end GroupsCore.ngens(SL::SpecialLinearGroup{N}) where {N} = N^2 - N -Base.show(io::IO, SL::SpecialLinearGroup{N,T}) where {N,T} = - print(io, "special linear group of $N×$N matrices over $T") +function Base.show(io::IO, ::SpecialLinearGroup{N,T}) where {N,T} + return print(io, "SL{$N,$T}") +end function Base.show( io::IO, ::MIME"text/plain", - sl::Groups.AbstractFPGroupElement{<:SpecialLinearGroup{N}} -) where {N} - - Groups.normalform!(sl) - - print(io, "SL{$N,$(eltype(sl))} matrix: ") - KnuthBendix.print_repr(io, word(sl), alphabet(sl)) - println(io) - Base.print_array(io, matrix_repr(sl)) + SL::SpecialLinearGroup{N,T}, +) where {N,T} + return print(io, "special linear group of $N×$N matrices over $T") end - -Base.show(io::IO, sl::Groups.AbstractFPGroupElement{<:SpecialLinearGroup}) = - KnuthBendix.print_repr(io, word(sl), alphabet(sl)) diff --git a/src/matrix_groups/Spn.jl b/src/matrix_groups/Spn.jl index 98f556a..d66c0af 100644 --- a/src/matrix_groups/Spn.jl +++ b/src/matrix_groups/Spn.jl @@ -21,20 +21,11 @@ end 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,T}) where {N,T} = print(io, "Sp{$N,$T}") -function Base.show( - io::IO, - ::MIME"text/plain", - sp::Groups.AbstractFPGroupElement{<:SymplecticGroup{N}} -) where {N} - Groups.normalform!(sp) - print(io, "$N×$N symplectic matrix: ") - KnuthBendix.print_repr(io, word(sp), alphabet(sp)) - println(io) - Base.print_array(io, matrix_repr(sp)) +function Base.show(io::IO, ::MIME"text/plain", ::SymplecticGroup{N}) where {N} + return print(io, "group of $N×$N symplectic matrices") end - _offdiag_idcs(n) = ((i, j) for i in 1:n for j in 1:n if i ≠ j) function symplectic_gens(N, T=Int8) diff --git a/src/matrix_groups/abstract.jl b/src/matrix_groups/abstract.jl index d90613b..3caca2c 100644 --- a/src/matrix_groups/abstract.jl +++ b/src/matrix_groups/abstract.jl @@ -38,3 +38,29 @@ function Base.rand( S = gens(Mgroup) return prod(g -> rand(rng, Bool) ? g : inv(g), rand(rng, S, rand(rng, 1:30))) end + +function Base.show(io::IO, M::AbstractMatrixGroup) + g = gens(M, 1) + N = size(g, 1) + print(io, "H ⩽ GL{$N,$(eltype(g))}") +end + +function Base.show(io::IO, ::MIME"text/plain", M::AbstractMatrixGroup) + N = size(gens(M, 1), 1) + ng = GroupsCore.ngens(M) + print(io, "subgroup of $N×$N invertible matrices with $(ng) generators") +end + +Base.show(io::IO, mat::Groups.AbstractFPGroupElement{<:AbstractMatrixGroup}) = + KnuthBendix.print_repr(io, word(mat), alphabet(mat)) + +function Base.show( + io::IO, + ::MIME"text/plain", + mat::Groups.AbstractFPGroupElement{<:AbstractMatrixGroup{N}} +) where {N} + Groups.normalform!(mat) + KnuthBendix.print_repr(io, word(mat), alphabet(mat)) + println(io, " ∈ ", parent(mat)) + Base.print_array(io, matrix(mat)) +end From 40cd92e3c427702c6d01103e20768db3ed288767 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 18:25:55 +0100 Subject: [PATCH 06/12] simplify parametrisation of SLn and Spn --- src/matrix_groups/SLn.jl | 25 +++++++++++++------------ src/matrix_groups/Spn.jl | 18 ++++++++---------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/matrix_groups/SLn.jl b/src/matrix_groups/SLn.jl index d95107e..57e4f22 100644 --- a/src/matrix_groups/SLn.jl +++ b/src/matrix_groups/SLn.jl @@ -1,25 +1,26 @@ include("eltary_matrices.jl") -struct SpecialLinearGroup{N,T,R,A,S} <: AbstractMatrixGroup{N,T} +struct SpecialLinearGroup{N,T,R,S} <: AbstractMatrixGroup{N,T} base_ring::R - alphabet::A - gens::S + alphabet::Alphabet{S} + gens::Vector{S} 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) - return new{ - N, - eltype(base_ring), - typeof(base_ring), - typeof(alphabet), - typeof(S) - }(base_ring, alphabet, S) + T = eltype(base_ring) + R = typeof(base_ring) + St = eltype(S) + + return new{N,T,R,St}(base_ring, alphabet, S) end end -GroupsCore.ngens(SL::SpecialLinearGroup{N}) where {N} = N^2 - N +GroupsCore.ngens(SL::SpecialLinearGroup) = length(SL.gens) function Base.show(io::IO, ::SpecialLinearGroup{N,T}) where {N,T} return print(io, "SL{$N,$T}") diff --git a/src/matrix_groups/Spn.jl b/src/matrix_groups/Spn.jl index d66c0af..2361050 100644 --- a/src/matrix_groups/Spn.jl +++ b/src/matrix_groups/Spn.jl @@ -1,21 +1,19 @@ include("eltary_symplectic.jl") -struct SymplecticGroup{N,T,R,A,S} <: AbstractMatrixGroup{N,T} +struct SymplecticGroup{N,T,R,S} <: AbstractMatrixGroup{N,T} base_ring::R - alphabet::A - gens::S + alphabet::Alphabet{S} + gens::Vector{S} function SymplecticGroup{N}(base_ring) where {N} S = symplectic_gens(N, eltype(base_ring)) alphabet = Alphabet(S) - return new{ - N, - eltype(base_ring), - typeof(base_ring), - typeof(alphabet), - typeof(S) - }(base_ring, alphabet, S) + T = eltype(base_ring) + R = typeof(base_ring) + St = eltype(S) + + return new{N,T,R,St}(base_ring, alphabet, S) end end From 46c95dbb83d409029ef39d9e9edc483c9473e489 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 18:26:45 +0100 Subject: [PATCH 07/12] add general matrix groups --- src/matrix_groups/MatrixGroups.jl | 3 ++- src/matrix_groups/matrix_generators.jl | 36 ++++++++++++++++++++++++++ src/matrix_groups/matrix_group.jl | 25 ++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/matrix_groups/matrix_generators.jl create mode 100644 src/matrix_groups/matrix_group.jl diff --git a/src/matrix_groups/MatrixGroups.jl b/src/matrix_groups/MatrixGroups.jl index 486baf1..64ad756 100644 --- a/src/matrix_groups/MatrixGroups.jl +++ b/src/matrix_groups/MatrixGroups.jl @@ -9,10 +9,11 @@ import GroupsCore.Random # GroupsCore rand using ..Groups using Groups.KnuthBendix -export SpecialLinearGroup, SymplecticGroup +export MatrixGroup, SpecialLinearGroup, SymplecticGroup include("abstract.jl") +include("matrix_group.jl") include("SLn.jl") include("Spn.jl") diff --git a/src/matrix_groups/matrix_generators.jl b/src/matrix_groups/matrix_generators.jl new file mode 100644 index 0000000..2a4975c --- /dev/null +++ b/src/matrix_groups/matrix_generators.jl @@ -0,0 +1,36 @@ +struct MatrixElt{N,T,N²} <: Groups.GSymbol + id::Symbol + inv::Bool + mat::StaticArrays.SMatrix{N,N,T,N²} + + function MatrixElt{N,T}( + id::Symbol, + mat::AbstractMatrix, + inv::Bool = false, + ) where {N,T} + n = LinearAlgebra.checksquare(mat) + @assert N == n + @assert !iszero(LinearAlgebra.det(mat)) + return new{N,T,N^2}(id, inv, mat) + end +end + +function MatrixElt{N}( + id::Symbol, + mat::AbstractMatrix, + inv::Bool = false, +) where {N} + return MatrixElt{N,eltype(mat)}(id, mat, inv) +end + +Base.show(io::IO, m::MatrixElt) = print(io, m.id, m.inv ? "⁻¹" : "") + +Base.:(==)(m::MatrixElt, n::MatrixElt) = m.mat == n.mat + +Base.hash(m::MatrixElt, h::UInt) = hash(m.mat, hash(typeof(m), h)) + +function Base.inv(m::MatrixElt{N,T}) where {N,T} + return MatrixElt{N,T}(m.id, round.(T, inv(m.mat)), !m.inv) +end + +matrix(m::MatrixElt) = m.mat diff --git a/src/matrix_groups/matrix_group.jl b/src/matrix_groups/matrix_group.jl new file mode 100644 index 0000000..51355db --- /dev/null +++ b/src/matrix_groups/matrix_group.jl @@ -0,0 +1,25 @@ +include("matrix_generators.jl") + +struct MatrixGroup{N,T,R,S} <: AbstractMatrixGroup{N,T} + base_ring::R + alphabet::Alphabet{S} + gens::Vector{S} +end + +function MatrixGroup{N}( + gens::AbstractVector{<:AbstractMatrix{T}}, + base_ring = T, +) where {N,T} + S = map(enumerate(gens)) do (i, mat) + id = Symbol('m', Groups.subscriptify(i)) + return MatrixElt{N}(id, mat) + end + alphabet = Alphabet(S) + + R = typeof(base_ring) + St = eltype(S) + + return MatrixGroup{N,T,R,St}(base_ring, alphabet, S) +end + +GroupsCore.ngens(M::MatrixGroup) = length(M.gens) From b52de81e060cc3ff1c5d60ed385b6a1c68a162f6 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 18:28:10 +0100 Subject: [PATCH 08/12] update tests for show for SLn, Spn --- test/matrix_groups.jl | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/test/matrix_groups.jl b/test/matrix_groups.jl index ef27c9d..4e99f04 100644 --- a/test/matrix_groups.jl +++ b/test/matrix_groups.jl @@ -7,7 +7,7 @@ using Groups.MatrixGroups S = gens(SL3Z) union!(S, inv.(S)) - _, sizes = Groups.wlmetric_ball(S, radius=4) + _, sizes = Groups.wlmetric_ball(S; radius = 4) @test sizes == [13, 121, 883, 5455] @@ -20,9 +20,9 @@ using Groups.MatrixGroups S = [w, r, s] S = unique([S; inv.(S)]) - _, sizes = Groups.wlmetric_ball(S, radius=4) + _, sizes = Groups.wlmetric_ball(S; radius = 4) @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] Logging.with_logger(Logging.NullLogger()) do @@ -35,15 +35,18 @@ using Groups.MatrixGroups end end - x = w * inv(w) * r @test length(word(x)) == 5 @test size(x) == (3, 3) @test eltype(x) == Int8 - @test contains(sprint(print, SL3Z), "special linear group of 3×3") - @test contains(sprint(show, MIME"text/plain"(), x), "SL{3,Int8} matrix:") + @test contains(sprint(show, SL3Z), "SL{3,Int8}") + @test contains( + sprint(show, MIME"text/plain"(), SL3Z), + "special linear group", + ) + @test contains(sprint(show, MIME"text/plain"(), x), "∈ SL{3,Int8}") @test sprint(print, x) isa String @test length(word(x)) == 3 @@ -62,8 +65,6 @@ using Groups.MatrixGroups end end - @test contains(sprint(print, Sp6), "group of 6×6 symplectic matrices") - x = gens(Sp6, 1) x *= inv(x) * gens(Sp6, 2) @@ -71,13 +72,18 @@ using Groups.MatrixGroups @test size(x) == (6, 6) @test eltype(x) == Int8 - @test contains(sprint(show, MIME"text/plain"(), x), "6×6 symplectic matrix:") + @test contains(sprint(show, Sp6), "Sp{6,Int8}") + @test contains( + sprint(show, MIME"text/plain"(), Sp6), + "group of 6×6 symplectic matrices", + ) + @test contains(sprint(show, MIME"text/plain"(), x), "∈ Sp{6,Int8}") @test sprint(print, x) isa String @test length(word(x)) == 1 for g in gens(Sp6) - @test MatrixGroups.issymplectic(MatrixGroups.matrix_repr(g)) + @test MatrixGroups.issymplectic(MatrixGroups.matrix(g)) end end end From a0d2186477dae8aaad5523f1601dba8389ce532b Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 18:30:55 +0100 Subject: [PATCH 09/12] add tests for MatrixGroups --- test/matrix_groups.jl | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/matrix_groups.jl b/test/matrix_groups.jl index 4e99f04..e93c70e 100644 --- a/test/matrix_groups.jl +++ b/test/matrix_groups.jl @@ -86,4 +86,36 @@ using Groups.MatrixGroups @test MatrixGroups.issymplectic(MatrixGroups.matrix(g)) end end + + @testset "General matrix group" begin + Sp6 = MatrixGroups.SymplecticGroup{6}(Int8) + G = Groups.MatrixGroup{6}(Matrix{Int16}.(gens(Sp6))) + + Logging.with_logger(Logging.NullLogger()) do + @testset "GroupsCore conformance" begin + test_Group_interface(G) + g = G(rand(1:length(alphabet(G)), 10)) + h = G(rand(1:length(alphabet(G)), 10)) + + test_GroupElement_interface(g, h) + end + end + + x = gens(G, 1) + x *= inv(x) * gens(G, 2) + + @test length(word(x)) == 3 + @test size(x) == (6, 6) + @test eltype(x) == Int16 + + @test contains(sprint(show, G), "H ⩽ GL{6,Int16}") + @test contains( + sprint(show, MIME"text/plain"(), G), + "subgroup of 6×6 invertible matrices", + ) + @test contains(sprint(show, MIME"text/plain"(), x), "∈ H ⩽ GL{6,Int16}") + @test sprint(print, x) isa String + + @test length(word(x)) == 1 + end end From 29af9659d96c484622094500eb9db294de8fe6e7 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 18:32:27 +0100 Subject: [PATCH 10/12] format MatrixGroups module --- src/matrix_groups/Spn.jl | 25 ++++++++--- src/matrix_groups/abstract.jl | 61 ++++++++++++++++++-------- src/matrix_groups/eltary_matrices.jl | 22 ++++++---- src/matrix_groups/eltary_symplectic.jl | 29 ++++++++---- 4 files changed, 93 insertions(+), 44 deletions(-) diff --git a/src/matrix_groups/Spn.jl b/src/matrix_groups/Spn.jl index 2361050..7bcfbce 100644 --- a/src/matrix_groups/Spn.jl +++ b/src/matrix_groups/Spn.jl @@ -24,15 +24,21 @@ Base.show(io::IO, ::SymplecticGroup{N,T}) where {N,T} = print(io, "Sp{$N,$T}") function Base.show(io::IO, ::MIME"text/plain", ::SymplecticGroup{N}) where {N} return print(io, "group of $N×$N symplectic matrices") end -_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!")) n = N ÷ 2 - a_ijs = [ElementarySymplectic{N}(:A, i, j, one(T)) for (i, j) in _offdiag_idcs(n)] + _offdiag_idcs(n) = ((i, j) for i in 1:n for j in 1:n if i ≠ j) + + 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] - 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] @@ -49,11 +55,16 @@ function _std_symplectic_form(m::AbstractMatrix) n = r ÷ 2 𝕆 = zeros(eltype(m), n, n) 𝕀 = one(eltype(m)) * LinearAlgebra.I - Ω = [𝕆 -𝕀 - 𝕀 𝕆] + Ω = [ + 𝕆 -𝕀 + 𝕀 𝕆 + ] return Ω 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 end diff --git a/src/matrix_groups/abstract.jl b/src/matrix_groups/abstract.jl index 3caca2c..ac2b625 100644 --- a/src/matrix_groups/abstract.jl +++ b/src/matrix_groups/abstract.jl @@ -1,26 +1,31 @@ abstract type AbstractMatrixGroup{N,T} <: Groups.AbstractFPGroup end -const MatrixGroupElement{N,T} = Groups.AbstractFPGroupElement{<:AbstractMatrixGroup{N,T}} +const MatrixGroupElement{N,T} = + Groups.AbstractFPGroupElement{<:AbstractMatrixGroup{N,T}} -Base.isone(g::MatrixGroupElement{N,T}) where {N,T} = - isone(word(g)) || isone(matrix(g)) +function Base.isone(g::MatrixGroupElement{N,T}) where {N,T} + return isone(word(g)) || isone(matrix(g)) +end -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 word(m1) == word(m2) && return true return matrix(m1) == matrix(m2) end -Base.size(m::MatrixGroupElement{N}) where {N} = (N, N) -Base.eltype(m::MatrixGroupElement{N,T}) where {N,T} = T +Base.size(::MatrixGroupElement{N}) where {N} = (N, N) +Base.size(::MatrixGroupElement{N}, d) where {N} = ifelse(d::Integer <= 2, N, 1) +Base.eltype(::MatrixGroupElement{N,T}) where {N,T} = T # three structural assumptions about matrix groups -Groups.word(sl::MatrixGroupElement) = sl.word -Base.parent(sl::MatrixGroupElement) = sl.parent -Groups.alphabet(M::MatrixGroup) = M.alphabet -Groups.rewriting(M::MatrixGroup) = alphabet(M) +Groups.word(m::MatrixGroupElement) = m.word +Base.parent(m::MatrixGroupElement) = m.parent +Groups.alphabet(M::AbstractMatrixGroup) = M.alphabet +Groups.rewriting(M::AbstractMatrixGroup) = alphabet(M) -Base.hash(m::MatrixGroupElement, h::UInt) = - hash(matrix(m), hash(parent(m), h)) +Base.hash(m::MatrixGroupElement, h::UInt) = hash(matrix(m), hash(parent(m), h)) function matrix(m::MatrixGroupElement{N,T}) where {N,T} if isone(word(m)) @@ -30,37 +35,55 @@ function matrix(m::MatrixGroupElement{N,T}) where {N,T} return prod(matrix(A[l]) for l in word(m)) end +function Base.convert( + ::Type{M}, + m::MatrixGroupElement, +) where {M<:AbstractMatrix} + return convert(M, matrix(m)) +end +(M::Type{<:AbstractMatrix})(m::MatrixGroupElement) = convert(M, m) + function Base.rand( rng::Random.AbstractRNG, rs::Random.SamplerTrivial{<:AbstractMatrixGroup}, ) Mgroup = rs[] S = gens(Mgroup) - return prod(g -> rand(rng, Bool) ? g : inv(g), rand(rng, S, rand(rng, 1:30))) + return prod( + g -> rand(rng, Bool) ? g : inv(g), + rand(rng, S, rand(rng, 1:30)), + ) end function Base.show(io::IO, M::AbstractMatrixGroup) g = gens(M, 1) N = size(g, 1) - print(io, "H ⩽ GL{$N,$(eltype(g))}") + return print(io, "H ⩽ GL{$N,$(eltype(g))}") end function Base.show(io::IO, ::MIME"text/plain", M::AbstractMatrixGroup) N = size(gens(M, 1), 1) ng = GroupsCore.ngens(M) - print(io, "subgroup of $N×$N invertible matrices with $(ng) generators") + return print( + io, + "subgroup of $N×$N invertible matrices with $(ng) generators", + ) end -Base.show(io::IO, mat::Groups.AbstractFPGroupElement{<:AbstractMatrixGroup}) = - KnuthBendix.print_repr(io, word(mat), alphabet(mat)) +function Base.show( + io::IO, + mat::Groups.AbstractFPGroupElement{<:AbstractMatrixGroup}, +) + return KnuthBendix.print_repr(io, word(mat), alphabet(mat)) +end function Base.show( io::IO, ::MIME"text/plain", - mat::Groups.AbstractFPGroupElement{<:AbstractMatrixGroup{N}} + mat::Groups.AbstractFPGroupElement{<:AbstractMatrixGroup{N}}, ) where {N} Groups.normalform!(mat) KnuthBendix.print_repr(io, word(mat), alphabet(mat)) println(io, " ∈ ", parent(mat)) - Base.print_array(io, matrix(mat)) + return Base.print_array(io, matrix(mat)) end diff --git a/src/matrix_groups/eltary_matrices.jl b/src/matrix_groups/eltary_matrices.jl index 42b582d..8181b11 100644 --- a/src/matrix_groups/eltary_matrices.jl +++ b/src/matrix_groups/eltary_matrices.jl @@ -2,23 +2,27 @@ struct ElementaryMatrix{N,T} <: Groups.GSymbol i::Int j::Int val::T - ElementaryMatrix{N}(i, j, val=1) where {N} = - (@assert i ≠ j; new{N,typeof(val)}(i, j, val)) + function ElementaryMatrix{N}(i, j, val = 1) where {N} + return (@assert i ≠ j; new{N,typeof(val)}(i, j, val)) + end end function Base.show(io::IO, e::ElementaryMatrix) print(io, 'E', Groups.subscriptify(e.i), Groups.subscriptify(e.j)) - !isone(e.val) && print(io, "^$(e.val)") + return !isone(e.val) && print(io, "^$(e.val)") end -Base.:(==)(e::ElementaryMatrix{N}, f::ElementaryMatrix{N}) where {N} = - e.i == f.i && e.j == f.j && e.val == f.val +function Base.:(==)(e::ElementaryMatrix{N}, f::ElementaryMatrix{N}) where {N} + return e.i == f.i && e.j == f.j && e.val == f.val +end -Base.hash(e::ElementaryMatrix, h::UInt) = - hash(typeof(e), hash((e.i, e.j, e.val), h)) +function Base.hash(e::ElementaryMatrix, h::UInt) + return hash(typeof(e), hash((e.i, e.j, e.val), h)) +end -Base.inv(e::ElementaryMatrix{N}) where {N} = - ElementaryMatrix{N}(e.i, e.j, -e.val) +function Base.inv(e::ElementaryMatrix{N}) where {N} + return ElementaryMatrix{N}(e.i, e.j, -e.val) +end function matrix(e::ElementaryMatrix{N,T}) where {N,T} m = StaticArrays.MMatrix{N,N,T}(LinearAlgebra.I) diff --git a/src/matrix_groups/eltary_symplectic.jl b/src/matrix_groups/eltary_symplectic.jl index 91ab941..1f70a5c 100644 --- a/src/matrix_groups/eltary_symplectic.jl +++ b/src/matrix_groups/eltary_symplectic.jl @@ -3,7 +3,12 @@ struct ElementarySymplectic{N,T} <: Groups.GSymbol i::Int j::Int 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 iseven(N) n = N ÷ 2 @@ -19,7 +24,7 @@ end function Base.show(io::IO, s::ElementarySymplectic) i, j = Groups.subscriptify(s.i), Groups.subscriptify(s.j) print(io, s.symbol, i, j) - !isone(s.val) && print(io, "^$(s.val)") + return !isone(s.val) && print(io, "^$(s.val)") end _ind(s::ElementarySymplectic{N}) where {N} = (s.i, s.j) @@ -41,21 +46,27 @@ function _dual_ind(N_half, i, j) return i, j 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 s.symbol == t.symbol || return false s.val == t.val || return false return _ind(t) == _ind(s) || _ind(t) == _dual_ind(s) end -Base.hash(s::ElementarySymplectic, h::UInt) = - hash(Set([_ind(s); _dual_ind(s)]), hash(s.symbol, hash(s.val, h))) +function Base.hash(s::ElementarySymplectic, h::UInt) + return hash(Set([_ind(s); _dual_ind(s)]), hash(s.symbol, hash(s.val, h))) +end -LinearAlgebra.transpose(s::ElementarySymplectic{N}) where {N} = - ElementarySymplectic{N}(s.symbol, s.j, s.i, s.val) +function LinearAlgebra.transpose(s::ElementarySymplectic{N}) where {N} + return ElementarySymplectic{N}(s.symbol, s.j, s.i, s.val) +end -Base.inv(s::ElementarySymplectic{N}) where {N} = - ElementarySymplectic{N}(s.symbol, s.i, s.j, -s.val) +function Base.inv(s::ElementarySymplectic{N}) where {N} + return ElementarySymplectic{N}(s.symbol, s.i, s.j, -s.val) +end function matrix(s::ElementarySymplectic{N,T}) where {N,T} @assert iseven(N) From 3cdef72977f4b11cdb750c3915315c53df5c44f2 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 18:37:10 +0100 Subject: [PATCH 11/12] format aut_groups --- src/aut_groups/gersten_relations.jl | 30 +++++++++++++----- src/aut_groups/mcg.jl | 49 ++++++++++++++++++++++------- src/aut_groups/sautFn.jl | 16 +++++++--- src/aut_groups/symplectic_twists.jl | 36 ++++++++++++++------- src/aut_groups/transvections.jl | 21 ++++++++----- 5 files changed, 109 insertions(+), 43 deletions(-) diff --git a/src/aut_groups/gersten_relations.jl b/src/aut_groups/gersten_relations.jl index d91a8ef..00e04f5 100644 --- a/src/aut_groups/gersten_relations.jl +++ b/src/aut_groups/gersten_relations.jl @@ -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] S = [ϱ(i, j) for (i, j) in indexing] @@ -40,12 +40,17 @@ function _hexagonal_rule( return W(T[A[x], A[inv(y)], A[z]]) => W(T[A[z], A[w^-1], A[x]]) end -gersten_relations(n::Integer; commutative) = - gersten_relations(Word{UInt8}, n, commutative=commutative) +function gersten_relations(n::Integer; commutative) + return gersten_relations(Word{UInt8}, n; commutative = commutative) +end -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" - A = gersten_alphabet(n, commutative=commutative) + A = gersten_alphabet(n; commutative = commutative) @assert length(A) <= typemax(eltype(W)) "Type $W can not represent words over alphabet with $(length(A)) letters." rels = Pair{W,W}[] @@ -74,7 +79,10 @@ function gersten_relations(::Type{W}, n::Integer; commutative) where {W<:Abstrac for (i, j, k) in Iterators.product(1:n, 1:n, 1:n) if (i ≠ j && k ≠ i && k ≠ j) - push!(rels, _pentagonal_rule(W, A, ϱ(i, j)^-1, ϱ(j, k)^-1, ϱ(i, k)^-1)) + push!( + rels, + _pentagonal_rule(W, A, ϱ(i, j)^-1, ϱ(j, k)^-1, ϱ(i, k)^-1), + ) push!(rels, _pentagonal_rule(W, A, ϱ(i, j)^-1, ϱ(j, k), ϱ(i, k))) commutative && continue @@ -83,7 +91,10 @@ function gersten_relations(::Type{W}, n::Integer; commutative) where {W<:Abstrac push!(rels, _pentagonal_rule(W, A, ϱ(i, j), λ(j, k)^-1, ϱ(i, k))) # the same as above, but with ϱ ↔ λ: - push!(rels, _pentagonal_rule(W, A, λ(i, j)^-1, λ(j, k)^-1, λ(i, k)^-1)) + push!( + rels, + _pentagonal_rule(W, A, λ(i, j)^-1, λ(j, k)^-1, λ(i, k)^-1), + ) push!(rels, _pentagonal_rule(W, A, λ(i, j)^-1, λ(j, k), λ(i, k))) push!(rels, _pentagonal_rule(W, A, λ(i, j), ϱ(j, k), λ(i, k)^-1)) @@ -94,7 +105,10 @@ function gersten_relations(::Type{W}, n::Integer; commutative) where {W<:Abstrac if !commutative for (i, j) in Iterators.product(1:n, 1:n) 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)]]) push!(rels, w^2 => inv(w, A)^2) end diff --git a/src/aut_groups/mcg.jl b/src/aut_groups/mcg.jl index 1fc6286..cb10b96 100644 --- a/src/aut_groups/mcg.jl +++ b/src/aut_groups/mcg.jl @@ -17,7 +17,7 @@ function Base.show(io::IO, S::SurfaceGroup) end end -function SurfaceGroup(genus::Integer, boundaries::Integer, W=Word{Int16}) +function SurfaceGroup(genus::Integer, boundaries::Integer, W = Word{Int16}) @assert genus > 1 # The (confluent) rewriting systems comes from @@ -31,7 +31,15 @@ function SurfaceGroup(genus::Integer, boundaries::Integer, W=Word{Int16}) ltrs = String[] for i in 1:genus 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 Al = Alphabet(reverse!(ltrs)) @@ -51,9 +59,13 @@ function SurfaceGroup(genus::Integer, boundaries::Integer, W=Word{Int16}) comms = W(word) word_rels = [comms => one(comms)] - rws = let R = KnuthBendix.RewritingSystem(word_rels, KnuthBendix.Recursive(Al)) - KnuthBendix.IndexAutomaton(KnuthBendix.knuthbendix(R)) - end + rws = + let R = KnuthBendix.RewritingSystem( + word_rels, + KnuthBendix.Recursive(Al), + ) + KnuthBendix.IndexAutomaton(KnuthBendix.knuthbendix(R)) + end elseif boundaries == 1 word_rels = Pair{W,W}[] rws = let R = RewritingSystem(word_rels, KnuthBendix.LenLex(Al)) @@ -66,7 +78,13 @@ function SurfaceGroup(genus::Integer, boundaries::Integer, W=Word{Int16}) F = FreeGroup(Al) rels = [F(lhs) => F(rhs) for (lhs, rhs) in word_rels] - return SurfaceGroup(genus, boundaries, [Al[i] for i in 2:2:length(Al)], rels, rws) + return SurfaceGroup( + genus, + boundaries, + [Al[i] for i in 2:2:length(Al)], + rels, + rws, + ) end rewriting(S::SurfaceGroup) = S.rw @@ -75,17 +93,26 @@ relations(S::SurfaceGroup) = S.relations function symplectic_twists(π₁Σ::SurfaceGroup) g = genus(π₁Σ) - saut = SpecialAutomorphismGroup(FreeGroup(2g), max_rules=1000) + 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] - 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] return [Aij; Bij; mBij; Bii; mBii] end diff --git a/src/aut_groups/sautFn.jl b/src/aut_groups/sautFn.jl index b0805fa..f4fe6b4 100644 --- a/src/aut_groups/sautFn.jl +++ b/src/aut_groups/sautFn.jl @@ -1,10 +1,13 @@ include("transvections.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 - A, rels = gersten_relations(n, commutative=false) + A, rels = gersten_relations(n; commutative = false) S = [A[i] for i in 1:2:length(A)] max_rules = 1000 * n @@ -12,7 +15,10 @@ function SpecialAutomorphismGroup(F::FreeGroup; ordering=KnuthBendix.LenLex, kwa rws = Logging.with_logger(Logging.NullLogger()) do rws = KnuthBendix.RewritingSystem(rels, ordering(A)) # the rws is not confluent, let's suppress warning about it - KnuthBendix.knuthbendix(rws, KnuthBendix.Settings(; max_rules=max_rules, kwargs...)) + return KnuthBendix.knuthbendix( + rws, + KnuthBendix.Settings(; max_rules = max_rules, kwargs...), + ) end idxA = KnuthBendix.IndexAutomaton(rws) @@ -21,5 +27,5 @@ end function relations(G::AutomorphismGroup{<:FreeGroup}) n = length(alphabet(object(G))) ÷ 2 - return last(gersten_relations(n, commutative=false)) + return last(gersten_relations(n; commutative = false)) end diff --git a/src/aut_groups/symplectic_twists.jl b/src/aut_groups/symplectic_twists.jl index 7a48233..a04ac08 100644 --- a/src/aut_groups/symplectic_twists.jl +++ b/src/aut_groups/symplectic_twists.jl @@ -47,7 +47,15 @@ function Te_diagonal(λ::Groups.ΡΛ, ϱ::Groups.ΡΛ, i::Integer) return g 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(b₀, A) X = a₄ * a₅ * a₃ * a₄ # from Primer b₁ = inv(X, A) * a₀ * X # from Primer @@ -85,7 +93,8 @@ function Te(λ::ΡΛ, ϱ::ΡΛ, i, j) if mod(j - (i + 1), genus) == 0 return Te_diagonal(λ, ϱ, i) else - return inv(Te_lantern( + return inv( + Te_lantern( A, # Our notation: # Primer notation: inv(Ta(λ, i + 1), A), # b₀ @@ -94,7 +103,9 @@ function Te(λ::ΡΛ, ϱ::ΡΛ, i, j) inv(Te_diagonal(λ, ϱ, i), A), # a₃ inv(Tα(λ, i + 1), A), # a₄ inv(Te(λ, ϱ, i + 1, j), A), # a₅ - ), A) + ), + A, + ) end end @@ -105,7 +116,6 @@ Return the element of `G` which corresponds to shifting generators of the free g In the corresponding mapping class group this element acts by rotation of the surface anti-clockwise. """ function rotation_element(G::AutomorphismGroup{<:FreeGroup}) - A = alphabet(G) @assert iseven(ngens(object(G))) genus = ngens(object(G)) ÷ 2 @@ -140,7 +150,10 @@ function rotation_element(λ::ΡΛ, ϱ::ΡΛ) Ta(λ, i) * inv(Te_diagonal(λ, ϱ, i), A) - Ta(λ, i) * inv(Ta(λ, j) * Tα(λ, j), A)^6 * (Ta(λ, j) * Tα(λ, j) * z)^4 * c + return Ta(λ, i) * + inv(Ta(λ, j) * Tα(λ, j), A)^6 * + (Ta(λ, j) * Tα(λ, j) * z)^4 * + c end τ = (Ta(λ, 1) * Tα(λ, 1))^6 * prod(halftwists) @@ -148,7 +161,6 @@ function rotation_element(λ::ΡΛ, ϱ::ΡΛ) end function mcg_twists(G::AutomorphismGroup{<:FreeGroup}) - @assert iseven(ngens(object(G))) genus = ngens(object(G)) ÷ 2 @@ -178,7 +190,9 @@ struct SymplecticMappingClass{T,F} <: GSymbol f::F end -Base.:(==)(a::SymplecticMappingClass, b::SymplecticMappingClass) = a.autFn_word == b.autFn_word +function Base.:(==)(a::SymplecticMappingClass, b::SymplecticMappingClass) + return a.autFn_word == b.autFn_word +end Base.hash(a::SymplecticMappingClass, h::UInt) = hash(a.autFn_word, h) @@ -187,8 +201,8 @@ function SymplecticMappingClass( id::Symbol, i::Integer, j::Integer; - minus=false, - inverse=false + minus = false, + inverse = false, ) @assert i > 0 && j > 0 id === :A && @assert i ≠ j @@ -246,7 +260,7 @@ function Base.show(io::IO, smc::SymplecticMappingClass) else print(io, smc.id, subscriptify(smc.i), ".", subscriptify(smc.j)) end - smc.inv && print(io, "^-1") + return smc.inv && print(io, "^-1") end function Base.inv(m::SymplecticMappingClass) @@ -259,7 +273,7 @@ end function evaluate!( t::NTuple{N,T}, smc::SymplecticMappingClass, - tmp=nothing, + tmp = nothing, ) where {N,T} t = smc.f(t) for i in 1:N diff --git a/src/aut_groups/transvections.jl b/src/aut_groups/transvections.jl index 63c9717..04505d2 100644 --- a/src/aut_groups/transvections.jl +++ b/src/aut_groups/transvections.jl @@ -4,7 +4,7 @@ struct Transvection <: GSymbol j::UInt16 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 (:ϱ, :λ) return new(id, i, j, inv) end @@ -20,20 +20,23 @@ function Base.show(io::IO, t::Transvection) 'λ' end print(io, id, subscriptify(t.i), '.', subscriptify(t.j)) - t.inv && print(io, "^-1") + return t.inv && print(io, "^-1") end Base.inv(t::Transvection) = Transvection(t.id, t.i, t.j, !t.inv) -Base.:(==)(t::Transvection, s::Transvection) = - t.id === s.id && t.i == s.i && t.j == s.j && t.inv == s.inv +function Base.:(==)(t::Transvection, s::Transvection) + return t.id === s.id && t.i == s.i && t.j == s.j && t.inv == s.inv +end -Base.hash(t::Transvection, h::UInt) = hash(hash(t.id, hash(t.i)), hash(t.j, hash(t.inv, h))) +function Base.hash(t::Transvection, h::UInt) + return hash(hash(t.id, hash(t.i)), hash(t.j, hash(t.inv, h))) +end Base.@propagate_inbounds @inline function evaluate!( v::NTuple{T,N}, t::Transvection, - tmp=one(first(v)), + tmp = one(first(v)), ) where {T,N} i, j = t.i, t.j @assert 1 ≤ i ≤ length(v) && 1 ≤ j ≤ length(v) @@ -84,7 +87,7 @@ end function Base.show(io::IO, p::PermRightAut) print(io, 'σ') - join(io, (subscriptify(Int(i)) for i in p.perm)) + return join(io, (subscriptify(Int(i)) for i in p.perm)) end Base.inv(p::PermRightAut) = PermRightAut(invperm(p.perm)) @@ -92,4 +95,6 @@ Base.inv(p::PermRightAut) = PermRightAut(invperm(p.perm)) Base.:(==)(p::PermRightAut, q::PermRightAut) = p.perm == q.perm 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] +function evaluate!(v::NTuple{T,N}, p::PermRightAut, tmp = nothing) where {T,N} + return v[p.perm] +end From af3913d0856d0e5ce80b0d4bfc246eed791ae632 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 15 Mar 2023 19:07:14 +0100 Subject: [PATCH 12/12] more formatting --- .JuliaFormatter.toml | 1 + src/Groups.jl | 9 +++- src/abelianize.jl | 12 +++-- src/autgroups.jl | 47 +++++++++++++------ src/constructions/direct_power.jl | 58 +++++++++++++++-------- src/constructions/direct_product.jl | 68 ++++++++++++++++++--------- src/constructions/wreath_product.jl | 40 +++++++++------- src/hashing.jl | 8 +++- src/homomorphisms.jl | 13 ++++-- src/types.jl | 71 ++++++++++++++++------------- src/wl_ball.jl | 50 +++++++++++++------- 11 files changed, 245 insertions(+), 132 deletions(-) create mode 120000 .JuliaFormatter.toml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 120000 index 0000000..90107d8 --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1 @@ +../.JuliaFormatter.toml \ No newline at end of file diff --git a/src/Groups.jl b/src/Groups.jl index f34a7b7..96c7d09 100644 --- a/src/Groups.jl +++ b/src/Groups.jl @@ -14,7 +14,14 @@ import KnuthBendix: alphabet, ordering export MatrixGroups -export Alphabet, AutomorphismGroup, FreeGroup, FreeGroup, FPGroup, FPGroupElement, SpecialAutomorphismGroup, Homomorphism +export Alphabet, + AutomorphismGroup, + FreeGroup, + FreeGroup, + FPGroup, + FPGroupElement, + SpecialAutomorphismGroup, + Homomorphism export alphabet, evaluate, word, gens diff --git a/src/abelianize.jl b/src/abelianize.jl index 1ab92ee..1ad1588 100644 --- a/src/abelianize.jl +++ b/src/abelianize.jl @@ -1,7 +1,8 @@ function _abelianize( i::Integer, source::AutomorphismGroup{<:FreeGroup}, - target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T} + target::MatrixGroups.SpecialLinearGroup{N,T}, +) where {N,T} n = ngens(object(source)) @assert n == N aut = alphabet(source)[i] @@ -12,7 +13,7 @@ function _abelianize( eij = MatrixGroups.ElementaryMatrix{N}( aut.j, aut.i, - ifelse(aut.inv, -one(T), one(T)) + ifelse(aut.inv, -one(T), one(T)), ) k = alphabet(target)[eij] return word_type(target)([k]) @@ -24,7 +25,8 @@ end function _abelianize( i::Integer, 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)) @assert n == N g = alphabet(source)[i].autFn_word @@ -39,7 +41,7 @@ end function Groups._abelianize( i::Integer, source::AutomorphismGroup{<:Groups.SurfaceGroup}, - target::MatrixGroups.SymplecticGroup{N,T} + target::MatrixGroups.SymplecticGroup{N,T}, ) where {N,T} @assert iseven(N) As = alphabet(source) @@ -50,7 +52,7 @@ function Groups._abelianize( MatrixGroups.SpecialLinearGroup{2genus}(T) end - 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) Dict(MatrixGroups.matrix(g) => word(g) for g in union(S, inv.(S))) diff --git a/src/autgroups.jl b/src/autgroups.jl index c255b47..2d4ff18 100644 --- a/src/autgroups.jl +++ b/src/autgroups.jl @@ -1,5 +1,5 @@ function KnuthBendix.Alphabet(S::AbstractVector{<:GSymbol}) - S = unique!([S; inv.(S)]) + S = union(S, inv.(S)) inversions = [findfirst(==(inv(s)), S) for s in S] return Alphabet(S, inversions) end @@ -26,7 +26,10 @@ function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup}) return imf end -function Base.:(==)(g::A, h::A) where {A<:AbstractFPGroupElement{<:AutomorphismGroup}} +function Base.:(==)( + g::A, + h::A, +) where {A<:AbstractFPGroupElement{<:AutomorphismGroup}} @assert parent(g) === parent(h) if _isvalidhash(g) && _isvalidhash(h) @@ -79,32 +82,46 @@ end # eye-candy -Base.show(io::IO, ::Type{<:FPGroupElement{<:AutomorphismGroup{T}}}) where {T} = - print(io, "Automorphism{$T, …}") +function Base.show( + io::IO, + ::Type{<:FPGroupElement{<:AutomorphismGroup{T}}}, +) where {T} + return print(io, "Automorphism{$T, …}") +end -Base.show(io::IO, A::AutomorphismGroup) = print(io, "automorphism group of ", object(A)) +function Base.show(io::IO, A::AutomorphismGroup) + return print(io, "automorphism group of ", object(A)) +end -function Base.show(io::IO, ::MIME"text/plain", a::AbstractFPGroupElement{<:AutomorphismGroup}) +function Base.show( + io::IO, + ::MIME"text/plain", + a::AbstractFPGroupElement{<:AutomorphismGroup}, +) println(io, " ┌ $(a):") d = domain(a) im = evaluate(a) for (x, imx) in zip(d, im[1:end-1]) println(io, " │ $x ↦ $imx") end - println(io, " └ $(last(d)) ↦ $(last(im))") + return println(io, " └ $(last(d)) ↦ $(last(im))") end ## Automorphism Evaluation -domain(f::AbstractFPGroupElement{<:AutomorphismGroup}) = deepcopy(parent(f).domain) +function domain(f::AbstractFPGroupElement{<:AutomorphismGroup}) + return deepcopy(parent(f).domain) +end # tuple(gens(object(parent(f)))...) -evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f) +function evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) + return evaluate!(domain(f), f) +end function evaluate!( t::NTuple{N,T}, f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}}, - tmp=one(first(t)), + tmp = one(first(t)), ) where {N,T<:FPGroupElement} A = alphabet(f) for idx in word(f) @@ -113,7 +130,11 @@ function evaluate!( return t 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)))`") +function 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)))`", + ) +end # forward evaluate by substitution @@ -135,13 +156,13 @@ function LettersMap(a::FPGroupElement{<:AutomorphismGroup}) # (trusting it's a set of generators that define a) @assert length(dom) == length(img) - indices_map = Dict(A[A[fl]] => word(im) for (fl, im) in zip(first_letters, img)) + indices_map = + Dict(A[A[fl]] => word(im) for (fl, im) in zip(first_letters, img)) # inverses of generators are dealt lazily in getindex return LettersMap(indices_map, A) end - function Base.getindex(lm::LettersMap, i::Integer) # here i is an index of an alphabet @boundscheck 1 ≤ i ≤ length(lm.A) diff --git a/src/constructions/direct_power.jl b/src/constructions/direct_power.jl index 25ffb4f..7e69b68 100644 --- a/src/constructions/direct_power.jl +++ b/src/constructions/direct_power.jl @@ -12,25 +12,29 @@ struct DirectPowerElement{GEl,N,Gr<:GroupsCore.Group} <: GroupsCore.GroupElement parent::DirectPower{Gr,N,GEl} end -DirectPowerElement( +function DirectPowerElement( elts::AbstractVector{<:GroupsCore.GroupElement}, G::DirectPower, -) = DirectPowerElement(ntuple(i -> elts[i], _nfold(G)), G) +) + return DirectPowerElement(ntuple(i -> elts[i], _nfold(G)), G) +end _nfold(::DirectPower{Gr,N}) where {Gr,N} = N -Base.one(G::DirectPower) = - DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G) +function Base.one(G::DirectPower) + return DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G) +end -Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl} = - DirectPowerElement{GEl,N,Gr} +function Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl} + return DirectPowerElement{GEl,N,Gr} +end function Base.iterate(G::DirectPower) itr = Iterators.ProductIterator(ntuple(i -> G.group, _nfold(G))) res = iterate(itr) @assert res !== nothing elt = DirectPowerElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.iterate(G::DirectPower, state) @@ -38,7 +42,7 @@ function Base.iterate(G::DirectPower, state) res = iterate(itr, st) res === nothing && return nothing elt = DirectPowerElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N} @@ -49,8 +53,9 @@ end Base.size(G::DirectPower) = ntuple(_ -> length(G.group), _nfold(G)) -GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} = - convert(I, order(I, G.group)^_nfold(G)) +function GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} + return convert(I, order(I, G.group)^_nfold(G)) +end GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group) @@ -83,13 +88,18 @@ end GroupsCore.parent(g::DirectPowerElement) = g.parent -Base.:(==)(g::DirectPowerElement, h::DirectPowerElement) = - (parent(g) === parent(h) && g.elts == h.elts) +function Base.:(==)(g::DirectPowerElement, h::DirectPowerElement) + return (parent(g) === parent(h) && g.elts == h.elts) +end Base.hash(g::DirectPowerElement, h::UInt) = hash(g.elts, hash(parent(g), h)) -Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict) = - DirectPowerElement(Base.deepcopy_internal(g.elts, stackdict), parent(g)) +function Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict) + return DirectPowerElement( + Base.deepcopy_internal(g.elts, stackdict), + parent(g), + ) +end Base.inv(g::DirectPowerElement) = DirectPowerElement(inv.(g.elts), parent(g)) @@ -98,15 +108,25 @@ function Base.:(*)(g::DirectPowerElement, h::DirectPowerElement) return DirectPowerElement(g.elts .* h.elts, parent(g)) end -GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} = - convert(I, reduce(lcm, (order(I, h) for h in g.elts), init=one(I))) +function GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} + return convert(I, reduce(lcm, (order(I, h) for h in g.elts); init = one(I))) +end Base.isone(g::DirectPowerElement) = all(isone, g.elts) function Base.show(io::IO, G::DirectPower) n = _nfold(G) nn = n == 1 ? "1-st" : n == 2 ? "2-nd" : n == 3 ? "3-rd" : "$n-th" - print(io, "Direct $(nn) power of $(G.group)") + return print(io, "Direct $(nn) power of $(G.group)") +end +function Base.show(io::IO, g::DirectPowerElement) + return print(io, "( ", join(g.elts, ", "), " )") +end + +# convienience: +Base.@propagate_inbounds function Base.getindex( + g::DirectPowerElement, + i::Integer, +) + return g.elts[i] end -Base.show(io::IO, g::DirectPowerElement) = - print(io, "( ", join(g.elts, ", "), " )") diff --git a/src/constructions/direct_product.jl b/src/constructions/direct_product.jl index 0ea6dfe..a522f6e 100644 --- a/src/constructions/direct_product.jl +++ b/src/constructions/direct_product.jl @@ -14,18 +14,22 @@ end DirectProductElement(g, h, G::DirectProduct) = DirectProduct((g, h), G) -Base.one(G::DirectProduct) = - DirectProductElement((one(G.first), one(G.last)), G) +function Base.one(G::DirectProduct) + return DirectProductElement((one(G.first), one(G.last)), G) +end -Base.eltype(::Type{<:DirectProduct{Gt,Ht,GEl,HEl}}) where {Gt,Ht,GEl,HEl} = - DirectProductElement{GEl,HEl,Gt,Ht} +function Base.eltype( + ::Type{<:DirectProduct{Gt,Ht,GEl,HEl}}, +) where {Gt,Ht,GEl,HEl} + return DirectProductElement{GEl,HEl,Gt,Ht} +end function Base.iterate(G::DirectProduct) itr = Iterators.product(G.first, G.last) res = iterate(itr) @assert res !== nothing elt = DirectProductElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.iterate(G::DirectProduct, state) @@ -33,7 +37,7 @@ function Base.iterate(G::DirectProduct, state) res = iterate(itr, st) res === nothing && return nothing elt = DirectProductElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.IteratorSize(::Type{<:DirectProduct{Gt,Ht}}) where {Gt,Ht} @@ -50,15 +54,18 @@ end Base.size(G::DirectProduct) = (length(G.first), length(G.last)) -GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer} = - convert(I, order(I, G.first) * order(I, G.last)) +function GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer} + return convert(I, order(I, G.first) * order(I, G.last)) +end GroupsCore.ngens(G::DirectProduct) = ngens(G.first) + ngens(G.last) function GroupsCore.gens(G::DirectProduct) - gens_first = [DirectProductElement((g, one(G.last)), G) for g in gens(G.first)] + gens_first = + [DirectProductElement((g, one(G.last)), G) for g in gens(G.first)] - gens_last = [DirectProductElement((one(G.first), g), G) for g in gens(G.last)] + gens_last = + [DirectProductElement((one(G.first), g), G) for g in gens(G.last)] return [gens_first; gens_last] end @@ -75,28 +82,45 @@ end GroupsCore.parent(g::DirectProductElement) = g.parent -Base.:(==)(g::DirectProductElement, h::DirectProductElement) = - (parent(g) === parent(h) && g.elts == h.elts) +function Base.:(==)(g::DirectProductElement, h::DirectProductElement) + return (parent(g) === parent(h) && g.elts == h.elts) +end Base.hash(g::DirectProductElement, h::UInt) = hash(g.elts, hash(parent(g), h)) -Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict) = - DirectProductElement(Base.deepcopy_internal(g.elts, stackdict), parent(g)) +function Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict) + return DirectProductElement( + Base.deepcopy_internal(g.elts, stackdict), + parent(g), + ) +end -Base.inv(g::DirectProductElement) = - DirectProductElement(inv.(g.elts), parent(g)) +function Base.inv(g::DirectProductElement) + return DirectProductElement(inv.(g.elts), parent(g)) +end function Base.:(*)(g::DirectProductElement, h::DirectProductElement) @assert parent(g) === parent(h) return DirectProductElement(g.elts .* h.elts, parent(g)) end -GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer} = - convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts)))) +function GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer} + return convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts)))) +end Base.isone(g::DirectProductElement) = all(isone, g.elts) -Base.show(io::IO, G::DirectProduct) = - print(io, "Direct product of $(G.first) and $(G.last)") -Base.show(io::IO, g::DirectProductElement) = - print(io, "( $(join(g.elts, ",")) )") +function Base.show(io::IO, G::DirectProduct) + return print(io, "Direct product of $(G.first) and $(G.last)") +end +function Base.show(io::IO, g::DirectProductElement) + return print(io, "( $(join(g.elts, ",")) )") +end + +# convienience: +Base.@propagate_inbounds function Base.getindex( + g::DirectProductElement, + i::Integer, +) + return g.elts[i] +end diff --git a/src/constructions/wreath_product.jl b/src/constructions/wreath_product.jl index aa61198..bb4fa57 100644 --- a/src/constructions/wreath_product.jl +++ b/src/constructions/wreath_product.jl @@ -1,4 +1,5 @@ -import PermutationGroups: AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup +import PermutationGroups: + AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup """ WreathProduct(G::Group, P::AbstractPermutationGroup) <: Group @@ -38,21 +39,22 @@ struct WreathProductElement{ p::AbstractPerm, W::WreathProduct, ) - new{typeof(n),typeof(p),typeof(W)}(n, p, W) + return new{typeof(n),typeof(p),typeof(W)}(n, p, W) end end Base.one(W::WreathProduct) = WreathProductElement(one(W.N), one(W.P), W) -Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} = - WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}} +function Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} + return WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}} +end function Base.iterate(G::WreathProduct) itr = Iterators.product(G.N, G.P) res = iterate(itr) @assert res !== nothing elt = WreathProductElement(first(res)..., G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.iterate(G::WreathProduct, state) @@ -60,7 +62,7 @@ function Base.iterate(G::WreathProduct, state) res = iterate(itr, st) res === nothing && return nothing elt = WreathProductElement(first(res)..., G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.IteratorSize(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} @@ -78,8 +80,9 @@ end Base.size(G::WreathProduct) = (length(G.N), length(G.P)) -GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer} = - convert(I, order(I, G.N) * order(I, G.P)) +function GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer} + return convert(I, order(I, G.N) * order(I, G.P)) +end function GroupsCore.gens(G::WreathProduct) N_gens = [WreathProductElement(n, one(G.P), G) for n in gens(G.N)] @@ -93,18 +96,19 @@ function Base.rand( rng::Random.AbstractRNG, rs::Random.SamplerTrivial{<:WreathProduct}, ) - G = rs[] return WreathProductElement(rand(rng, G.N), rand(rng, G.P), G) end GroupsCore.parent(g::WreathProductElement) = g.parent -Base.:(==)(g::WreathProductElement, h::WreathProductElement) = - parent(g) === parent(h) && g.n == h.n && g.p == h.p +function Base.:(==)(g::WreathProductElement, h::WreathProductElement) + return parent(g) === parent(h) && g.n == h.n && g.p == h.p +end -Base.hash(g::WreathProductElement, h::UInt) = - hash(g.n, hash(g.p, hash(g.parent, h))) +function Base.hash(g::WreathProductElement, h::UInt) + return hash(g.n, hash(g.p, hash(g.parent, h))) +end function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict) return WreathProductElement( @@ -114,8 +118,9 @@ function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict) ) end -_act(p::AbstractPerm, n::DirectPowerElement) = - DirectPowerElement(n.elts^p, parent(n)) +function _act(p::AbstractPerm, n::DirectPowerElement) + return DirectPowerElement(n.elts^p, parent(n)) +end function Base.inv(g::WreathProductElement) pinv = inv(g.p) @@ -129,8 +134,9 @@ end Base.isone(g::WreathProductElement) = isone(g.n) && isone(g.p) -Base.show(io::IO, G::WreathProduct) = - print(io, "Wreath product of $(G.N.group) by $(G.P)") +function Base.show(io::IO, G::WreathProduct) + return print(io, "Wreath product of $(G.N.group) by $(G.P)") +end Base.show(io::IO, g::WreathProductElement) = print(io, "( $(g.n)≀$(g.p) )") Base.copy(g::WreathProductElement) = WreathProductElement(g.n, g.p, parent(g)) diff --git a/src/hashing.jl b/src/hashing.jl index ed729b1..5c33019 100644 --- a/src/hashing.jl +++ b/src/hashing.jl @@ -20,8 +20,12 @@ _isvalidhash(g::AbstractFPGroupElement) = bitget(g.savedhash, 1) _setnormalform(h::UInt, v::Bool) = bitset(h, v, 0) _setvalidhash(h::UInt, v::Bool) = bitset(h, v, 1) -_setnormalform!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v) -_setvalidhash!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setvalidhash(g.savedhash, v) +function _setnormalform!(g::AbstractFPGroupElement, v::Bool) + return g.savedhash = _setnormalform(g.savedhash, v) +end +function _setvalidhash!(g::AbstractFPGroupElement, v::Bool) + return g.savedhash = _setvalidhash(g.savedhash, v) +end # To update hash use this internal method, possibly only after computing the # normal form of `g`: diff --git a/src/homomorphisms.jl b/src/homomorphisms.jl index d045d47..09e9355 100644 --- a/src/homomorphisms.jl +++ b/src/homomorphisms.jl @@ -67,11 +67,13 @@ struct Homomorphism{Gr1,Gr2,I,W} f, source::AbstractFPGroup, target::AbstractFPGroup; - check=true + check = true, ) A = alphabet(source) - dct = Dict(i => convert(word_type(target), f(i, source, target)) - for i in 1:length(A)) + dct = Dict( + i => convert(word_type(target), f(i, source, target)) for + i in 1:length(A) + ) I = eltype(word_type(source)) W = word_type(target) hom = new{typeof(source),typeof(target),I,W}(dct, source, target) @@ -79,7 +81,6 @@ struct Homomorphism{Gr1,Gr2,I,W} if check @assert hom(one(source)) == one(target) for x in gens(source) - @assert hom(x^-1) == hom(x)^-1 for y in gens(source) @@ -111,4 +112,6 @@ function (h::Homomorphism)(g::AbstractFPGroupElement) return h.target(w) end -Base.show(io::IO, h::Homomorphism) = print(io, "Homomorphism\n from : $(h.source)\n to : $(h.target)") +function Base.show(io::IO, h::Homomorphism) + return print(io, "Homomorphism\n from : $(h.source)\n to : $(h.target)") +end diff --git a/src/types.jl b/src/types.jl index bbe332f..336b570 100644 --- a/src/types.jl +++ b/src/types.jl @@ -42,10 +42,7 @@ KnuthBendix.alphabet(G::AbstractFPGroup) = alphabet(ordering(G)) Base.@propagate_inbounds function (G::AbstractFPGroup)( word::AbstractVector{<:Integer}, ) - @boundscheck @assert all( - l -> 1 <= l <= length(alphabet(G)), - word, - ) + @boundscheck @assert all(l -> 1 <= l <= length(alphabet(G)), word) return FPGroupElement(word_type(G)(word), G) end @@ -53,8 +50,9 @@ end Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G) -Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} = - FPGroupElement{FPG,word_type(FPG)} +function Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} + return FPGroupElement{FPG,word_type(FPG)} +end include("iteration.jl") @@ -65,8 +63,9 @@ function GroupsCore.gens(G::AbstractFPGroup, i::Integer) l = alphabet(G)[G.gens[i]] return FPGroupElement(word_type(G)([l]), G) end -GroupsCore.gens(G::AbstractFPGroup) = - [gens(G, i) for i in 1:GroupsCore.ngens(G)] +function GroupsCore.gens(G::AbstractFPGroup) + return [gens(G, i) for i in 1:GroupsCore.ngens(G)] +end # TODO: ProductReplacementAlgorithm function Base.rand( @@ -79,9 +78,11 @@ function Base.rand( return FPGroupElement(word_type(G)(rand(1:nletters, l)), G) end -Base.isfinite(::AbstractFPGroup) = ( - @warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false -) +function Base.isfinite(::AbstractFPGroup) + return ( + @warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false + ) +end ## FPGroupElement @@ -93,18 +94,22 @@ mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <: savedhash::UInt parent::Gr - FPGroupElement( + function FPGroupElement( word::W, G::AbstractFPGroup, - hash::UInt=UInt(0), - ) where {W<:AbstractWord} = new{typeof(G),W}(word, hash, G) + hash::UInt = UInt(0), + ) where {W<:AbstractWord} + return new{typeof(G),W}(word, hash, G) + end - FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} = - new{Gr,W}(word, UInt(0), G) + function FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} + return new{Gr,W}(word, UInt(0), G) + end end -Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr} = - print(io, FPGroupElement, "{$Gr, …}") +function Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr} + return print(io, FPGroupElement, "{$Gr, …}") +end word(f::AbstractFPGroupElement) = f.word @@ -142,11 +147,12 @@ function Base.:(*)(g::GEl, h::GEl) where {GEl<:AbstractFPGroupElement} return GEl(word(g) * word(h), parent(g)) end -GroupsCore.isfiniteorder(g::AbstractFPGroupElement) = - isone(g) ? true : - ( +function GroupsCore.isfiniteorder(g::AbstractFPGroupElement) + return isone(g) ? true : + ( @warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false ) +end # additional methods: Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g))) @@ -167,9 +173,7 @@ end FreeGroup(gens, A::Alphabet) = FreeGroup(gens, KnuthBendix.LenLex(A)) function FreeGroup(A::Alphabet) - @boundscheck @assert all( - KnuthBendix.hasinverse(l, A) for l in A - ) + @boundscheck @assert all(KnuthBendix.hasinverse(l, A) for l in A) gens = Vector{eltype(A)}() invs = Vector{eltype(A)}() for l in A @@ -193,8 +197,9 @@ function FreeGroup(n::Integer) return FreeGroup(symbols[1:2:2n], Alphabet(symbols, inverses)) end -Base.show(io::IO, F::FreeGroup) = - print(io, "free group on $(ngens(F)) generators") +function Base.show(io::IO, F::FreeGroup) + return print(io, "free group on $(ngens(F)) generators") +end # mandatory methods: KnuthBendix.ordering(F::FreeGroup) = F.ordering @@ -205,8 +210,9 @@ relations(F::FreeGroup) = Pair{eltype(F),eltype(F)}[] # these are mathematically correct Base.isfinite(::FreeGroup) = false -GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) = - isone(g) ? true : false +function GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) + return isone(g) ? true : false +end ## FP Groups @@ -222,8 +228,8 @@ rewriting(G::FPGroup) = G.rw function FPGroup( G::AbstractFPGroup, rels::AbstractVector{<:Pair{GEl,GEl}}; - ordering=KnuthBendix.ordering(G), - kwargs... + ordering = KnuthBendix.ordering(G), + kwargs..., ) where {GEl<:FPGroupElement} for (lhs, rhs) in rels @assert parent(lhs) === parent(rhs) === G @@ -253,8 +259,9 @@ function Base.show(io::IO, G::FPGroup) return print(io, " ⟩") end -Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T} = - print(io, FPGroup, "{$T, …}") +function Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T} + return print(io, FPGroup, "{$T, …}") +end ## GSymbol aka letter of alphabet diff --git a/src/wl_ball.jl b/src/wl_ball.jl index 0c52080..ae8db7d 100644 --- a/src/wl_ball.jl +++ b/src/wl_ball.jl @@ -8,22 +8,40 @@ radius and multiplication operation to be used. """ function wlmetric_ball( S::AbstractVector{T}, - center::T=one(first(S)); - radius=2, - op=*, - threading=true + 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) + 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} +function wlmetric_ball_serial( + S::AbstractVector{T}, + center::T = one(first(S)); + radius = 2, + op = *, +) where {T} @assert radius >= 1 - old = union!([center], [center * s for s in S]) - return _wlmetric_ball(S, old, radius, op, collect, unique!) + old = union!(OrderedSet([center]), [center * s for s in S]) + sizes = [1, length(old)] + for _ in 2:radius + new = collect( + op(o, s) for o in @view(old.dict.keys[sizes[end-1]:end]) for s in S + ) + union!(old, new) + push!(sizes, length(old)) + end + return old.dict.keys, sizes[2: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 old = union!([center], [center * s for s in S]) return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique) @@ -31,12 +49,13 @@ end function _wlmetric_ball(S, old, radius, op, collect, unique) sizes = [1, length(old)] - for r in 2:radius - old = let old = old, S = S, + for _ in 2:radius + old = let old = old, S = S new = collect( - (g = op(o, s); normalform!(g); hash(g); g) - # normalform! and hash are to make assure thread-safety of produced elts - for o in @view(old[sizes[end-1]:end]) for s in S + (g = op(o, s); + normalform!(g); + hash(g); + g) for o in @view(old[sizes[end-1]:end]) for s in S ) append!(old, new) @@ -46,4 +65,3 @@ function _wlmetric_ball(S, old, radius, op, collect, unique) end return old, sizes[2:end] end -