1
0
mirror of https://github.com/kalmarek/Groups.jl.git synced 2024-12-25 02:05:30 +01:00

sort out imports + first adjustments to Group Interface

This commit is contained in:
Marek Kaluba 2021-04-11 18:44:03 +02:00
parent 990c8dd1c3
commit 711988b98a
No known key found for this signature in database
GPG Key ID: 8BF1A3855328FC15
16 changed files with 98 additions and 85 deletions

View File

@ -20,7 +20,7 @@ struct FlipAut
end
struct PermAut
perm::Generic.Perm{Int8}
perm::AbstractAlgebra.Generic.Perm{Int8}
end
struct Identity end
@ -66,7 +66,7 @@ function flip(i::Integer, pow::Integer=1)
return AutSymbol(id, 1, FlipAut(i))
end
function AutSymbol(p::Generic.Perm, pow::Integer=1)
function AutSymbol(p::AbstractAlgebra.Generic.Perm, pow::Integer=1)
if pow != 1
p = p^pow
end
@ -81,7 +81,7 @@ end
ϱ(i::Integer, j::Integer, pow::Integer=1) = transvection_R(i, j, pow)
λ(i::Integer, j::Integer, pow::Integer=1) = transvection_L(i, j, pow)
ε(i::Integer, pow::Integer=1) = flip(i, pow)
σ(v::Generic.Perm, pow::Integer=1) = AutSymbol(v, pow)
σ(v::AbstractAlgebra.Generic.Perm, pow::Integer=1) = AutSymbol(v, pow)
function change_pow(s::AutSymbol, n::Integer)
iszero(n) && id_autsymbol()
@ -123,8 +123,8 @@ mutable struct Automorphism{N} <: GWord{AutSymbol}
end
end
elem_type(::Type{AutGroup{N}}) where N = Automorphism{N}
parent_type(::Type{Automorphism{N}}) where N = AutGroup{N}
Base.eltype(::Type{AutGroup{N}}) where N = Automorphism{N}
GroupsCore.parent_type(::Type{Automorphism{N}}) where N = AutGroup{N}
function AutGroup(G::FreeGroup; special=false)
S = AutSymbol[]
@ -140,7 +140,7 @@ function AutGroup(G::FreeGroup; special=false)
if !special
flips = [ε(i) for i in 1:n]
syms = [σ(p) for p in SymmetricGroup(Int8(n))][2:end]
syms = [σ(p) for p in AbstractAlgebra.SymmetricGroup(Int8(n))][2:end]
append!(S, [flips; syms])
end
@ -238,19 +238,19 @@ function compute_images(g::Automorphism)
return images
end
function (==)(g::Automorphism{N}, h::Automorphism{N}) where N
function Base.:(==)(g::Automorphism{N}, h::Automorphism{N}) where N
syllables(g) == syllables(h) && return true
img_computed, imh_computed = false, false
if ismodified(g)
img = compute_images(g) # sets modified bit
hash(g, images=img)
hash(g; images=img)
img_computed = true
end
if ismodified(h)
imh = compute_images(h) # sets modified bit
hash(h, images=imh)
hash(h; images=imh)
imh_computed = true
end
@ -282,7 +282,7 @@ end
# String I/O
#
function show(io::IO, G::AutGroup)
function Base.show(io::IO, G::AutGroup)
print(io, "Automorphism Group of $(G.objectGroup)\n")
print(io, "Generated by $(gens(G))")
end

View File

@ -29,8 +29,8 @@ export FPGroupElem, FPGroup
# Type and parent object methods
#
AbstractAlgebra.elem_type(::Type{FPGroup}) = FPGroupElem
AbstractAlgebra.parent_type(::Type{FPGroupElem}) = FPGroup
Base.eltype(::Type{FPGroup}) = FPGroupElem
GroupsCore.parent_type(::Type{FPGroupElem}) = FPGroup
###############################################################################
#
@ -76,7 +76,7 @@ end
# String I/O
#
function show(io::IO, G::FPGroup)
function Base.show(io::IO, G::FPGroup)
print(io, "FPgroup on $(length(G.gens)) generators ")
strrels = join(G.rels, ", ")
if length(strrels) > 200

