more formatting

This commit is contained in:
Marek Kaluba 2023-03-15 19:07:14 +01:00
parent 3cdef72977
commit af3913d085
No known key found for this signature in database
GPG Key ID: 8BF1A3855328FC15
11 changed files with 245 additions and 132 deletions

1
.JuliaFormatter.toml Symbolic link
View File

@ -0,0 +1 @@
../.JuliaFormatter.toml

View File

@ -14,7 +14,14 @@ import KnuthBendix: alphabet, ordering
export MatrixGroups export MatrixGroups
export Alphabet, AutomorphismGroup, FreeGroup, FreeGroup, FPGroup, FPGroupElement, SpecialAutomorphismGroup, Homomorphism export Alphabet,
AutomorphismGroup,
FreeGroup,
FreeGroup,
FPGroup,
FPGroupElement,
SpecialAutomorphismGroup,
Homomorphism
export alphabet, evaluate, word, gens export alphabet, evaluate, word, gens

View File

@ -1,7 +1,8 @@
function _abelianize( function _abelianize(
i::Integer, i::Integer,
source::AutomorphismGroup{<:FreeGroup}, source::AutomorphismGroup{<:FreeGroup},
target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T} target::MatrixGroups.SpecialLinearGroup{N,T},
) where {N,T}
n = ngens(object(source)) n = ngens(object(source))
@assert n == N @assert n == N
aut = alphabet(source)[i] aut = alphabet(source)[i]
@ -12,7 +13,7 @@ function _abelianize(
eij = MatrixGroups.ElementaryMatrix{N}( eij = MatrixGroups.ElementaryMatrix{N}(
aut.j, aut.j,
aut.i, aut.i,
ifelse(aut.inv, -one(T), one(T)) ifelse(aut.inv, -one(T), one(T)),
) )
k = alphabet(target)[eij] k = alphabet(target)[eij]
return word_type(target)([k]) return word_type(target)([k])
@ -24,7 +25,8 @@ end
function _abelianize( function _abelianize(
i::Integer, i::Integer,
source::AutomorphismGroup{<:Groups.SurfaceGroup}, source::AutomorphismGroup{<:Groups.SurfaceGroup},
target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T} target::MatrixGroups.SpecialLinearGroup{N,T},
) where {N,T}
n = ngens(Groups.object(source)) n = ngens(Groups.object(source))
@assert n == N @assert n == N
g = alphabet(source)[i].autFn_word g = alphabet(source)[i].autFn_word
@ -39,7 +41,7 @@ end
function Groups._abelianize( function Groups._abelianize(
i::Integer, i::Integer,
source::AutomorphismGroup{<:Groups.SurfaceGroup}, source::AutomorphismGroup{<:Groups.SurfaceGroup},
target::MatrixGroups.SymplecticGroup{N,T} target::MatrixGroups.SymplecticGroup{N,T},
) where {N,T} ) where {N,T}
@assert iseven(N) @assert iseven(N)
As = alphabet(source) As = alphabet(source)
@ -50,7 +52,7 @@ function Groups._abelianize(
MatrixGroups.SpecialLinearGroup{2genus}(T) MatrixGroups.SpecialLinearGroup{2genus}(T)
end end
ab = Groups.Homomorphism(Groups._abelianize, source, SlN, check=false) ab = Groups.Homomorphism(Groups._abelianize, source, SlN; check = false)
matrix_spn_map = let S = gens(target) matrix_spn_map = let S = gens(target)
Dict(MatrixGroups.matrix(g) => word(g) for g in union(S, inv.(S))) Dict(MatrixGroups.matrix(g) => word(g) for g in union(S, inv.(S)))

View File

@ -1,5 +1,5 @@
function KnuthBendix.Alphabet(S::AbstractVector{<:GSymbol}) function KnuthBendix.Alphabet(S::AbstractVector{<:GSymbol})
S = unique!([S; inv.(S)]) S = union(S, inv.(S))
inversions = [findfirst(==(inv(s)), S) for s in S] inversions = [findfirst(==(inv(s)), S) for s in S]
return Alphabet(S, inversions) return Alphabet(S, inversions)
end end
@ -26,7 +26,10 @@ function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup})
return imf return imf
end end
function Base.:(==)(g::A, h::A) where {A<:AbstractFPGroupElement{<: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)
@ -79,32 +82,46 @@ end
# eye-candy # eye-candy
Base.show(io::IO, ::Type{<:FPGroupElement{<:AutomorphismGroup{T}}}) where {T} = function Base.show(
print(io, "Automorphism{$T, …}") io::IO,
::Type{<:FPGroupElement{<:AutomorphismGroup{T}}},
) where {T}
return print(io, "Automorphism{$T, …}")
end
Base.show(io::IO, A::AutomorphismGroup) = print(io, "automorphism group of ", object(A)) function Base.show(io::IO, A::AutomorphismGroup)
return print(io, "automorphism group of ", object(A))
end
function Base.show(io::IO, ::MIME"text/plain", a::AbstractFPGroupElement{<:AutomorphismGroup}) function Base.show(
io::IO,
::MIME"text/plain",
a::AbstractFPGroupElement{<:AutomorphismGroup},
)
println(io, "$(a):") println(io, "$(a):")
d = domain(a) d = domain(a)
im = evaluate(a) im = evaluate(a)
for (x, imx) in zip(d, im[1:end-1]) for (x, imx) in zip(d, im[1:end-1])
println(io, "$x$imx") println(io, "$x$imx")
end end
println(io, "$(last(d))$(last(im))") return println(io, "$(last(d))$(last(im))")
end end
## Automorphism Evaluation ## Automorphism Evaluation
domain(f::AbstractFPGroupElement{<:AutomorphismGroup}) = deepcopy(parent(f).domain) function domain(f::AbstractFPGroupElement{<:AutomorphismGroup})
return deepcopy(parent(f).domain)
end
# tuple(gens(object(parent(f)))...) # tuple(gens(object(parent(f)))...)
evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f) function evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup})
return evaluate!(domain(f), f)
end
function evaluate!( function evaluate!(
t::NTuple{N,T}, t::NTuple{N,T},
f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}}, f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}},
tmp=one(first(t)), tmp = one(first(t)),
) where {N,T<:FPGroupElement} ) where {N,T<:FPGroupElement}
A = alphabet(f) A = alphabet(f)
for idx in word(f) for idx in word(f)
@ -113,7 +130,11 @@ function evaluate!(
return t return t
end end
evaluate!(t::NTuple{N,T}, s::GSymbol, tmp=nothing) where {N,T} = throw("you need to implement `evaluate!(::$(typeof(t)), ::$(typeof(s)), ::Alphabet, tmp=one(first(t)))`") function evaluate!(t::NTuple{N,T}, s::GSymbol, tmp = nothing) where {N,T}
throw(
"you need to implement `evaluate!(::$(typeof(t)), ::$(typeof(s)), ::Alphabet, tmp=one(first(t)))`",
)
end
# forward evaluate by substitution # forward evaluate by substitution
@ -135,13 +156,13 @@ function LettersMap(a::FPGroupElement{<:AutomorphismGroup})
# (trusting it's a set of generators that define a) # (trusting it's a set of generators that define a)
@assert length(dom) == length(img) @assert length(dom) == length(img)
indices_map = Dict(A[A[fl]] => word(im) for (fl, im) in zip(first_letters, img)) indices_map =
Dict(A[A[fl]] => word(im) for (fl, im) in zip(first_letters, img))
# inverses of generators are dealt lazily in getindex # inverses of generators are dealt lazily in getindex
return LettersMap(indices_map, A) return LettersMap(indices_map, A)
end end
function Base.getindex(lm::LettersMap, i::Integer) function Base.getindex(lm::LettersMap, i::Integer)
# here i is an index of an alphabet # here i is an index of an alphabet
@boundscheck 1 i length(lm.A) @boundscheck 1 i length(lm.A)

View File

@ -12,25 +12,29 @@ struct DirectPowerElement{GEl,N,Gr<:GroupsCore.Group} <: GroupsCore.GroupElement
parent::DirectPower{Gr,N,GEl} parent::DirectPower{Gr,N,GEl}
end end
DirectPowerElement( function DirectPowerElement(
elts::AbstractVector{<:GroupsCore.GroupElement}, elts::AbstractVector{<:GroupsCore.GroupElement},
G::DirectPower, G::DirectPower,
) = DirectPowerElement(ntuple(i -> elts[i], _nfold(G)), G) )
return DirectPowerElement(ntuple(i -> elts[i], _nfold(G)), G)
end
_nfold(::DirectPower{Gr,N}) where {Gr,N} = N _nfold(::DirectPower{Gr,N}) where {Gr,N} = N
Base.one(G::DirectPower) = function Base.one(G::DirectPower)
DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G) return DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G)
end
Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl} = function Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl}
DirectPowerElement{GEl,N,Gr} return DirectPowerElement{GEl,N,Gr}
end
function Base.iterate(G::DirectPower) function Base.iterate(G::DirectPower)
itr = Iterators.ProductIterator(ntuple(i -> G.group, _nfold(G))) itr = Iterators.ProductIterator(ntuple(i -> G.group, _nfold(G)))
res = iterate(itr) res = iterate(itr)
@assert res !== nothing @assert res !== nothing
elt = DirectPowerElement(first(res), G) elt = DirectPowerElement(first(res), G)
return elt, (iterator=itr, state=last(res)) return elt, (iterator = itr, state = last(res))
end end
function Base.iterate(G::DirectPower, state) function Base.iterate(G::DirectPower, state)
@ -38,7 +42,7 @@ function Base.iterate(G::DirectPower, state)
res = iterate(itr, st) res = iterate(itr, st)
res === nothing && return nothing res === nothing && return nothing
elt = DirectPowerElement(first(res), G) elt = DirectPowerElement(first(res), G)
return elt, (iterator=itr, state=last(res)) return elt, (iterator = itr, state = last(res))
end end
function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N} function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N}
@ -49,8 +53,9 @@ end
Base.size(G::DirectPower) = ntuple(_ -> length(G.group), _nfold(G)) Base.size(G::DirectPower) = ntuple(_ -> length(G.group), _nfold(G))
GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} = function GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer}
convert(I, order(I, G.group)^_nfold(G)) return convert(I, order(I, G.group)^_nfold(G))
end
GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group) GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group)
@ -83,13 +88,18 @@ end
GroupsCore.parent(g::DirectPowerElement) = g.parent GroupsCore.parent(g::DirectPowerElement) = g.parent
Base.:(==)(g::DirectPowerElement, h::DirectPowerElement) = function Base.:(==)(g::DirectPowerElement, h::DirectPowerElement)
(parent(g) === parent(h) && g.elts == h.elts) return (parent(g) === parent(h) && g.elts == h.elts)
end
Base.hash(g::DirectPowerElement, h::UInt) = hash(g.elts, hash(parent(g), h)) Base.hash(g::DirectPowerElement, h::UInt) = hash(g.elts, hash(parent(g), h))
Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict) = function Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict)
DirectPowerElement(Base.deepcopy_internal(g.elts, stackdict), parent(g)) return DirectPowerElement(
Base.deepcopy_internal(g.elts, stackdict),
parent(g),
)
end
Base.inv(g::DirectPowerElement) = DirectPowerElement(inv.(g.elts), parent(g)) Base.inv(g::DirectPowerElement) = DirectPowerElement(inv.(g.elts), parent(g))
@ -98,15 +108,25 @@ function Base.:(*)(g::DirectPowerElement, h::DirectPowerElement)
return DirectPowerElement(g.elts .* h.elts, parent(g)) return DirectPowerElement(g.elts .* h.elts, parent(g))
end end
GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} = function GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer}
convert(I, reduce(lcm, (order(I, h) for h in g.elts), init=one(I))) return convert(I, reduce(lcm, (order(I, h) for h in g.elts); init = one(I)))
end
Base.isone(g::DirectPowerElement) = all(isone, g.elts) Base.isone(g::DirectPowerElement) = all(isone, g.elts)
function Base.show(io::IO, G::DirectPower) function Base.show(io::IO, G::DirectPower)
n = _nfold(G) n = _nfold(G)
nn = n == 1 ? "1-st" : n == 2 ? "2-nd" : n == 3 ? "3-rd" : "$n-th" nn = n == 1 ? "1-st" : n == 2 ? "2-nd" : n == 3 ? "3-rd" : "$n-th"
print(io, "Direct $(nn) power of $(G.group)") return print(io, "Direct $(nn) power of $(G.group)")
end
function Base.show(io::IO, g::DirectPowerElement)
return print(io, "( ", join(g.elts, ", "), " )")
end
# convienience:
Base.@propagate_inbounds function Base.getindex(
g::DirectPowerElement,
i::Integer,
)
return g.elts[i]
end end
Base.show(io::IO, g::DirectPowerElement) =
print(io, "( ", join(g.elts, ", "), " )")

