introduce AbstractFPGroupElement

This commit is contained in:
Marek Kaluba 2021-06-29 16:52:35 +02:00
parent 394d9a7aac
commit 29b6675a8a
No known key found for this signature in database
GPG Key ID: 8BF1A3855328FC15
5 changed files with 40 additions and 35 deletions

View File

@ -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)

View File

@ -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[])))

View File

@ -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))

View File

@ -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

View File

@ -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