1
0
mirror of https://github.com/kalmarek/Groups.jl.git synced 2024-12-25 18:15:29 +01:00

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 object(G::AutomorphismGroup) = G.group
rewriting(G::AutomorphismGroup) = G.rws rewriting(G::AutomorphismGroup) = G.rws
function equality_data(f::FPGroupElement{<:AutomorphismGroup}) function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup})
imf = evaluate(f) imf = evaluate(f)
# return normalform!.(imf) # return normalform!.(imf)
@ -26,7 +26,7 @@ function equality_data(f::FPGroupElement{<:AutomorphismGroup})
return imf return imf
end 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) @assert parent(g) === parent(h)
if _isvalidhash(g) && _isvalidhash(h) if _isvalidhash(g) && _isvalidhash(h)
@ -70,7 +70,7 @@ function Base.:(==)(g::A, h::A) where {A<:FPGroupElement{<:AutomorphismGroup}}
return equal return equal
end end
function Base.isone(g::FPGroupElement{<:AutomorphismGroup}) function Base.isone(g::AbstractFPGroupElement{<:AutomorphismGroup})
if length(word(g)) > 8 if length(word(g)) > 8
normalform!(g) normalform!(g)
end end
@ -79,21 +79,21 @@ end
# eye-candy # 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,…}") print(io, "Automorphism{$T,…}")
Base.show(io::IO, A::AutomorphismGroup) = print(io, "automorphism group of ", object(A)) Base.show(io::IO, A::AutomorphismGroup) = print(io, "automorphism group of ", object(A))
## Automorphism Evaluation ## Automorphism Evaluation
domain(f::FPGroupElement{<:AutomorphismGroup}) = deepcopy(parent(f).domain) domain(f::AbstractFPGroupElement{<:AutomorphismGroup}) = deepcopy(parent(f).domain)
# tuple(gens(object(parent(f)))...) # tuple(gens(object(parent(f)))...)
evaluate(f::FPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f) evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f)
function evaluate!( function evaluate!(
t::NTuple{N,T}, t::NTuple{N,T},
f::FPGroupElement{<:AutomorphismGroup{<:Group}}, f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}},
tmp = one(first(t)), tmp = one(first(t)),
) where {N, T} ) where {N, T}
A = alphabet(f) A = alphabet(f)

View File

@ -43,7 +43,7 @@ function SurfaceGroup(genus::Integer, boundaries::Integer)
comms = Word(word) comms = Word(word)
word_rels = [ comms => one(comms) ] word_rels = [ comms => one(comms) ]
rws = RewritingSystem(word_rels, KnuthBendix.RecursivePathOrder(Al)) rws = KnuthBendix.RewritingSystem(word_rels, KnuthBendix.RecursivePathOrder(Al))
KnuthBendix.knuthbendix!(rws) KnuthBendix.knuthbendix!(rws)
elseif boundaries == 1 elseif boundaries == 1
S = typeof(one(Word(Int[]))) S = typeof(one(Word(Int[])))

View File