View File

@ -14,18 +14,22 @@ end
DirectProductElement(g, h, G::DirectProduct) = DirectProduct((g, h), G) DirectProductElement(g, h, G::DirectProduct) = DirectProduct((g, h), G)
Base.one(G::DirectProduct) = function Base.one(G::DirectProduct)
DirectProductElement((one(G.first), one(G.last)), G) return DirectProductElement((one(G.first), one(G.last)), G)
end
Base.eltype(::Type{<:DirectProduct{Gt,Ht,GEl,HEl}}) where {Gt,Ht,GEl,HEl} = function Base.eltype(
DirectProductElement{GEl,HEl,Gt,Ht} ::Type{<:DirectProduct{Gt,Ht,GEl,HEl}},
) where {Gt,Ht,GEl,HEl}
return DirectProductElement{GEl,HEl,Gt,Ht}
end
function Base.iterate(G::DirectProduct) function Base.iterate(G::DirectProduct)
itr = Iterators.product(G.first, G.last) itr = Iterators.product(G.first, G.last)
res = iterate(itr) res = iterate(itr)
@assert res !== nothing @assert res !== nothing
elt = DirectProductElement(first(res), G) elt = DirectProductElement(first(res), G)
return elt, (iterator=itr, state=last(res)) return elt, (iterator = itr, state = last(res))
end end
function Base.iterate(G::DirectProduct, state) function Base.iterate(G::DirectProduct, state)
@ -33,7 +37,7 @@ function Base.iterate(G::DirectProduct, state)
res = iterate(itr, st) res = iterate(itr, st)
res === nothing && return nothing res === nothing && return nothing
elt = DirectProductElement(first(res), G) elt = DirectProductElement(first(res), G)
return elt, (iterator=itr, state=last(res)) return elt, (iterator = itr, state = last(res))
end end
function Base.IteratorSize(::Type{<:DirectProduct{Gt,Ht}}) where {Gt,Ht} function Base.IteratorSize(::Type{<:DirectProduct{Gt,Ht}}) where {Gt,Ht}
@ -50,15 +54,18 @@ end
Base.size(G::DirectProduct) = (length(G.first), length(G.last)) Base.size(G::DirectProduct) = (length(G.first), length(G.last))
GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer} = function GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer}
convert(I, order(I, G.first) * order(I, G.last)) return convert(I, order(I, G.first) * order(I, G.last))
end
GroupsCore.ngens(G::DirectProduct) = ngens(G.first) + ngens(G.last) GroupsCore.ngens(G::DirectProduct) = ngens(G.first) + ngens(G.last)
function GroupsCore.gens(G::DirectProduct) function GroupsCore.gens(G::DirectProduct)
gens_first = [DirectProductElement((g, one(G.last)), G) for g in gens(G.first)] gens_first =
[DirectProductElement((g, one(G.last)), G) for g in gens(G.first)]
gens_last = [DirectProductElement((one(G.first), g), G) for g in gens(G.last)] gens_last =
[DirectProductElement((one(G.first), g), G) for g in gens(G.last)]
return [gens_first; gens_last] return [gens_first; gens_last]
end end
@ -75,28 +82,45 @@ end
GroupsCore.parent(g::DirectProductElement) = g.parent GroupsCore.parent(g::DirectProductElement) = g.parent
Base.:(==)(g::DirectProductElement, h::DirectProductElement) = function Base.:(==)(g::DirectProductElement, h::DirectProductElement)
(parent(g) === parent(h) && g.elts == h.elts) return (parent(g) === parent(h) && g.elts == h.elts)
end
Base.hash(g::DirectProductElement, h::UInt) = hash(g.elts, hash(parent(g), h)) Base.hash(g::DirectProductElement, h::UInt) = hash(g.elts, hash(parent(g), h))
Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict) = function Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict)
DirectProductElement(Base.deepcopy_internal(g.elts, stackdict), parent(g)) return DirectProductElement(
Base.deepcopy_internal(g.elts, stackdict),
parent(g),
)
end
Base.inv(g::DirectProductElement) = function Base.inv(g::DirectProductElement)
DirectProductElement(inv.(g.elts), parent(g)) return DirectProductElement(inv.(g.elts), parent(g))
end
function Base.:(*)(g::DirectProductElement, h::DirectProductElement) function Base.:(*)(g::DirectProductElement, h::DirectProductElement)
@assert parent(g) === parent(h) @assert parent(g) === parent(h)
return DirectProductElement(g.elts .* h.elts, parent(g)) return DirectProductElement(g.elts .* h.elts, parent(g))
end end
GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer} = function GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer}
convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts)))) return convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts))))
end
Base.isone(g::DirectProductElement) = all(isone, g.elts) Base.isone(g::DirectProductElement) = all(isone, g.elts)
Base.show(io::IO, G::DirectProduct) = function Base.show(io::IO, G::DirectProduct)
print(io, "Direct product of $(G.first) and $(G.last)") return print(io, "Direct product of $(G.first) and $(G.last)")
Base.show(io::IO, g::DirectProductElement) = end
print(io, "( $(join(g.elts, ",")) )") function Base.show(io::IO, g::DirectProductElement)
return print(io, "( $(join(g.elts, ",")) )")
end
# convienience:
Base.@propagate_inbounds function Base.getindex(
g::DirectProductElement,
i::Integer,
)
return g.elts[i]
end