View File

@ -27,8 +27,8 @@ export FreeGroupElem, FreeGroup
# Type and parent object methods
#
AbstractAlgebra.elem_type(::Type{FreeGroup}) = FreeGroupElem
AbstractAlgebra.parent_type(::Type{FreeGroupElem}) = FreeGroup
Base.eltype(::Type{FreeGroup}) = FreeGroupElem
GroupsCore.parent_type(::Type{FreeGroupElem}) = FreeGroup
###############################################################################
#
@ -67,7 +67,7 @@ end
# String I/O
#
function show(io::IO, G::FreeGroup)
function Base.show(io::IO, G::FreeGroup)
print(io, "Free group on $(length(G.gens)) generators: ")
join(io, G.gens, ", ")
end

View File

@ -1,19 +1,11 @@
module Groups
using AbstractAlgebra
import AbstractAlgebra: Group, GroupElem, Ring
import AbstractAlgebra: parent, parent_type, elem_type
import AbstractAlgebra: order, gens, matrix_repr
import Base: length, ==, hash, show, convert, eltype, iterate
import Base: inv, reduce, *, ^, power_by_squaring
import Base: findfirst, findnext, findlast, findprev, replace
import Base: deepcopy_internal
using GroupsCore
using LinearAlgebra
using ThreadsX
import AbstractAlgebra
export gens, FreeGroup, Aut, SAut
include("types.jl")
@ -23,7 +15,6 @@ include("FPGroups.jl")
include("AutGroup.jl")
include("symbols.jl")
include("fallbacks.jl")
include("words.jl")
include("hashing.jl")
include("freereduce.jl")
@ -56,11 +47,7 @@ end
# Misc
#
"""
gens(G::AbstractFPGroups)
Return vector of generators of `G`, as its elements.
"""
AbstractAlgebra.gens(G::AbstractFPGroup) = G.(G.gens)
GroupsCore.gens(G::AbstractFPGroup) = G.(G.gens)
"""
wlmetric_ball(S::AbstractVector{<:GroupElem}
@ -74,7 +61,7 @@ function wlmetric_ball_serial(
S::AbstractVector{T};
radius = 2,
op = *,
) where {T<:Union{GroupElem,NCRingElem}}
) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}}
old = unique!([one(first(S)), S...])
sizes = [1, length(old)]
for i = 2:radius
@ -91,7 +78,7 @@ function wlmetric_ball_thr(
S::AbstractVector{T};
radius = 2,
op = *,
) where {T<:Union{GroupElem,NCRingElem}}
) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}}
old = unique!([one(first(S)), S...])
sizes = [1, length(old)]
for r = 2:radius
@ -114,7 +101,7 @@ function wlmetric_ball_serial(
center::T;
radius = 2,
op = *,
) where {T<:Union{GroupElem,NCRingElem}}
) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}}
E, sizes = wlmetric_ball_serial(S, radius = radius, op = op)
isone(center) && return E, sizes
return c .* E, sizes
@ -125,7 +112,7 @@ function wlmetric_ball_thr(
center::T;
radius = 2,
op = *,
) where {T<:Union{GroupElem,NCRingElem}}
) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}}
E, sizes = wlmetric_ball_thr(S, radius = radius, op = op)
isone(center) && return E, sizes
return c .* E, sizes
@ -137,7 +124,7 @@ function wlmetric_ball(
radius = 2,
op = *,
threading = true,
) where {T<:Union{GroupElem,NCRingElem}}
) where {T<:Union{GroupElement,AbstractAlgebra.NCRingElem}}
threading && return wlmetric_ball_thr(S, center, radius = radius, op = op)
return return wlmetric_ball_serial(S, center, radius = radius, op = op)
end

View File

@ -55,15 +55,15 @@ lmul!(out::T, v::T) where T<:GWord = freereduce!(prepend!(out, v))
lmul!(out::T, x::T, y::T) where T <: GWord = rmul!(out, y, x)
AbstractAlgebra.mul!(out::T, x::T, y::T) where T <: GWord = rmul!(out, x, y)
GroupsCore.mul!(out::T, x::T, y::T) where T <: GWord = rmul!(out, x, y)
(*)(W::GW, Z::GW) where GW <: GWord = rmul!(deepcopy(W), W, Z)
(*)(W::GWord, s::GSymbol) = freereduce!(push!(deepcopy(W), s))
(*)(s::GSymbol, W::GWord) = freereduce!(pushfirst!(deepcopy(W), s))
Base.:(*)(W::GW, Z::GW) where GW <: GWord = rmul!(deepcopy(W), W, Z)
Base.:(*)(W::GWord, s::GSymbol) = freereduce!(push!(deepcopy(W), s))
Base.:(*)(s::GSymbol, W::GWord) = freereduce!(pushfirst!(deepcopy(W), s))
function power_by_squaring(W::GWord, p::Integer)
function Base.power_by_squaring(W::GWord, p::Integer)
if p < 0
return power_by_squaring(inv(W), -p)
return Base.power_by_squaring(inv(W), -p)
elseif p == 0
return one(W)
elseif p == 1
@ -90,4 +90,4 @@ function power_by_squaring(W::GWord, p::Integer)
return freereduce!(Z)
end
(^)(x::GWord, n::Integer) = power_by_squaring(x,n)
Base.:(^)(x::GWord, n::Integer) = Base.power_by_squaring(x,n)

View File

@ -1,16 +0,0 @@
# workarounds
Base.one(G::Generic.SymmetricGroup) = Generic.Perm(G.n)
# fallback definitions
# note: the user should implement those on type, when possible
Base.eltype(w::GW) where GW<:GWord = eltype(GW)
AbstractAlgebra.elem_type(G::Gr) where Gr <:AbstractFPGroup = elem_type(Gr)
AbstractAlgebra.parent_type(g::Gw) where Gw <:GWord = parent_type(parent(Gr))
function Base.one(G::Gr) where Gr <: AbstractFPGroup
El = elem_type(G)
id = El(eltype(El)[])
id.parent = G
return id
end

View File

@ -28,10 +28,11 @@ function issubword(z::GWord, w::GWord, sindex::Integer)
return true
end
"""doc
"""
Find the first syllable index k>=i such that Z < syllables(W)[k:k+syllablelength(Z)-1]
"""
function findnext(subword::GWord, word::GWord, start::Integer)
function Base.findnext(subword::GWord, word::GWord, start::Integer)
@boundscheck 1 start syllablelength(word) || throw(BoundsError(word, start))
isempty(subword) && return start
stop = syllablelength(word) - syllablelength(subword) +1
@ -42,7 +43,7 @@ function findnext(subword::GWord, word::GWord, start::Integer)
return nothing
end
function findnext(s::FreeSymbol, word::GWord, start::Integer)
function Base.findnext(s::FreeSymbol, word::GWord, start::Integer)
@boundscheck 1 start syllablelength(word) || throw(BoundsError(word, start))
isone(s) && return start
stop = syllablelength(word)
@ -53,7 +54,7 @@ function findnext(s::FreeSymbol, word::GWord, start::Integer)
return nothing
end
function findprev(subword::GWord, word::GWord, start::Integer)
function Base.findprev(subword::GWord, word::GWord, start::Integer)
@boundscheck 1 start syllablelength(word) || throw(BoundsError(word, start))
isempty(subword) && return start
stop = 1
@ -64,7 +65,7 @@ function findprev(subword::GWord, word::GWord, start::Integer)
return nothing
end
function findprev(s::FreeSymbol, word::GWord, start::Integer)
function Base.findprev(s::FreeSymbol, word::GWord, start::Integer)
@boundscheck 1 start syllablelength(word) || throw(BoundsError(word, start))
isone(s) && return start
stop = 1
@ -75,11 +76,11 @@ function findprev(s::FreeSymbol, word::GWord, start::Integer)
return nothing
end
findfirst(subword::GWord, word::GWord) = findnext(subword, word, 1)
findlast(subword::GWord, word::GWord) =
Base.findfirst(subword::GWord, word::GWord) = findnext(subword, word, 1)
Base.findlast(subword::GWord, word::GWord) =
findprev(subword, word, syllablelength(word)-syllablelength(subword)+1)
function replace!(out::GW, W::GW, lhs_rhs::Pair{GS, T}; count::Integer=typemax(Int)) where
function Base.replace!(out::GW, W::GW, lhs_rhs::Pair{GS, T}; count::Integer=typemax(Int)) where
{GS<:GSymbol, T<:GWord, GW<:GWord}
(count == 0 || isempty(W)) && return W
count < 0 && throw(DomainError(count, "`count` must be non-negative."))
@ -117,7 +118,7 @@ function replace!(out::GW, W::GW, lhs_rhs::Pair{GS, T}; count::Integer=typemax(I
return freereduce!(out)
end
function replace!(out::GW, W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where
function Base.replace!(out::GW, W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where
{GW<:GWord, T <: GWord}
(count == 0 || isempty(W)) && return W
count < 0 && throw(DomainError(count, "`count` must be non-negative."))
@ -164,12 +165,12 @@ function replace!(out::GW, W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(In
return freereduce!(out)
end
function replace(W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where
function Base.replace(W::GW, lhs_rhs::Pair{T, T}; count::Integer=typemax(Int)) where
{GW<:GWord, T <: GWord}
return replace!(one(W), W, lhs_rhs; count=count)
end
function replace(W::GW, subst_dict::Dict{T,T}) where {GW<:GWord, T<:GWord}
function Base.replace(W::GW, subst_dict::Dict{T,T}) where {GW<:GWord, T<:GWord}
out = W
for toreplace in reverse!(sort!(collect(keys(subst_dict)), by=length))
replacement = subst_dict[toreplace]

View File

@ -46,4 +46,4 @@ performs reduction/simplification of a group element (word in generators).
The default reduction is the reduction in the free group reduction.
More specific procedures should be dispatched on `GWord`s type parameter.
"""
reduce(w::GWord) = reduce!(deepcopy(w))
Base.reduce(w::GWord) = reduce!(deepcopy(w))

View File

@ -9,7 +9,7 @@ function hash_internal(W::GWord)
return hash(syllables(W), hash(typeof(W), h))
end
function hash(W::GWord, h::UInt=UInt(0); kwargs...)
function Base.hash(W::GWord, h::UInt=UInt(0); kwargs...)
if ismodified(W)
savehash!(W, hash_internal(W; kwargs...))
unsetmodified!(W)
@ -25,7 +25,7 @@ function Base.deepcopy_internal(W::T, dict::IdDict) where T<:GWord
return g
end
function (==)(W::T, Z::T) where T <: GWord
function Base.:(==)(W::T, Z::T) where T <: GWord
hash(W) != hash(Z) && return false # distinguishes parent and parentless words
if hasparent(W) && hasparent(Z)
parent(W) != parent(Z) && return false

View File

@ -12,7 +12,7 @@ Base.isone(s::GSymbol) = iszero(s.pow)
Base.inv(s::GSymbol) = change_pow(s, -s.pow)
Base.hash(s::S, h::UInt) where S<:GSymbol = hash(s.id, hash(s.pow, hash(S, h)))
function (==)(s::GSymbol, t::GSymbol)
function Base.:(==)(s::GSymbol, t::GSymbol)
isone(s) && isone(t) && return true
s.pow == t.pow && s.id == t.id && return true
return false

View File

@ -1,7 +1,14 @@
abstract type AbstractFPGroup <: Group end
abstract type AbstractFPGroup <: GroupsCore.Group end
function Base.one(G::Gr) where Gr <: AbstractFPGroup
El = eltype(G)
id = El(eltype(El)[])
id.parent = G
return id
end
"""
::GSymbol
GSymbol
Represents a syllable. Abstract type which all group symbols of
`AbstractFPGroups` should subtype. Each concrete subtype should implement fields:
* `id` which is the `Symbol` representation/identification of a symbol
@ -9,7 +16,7 @@ Represents a syllable. Abstract type which all group symbols of
"""
abstract type GSymbol end
abstract type GWord{T<:GSymbol} <: GroupElem end
abstract type GWord{T<:GSymbol} <: GroupsCore.GroupElement end
"""
W::GroupWord{T} <: GWord{T<:GSymbol} <:GroupElem

View File

@ -5,7 +5,7 @@ setmodified!(w::GWord) = (w.modified = true; w)
unsetmodified!(w::GWord) = (w.modified = false; w)
savehash!(w::GWord, h::UInt) = (w.savedhash = h; w)
savedhash(w::GWord) = w.savedhash
parent(w::GWord) = w.parent
Base.parent(w::GWord) = w.parent
hasparent(w::GWord) = isdefined(w, :parent)
setparent!(w::GWord, G::AbstractFPGroup) = (w.parent = G; w)

View File

@ -1,6 +1,8 @@
import AbstractAlgebra.@perm_str
@testset "Automorphisms" begin
G = SymmetricGroup(Int8(4))
G = AbstractAlgebra.SymmetricGroup(Int8(4))
@testset "AutSymbol" begin
@test_throws MethodError Groups.AutSymbol(:a)
@ -91,7 +93,7 @@
f = Groups.AutSymbol(:a, 1, Groups.FlipAut(1))
@test isa(Automorphism{3}(f), Groups.GWord)
@test isa(Automorphism{3}(f), Automorphism)
@test isa(AutGroup(FreeGroup(3)), AbstractAlgebra.Group)
@test isa(AutGroup(FreeGroup(3)), GroupsCore.Group)
@test isa(AutGroup(FreeGroup(1)), Groups.AbstractFPGroup)
A = AutGroup(FreeGroup(1))

View File

@ -42,7 +42,7 @@ end
end
@testset "FreeGroup" begin
@test isa(FreeGroup(["s", "t"]), AbstractAlgebra.Group)
@test isa(FreeGroup(["s", "t"]), GroupsCore.Group)
G = FreeGroup(["s", "t"])
s, t = gens(G)
@ -87,7 +87,7 @@ end
w = deepcopy(t)
@test length(Groups.rmul!(w, t)) == 2
@test length(Groups.lmul!(w, inv(t))) == 1
w = AbstractAlgebra.mul!(w, w, s)
w = GroupsCore.mul!(w, w, s)
@test length(w) == 2
@test length(Groups.lmul!(w, inv(s))) == 3

View File

@ -1,13 +1,14 @@
using Test
using AbstractAlgebra
import AbstractAlgebra
using Groups
include("symmetric.jl")
using LinearAlgebra
@testset "Groups" begin
@testset "wlmetric_ball" begin
M = MatrixAlgebra(zz, 3)
M = AbstractAlgebra.MatrixAlgebra(AbstractAlgebra.zz, 3)
w = one(M); w[1,2] = 1;
r = one(M); r[2,3] = -3;
s = one(M); s[1,3] = 2; s[3,2] = -1;

31
test/symmetric.jl Normal file
View File

@ -0,0 +1,31 @@
import AbstractAlgebra
using GroupsCore
# disambiguation
GroupsCore.order(
::Type{I},
G::AbstractAlgebra.Generic.SymmetricGroup,
) where {I<:Integer} = I(factorial(G.n))
# disambiguation
GroupsCore.order(
::Type{I},
g::AbstractAlgebra.Generic.Perm,
) where {I<:Integer} =
I(foldl(lcm, length(c) for c in AbstractAlgebra.cycles(g)))
# correct the AA length:
Base.length(G::AbstractAlgebra.Generic.SymmetricGroup) = order(Int, G)
# genuinely new methods:
Base.IteratorSize(::Type{<:AbstractAlgebra.AbstractPermutationGroup}) = Base.HasLength()
function GroupsCore.gens(G::AbstractAlgebra.Generic.SymmetricGroup{I}) where {I}
a, b = one(G), one(G)
circshift!(a.d, b.d, -1)
b.d[1], b.d[2] = 2, 1
return [a, b]
end
Base.deepcopy_internal(g::AbstractAlgebra.Generic.Perm, ::IdDict) =
AbstractAlgebra.Generic.Perm(deepcopy(g.d), false)