From 711988b98a47fa710afb4fa61f64fefc20d95eee Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Sun, 11 Apr 2021 18:44:03 +0200 Subject: [PATCH] sort out imports + first adjustments to Group Interface --- src/AutGroup.jl | 20 ++++++++++---------- src/FPGroups.jl | 6 +++--- src/FreeGroup.jl | 6 +++--- src/Groups.jl | 29 ++++++++--------------------- src/arithmetic.jl | 14 +++++++------- src/fallbacks.jl | 16 ---------------- src/findreplace.jl | 23 ++++++++++++----------- src/freereduce.jl | 2 +- src/hashing.jl | 4 ++-- src/symbols.jl | 2 +- src/types.jl | 13 ++++++++++--- src/words.jl | 2 +- test/AutGroup-tests.jl | 6 ++++-- test/FreeGroup-tests.jl | 4 ++-- test/runtests.jl | 5 +++-- test/symmetric.jl | 31 +++++++++++++++++++++++++++++++ 16 files changed, 98 insertions(+), 85 deletions(-) delete mode 100644 src/fallbacks.jl create mode 100644 test/symmetric.jl diff --git a/src/AutGroup.jl b/src/AutGroup.jl index 1ce4b00..901a616 100644 --- a/src/AutGroup.jl +++ b/src/AutGroup.jl @@ -20,7 +20,7 @@ struct FlipAut end struct PermAut - perm::Generic.Perm{Int8} + perm::AbstractAlgebra.Generic.Perm{Int8} end struct Identity end @@ -66,7 +66,7 @@ function flip(i::Integer, pow::Integer=1) return AutSymbol(id, 1, FlipAut(i)) end -function AutSymbol(p::Generic.Perm, pow::Integer=1) +function AutSymbol(p::AbstractAlgebra.Generic.Perm, pow::Integer=1) if pow != 1 p = p^pow end @@ -81,7 +81,7 @@ end ϱ(i::Integer, j::Integer, pow::Integer=1) = transvection_R(i, j, pow) λ(i::Integer, j::Integer, pow::Integer=1) = transvection_L(i, j, pow) ε(i::Integer, pow::Integer=1) = flip(i, pow) -σ(v::Generic.Perm, pow::Integer=1) = AutSymbol(v, pow) +σ(v::AbstractAlgebra.Generic.Perm, pow::Integer=1) = AutSymbol(v, pow) function change_pow(s::AutSymbol, n::Integer) iszero(n) && id_autsymbol() @@ -123,8 +123,8 @@ mutable struct Automorphism{N} <: GWord{AutSymbol} end end -elem_type(::Type{AutGroup{N}}) where N = Automorphism{N} -parent_type(::Type{Automorphism{N}}) where N = AutGroup{N} +Base.eltype(::Type{AutGroup{N}}) where N = Automorphism{N} +GroupsCore.parent_type(::Type{Automorphism{N}}) where N = AutGroup{N} function AutGroup(G::FreeGroup; special=false) S = AutSymbol[] @@ -140,7 +140,7 @@ function AutGroup(G::FreeGroup; special=false) if !special flips = [ε(i) for i in 1:n] - syms = [σ(p) for p in SymmetricGroup(Int8(n))][2:end] + syms = [σ(p) for p in AbstractAlgebra.SymmetricGroup(Int8(n))][2:end] append!(S, [flips; syms]) end @@ -238,19 +238,19 @@ function compute_images(g::Automorphism) return images end -function (==)(g::Automorphism{N}, h::Automorphism{N}) where N +function Base.:(==)(g::Automorphism{N}, h::Automorphism{N}) where N syllables(g) == syllables(h) && return true img_computed, imh_computed = false, false if ismodified(g) img = compute_images(g) # sets modified bit - hash(g, images=img) + hash(g; images=img) img_computed = true end if ismodified(h) imh = compute_images(h) # sets modified bit - hash(h, images=imh) + hash(h; images=imh) imh_computed = true end @@ -282,7 +282,7 @@ end # String I/O # -function show(io::IO, G::AutGroup) +function Base.show(io::IO, G::AutGroup) print(io, "Automorphism Group of $(G.objectGroup)\n") print(io, "Generated by $(gens(G))") end diff --git a/src/FPGroups.jl b/src/FPGroups.jl index ff25389..d7c909c 100644 --- a/src/FPGroups.jl +++ b/src/FPGroups.jl @@ -29,8 +29,8 @@ export FPGroupElem, FPGroup # Type and parent object methods # -AbstractAlgebra.elem_type(::Type{FPGroup}) = FPGroupElem -AbstractAlgebra.parent_type(::Type{FPGroupElem}) = FPGroup +Base.eltype(::Type{FPGroup}) = FPGroupElem +GroupsCore.parent_type(::Type{FPGroupElem}) = FPGroup ############################################################################### # @@ -76,7 +76,7 @@ end # String I/O # -function show(io::IO, G::FPGroup) +function Base.show(io::IO, G::FPGroup) print(io, "FPgroup on $(length(G.gens)) generators ") strrels = join(G.rels, ", ") if length(strrels) > 200 diff --git a/src/FreeGroup.jl b/src/FreeGroup.jl index 9800d62..de1fab5 100644 --- a/src/FreeGroup.jl +++ b/src/FreeGroup.jl @@ -27,8 +27,8 @@ export FreeGroupElem, FreeGroup # Type and parent object methods # -AbstractAlgebra.elem_type(::Type{FreeGroup}) = FreeGroupElem -AbstractAlgebra.parent_type(::Type{FreeGroupElem}) = FreeGroup +Base.eltype(::Type{FreeGroup}) = FreeGroupElem +GroupsCore.parent_type(::Type{FreeGroupElem}) = FreeGroup ############################################################################### # @@ -67,7 +67,7 @@ end # String I/O # -function show(io::IO, G::FreeGroup) +function Base.show(io::IO, G::FreeGroup) print(io, "Free group on $(length(G.gens)) generators: ") join(io, G.gens, ", ") end diff --git a/src/Groups.jl b/src/Groups.jl index 7201de7..0789323 100644 --- a/src/Groups.jl +++ b/src/Groups.jl @@ -1,19 +1,11 @@ module Groups -using AbstractAlgebra -import AbstractAlgebra: Group, GroupElem, Ring -import AbstractAlgebra: parent, parent_type, elem_type -import AbstractAlgebra: order, gens, matrix_repr - -import Base: length, ==, hash, show, convert, eltype, iterate -import Base: inv, reduce, *, ^, power_by_squaring -import Base: findfirst, findnext, findlast, findprev, replace -import Base: deepcopy_internal - using GroupsCore using LinearAlgebra using ThreadsX +import AbstractAlgebra + export gens, FreeGroup, Aut, SAut include("types.jl") @@ -23,7 +15,6 @@ include("FPGroups.jl") include("AutGroup.jl") include("symbols.jl") -include("fallbacks.jl") include("words.jl") include("hashing.jl") include("freereduce.jl") @@ -56,11 +47,7 @@ end # Misc # -""" - gens(G::AbstractFPGroups) -Return vector of generators of `G`, as its elements. -""" -AbstractAlgebra.gens(G::AbstractFPGroup) = G.(G.gens) +GroupsCore.gens(G::AbstractFPGroup) = G.(G.gens) """ wlmetric_ball(S::AbstractVector{<:GroupElem} @@ -74,7 +61,7 @@ function wlmetric_ball_serial( S::AbstractVector{T}; radius = 2, op = *, -) where {T<:Union{GroupElem,NCRingElem}} +) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}} old = unique!([one(first(S)), S...]) sizes = [1, length(old)] for i = 2:radius @@ -91,7 +78,7 @@ function wlmetric_ball_thr( S::AbstractVector{T}; radius = 2, op = *, -) where {T<:Union{GroupElem,NCRingElem}} +) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}} old = unique!([one(first(S)), S...]) sizes = [1, length(old)] for r = 2:radius @@ -114,7 +101,7 @@ function wlmetric_ball_serial( center::T; radius = 2, op = *, -) where {T<:Union{GroupElem,NCRingElem}} +) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}} E, sizes = wlmetric_ball_serial(S, radius = radius, op = op) isone(center) && return E, sizes return c .* E, sizes @@ -125,7 +112,7 @@ function wlmetric_ball_thr( center::T; radius = 2, op = *, -) where {T<:Union{GroupElem,NCRingElem}} +) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}} E, sizes = wlmetric_ball_thr(S, radius = radius, op = op) isone(center) && return E, sizes return c .* E, sizes @@ -137,7 +124,7 @@ function wlmetric_ball( radius = 2, op = *, threading = true, -) where {T<:Union{GroupElem,NCRingElem}} +) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}} threading && return wlmetric_ball_thr(S, center, radius = radius, op = op) return return wlmetric_ball_serial(S, center, radius = radius, op = op) end diff --git a/src/arithmetic.jl b/src/arithmetic.jl index f84527d..59ac04a 100644 --- a/src/arithmetic.jl +++ b/src/arithmetic.jl @@ -55,15 +55,15 @@ lmul!(out::T, v::T) where T<:GWord = freereduce!(prepend!(out, v)) lmul!(out::T, x::T, y::T) where T <: GWord = rmul!(out, y, x) -AbstractAlgebra.mul!(out::T, x::T, y::T) where T <: GWord = rmul!(out, x, y) +GroupsCore.mul!(out::T, x::T, y::T) where T <: GWord = rmul!(out, x, y) -(*)(W::GW, Z::GW) where GW <: GWord = rmul!(deepcopy(W), W, Z) -(*)(W::GWord, s::GSymbol) = freereduce!(push!(deepcopy(W), s)) -(*)(s::GSymbol, W::GWord) = freereduce!(pushfirst!(deepcopy(W), s)) +Base.:(*)(W::GW, Z::GW) where GW <: GWord = rmul!(deepcopy(W), W, Z) +Base.:(*)(W::GWord, s::GSymbol) = freereduce!(push!(deepcopy(W), s)) +Base.:(*)(s::GSymbol, W::GWord) = freereduce!(pushfirst!(deepcopy(W), s)) -function power_by_squaring(W::GWord, p::Integer) +function Base.power_by_squaring(W::GWord, p::Integer) if p < 0 - return power_by_squaring(inv(W), -p) + return Base.power_by_squaring(inv(W), -p) elseif p == 0 return one(W) elseif p == 1 @@ -90,4 +90,4 @@ function power_by_squaring(W::GWord, p::Integer) return freereduce!(Z) end -(^)(x::GWord, n::Integer) = power_by_squaring(x,n) +Base.:(^)(x::GWord, n::Integer) = Base.power_by_squaring(x,n) diff --git a/src/fallbacks.jl b/src/fallbacks.jl deleted file mode 100644 index 8fccc98..0000000 --- a/src/fallbacks.jl +++ /dev/null @@ -1,16 +0,0 @@ -# workarounds -Base.one(G::Generic.SymmetricGroup) = Generic.Perm(G.n) - -# fallback definitions -# note: the user should implement those on type, when possible -Base.eltype(w::GW) where GW<:GWord = eltype(GW) -AbstractAlgebra.elem_type(G::Gr) where Gr <:AbstractFPGroup = elem_type(Gr) - -AbstractAlgebra.parent_type(g::Gw) where Gw <:GWord = parent_type(parent(Gr)) - -function Base.one(G::Gr) where Gr <: AbstractFPGroup - El = elem_type(G) - id = El(eltype(El)[]) - id.parent = G - return id -end diff --git a/src/findreplace.jl b/src/findreplace.jl index 50fc358..fe59ee4 100644 --- a/src/findreplace.jl +++ b/src/findreplace.jl @@ -28,10 +28,11 @@ function issubword(z::GWord, w::GWord, sindex::Integer) return true end -"""doc +""" + Find the first syllable index k>=i such that Z < syllables(W)[k:k+syllablelength(Z)-1] """ -function findnext(subword::GWord, word::GWord, start::Integer) +function Base.findnext(subword::GWord, word::GWord, start::Integer) @boundscheck 1 ≤ start ≤ syllablelength(word) || throw(BoundsError(word, start)) isempty(subword) && return start stop = syllablelength(word) - syllablelength(subword) +1 @@ -42,7 +43,7 @@ function findnext(subword::GWord, word::GWord, start::Integer) return nothing end -function findnext(s::FreeSymbol, word::GWord, start::Integer) +function Base.findnext(s::FreeSymbol, word::GWord, start::Integer) @boundscheck 1 ≤ start ≤ syllablelength(word) || throw(BoundsError(word, start)) isone(s) && return start stop = syllablelength(word) @@ -53,7 +54,7 @@ function findnext(s::FreeSymbol, word::GWord, start::Integer) return nothing end -function findprev(subword::GWord, word::GWord, start::Integer) +function Base.findprev(subword::GWord, word::GWord, start::Integer) @boundscheck 1 ≤ start ≤ syllablelength(word) || throw(BoundsError(word, start)) isempty(subword) && return start stop = 1 @@ -64,7 +65,7 @@ function findprev(subword::GWord, word::GWord, start::Integer) return nothing end -function findprev(s::FreeSymbol, word::GWord, start::Integer) +function Base.findprev(s::FreeSymbol, word::GWord, start::Integer) @boundscheck 1 ≤ start ≤ syllablelength(word) || throw(BoundsError(word, start)) isone(s) && return start stop = 1 @@ -75,11 +76,11 @@ function findprev(s::FreeSymbol, word::GWord, start::Integer) return nothing end -findfirst(subword::GWord, word::GWord) = findnext(subword, word, 1) -findlast(subword::GWord, word::GWord) = +Base.findfirst(subword::GWord, word::GWord) = findnext(subword, word, 1) +Base.findlast(subword::GWord, word::GWord) = findprev(subword, word, syllablelength(word)-syllablelength(subword)+1) -function replace!(out::GW, W::GW, lhs_rhs::Pair{GS, T}; count::Integer=typemax(Int)) where +function Base.replace!(out::GW, W::GW, lhs_rhs::Pair{GS, T}; count::Integer=typemax(Int)) where {GS<:GSymbol, T<:GWord, GW<:GWord} (count == 0 || isempty(W)) && return W count < 0 && throw(DomainError(count, "`count` must be non-negative.")) @@ -117,7 +118,7 @@ function replace!(out::GW, W::GW, lhs_rhs::Pair{GS, T}; count::Integer=typemax(I return freereduce!(out) end -function replace!(out::GW, W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where +function Base.replace!(out::GW, W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where {GW<:GWord, T <: GWord} (count == 0 || isempty(W)) && return W count < 0 && throw(DomainError(count, "`count` must be non-negative.")) @@ -164,12 +165,12 @@ function replace!(out::GW, W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(In return freereduce!(out) end -function replace(W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where +function Base.replace(W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where {GW<:GWord, T <: GWord} return replace!(one(W), W, lhs_rhs; count=count) end -function replace(W::GW, subst_dict::Dict{T,T}) where {GW<:GWord, T<:GWord} +function Base.replace(W::GW, subst_dict::Dict{T,T}) where {GW<:GWord, T<:GWord} out = W for toreplace in reverse!(sort!(collect(keys(subst_dict)), by=length)) replacement = subst_dict[toreplace] diff --git a/src/freereduce.jl b/src/freereduce.jl index 715bc30..017f829 100644 --- a/src/freereduce.jl +++ b/src/freereduce.jl @@ -46,4 +46,4 @@ performs reduction/simplification of a group element (word in generators). The default reduction is the reduction in the free group reduction. More specific procedures should be dispatched on `GWord`s type parameter. """ -reduce(w::GWord) = reduce!(deepcopy(w)) +Base.reduce(w::GWord) = reduce!(deepcopy(w)) diff --git a/src/hashing.jl b/src/hashing.jl index 316bd06..b9fd17f 100644 --- a/src/hashing.jl +++ b/src/hashing.jl @@ -9,7 +9,7 @@ function hash_internal(W::GWord) return hash(syllables(W), hash(typeof(W), h)) end -function hash(W::GWord, h::UInt=UInt(0); kwargs...) +function Base.hash(W::GWord, h::UInt=UInt(0); kwargs...) if ismodified(W) savehash!(W, hash_internal(W; kwargs...)) unsetmodified!(W) @@ -25,7 +25,7 @@ function Base.deepcopy_internal(W::T, dict::IdDict) where T<:GWord return g end -function (==)(W::T, Z::T) where T <: GWord +function Base.:(==)(W::T, Z::T) where T <: GWord hash(W) != hash(Z) && return false # distinguishes parent and parentless words if hasparent(W) && hasparent(Z) parent(W) != parent(Z) && return false diff --git a/src/symbols.jl b/src/symbols.jl index a6258bc..bd69a09 100644 --- a/src/symbols.jl +++ b/src/symbols.jl @@ -12,7 +12,7 @@ Base.isone(s::GSymbol) = iszero(s.pow) Base.inv(s::GSymbol) = change_pow(s, -s.pow) Base.hash(s::S, h::UInt) where S<:GSymbol = hash(s.id, hash(s.pow, hash(S, h))) -function (==)(s::GSymbol, t::GSymbol) +function Base.:(==)(s::GSymbol, t::GSymbol) isone(s) && isone(t) && return true s.pow == t.pow && s.id == t.id && return true return false diff --git a/src/types.jl b/src/types.jl index e3a93bf..316554a 100644 --- a/src/types.jl +++ b/src/types.jl @@ -1,7 +1,14 @@ -abstract type AbstractFPGroup <: Group end +abstract type AbstractFPGroup <: GroupsCore.Group end + +function Base.one(G::Gr) where Gr <: AbstractFPGroup + El = eltype(G) + id = El(eltype(El)[]) + id.parent = G + return id +end """ - ::GSymbol + GSymbol Represents a syllable. Abstract type which all group symbols of `AbstractFPGroups` should subtype. Each concrete subtype should implement fields: * `id` which is the `Symbol` representation/identification of a symbol @@ -9,7 +16,7 @@ Represents a syllable. Abstract type which all group symbols of """ abstract type GSymbol end -abstract type GWord{T<:GSymbol} <: GroupElem end +abstract type GWord{T<:GSymbol} <: GroupsCore.GroupElement end """ W::GroupWord{T} <: GWord{T<:GSymbol} <:GroupElem diff --git a/src/words.jl b/src/words.jl index 1a1c76e..976ffca 100644 --- a/src/words.jl +++ b/src/words.jl @@ -5,7 +5,7 @@ setmodified!(w::GWord) = (w.modified = true; w) unsetmodified!(w::GWord) = (w.modified = false; w) savehash!(w::GWord, h::UInt) = (w.savedhash = h; w) savedhash(w::GWord) = w.savedhash -parent(w::GWord) = w.parent +Base.parent(w::GWord) = w.parent hasparent(w::GWord) = isdefined(w, :parent) setparent!(w::GWord, G::AbstractFPGroup) = (w.parent = G; w) diff --git a/test/AutGroup-tests.jl b/test/AutGroup-tests.jl index 234ac60..52a4631 100644 --- a/test/AutGroup-tests.jl +++ b/test/AutGroup-tests.jl @@ -1,6 +1,8 @@ +import AbstractAlgebra.@perm_str + @testset "Automorphisms" begin - G = SymmetricGroup(Int8(4)) + G = AbstractAlgebra.SymmetricGroup(Int8(4)) @testset "AutSymbol" begin @test_throws MethodError Groups.AutSymbol(:a) @@ -91,7 +93,7 @@ f = Groups.AutSymbol(:a, 1, Groups.FlipAut(1)) @test isa(Automorphism{3}(f), Groups.GWord) @test isa(Automorphism{3}(f), Automorphism) - @test isa(AutGroup(FreeGroup(3)), AbstractAlgebra.Group) + @test isa(AutGroup(FreeGroup(3)), GroupsCore.Group) @test isa(AutGroup(FreeGroup(1)), Groups.AbstractFPGroup) A = AutGroup(FreeGroup(1)) diff --git a/test/FreeGroup-tests.jl b/test/FreeGroup-tests.jl index 49f4b82..12c2c42 100644 --- a/test/FreeGroup-tests.jl +++ b/test/FreeGroup-tests.jl @@ -42,7 +42,7 @@ end end @testset "FreeGroup" begin - @test isa(FreeGroup(["s", "t"]), AbstractAlgebra.Group) + @test isa(FreeGroup(["s", "t"]), GroupsCore.Group) G = FreeGroup(["s", "t"]) s, t = gens(G) @@ -87,7 +87,7 @@ end w = deepcopy(t) @test length(Groups.rmul!(w, t)) == 2 @test length(Groups.lmul!(w, inv(t))) == 1 - w = AbstractAlgebra.mul!(w, w, s) + w = GroupsCore.mul!(w, w, s) @test length(w) == 2 @test length(Groups.lmul!(w, inv(s))) == 3 diff --git a/test/runtests.jl b/test/runtests.jl index 3841aad..8fd5944 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,13 +1,14 @@ using Test -using AbstractAlgebra +import AbstractAlgebra using Groups +include("symmetric.jl") using LinearAlgebra @testset "Groups" begin @testset "wlmetric_ball" begin - M = MatrixAlgebra(zz, 3) + M = AbstractAlgebra.MatrixAlgebra(AbstractAlgebra.zz, 3) w = one(M); w[1,2] = 1; r = one(M); r[2,3] = -3; s = one(M); s[1,3] = 2; s[3,2] = -1; diff --git a/test/symmetric.jl b/test/symmetric.jl new file mode 100644 index 0000000..f4ea750 --- /dev/null +++ b/test/symmetric.jl @@ -0,0 +1,31 @@ +import AbstractAlgebra +using GroupsCore + +# disambiguation +GroupsCore.order( + ::Type{I}, + G::AbstractAlgebra.Generic.SymmetricGroup, +) where {I<:Integer} = I(factorial(G.n)) + +# disambiguation +GroupsCore.order( + ::Type{I}, + g::AbstractAlgebra.Generic.Perm, +) where {I<:Integer} = + I(foldl(lcm, length(c) for c in AbstractAlgebra.cycles(g))) + +# correct the AA length: +Base.length(G::AbstractAlgebra.Generic.SymmetricGroup) = order(Int, G) + +# genuinely new methods: +Base.IteratorSize(::Type{<:AbstractAlgebra.AbstractPermutationGroup}) = Base.HasLength() + +function GroupsCore.gens(G::AbstractAlgebra.Generic.SymmetricGroup{I}) where {I} + a, b = one(G), one(G) + circshift!(a.d, b.d, -1) + b.d[1], b.d[2] = 2, 1 + return [a, b] +end + +Base.deepcopy_internal(g::AbstractAlgebra.Generic.Perm, ::IdDict) = + AbstractAlgebra.Generic.Perm(deepcopy(g.d), false)