View File

@ -1,4 +1,5 @@
import PermutationGroups: AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup import PermutationGroups:
AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup
""" """
WreathProduct(G::Group, P::AbstractPermutationGroup) <: Group WreathProduct(G::Group, P::AbstractPermutationGroup) <: Group
@ -38,21 +39,22 @@ struct WreathProductElement{
p::AbstractPerm, p::AbstractPerm,
W::WreathProduct, W::WreathProduct,
) )
new{typeof(n),typeof(p),typeof(W)}(n, p, W) return new{typeof(n),typeof(p),typeof(W)}(n, p, W)
end end
end end
Base.one(W::WreathProduct) = WreathProductElement(one(W.N), one(W.P), W) Base.one(W::WreathProduct) = WreathProductElement(one(W.N), one(W.P), W)
Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} = function Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr}
WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}} return WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}}
end
function Base.iterate(G::WreathProduct) function Base.iterate(G::WreathProduct)
itr = Iterators.product(G.N, G.P) itr = Iterators.product(G.N, G.P)
res = iterate(itr) res = iterate(itr)
@assert res !== nothing @assert res !== nothing
elt = WreathProductElement(first(res)..., G) elt = WreathProductElement(first(res)..., G)
return elt, (iterator=itr, state=last(res)) return elt, (iterator = itr, state = last(res))
end end
function Base.iterate(G::WreathProduct, state) function Base.iterate(G::WreathProduct, state)
@ -60,7 +62,7 @@ function Base.iterate(G::WreathProduct, state)
res = iterate(itr, st) res = iterate(itr, st)
res === nothing && return nothing res === nothing && return nothing
elt = WreathProductElement(first(res)..., G) elt = WreathProductElement(first(res)..., G)
return elt, (iterator=itr, state=last(res)) return elt, (iterator = itr, state = last(res))
end end
function Base.IteratorSize(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} function Base.IteratorSize(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr}
@ -78,8 +80,9 @@ end
Base.size(G::WreathProduct) = (length(G.N), length(G.P)) Base.size(G::WreathProduct) = (length(G.N), length(G.P))
GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer} = function GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer}
convert(I, order(I, G.N) * order(I, G.P)) return convert(I, order(I, G.N) * order(I, G.P))
end
function GroupsCore.gens(G::WreathProduct) function GroupsCore.gens(G::WreathProduct)
N_gens = [WreathProductElement(n, one(G.P), G) for n in gens(G.N)] N_gens = [WreathProductElement(n, one(G.P), G) for n in gens(G.N)]
@ -93,18 +96,19 @@ function Base.rand(
rng::Random.AbstractRNG, rng::Random.AbstractRNG,
rs::Random.SamplerTrivial{<:WreathProduct}, rs::Random.SamplerTrivial{<:WreathProduct},
) )
G = rs[] G = rs[]
return WreathProductElement(rand(rng, G.N), rand(rng, G.P), G) return WreathProductElement(rand(rng, G.N), rand(rng, G.P), G)
end end
GroupsCore.parent(g::WreathProductElement) = g.parent GroupsCore.parent(g::WreathProductElement) = g.parent
Base.:(==)(g::WreathProductElement, h::WreathProductElement) = function Base.:(==)(g::WreathProductElement, h::WreathProductElement)
parent(g) === parent(h) && g.n == h.n && g.p == h.p return parent(g) === parent(h) && g.n == h.n && g.p == h.p
end
Base.hash(g::WreathProductElement, h::UInt) = function Base.hash(g::WreathProductElement, h::UInt)
hash(g.n, hash(g.p, hash(g.parent, h))) return hash(g.n, hash(g.p, hash(g.parent, h)))
end
function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict) function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict)
return WreathProductElement( return WreathProductElement(
@ -114,8 +118,9 @@ function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict)
) )
end end
_act(p::AbstractPerm, n::DirectPowerElement) = function _act(p::AbstractPerm, n::DirectPowerElement)
DirectPowerElement(n.elts^p, parent(n)) return DirectPowerElement(n.elts^p, parent(n))
end
function Base.inv(g::WreathProductElement) function Base.inv(g::WreathProductElement)
pinv = inv(g.p) pinv = inv(g.p)
@ -129,8 +134,9 @@ end
Base.isone(g::WreathProductElement) = isone(g.n) && isone(g.p) Base.isone(g::WreathProductElement) = isone(g.n) && isone(g.p)
Base.show(io::IO, G::WreathProduct) = function Base.show(io::IO, G::WreathProduct)
print(io, "Wreath product of $(G.N.group) by $(G.P)") return print(io, "Wreath product of $(G.N.group) by $(G.P)")
end
Base.show(io::IO, g::WreathProductElement) = print(io, "( $(g.n)$(g.p) )") Base.show(io::IO, g::WreathProductElement) = print(io, "( $(g.n)$(g.p) )")
Base.copy(g::WreathProductElement) = WreathProductElement(g.n, g.p, parent(g)) Base.copy(g::WreathProductElement) = WreathProductElement(g.n, g.p, parent(g))

