diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 120000 index 0000000..90107d8 --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1 @@ +../.JuliaFormatter.toml \ No newline at end of file diff --git a/src/Groups.jl b/src/Groups.jl index f34a7b7..96c7d09 100644 --- a/src/Groups.jl +++ b/src/Groups.jl @@ -14,7 +14,14 @@ import KnuthBendix: alphabet, ordering 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 diff --git a/src/abelianize.jl b/src/abelianize.jl index 1ab92ee..1ad1588 100644 --- a/src/abelianize.jl +++ b/src/abelianize.jl @@ -1,7 +1,8 @@ function _abelianize( i::Integer, source::AutomorphismGroup{<:FreeGroup}, - target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T} + target::MatrixGroups.SpecialLinearGroup{N,T}, +) where {N,T} n = ngens(object(source)) @assert n == N aut = alphabet(source)[i] @@ -12,7 +13,7 @@ function _abelianize( eij = MatrixGroups.ElementaryMatrix{N}( aut.j, aut.i, - ifelse(aut.inv, -one(T), one(T)) + ifelse(aut.inv, -one(T), one(T)), ) k = alphabet(target)[eij] return word_type(target)([k]) @@ -24,7 +25,8 @@ end function _abelianize( i::Integer, 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)) @assert n == N g = alphabet(source)[i].autFn_word @@ -39,7 +41,7 @@ end function Groups._abelianize( i::Integer, source::AutomorphismGroup{<:Groups.SurfaceGroup}, - target::MatrixGroups.SymplecticGroup{N,T} + target::MatrixGroups.SymplecticGroup{N,T}, ) where {N,T} @assert iseven(N) As = alphabet(source) @@ -50,7 +52,7 @@ function Groups._abelianize( MatrixGroups.SpecialLinearGroup{2genus}(T) 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) Dict(MatrixGroups.matrix(g) => word(g) for g in union(S, inv.(S))) diff --git a/src/autgroups.jl b/src/autgroups.jl index c255b47..2d4ff18 100644 --- a/src/autgroups.jl +++ b/src/autgroups.jl @@ -1,5 +1,5 @@ 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] return Alphabet(S, inversions) end @@ -26,7 +26,10 @@ function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup}) return imf 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) if _isvalidhash(g) && _isvalidhash(h) @@ -79,32 +82,46 @@ end # eye-candy -Base.show(io::IO, ::Type{<:FPGroupElement{<:AutomorphismGroup{T}}}) where {T} = - print(io, "Automorphism{$T, …}") +function Base.show( + 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):") d = domain(a) im = evaluate(a) for (x, imx) in zip(d, im[1:end-1]) println(io, " │ $x ↦ $imx") end - println(io, " └ $(last(d)) ↦ $(last(im))") + return println(io, " └ $(last(d)) ↦ $(last(im))") end ## 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)))...) -evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f) +function evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) + return evaluate!(domain(f), f) +end function evaluate!( t::NTuple{N,T}, f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}}, - tmp=one(first(t)), + tmp = one(first(t)), ) where {N,T<:FPGroupElement} A = alphabet(f) for idx in word(f) @@ -113,7 +130,11 @@ function evaluate!( return t 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 @@ -135,13 +156,13 @@ function LettersMap(a::FPGroupElement{<:AutomorphismGroup}) # (trusting it's a set of generators that define a) @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 return LettersMap(indices_map, A) end - function Base.getindex(lm::LettersMap, i::Integer) # here i is an index of an alphabet @boundscheck 1 ≤ i ≤ length(lm.A) diff --git a/src/constructions/direct_power.jl b/src/constructions/direct_power.jl index 25ffb4f..7e69b68 100644 --- a/src/constructions/direct_power.jl +++ b/src/constructions/direct_power.jl @@ -12,25 +12,29 @@ struct DirectPowerElement{GEl,N,Gr<:GroupsCore.Group} <: GroupsCore.GroupElement parent::DirectPower{Gr,N,GEl} end -DirectPowerElement( +function DirectPowerElement( elts::AbstractVector{<:GroupsCore.GroupElement}, 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 -Base.one(G::DirectPower) = - DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G) +function Base.one(G::DirectPower) + return DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G) +end -Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl} = - DirectPowerElement{GEl,N,Gr} +function Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl} + return DirectPowerElement{GEl,N,Gr} +end function Base.iterate(G::DirectPower) itr = Iterators.ProductIterator(ntuple(i -> G.group, _nfold(G))) res = iterate(itr) @assert res !== nothing elt = DirectPowerElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.iterate(G::DirectPower, state) @@ -38,7 +42,7 @@ function Base.iterate(G::DirectPower, state) res = iterate(itr, st) res === nothing && return nothing elt = DirectPowerElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end 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)) -GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} = - convert(I, order(I, G.group)^_nfold(G)) +function GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} + return convert(I, order(I, G.group)^_nfold(G)) +end GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group) @@ -83,13 +88,18 @@ end GroupsCore.parent(g::DirectPowerElement) = g.parent -Base.:(==)(g::DirectPowerElement, h::DirectPowerElement) = - (parent(g) === parent(h) && g.elts == h.elts) +function Base.:(==)(g::DirectPowerElement, h::DirectPowerElement) + return (parent(g) === parent(h) && g.elts == h.elts) +end Base.hash(g::DirectPowerElement, h::UInt) = hash(g.elts, hash(parent(g), h)) -Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict) = - DirectPowerElement(Base.deepcopy_internal(g.elts, stackdict), parent(g)) +function Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict) + return DirectPowerElement( + Base.deepcopy_internal(g.elts, stackdict), + parent(g), + ) +end 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)) end -GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} = - convert(I, reduce(lcm, (order(I, h) for h in g.elts), init=one(I))) +function GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} + 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) function Base.show(io::IO, G::DirectPower) n = _nfold(G) 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 -Base.show(io::IO, g::DirectPowerElement) = - print(io, "( ", join(g.elts, ", "), " )") diff --git a/src/constructions/direct_product.jl b/src/constructions/direct_product.jl index 0ea6dfe..a522f6e 100644 --- a/src/constructions/direct_product.jl +++ b/src/constructions/direct_product.jl @@ -14,18 +14,22 @@ end DirectProductElement(g, h, G::DirectProduct) = DirectProduct((g, h), G) -Base.one(G::DirectProduct) = - DirectProductElement((one(G.first), one(G.last)), G) +function Base.one(G::DirectProduct) + return DirectProductElement((one(G.first), one(G.last)), G) +end -Base.eltype(::Type{<:DirectProduct{Gt,Ht,GEl,HEl}}) where {Gt,Ht,GEl,HEl} = - DirectProductElement{GEl,HEl,Gt,Ht} +function Base.eltype( + ::Type{<:DirectProduct{Gt,Ht,GEl,HEl}}, +) where {Gt,Ht,GEl,HEl} + return DirectProductElement{GEl,HEl,Gt,Ht} +end function Base.iterate(G::DirectProduct) itr = Iterators.product(G.first, G.last) res = iterate(itr) @assert res !== nothing elt = DirectProductElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.iterate(G::DirectProduct, state) @@ -33,7 +37,7 @@ function Base.iterate(G::DirectProduct, state) res = iterate(itr, st) res === nothing && return nothing elt = DirectProductElement(first(res), G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end 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)) -GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer} = - convert(I, order(I, G.first) * order(I, G.last)) +function GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer} + return convert(I, order(I, G.first) * order(I, G.last)) +end GroupsCore.ngens(G::DirectProduct) = ngens(G.first) + ngens(G.last) 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] end @@ -75,28 +82,45 @@ end GroupsCore.parent(g::DirectProductElement) = g.parent -Base.:(==)(g::DirectProductElement, h::DirectProductElement) = - (parent(g) === parent(h) && g.elts == h.elts) +function Base.:(==)(g::DirectProductElement, h::DirectProductElement) + return (parent(g) === parent(h) && g.elts == h.elts) +end Base.hash(g::DirectProductElement, h::UInt) = hash(g.elts, hash(parent(g), h)) -Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict) = - DirectProductElement(Base.deepcopy_internal(g.elts, stackdict), parent(g)) +function Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict) + return DirectProductElement( + Base.deepcopy_internal(g.elts, stackdict), + parent(g), + ) +end -Base.inv(g::DirectProductElement) = - DirectProductElement(inv.(g.elts), parent(g)) +function Base.inv(g::DirectProductElement) + return DirectProductElement(inv.(g.elts), parent(g)) +end function Base.:(*)(g::DirectProductElement, h::DirectProductElement) @assert parent(g) === parent(h) return DirectProductElement(g.elts .* h.elts, parent(g)) end -GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer} = - convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts)))) +function GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer} + return convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts)))) +end Base.isone(g::DirectProductElement) = all(isone, g.elts) -Base.show(io::IO, G::DirectProduct) = - print(io, "Direct product of $(G.first) and $(G.last)") -Base.show(io::IO, g::DirectProductElement) = - print(io, "( $(join(g.elts, ",")) )") +function Base.show(io::IO, G::DirectProduct) + return print(io, "Direct product of $(G.first) and $(G.last)") +end +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 diff --git a/src/constructions/wreath_product.jl b/src/constructions/wreath_product.jl index aa61198..bb4fa57 100644 --- a/src/constructions/wreath_product.jl +++ b/src/constructions/wreath_product.jl @@ -1,4 +1,5 @@ -import PermutationGroups: AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup +import PermutationGroups: + AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup """ WreathProduct(G::Group, P::AbstractPermutationGroup) <: Group @@ -38,21 +39,22 @@ struct WreathProductElement{ p::AbstractPerm, 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 Base.one(W::WreathProduct) = WreathProductElement(one(W.N), one(W.P), W) -Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} = - WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}} +function Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} + return WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}} +end function Base.iterate(G::WreathProduct) itr = Iterators.product(G.N, G.P) res = iterate(itr) @assert res !== nothing elt = WreathProductElement(first(res)..., G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end function Base.iterate(G::WreathProduct, state) @@ -60,7 +62,7 @@ function Base.iterate(G::WreathProduct, state) res = iterate(itr, st) res === nothing && return nothing elt = WreathProductElement(first(res)..., G) - return elt, (iterator=itr, state=last(res)) + return elt, (iterator = itr, state = last(res)) end 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)) -GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer} = - convert(I, order(I, G.N) * order(I, G.P)) +function GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer} + return convert(I, order(I, G.N) * order(I, G.P)) +end function GroupsCore.gens(G::WreathProduct) N_gens = [WreathProductElement(n, one(G.P), G) for n in gens(G.N)] @@ -93,18 +96,19 @@ function Base.rand( rng::Random.AbstractRNG, rs::Random.SamplerTrivial{<:WreathProduct}, ) - G = rs[] return WreathProductElement(rand(rng, G.N), rand(rng, G.P), G) end GroupsCore.parent(g::WreathProductElement) = g.parent -Base.:(==)(g::WreathProductElement, h::WreathProductElement) = - parent(g) === parent(h) && g.n == h.n && g.p == h.p +function Base.:(==)(g::WreathProductElement, h::WreathProductElement) + return parent(g) === parent(h) && g.n == h.n && g.p == h.p +end -Base.hash(g::WreathProductElement, h::UInt) = - hash(g.n, hash(g.p, hash(g.parent, h))) +function Base.hash(g::WreathProductElement, h::UInt) + return hash(g.n, hash(g.p, hash(g.parent, h))) +end function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict) return WreathProductElement( @@ -114,8 +118,9 @@ function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict) ) end -_act(p::AbstractPerm, n::DirectPowerElement) = - DirectPowerElement(n.elts^p, parent(n)) +function _act(p::AbstractPerm, n::DirectPowerElement) + return DirectPowerElement(n.elts^p, parent(n)) +end function Base.inv(g::WreathProductElement) pinv = inv(g.p) @@ -129,8 +134,9 @@ end Base.isone(g::WreathProductElement) = isone(g.n) && isone(g.p) -Base.show(io::IO, G::WreathProduct) = - print(io, "Wreath product of $(G.N.group) by $(G.P)") +function Base.show(io::IO, G::WreathProduct) + 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.copy(g::WreathProductElement) = WreathProductElement(g.n, g.p, parent(g)) diff --git a/src/hashing.jl b/src/hashing.jl index ed729b1..5c33019 100644 --- a/src/hashing.jl +++ b/src/hashing.jl @@ -20,8 +20,12 @@ _isvalidhash(g::AbstractFPGroupElement) = bitget(g.savedhash, 1) _setnormalform(h::UInt, v::Bool) = bitset(h, v, 0) _setvalidhash(h::UInt, v::Bool) = bitset(h, v, 1) -_setnormalform!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v) -_setvalidhash!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setvalidhash(g.savedhash, v) +function _setnormalform!(g::AbstractFPGroupElement, v::Bool) + 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 # normal form of `g`: diff --git a/src/homomorphisms.jl b/src/homomorphisms.jl index d045d47..09e9355 100644 --- a/src/homomorphisms.jl +++ b/src/homomorphisms.jl @@ -67,11 +67,13 @@ struct Homomorphism{Gr1,Gr2,I,W} f, source::AbstractFPGroup, target::AbstractFPGroup; - check=true + check = true, ) A = alphabet(source) - dct = Dict(i => convert(word_type(target), f(i, source, target)) - for i in 1:length(A)) + dct = Dict( + i => convert(word_type(target), f(i, source, target)) for + i in 1:length(A) + ) I = eltype(word_type(source)) W = word_type(target) hom = new{typeof(source),typeof(target),I,W}(dct, source, target) @@ -79,7 +81,6 @@ struct Homomorphism{Gr1,Gr2,I,W} if check @assert hom(one(source)) == one(target) for x in gens(source) - @assert hom(x^-1) == hom(x)^-1 for y in gens(source) @@ -111,4 +112,6 @@ function (h::Homomorphism)(g::AbstractFPGroupElement) return h.target(w) 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 diff --git a/src/types.jl b/src/types.jl index bbe332f..336b570 100644 --- a/src/types.jl +++ b/src/types.jl @@ -42,10 +42,7 @@ KnuthBendix.alphabet(G::AbstractFPGroup) = alphabet(ordering(G)) Base.@propagate_inbounds function (G::AbstractFPGroup)( word::AbstractVector{<:Integer}, ) - @boundscheck @assert all( - l -> 1 <= l <= length(alphabet(G)), - word, - ) + @boundscheck @assert all(l -> 1 <= l <= length(alphabet(G)), word) return FPGroupElement(word_type(G)(word), G) end @@ -53,8 +50,9 @@ end Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G) -Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} = - FPGroupElement{FPG,word_type(FPG)} +function Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} + return FPGroupElement{FPG,word_type(FPG)} +end include("iteration.jl") @@ -65,8 +63,9 @@ function GroupsCore.gens(G::AbstractFPGroup, i::Integer) l = alphabet(G)[G.gens[i]] return FPGroupElement(word_type(G)([l]), G) end -GroupsCore.gens(G::AbstractFPGroup) = - [gens(G, i) for i in 1:GroupsCore.ngens(G)] +function GroupsCore.gens(G::AbstractFPGroup) + return [gens(G, i) for i in 1:GroupsCore.ngens(G)] +end # TODO: ProductReplacementAlgorithm function Base.rand( @@ -79,9 +78,11 @@ function Base.rand( return FPGroupElement(word_type(G)(rand(1:nletters, l)), G) end -Base.isfinite(::AbstractFPGroup) = ( - @warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false -) +function Base.isfinite(::AbstractFPGroup) + return ( + @warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false + ) +end ## FPGroupElement @@ -93,18 +94,22 @@ mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <: savedhash::UInt parent::Gr - FPGroupElement( + function FPGroupElement( word::W, G::AbstractFPGroup, - hash::UInt=UInt(0), - ) where {W<:AbstractWord} = new{typeof(G),W}(word, hash, G) + hash::UInt = UInt(0), + ) where {W<:AbstractWord} + return new{typeof(G),W}(word, hash, G) + end - FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} = - new{Gr,W}(word, UInt(0), G) + function FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} + return new{Gr,W}(word, UInt(0), G) + end end -Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr} = - print(io, FPGroupElement, "{$Gr, …}") +function Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr} + return print(io, FPGroupElement, "{$Gr, …}") +end 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)) end -GroupsCore.isfiniteorder(g::AbstractFPGroupElement) = - isone(g) ? true : - ( +function GroupsCore.isfiniteorder(g::AbstractFPGroupElement) + return isone(g) ? true : + ( @warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false ) +end # additional methods: Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g))) @@ -167,9 +173,7 @@ end FreeGroup(gens, A::Alphabet) = FreeGroup(gens, KnuthBendix.LenLex(A)) function FreeGroup(A::Alphabet) - @boundscheck @assert all( - KnuthBendix.hasinverse(l, A) for l in A - ) + @boundscheck @assert all(KnuthBendix.hasinverse(l, A) for l in A) gens = Vector{eltype(A)}() invs = Vector{eltype(A)}() for l in A @@ -193,8 +197,9 @@ function FreeGroup(n::Integer) return FreeGroup(symbols[1:2:2n], Alphabet(symbols, inverses)) end -Base.show(io::IO, F::FreeGroup) = - print(io, "free group on $(ngens(F)) generators") +function Base.show(io::IO, F::FreeGroup) + return print(io, "free group on $(ngens(F)) generators") +end # mandatory methods: KnuthBendix.ordering(F::FreeGroup) = F.ordering @@ -205,8 +210,9 @@ relations(F::FreeGroup) = Pair{eltype(F),eltype(F)}[] # these are mathematically correct Base.isfinite(::FreeGroup) = false -GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) = - isone(g) ? true : false +function GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) + return isone(g) ? true : false +end ## FP Groups @@ -222,8 +228,8 @@ rewriting(G::FPGroup) = G.rw function FPGroup( G::AbstractFPGroup, rels::AbstractVector{<:Pair{GEl,GEl}}; - ordering=KnuthBendix.ordering(G), - kwargs... + ordering = KnuthBendix.ordering(G), + kwargs..., ) where {GEl<:FPGroupElement} for (lhs, rhs) in rels @assert parent(lhs) === parent(rhs) === G @@ -253,8 +259,9 @@ function Base.show(io::IO, G::FPGroup) return print(io, " ⟩") end -Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T} = - print(io, FPGroup, "{$T, …}") +function Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T} + return print(io, FPGroup, "{$T, …}") +end ## GSymbol aka letter of alphabet diff --git a/src/wl_ball.jl b/src/wl_ball.jl index 0c52080..ae8db7d 100644 --- a/src/wl_ball.jl +++ b/src/wl_ball.jl @@ -8,22 +8,40 @@ radius and multiplication operation to be used. """ function wlmetric_ball( S::AbstractVector{T}, - center::T=one(first(S)); - radius=2, - op=*, - threading=true + center::T = one(first(S)); + radius = 2, + op = *, + threading = true, ) where {T} - threading && return wlmetric_ball_thr(S, center, radius=radius, op=op) - return wlmetric_ball_serial(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) 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 - old = union!([center], [center * s for s in S]) - return _wlmetric_ball(S, old, radius, op, collect, unique!) + old = union!(OrderedSet([center]), [center * s for s in S]) + 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 -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 old = union!([center], [center * s for s in S]) 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) sizes = [1, length(old)] - for r in 2:radius - old = let old = old, S = S, + for _ in 2:radius + old = let old = old, S = S new = collect( - (g = op(o, s); normalform!(g); hash(g); g) - # normalform! and hash are to make assure thread-safety of produced elts - for o in @view(old[sizes[end-1]:end]) for s in S + (g = op(o, s); + normalform!(g); + hash(g); + g) for o in @view(old[sizes[end-1]:end]) for s in S ) append!(old, new) @@ -46,4 +65,3 @@ function _wlmetric_ball(S, old, radius, op, collect, unique) end return old, sizes[2:end] end -