@ -1,6 +1,6 @@
## Hashing ## 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) bitget(h::UInt, n::Int) = Bool((h & (1 << n)) >> n)
bitclear(h::UInt, n::Int) = h & ~(1 << 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? # * `savedhash & 2` (the second bit): is the hash valid?
const __BITFLAGS_MASK = ~(~(UInt(0)) << 2) const __BITFLAGS_MASK = ~(~(UInt(0)) << 2)
isnormalform(g::FPGroupElement) = bitget(g.savedhash, 0) isnormalform(g::AbstractFPGroupElement) = bitget(g.savedhash, 0)
_isvalidhash(g::FPGroupElement) = bitget(g.savedhash, 1) _isvalidhash(g::AbstractFPGroupElement) = bitget(g.savedhash, 1)
_setnormalform(h::UInt, v::Bool) = bitset(h, v, 0) _setnormalform(h::UInt, v::Bool) = bitset(h, v, 0)
_setvalidhash(h::UInt, v::Bool) = bitset(h, v, 1) _setvalidhash(h::UInt, v::Bool) = bitset(h, v, 1)
_setnormalform!(g::FPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v) _setnormalform!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v)
_setvalidhash!(g::FPGroupElement, v::Bool) = g.savedhash = _setvalidhash(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 # To update hash use this internal method, possibly only after computing the
# normal form of `g`: # normal form of `g`:
function _update_savedhash!(g::FPGroupElement, data) function _update_savedhash!(g::AbstractFPGroupElement, data)
h = hash(data, hash(parent(g))) h = hash(data, hash(parent(g)))
h = (h << count_ones(__BITFLAGS_MASK)) | (__BITFLAGS_MASK & g.savedhash) h = (h << count_ones(__BITFLAGS_MASK)) | (__BITFLAGS_MASK & g.savedhash)
g.savedhash = _setvalidhash(h, true) g.savedhash = _setvalidhash(h, true)
return g return g
end end
function Base.hash(g::FPGroupElement, h::UInt) function Base.hash(g::AbstractFPGroupElement, h::UInt)
_isvalidhash(g) || _update_savedhash!(g, equality_data(g)) _isvalidhash(g) || _update_savedhash!(g, equality_data(g))
return hash(g.savedhash >> count_ones(__BITFLAGS_MASK), h) return hash(g.savedhash >> count_ones(__BITFLAGS_MASK), h)
end end
function Base.copyto!(res::FPGroupElement, g::FPGroupElement) function Base.copyto!(res::AbstractFPGroupElement, g::AbstractFPGroupElement)
@assert parent(res) === parent(g) @assert parent(res) === parent(g)
resize!(word(res), length(word(g))) resize!(word(res), length(word(g)))
copyto!(word(res), word(g)) copyto!(word(res), word(g))

View File

@ -2,7 +2,7 @@
normalform!(g::FPGroupElement) normalform!(g::FPGroupElement)
Compute the normal form of `g`, possibly modifying `g` in-place. 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 isnormalform(g) && return g
let w = one(word(g)) let w = one(word(g))
@ -21,7 +21,7 @@ end
normalform!(res::GEl, g::GEl) where GEl<:FPGroupElement normalform!(res::GEl, g::GEl) where GEl<:FPGroupElement
Compute the normal fom of `g`, storing it in `res`. 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) @boundscheck @assert parent(res) === parent(g)
if isnormalform(g) if isnormalform(g)
copyto!(res, 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. 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)) isone(res) && isnormalform(g) && return append!(res, word(g))
return KnuthBendix.rewrite_from_left!(res, word(g), rewriting(parent(g))) return KnuthBendix.rewrite_from_left!(res, word(g), rewriting(parent(g)))
end end

View File

@ -57,10 +57,12 @@ Base.isfinite(::AbstractFPGroup) = (@warn "using generic isfinite(::AbstractFPGr
## FPGroupElement ## 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 word::W
savedhash::UInt savedhash::UInt
parent::G parent::Gr
FPGroupElement(word::W, G::AbstractFPGroup) where {W<:AbstractWord} = FPGroupElement(word::W, G::AbstractFPGroup) where {W<:AbstractWord} =
new{typeof(G),W}(word, UInt(0), G) 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) new{typeof(G),W}(word, hash, G)
end end
word(f::FPGroupElement) = f.word word(f::AbstractFPGroupElement) = f.word
#convenience #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) f = normalform!(f)
KnuthBendix.print_repr(io, word(f), alphabet(f)) KnuthBendix.print_repr(io, word(f), alphabet(f))
end end
## GroupElement Interface for FPGroupElement ## GroupElement Interface for FPGroupElement
Base.parent(f::FPGroupElement) = f.parent Base.parent(f::AbstractFPGroupElement) = f.parent
GroupsCore.parent_type(::Type{<:FPGroupElement{G}}) where {G} = G 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) @boundscheck @assert parent(g) === parent(h)
normalform!(g) normalform!(g)
normalform!(h) normalform!(h)
@ -96,17 +98,20 @@ function Base.deepcopy_internal(g::FPGroupElement, stackdict::IdDict)
return FPGroupElement(copy(word(g)), g.savedhash, parent(g)) return FPGroupElement(copy(word(g)), g.savedhash, parent(g))
end end
Base.inv(g::FPGroupElement) = (G = parent(g); FPGroupElement(inv(alphabet(G), word(g)), G)) function Base.inv(g::GEl) where GEl <: AbstractFPGroupElement
G = parent(g)
function Base.:(*)(g::FPGroupElement, h::FPGroupElement) return GEl(inv(alphabet(G), word(g)), G)
@boundscheck @assert parent(g) === parent(h)
return FPGroupElement(word(g) * word(h), parent(g))
end 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: # additional methods:
Base.isone(g::FPGroupElement) = (normalform!(g); isempty(word(g))) Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g)))
## Free Groups ## Free Groups
@ -157,7 +162,7 @@ relations(F::FreeGroup) = Pair{eltype(F)}[]
# these are mathematically correct # these are mathematically correct
Base.isfinite(::FreeGroup) = false Base.isfinite(::FreeGroup) = false
GroupsCore.isfiniteorder(g::FPGroupElement{<:FreeGroup}) = isone(g) ? true : false GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) = isone(g) ? true : false
## FP Groups ## FP Groups