View File

@ -20,8 +20,12 @@ _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::AbstractFPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v) function _setnormalform!(g::AbstractFPGroupElement, v::Bool)
_setvalidhash!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setvalidhash(g.savedhash, v) return g.savedhash = _setnormalform(g.savedhash, v)
end
function _setvalidhash!(g::AbstractFPGroupElement, v::Bool)
return g.savedhash = _setvalidhash(g.savedhash, v)
end
# 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`:

View File

@ -67,11 +67,13 @@ struct Homomorphism{Gr1,Gr2,I,W}
f, f,
source::AbstractFPGroup, source::AbstractFPGroup,
target::AbstractFPGroup; target::AbstractFPGroup;
check=true check = true,
) )
A = alphabet(source) A = alphabet(source)
dct = Dict(i => convert(word_type(target), f(i, source, target)) dct = Dict(
for i in 1:length(A)) i => convert(word_type(target), f(i, source, target)) for
i in 1:length(A)
)
I = eltype(word_type(source)) I = eltype(word_type(source))
W = word_type(target) W = word_type(target)
hom = new{typeof(source),typeof(target),I,W}(dct, source, target) hom = new{typeof(source),typeof(target),I,W}(dct, source, target)
@ -79,7 +81,6 @@ struct Homomorphism{Gr1,Gr2,I,W}
if check if check
@assert hom(one(source)) == one(target) @assert hom(one(source)) == one(target)
for x in gens(source) for x in gens(source)
@assert hom(x^-1) == hom(x)^-1 @assert hom(x^-1) == hom(x)^-1
for y in gens(source) for y in gens(source)
@ -111,4 +112,6 @@ function (h::Homomorphism)(g::AbstractFPGroupElement)
return h.target(w) return h.target(w)
end end
Base.show(io::IO, h::Homomorphism) = print(io, "Homomorphism\n from : $(h.source)\n to : $(h.target)") function Base.show(io::IO, h::Homomorphism)
return print(io, "Homomorphism\n from : $(h.source)\n to : $(h.target)")
end

