diff --git a/Project.toml b/Project.toml index 513fe43..782e45f 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "0.5.2" [deps] AbstractAlgebra = "c3fe647b-3220-5bb0-a1ea-a7954cac585d" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" GroupsCore = "d5909c97-4eac-4ecc-a3dc-fdd0858a4120" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" ThreadsX = "ac1d9e8a-700a-412c-b207-f0111f4b6c0d" diff --git a/src/Groups.jl b/src/Groups.jl index fcfdd3e..e91e8eb 100644 --- a/src/Groups.jl +++ b/src/Groups.jl @@ -22,6 +22,8 @@ include("arithmetic.jl") include("findreplace.jl") module New +using DataStructures + include("new_types.jl") include("new_hashing.jl") include("normalform.jl") diff --git a/src/iteration.jl b/src/iteration.jl new file mode 100644 index 0000000..89ce140 --- /dev/null +++ b/src/iteration.jl @@ -0,0 +1,55 @@ +mutable struct FPIterState{GEl, T} + elts::OrderedSet{GEl} + u::GEl + v::GEl + elts_iter_state::T +end + +Base.in(x, itr::FPIterState) = x in itr.elts +Base.push!(itr::FPIterState, x) = push!(itr.elts, x) +function FPIterState(G::AbstractFPGroup) + S = OrderedSet([one(G)]) + elt, state = iterate(S) + return elt, FPIterState(S, one(G), one(G), state) +end + +function Base.iterate(G::AbstractFPGroup) + elt, state = FPIterState(G) + return one(G), (state, elt, 1) +end + +function Base.iterate(G::AbstractFPGroup, state) + iter, elt, gen_idx = state + + if gen_idx > length(alphabet(G)) + res = iterate(iter.elts, iter.elts_iter_state) + res === nothing && return nothing + gen_idx = 1 + elt = first(res) + iter.elts_iter_state = last(res) + end + + res = let (u, v) = (iter.u, iter.v), elt = elt + copyto!(v, elt) # this invalidates normalform of v + push!(word(v), gen_idx) + resize!(word(u), 0) + + _setnormalform!(v, false) + _setvalidhash!(v, false) + + @assert !isnormalform(v) + normalform!(u, v) + end + + if res in iter + return iterate(G, (iter, elt, gen_idx+1)) + else + w = deepcopy(res) + @assert isnormalform(w) + push!(iter, w) + return w, (iter, elt, gen_idx+1) + end +end + +# Groups.Core default: +# Base.IteratorSize(::Type{<:AbstractFPGroup}) = Base.SizeUnknown() diff --git a/src/new_types.jl b/src/new_types.jl index d05b030..8241414 100644 --- a/src/new_types.jl +++ b/src/new_types.jl @@ -43,50 +43,7 @@ Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G) Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} = FPGroupElement{FPG, word_type(FPG)} -struct FPGroupIter{GEl} - elts::Vector{GEl} - seen::Set{GEl} - u::GEl - v::GEl -end - -FPGroupIter(G::AbstractFPGroup) = - FPGroupIter([one(G)], Set([one(G)]), one(G), one(G)) - -Base.iterate(G::AbstractFPGroup) = one(G), (FPGroupIter(G), 1, 1) -@inline function Base.iterate(G::AbstractFPGroup, state) - iter, elt_idx, gen_idx = state - - if gen_idx > length(alphabet(G)) - elt_idx == length(iter.elts) && return nothing - gen_idx = 1 - elt_idx += 1 - end - - - res = let (u, v) = (iter.u, iter.v), elt = iter.elts[elt_idx] - copyto!(v, elt) # this invalidates normalform of v - @assert !isnormalform(v) - push!(word(v), gen_idx) - resize!(word(u), 0) - - normalform!(u, v) - end - - if res in iter.seen - return iterate(G, (iter, elt_idx, gen_idx+1)) - else - w = deepcopy(res) - @assert isnormalform(w) - push!(iter.elts, w) - push!(iter.seen, w) - state = (iter, elt_idx, gen_idx+1) - return w, state - end -end - -# the default: -# Base.IteratorSize(::Type{<:AbstractFPGroup}) = Base.SizeUnknown() +include("iteration.jl") GroupsCore.ngens(G::AbstractFPGroup) = length(G.gens)