From 29b6675a8ab820672de7d8ddd0ee58c6b6880dfd Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Tue, 29 Jun 2021 16:52:35 +0200 Subject: [PATCH] introduce AbstractFPGroupElement --- src/autgroups.jl | 14 +++++++------- src/groups/mcg.jl | 2 +- src/hashing.jl | 16 ++++++++-------- src/normalform.jl | 6 +++--- src/types.jl | 37 +++++++++++++++++++++---------------- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/autgroups.jl b/src/autgroups.jl index d214005..5df39de 100644 --- a/src/autgroups.jl +++ b/src/autgroups.jl @@ -14,7 +14,7 @@ end object(G::AutomorphismGroup) = G.group rewriting(G::AutomorphismGroup) = G.rws -function equality_data(f::FPGroupElement{<:AutomorphismGroup}) +function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup}) imf = evaluate(f) # return normalform!.(imf) @@ -26,7 +26,7 @@ function equality_data(f::FPGroupElement{<:AutomorphismGroup}) return imf end -function Base.:(==)(g::A, h::A) where {A<:FPGroupElement{<:AutomorphismGroup}} +function Base.:(==)(g::A, h::A) where {A<:AbstractFPGroupElement{<:AutomorphismGroup}} @assert parent(g) === parent(h) if _isvalidhash(g) && _isvalidhash(h) @@ -70,7 +70,7 @@ function Base.:(==)(g::A, h::A) where {A<:FPGroupElement{<:AutomorphismGroup}} return equal end -function Base.isone(g::FPGroupElement{<:AutomorphismGroup}) +function Base.isone(g::AbstractFPGroupElement{<:AutomorphismGroup}) if length(word(g)) > 8 normalform!(g) end @@ -79,21 +79,21 @@ end # eye-candy -Base.show(io::IO, ::Type{<:FPGroupElement{<:AutomorphismGroup{T}}}) where {T} = +Base.show(io::IO, ::Type{<:AbstractFPGroupElement{<:AutomorphismGroup{T}}}) where {T} = print(io, "Automorphism{$T,…}") Base.show(io::IO, A::AutomorphismGroup) = print(io, "automorphism group of ", object(A)) ## Automorphism Evaluation -domain(f::FPGroupElement{<:AutomorphismGroup}) = deepcopy(parent(f).domain) +domain(f::AbstractFPGroupElement{<:AutomorphismGroup}) = deepcopy(parent(f).domain) # tuple(gens(object(parent(f)))...) -evaluate(f::FPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f) +evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f) function evaluate!( t::NTuple{N,T}, - f::FPGroupElement{<:AutomorphismGroup{<:Group}}, + f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}}, tmp = one(first(t)), ) where {N, T} A = alphabet(f) diff --git a/src/groups/mcg.jl b/src/groups/mcg.jl index 536574a..37f40a4 100644 --- a/src/groups/mcg.jl +++ b/src/groups/mcg.jl @@ -43,7 +43,7 @@ function SurfaceGroup(genus::Integer, boundaries::Integer) comms = Word(word) word_rels = [ comms => one(comms) ] - rws = RewritingSystem(word_rels, KnuthBendix.RecursivePathOrder(Al)) + rws = KnuthBendix.RewritingSystem(word_rels, KnuthBendix.RecursivePathOrder(Al)) KnuthBendix.knuthbendix!(rws) elseif boundaries == 1 S = typeof(one(Word(Int[]))) diff --git a/src/hashing.jl b/src/hashing.jl index b8d7e4b..ed729b1 100644 --- a/src/hashing.jl +++ b/src/hashing.jl @@ -1,6 +1,6 @@ ## Hashing -equality_data(g::FPGroupElement) = (normalform!(g); word(g)) +equality_data(g::AbstractFPGroupElement) = (normalform!(g); word(g)) bitget(h::UInt, n::Int) = Bool((h & (1 << n)) >> n) bitclear(h::UInt, n::Int) = h & ~(1 << n) @@ -14,30 +14,30 @@ bitset(h::UInt, v::Bool, n::Int) = v ? bitset(h, n) : bitclear(h, n) # * `savedhash & 2` (the second bit): is the hash valid? const __BITFLAGS_MASK = ~(~(UInt(0)) << 2) -isnormalform(g::FPGroupElement) = bitget(g.savedhash, 0) -_isvalidhash(g::FPGroupElement) = bitget(g.savedhash, 1) +isnormalform(g::AbstractFPGroupElement) = bitget(g.savedhash, 0) +_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::FPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v) -_setvalidhash!(g::FPGroupElement, v::Bool) = g.savedhash = _setvalidhash(g.savedhash, v) +_setnormalform!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v) +_setvalidhash!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setvalidhash(g.savedhash, v) # To update hash use this internal method, possibly only after computing the # normal form of `g`: -function _update_savedhash!(g::FPGroupElement, data) +function _update_savedhash!(g::AbstractFPGroupElement, data) h = hash(data, hash(parent(g))) h = (h << count_ones(__BITFLAGS_MASK)) | (__BITFLAGS_MASK & g.savedhash) g.savedhash = _setvalidhash(h, true) return g end -function Base.hash(g::FPGroupElement, h::UInt) +function Base.hash(g::AbstractFPGroupElement, h::UInt) _isvalidhash(g) || _update_savedhash!(g, equality_data(g)) return hash(g.savedhash >> count_ones(__BITFLAGS_MASK), h) end -function Base.copyto!(res::FPGroupElement, g::FPGroupElement) +function Base.copyto!(res::AbstractFPGroupElement, g::AbstractFPGroupElement) @assert parent(res) === parent(g) resize!(word(res), length(word(g))) copyto!(word(res), word(g)) diff --git a/src/normalform.jl b/src/normalform.jl index f1d67ff..0b799e3 100644 --- a/src/normalform.jl +++ b/src/normalform.jl @@ -2,7 +2,7 @@ normalform!(g::FPGroupElement) Compute the normal form of `g`, possibly modifying `g` in-place. """ -@inline function normalform!(g::FPGroupElement) +@inline function normalform!(g::AbstractFPGroupElement) isnormalform(g) && return g let w = one(word(g)) @@ -21,7 +21,7 @@ end normalform!(res::GEl, g::GEl) where GEl<:FPGroupElement Compute the normal fom of `g`, storing it in `res`. """ -function normalform!(res::GEl, g::GEl) where {GEl<:FPGroupElement} +function normalform!(res::GEl, g::GEl) where {GEl<:AbstractFPGroupElement} @boundscheck @assert parent(res) === parent(g) if isnormalform(g) copyto!(res, g) @@ -40,7 +40,7 @@ Append the normal form of `g` to word `res`, modifying `res` in place. Defaults to the rewriting in the free group. """ -@inline function normalform!(res::AbstractWord, g::FPGroupElement) +@inline function normalform!(res::AbstractWord, g::AbstractFPGroupElement) isone(res) && isnormalform(g) && return append!(res, word(g)) return KnuthBendix.rewrite_from_left!(res, word(g), rewriting(parent(g))) end diff --git a/src/types.jl b/src/types.jl index bed9221..7b39048 100644 --- a/src/types.jl +++ b/src/types.jl @@ -57,10 +57,12 @@ Base.isfinite(::AbstractFPGroup) = (@warn "using generic isfinite(::AbstractFPGr ## FPGroupElement -mutable struct FPGroupElement{G<:AbstractFPGroup,W<:AbstractWord} <: GroupElement +abstract type AbstractFPGroupElement{Gr} <: GroupElement end + +mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <: AbstractFPGroupElement{Gr} word::W savedhash::UInt - parent::G + parent::Gr FPGroupElement(word::W, G::AbstractFPGroup) where {W<:AbstractWord} = new{typeof(G),W}(word, UInt(0), G) @@ -69,22 +71,22 @@ mutable struct FPGroupElement{G<:AbstractFPGroup,W<:AbstractWord} <: GroupElemen new{typeof(G),W}(word, hash, G) end -word(f::FPGroupElement) = f.word +word(f::AbstractFPGroupElement) = f.word #convenience -KnuthBendix.alphabet(g::FPGroupElement) = alphabet(parent(g)) +KnuthBendix.alphabet(g::AbstractFPGroupElement) = alphabet(parent(g)) -function Base.show(io::IO, f::FPGroupElement) +function Base.show(io::IO, f::AbstractFPGroupElement) f = normalform!(f) KnuthBendix.print_repr(io, word(f), alphabet(f)) end ## GroupElement Interface for FPGroupElement -Base.parent(f::FPGroupElement) = f.parent -GroupsCore.parent_type(::Type{<:FPGroupElement{G}}) where {G} = G +Base.parent(f::AbstractFPGroupElement) = f.parent +GroupsCore.parent_type(::Type{<:AbstractFPGroupElement{G}}) where {G} = G -function Base.:(==)(g::FPGroupElement, h::FPGroupElement) +function Base.:(==)(g::AbstractFPGroupElement, h::AbstractFPGroupElement) @boundscheck @assert parent(g) === parent(h) normalform!(g) normalform!(h) @@ -96,17 +98,20 @@ function Base.deepcopy_internal(g::FPGroupElement, stackdict::IdDict) return FPGroupElement(copy(word(g)), g.savedhash, parent(g)) end -Base.inv(g::FPGroupElement) = (G = parent(g); FPGroupElement(inv(alphabet(G), word(g)), G)) - -function Base.:(*)(g::FPGroupElement, h::FPGroupElement) - @boundscheck @assert parent(g) === parent(h) - return FPGroupElement(word(g) * word(h), parent(g)) +function Base.inv(g::GEl) where GEl <: AbstractFPGroupElement + G = parent(g) + return GEl(inv(alphabet(G), word(g)), G) end -GroupsCore.isfiniteorder(g::FPGroupElement) = isone(g) ? true : (@warn "using generic isfiniteorder(::FPGroupElement): the returned `false` might be wrong"; false) +function Base.:(*)(g::GEl, h::GEl) where GEl<:AbstractFPGroupElement + @boundscheck @assert parent(g) === parent(h) + return GEl(word(g) * word(h), parent(g)) +end + +GroupsCore.isfiniteorder(g::AbstractFPGroupElement) = isone(g) ? true : (@warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false) # additional methods: -Base.isone(g::FPGroupElement) = (normalform!(g); isempty(word(g))) +Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g))) ## Free Groups @@ -157,7 +162,7 @@ relations(F::FreeGroup) = Pair{eltype(F)}[] # these are mathematically correct Base.isfinite(::FreeGroup) = false -GroupsCore.isfiniteorder(g::FPGroupElement{<:FreeGroup}) = isone(g) ? true : false +GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) = isone(g) ? true : false ## FP Groups