mirror of
https://github.com/kalmarek/Groups.jl.git
synced 2024-12-26 02:20:30 +01:00
introduce AbstractFPGroupElement
This commit is contained in:
parent
394d9a7aac
commit
29b6675a8a
@ -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)
|
||||||
|
@ -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[])))
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
37
src/types.jl
37
src/types.jl
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user