View File

@ -42,10 +42,7 @@ KnuthBendix.alphabet(G::AbstractFPGroup) = alphabet(ordering(G))
Base.@propagate_inbounds function (G::AbstractFPGroup)( Base.@propagate_inbounds function (G::AbstractFPGroup)(
word::AbstractVector{<:Integer}, word::AbstractVector{<:Integer},
) )
@boundscheck @assert all( @boundscheck @assert all(l -> 1 <= l <= length(alphabet(G)), word)
l -> 1 <= l <= length(alphabet(G)),
word,
)
return FPGroupElement(word_type(G)(word), G) return FPGroupElement(word_type(G)(word), G)
end end
@ -53,8 +50,9 @@ end
Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G) Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G)
Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} = function Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup}
FPGroupElement{FPG,word_type(FPG)} return FPGroupElement{FPG,word_type(FPG)}
end
include("iteration.jl") include("iteration.jl")
@ -65,8 +63,9 @@ function GroupsCore.gens(G::AbstractFPGroup, i::Integer)
l = alphabet(G)[G.gens[i]] l = alphabet(G)[G.gens[i]]
return FPGroupElement(word_type(G)([l]), G) return FPGroupElement(word_type(G)([l]), G)
end end
GroupsCore.gens(G::AbstractFPGroup) = function GroupsCore.gens(G::AbstractFPGroup)
[gens(G, i) for i in 1:GroupsCore.ngens(G)] return [gens(G, i) for i in 1:GroupsCore.ngens(G)]
end
# TODO: ProductReplacementAlgorithm # TODO: ProductReplacementAlgorithm
function Base.rand( function Base.rand(
@ -79,9 +78,11 @@ function Base.rand(
return FPGroupElement(word_type(G)(rand(1:nletters, l)), G) return FPGroupElement(word_type(G)(rand(1:nletters, l)), G)
end end
Base.isfinite(::AbstractFPGroup) = ( function Base.isfinite(::AbstractFPGroup)
@warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false return (
) @warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false
)
end
## FPGroupElement ## FPGroupElement
@ -93,18 +94,22 @@ mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <:
savedhash::UInt savedhash::UInt
parent::Gr parent::Gr
FPGroupElement( function FPGroupElement(
word::W, word::W,
G::AbstractFPGroup, G::AbstractFPGroup,
hash::UInt=UInt(0), hash::UInt = UInt(0),
) where {W<:AbstractWord} = new{typeof(G),W}(word, hash, G) ) where {W<:AbstractWord}
return new{typeof(G),W}(word, hash, G)
end
FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} = function FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W}
new{Gr,W}(word, UInt(0), G) return new{Gr,W}(word, UInt(0), G)
end
end end
Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr} = function Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr}
print(io, FPGroupElement, "{$Gr, …}") return print(io, FPGroupElement, "{$Gr, …}")
end
word(f::AbstractFPGroupElement) = f.word word(f::AbstractFPGroupElement) = f.word
@ -142,11 +147,12 @@ function Base.:(*)(g::GEl, h::GEl) where {GEl<:AbstractFPGroupElement}
return GEl(word(g) * word(h), parent(g)) return GEl(word(g) * word(h), parent(g))
end end
GroupsCore.isfiniteorder(g::AbstractFPGroupElement) = function GroupsCore.isfiniteorder(g::AbstractFPGroupElement)
isone(g) ? true : return isone(g) ? true :
( (
@warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false @warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false
) )
end
# additional methods: # additional methods:
Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g))) Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g)))
@ -167,9 +173,7 @@ end
FreeGroup(gens, A::Alphabet) = FreeGroup(gens, KnuthBendix.LenLex(A)) FreeGroup(gens, A::Alphabet) = FreeGroup(gens, KnuthBendix.LenLex(A))
function FreeGroup(A::Alphabet) function FreeGroup(A::Alphabet)
@boundscheck @assert all( @boundscheck @assert all(KnuthBendix.hasinverse(l, A) for l in A)
KnuthBendix.hasinverse(l, A) for l in A
)
gens = Vector{eltype(A)}() gens = Vector{eltype(A)}()
invs = Vector{eltype(A)}() invs = Vector{eltype(A)}()
for l in A for l in A
@ -193,8 +197,9 @@ function FreeGroup(n::Integer)
return FreeGroup(symbols[1:2:2n], Alphabet(symbols, inverses)) return FreeGroup(symbols[1:2:2n], Alphabet(symbols, inverses))
end end
Base.show(io::IO, F::FreeGroup) = function Base.show(io::IO, F::FreeGroup)
print(io, "free group on $(ngens(F)) generators") return print(io, "free group on $(ngens(F)) generators")
end
# mandatory methods: # mandatory methods:
KnuthBendix.ordering(F::FreeGroup) = F.ordering KnuthBendix.ordering(F::FreeGroup) = F.ordering
@ -205,8 +210,9 @@ relations(F::FreeGroup) = Pair{eltype(F),eltype(F)}[]
# these are mathematically correct # these are mathematically correct
Base.isfinite(::FreeGroup) = false Base.isfinite(::FreeGroup) = false
GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) = function GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup})
isone(g) ? true : false return isone(g) ? true : false
end
## FP Groups ## FP Groups
@ -222,8 +228,8 @@ rewriting(G::FPGroup) = G.rw
function FPGroup( function FPGroup(
G::AbstractFPGroup, G::AbstractFPGroup,
rels::AbstractVector{<:Pair{GEl,GEl}}; rels::AbstractVector{<:Pair{GEl,GEl}};
ordering=KnuthBendix.ordering(G), ordering = KnuthBendix.ordering(G),
kwargs... kwargs...,
) where {GEl<:FPGroupElement} ) where {GEl<:FPGroupElement}
for (lhs, rhs) in rels for (lhs, rhs) in rels
@assert parent(lhs) === parent(rhs) === G @assert parent(lhs) === parent(rhs) === G
@ -253,8 +259,9 @@ function Base.show(io::IO, G::FPGroup)
return print(io, "") return print(io, "")
end end
Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T} = function Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T}
print(io, FPGroup, "{$T, …}") return print(io, FPGroup, "{$T, …}")
end
## GSymbol aka letter of alphabet ## GSymbol aka letter of alphabet

