Groups.jl/src/types.jl

215 lines
6.4 KiB
Julia
Raw Normal View History

2021-05-05 01:10:28 +02:00
## "Abstract" definitions
"""
AbstractFPGroup
An Abstract type representing finitely presented groups. Every instance `` must implement
* `KnuthBendix.alphabet(G::MyFPGroup)`
* `rewriting(G::MyFPGroup)` : return the rewriting object which must implement
> `KnuthBendix.rewrite_from_left!(u, v, rewriting(G))`.
By default `alphabet(G)` is returned, which amounts to free rewriting in `G`.
2021-05-05 02:35:12 +02:00
* `relations(G::MyFPGroup)` : return a set of defining relations.
2021-05-05 01:10:28 +02:00
AbstractFPGroup may also override `word_type(::Type{MyFPGroup}) = Word{UInt16}`,
2021-05-24 01:41:37 +02:00
which controls the word type used for group elements. If a group has more than `255` generators you need to define e.g.
> `word_type(::Type{MyFPGroup}) = Word{UInt16}`
2021-05-05 01:10:28 +02:00
"""
abstract type AbstractFPGroup <: GroupsCore.Group end
word_type(G::AbstractFPGroup) = word_type(typeof(G))
# the default:
2021-05-16 23:23:16 +02:00
word_type(::Type{<:AbstractFPGroup}) = Word{UInt8}
2021-05-05 01:10:28 +02:00
2021-05-16 23:22:33 +02:00
# the default (results in free rewriting)
rewriting(G::AbstractFPGroup) = alphabet(G)
2021-05-24 01:40:54 +02:00
Base.@propagate_inbounds function (G::AbstractFPGroup)(word::AbstractVector{<:Integer})
2021-05-16 23:22:33 +02:00
@boundscheck @assert all(l -> 1 <= l <= length(KnuthBendix.alphabet(G)), word)
2021-05-05 01:10:28 +02:00
return FPGroupElement(word_type(G)(word), G)
end
## Group Interface
Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G)
2021-05-16 23:22:33 +02:00
Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} = FPGroupElement{FPG,word_type(FPG)}
2021-05-05 01:10:28 +02:00
2021-05-07 18:14:13 +02:00
include("iteration.jl")
2021-05-05 01:10:28 +02:00
GroupsCore.ngens(G::AbstractFPGroup) = length(G.gens)
function GroupsCore.gens(G::AbstractFPGroup, i::Integer)
2021-05-16 23:22:33 +02:00
@boundscheck 1 <= i <= GroupsCore.ngens(G)
2021-05-05 02:33:36 +02:00
l = alphabet(G)[G.gens[i]]
return FPGroupElement(word_type(G)([l]), G)
2021-05-05 01:10:28 +02:00
end
GroupsCore.gens(G::AbstractFPGroup) = [gens(G, i) for i in 1:GroupsCore.ngens(G)]
# TODO: ProductReplacementAlgorithm
2021-05-16 23:22:33 +02:00
function Base.rand(rng::Random.AbstractRNG, rs::Random.SamplerTrivial{<:AbstractFPGroup})
2021-05-05 01:10:28 +02:00
l = rand(10:100)
G = rs[]
2021-05-05 02:33:36 +02:00
nletters = length(alphabet(G))
return FPGroupElement(word_type(G)(rand(1:nletters, l)), G)
2021-05-05 01:10:28 +02:00
end
Base.isfinite(::AbstractFPGroup) = (@warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false)
2021-05-05 01:10:28 +02:00
## FPGroupElement
2021-06-29 16:52:35 +02:00
abstract type AbstractFPGroupElement{Gr} <: GroupElement end
mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <: AbstractFPGroupElement{Gr}
2021-05-05 01:10:28 +02:00
word::W
savedhash::UInt
2021-06-29 16:52:35 +02:00
parent::Gr
2021-05-05 01:10:28 +02:00
FPGroupElement(word::W, G::AbstractFPGroup, hash::UInt=UInt(0)) where {W<:AbstractWord} =
2021-05-16 23:22:33 +02:00
new{typeof(G),W}(word, hash, G)
FPGroupElement{Gr, W}(word::AbstractWord, G::Gr) where {Gr, W} =
new{Gr, W}(word, UInt(0), G)
2021-05-05 01:10:28 +02:00
end
2021-06-29 16:52:35 +02:00
word(f::AbstractFPGroupElement) = f.word
2021-05-05 01:10:28 +02:00
#convenience
2021-06-29 16:52:35 +02:00
KnuthBendix.alphabet(g::AbstractFPGroupElement) = alphabet(parent(g))
2021-05-05 01:10:28 +02:00
2021-06-29 16:52:35 +02:00
function Base.show(io::IO, f::AbstractFPGroupElement)
2021-05-05 01:10:28 +02:00
f = normalform!(f)
2021-05-24 01:41:37 +02:00
KnuthBendix.print_repr(io, word(f), alphabet(f))
2021-05-05 01:10:28 +02:00
end
## GroupElement Interface for FPGroupElement
2021-06-29 16:52:35 +02:00
Base.parent(f::AbstractFPGroupElement) = f.parent
2021-05-05 01:10:28 +02:00
2021-06-29 16:52:35 +02:00
function Base.:(==)(g::AbstractFPGroupElement, h::AbstractFPGroupElement)
2021-05-05 01:10:28 +02:00
@boundscheck @assert parent(g) === parent(h)
2021-05-07 18:11:11 +02:00
normalform!(g)
normalform!(h)
2021-05-05 01:10:28 +02:00
hash(g) != hash(h) && return false
return word(g) == word(h)
end
function Base.deepcopy_internal(g::FPGroupElement, stackdict::IdDict)
return FPGroupElement(copy(word(g)), parent(g), g.savedhash)
2021-05-05 01:10:28 +02:00
end
2021-06-29 16:52:35 +02:00
function Base.inv(g::GEl) where GEl <: AbstractFPGroupElement
G = parent(g)
return GEl(inv(alphabet(G), word(g)), G)
end
2021-05-05 01:10:28 +02:00
2021-06-29 16:52:35 +02:00
function Base.:(*)(g::GEl, h::GEl) where GEl<:AbstractFPGroupElement
2021-05-05 01:10:28 +02:00
@boundscheck @assert parent(g) === parent(h)
2021-06-29 16:52:35 +02:00
return GEl(word(g) * word(h), parent(g))
2021-05-05 01:10:28 +02:00
end
2021-06-29 16:52:35 +02:00
GroupsCore.isfiniteorder(g::AbstractFPGroupElement) = isone(g) ? true : (@warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false)
2021-05-05 01:10:28 +02:00
# additional methods:
2021-06-29 16:52:35 +02:00
Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g)))
2021-05-05 01:10:28 +02:00
## Free Groups
struct FreeGroup{T} <: AbstractFPGroup
gens::Vector{T}
alphabet::KnuthBendix.Alphabet{T}
2021-05-16 23:22:33 +02:00
function FreeGroup(gens, A::KnuthBendix.Alphabet) where {W}
2021-05-05 01:10:28 +02:00
@assert length(gens) == length(unique(gens))
2021-05-16 23:22:33 +02:00
@assert all(l -> l in KnuthBendix.letters(A), gens)
2021-05-05 01:10:28 +02:00
return new{eltype(gens)}(gens, A)
end
end
2021-05-05 02:33:36 +02:00
function FreeGroup(A::Alphabet)
2021-05-16 23:22:33 +02:00
@boundscheck @assert all(KnuthBendix.hasinverse(l, A) for l in KnuthBendix.letters(A))
ltrs = KnuthBendix.letters(A)
gens = Vector{eltype(ltrs)}()
invs = Vector{eltype(ltrs)}()
for l in ltrs
l invs && continue
push!(gens, l)
push!(invs, inv(A, l))
end
return FreeGroup(gens, A)
2021-05-05 01:10:28 +02:00
end
2021-05-26 12:12:26 +02:00
function FreeGroup(n::Integer)
symbols = Symbol[]
inverses = Int[]
sizehint!(symbols, 2n)
sizehint!(inverses, 2n)
for i in 1:n
push!(symbols, Symbol(:f, i), Symbol(:F, i))
push!(inverses, 2i, 2i-1)
end
return FreeGroup(symbols[1:2:2n], Alphabet(symbols, inverses))
end
2021-05-05 01:10:28 +02:00
Base.show(io::IO, F::FreeGroup) = print(io, "free group on $(ngens(F)) generators")
# mandatory methods:
KnuthBendix.alphabet(F::FreeGroup) = F.alphabet
2021-05-05 02:35:12 +02:00
relations(F::FreeGroup) = Pair{eltype(F)}[]
# GroupsCore interface:
# these are mathematically correct
Base.isfinite(::FreeGroup) = false
2021-06-29 16:52:35 +02:00
GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) = isone(g) ? true : false
2021-05-05 02:35:12 +02:00
## FP Groups
2021-05-16 23:22:33 +02:00
struct FPGroup{T,R,S} <: AbstractFPGroup
2021-05-05 02:35:12 +02:00
gens::Vector{T}
2021-05-16 23:22:33 +02:00
relations::Vector{Pair{S,S}}
2021-05-05 02:35:12 +02:00
rws::R
end
KnuthBendix.alphabet(G::FPGroup) = alphabet(rewriting(G))
rewriting(G::FPGroup) = G.rws
relations(G::FPGroup) = G.relations
function FPGroup(
G::AbstractFPGroup,
2021-05-16 23:22:33 +02:00
rels::AbstractVector{<:Pair{GEl,GEl}};
ordering = KnuthBendix.LenLex,
kwargs...,
) where {GEl<:FPGroupElement}
2021-05-05 02:35:12 +02:00
O = ordering(alphabet(G))
for (lhs, rhs) in rels
@assert parent(lhs) === parent(rhs) === G
end
2021-05-16 23:22:33 +02:00
word_rels = [word(lhs) => word(rhs) for (lhs, rhs) in [relations(G); rels]]
2021-06-21 19:14:42 +02:00
rws = KnuthBendix.RewritingSystem(word_rels, O)
2021-05-05 02:35:12 +02:00
KnuthBendix.knuthbendix!(rws; kwargs...)
return FPGroup(G.gens, rels, rws)
end
function Base.show(io::IO, G::FPGroup)
print(io, "")
2021-05-26 12:07:15 +02:00
join(io, gens(G), ", ")
2021-05-05 02:35:12 +02:00
print(io, " | ")
2021-05-26 12:07:15 +02:00
join(io, relations(G), ", ")
2021-05-05 02:35:12 +02:00
print(io, "")
end
## GSymbol aka letter of alphabet
abstract type GSymbol end
Base.literal_pow(::typeof(^), t::GSymbol, ::Val{-1}) = inv(t)
2021-06-21 17:53:29 +02:00
function subscriptify(n::Integer)
subscript_0 = Int(0x2080) # Char(0x2080) -> subscript 0
return join([Char(subscript_0 + i) for i in reverse(digits(n))], "")
end