2021-05-05 01:10:28 +02:00
using GroupsCore
# using Groups
# import Groups.AbstractFPGroup
import KnuthBendix
import KnuthBendix : AbstractWord , Alphabet , Word , RewritingSystem
import KnuthBendix : alphabet
using Random
## "Abstract" definitions
"""
AbstractFPGroup
An Abstract type representing finitely presented groups . Every instance ` ` must implement
* ` KnuthBendix.alphabet(G::MyFPGroup) `
2021-05-05 02:32:27 +02:00
* ` 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
2021-05-05 02:32:27 +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)
2021-05-05 02:32:27 +02:00
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
2021-05-24 15:35:28 +02:00
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-05-16 23:22:33 +02:00
mutable struct FPGroupElement { G <: AbstractFPGroup , W <: AbstractWord } <: GroupElement
2021-05-05 01:10:28 +02:00
word :: W
savedhash :: UInt
parent :: G
2021-05-16 23:22:33 +02:00
FPGroupElement ( word :: W , G :: AbstractFPGroup ) where { W <: AbstractWord } =
new { typeof ( G ) , W } ( word , UInt ( 0 ) , G )
2021-05-05 01:10:28 +02:00
2021-05-16 23:22:33 +02:00
FPGroupElement ( word :: W , hash :: UInt , G :: AbstractFPGroup ) where { W <: AbstractWord } =
new { typeof ( G ) , W } ( word , hash , G )
2021-05-05 01:10:28 +02:00
end
word ( f :: FPGroupElement ) = f . word
#convenience
KnuthBendix . alphabet ( g :: FPGroupElement ) = alphabet ( parent ( g ) )
function Base . show ( io :: IO , f :: FPGroupElement )
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
Base . parent ( f :: FPGroupElement ) = f . parent
2021-05-16 23:22:33 +02:00
GroupsCore . parent_type ( :: Type { <: FPGroupElement { G } } ) where { G } = G
2021-05-05 01:10:28 +02:00
function Base . : ( == ) ( g :: FPGroupElement , h :: FPGroupElement )
@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 )
2021-05-07 18:11:11 +02:00
return FPGroupElement ( copy ( word ( g ) ) , g . savedhash , parent ( g ) )
2021-05-05 01:10:28 +02:00
end
2021-05-16 23:22:33 +02:00
Base . inv ( g :: FPGroupElement ) = ( G = parent ( g ) ; FPGroupElement ( inv ( alphabet ( G ) , word ( g ) ) , G ) )
2021-05-05 01:10:28 +02:00
function Base . : ( * ) ( g :: FPGroupElement , h :: FPGroupElement )
@boundscheck @assert parent ( g ) === parent ( h )
2021-05-16 23:22:33 +02:00
return FPGroupElement ( word ( g ) * word ( h ) , parent ( g ) )
2021-05-05 01:10:28 +02:00
end
2021-05-24 15:35:28 +02:00
GroupsCore . isfiniteorder ( g :: FPGroupElement ) = isone ( g ) ? true : ( @warn " using generic isfiniteorder(::FPGroupElement): the returned `false` might be wrong " ; false )
2021-05-05 01:10:28 +02:00
# additional methods:
Base . isone ( g :: FPGroupElement ) = ( normalform! ( g ) ; isempty ( word ( g ) ) )
## 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 ) )
2021-05-05 02:33:36 +02:00
return FreeGroup ( KnuthBendix . letters ( A ) , A )
2021-05-05 01:10:28 +02:00
end
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 ) } [ ]
2021-05-24 15:35:28 +02:00
# GroupsCore interface:
# these are mathematically correct
Base . isfinite ( :: FreeGroup ) = false
GroupsCore . isfiniteorder ( g :: FPGroupElement { <: 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-05-05 02:35:12 +02:00
rws = RewritingSystem ( word_rels , O )
KnuthBendix . knuthbendix! ( rws ; kwargs ... )
return FPGroup ( G . gens , rels , rws )
end
function Base . show ( io :: IO , G :: FPGroup )
print ( io , " ⟨ " )
2021-05-16 23:22:33 +02:00
Base . print_array ( io , reshape ( gens ( G ) , ( 1 , ngens ( G ) ) ) )
2021-05-05 02:35:12 +02:00
print ( io , " | " )
Base . print_array ( io , relations ( G ) )
print ( io , " ⟩ " )
end