View File

@ -8,22 +8,40 @@ radius and multiplication operation to be used.
""" """
function wlmetric_ball( function wlmetric_ball(
S::AbstractVector{T}, S::AbstractVector{T},
center::T=one(first(S)); center::T = one(first(S));
radius=2, radius = 2,
op=*, op = *,
threading=true threading = true,
) where {T} ) where {T}
threading && return wlmetric_ball_thr(S, center, radius=radius, op=op) threading && return wlmetric_ball_thr(S, center; radius = radius, op = op)
return wlmetric_ball_serial(S, center, radius=radius, op=op) return wlmetric_ball_serial(S, center; radius = radius, op = op)
end end
function wlmetric_ball_serial(S::AbstractVector{T}, center::T=one(first(S)); radius=2, op=*) where {T} function wlmetric_ball_serial(
S::AbstractVector{T},
center::T = one(first(S));
radius = 2,
op = *,
) where {T}
@assert radius >= 1 @assert radius >= 1
old = union!([center], [center * s for s in S]) old = union!(OrderedSet([center]), [center * s for s in S])
return _wlmetric_ball(S, old, radius, op, collect, unique!) sizes = [1, length(old)]
for _ in 2:radius
new = collect(
op(o, s) for o in @view(old.dict.keys[sizes[end-1]:end]) for s in S
)
union!(old, new)
push!(sizes, length(old))
end
return old.dict.keys, sizes[2:end]
end end
function wlmetric_ball_thr(S::AbstractVector{T}, center::T=one(first(S)); radius=2, op=*) where {T} function wlmetric_ball_thr(
S::AbstractVector{T},
center::T = one(first(S));
radius = 2,
op = *,
) where {T}
@assert radius >= 1 @assert radius >= 1
old = union!([center], [center * s for s in S]) old = union!([center], [center * s for s in S])
return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique) return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique)
@ -31,12 +49,13 @@ end
function _wlmetric_ball(S, old, radius, op, collect, unique) function _wlmetric_ball(S, old, radius, op, collect, unique)
sizes = [1, length(old)] sizes = [1, length(old)]
for r in 2:radius for _ in 2:radius
old = let old = old, S = S, old = let old = old, S = S
new = collect( new = collect(
(g = op(o, s); normalform!(g); hash(g); g) (g = op(o, s);
# normalform! and hash are to make assure thread-safety of produced elts normalform!(g);
for o in @view(old[sizes[end-1]:end]) for s in S hash(g);
g) for o in @view(old[sizes[end-1]:end]) for s in S
) )
append!(old, new) append!(old, new)
@ -46,4 +65,3 @@ function _wlmetric_ball(S, old, radius, op, collect, unique)
end end
return old, sizes[2:end] return old, sizes[2:end]
end end