diff --git a/Project.toml b/Project.toml index 6e57613..56b31ae 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Groups" uuid = "5d8bd718-bd84-11e8-3b40-ad14f4a32557" authors = ["Marek Kaluba "] -version = "0.7.6" +version = "0.7.7" [deps] GroupsCore = "d5909c97-4eac-4ecc-a3dc-fdd0858a4120" diff --git a/src/aut_groups/transvections.jl b/src/aut_groups/transvections.jl index 04505d2..5104cc7 100644 --- a/src/aut_groups/transvections.jl +++ b/src/aut_groups/transvections.jl @@ -14,12 +14,7 @@ end λ(i, j) = Transvection(:λ, i, j) function Base.show(io::IO, t::Transvection) - id = if t.id === :ϱ - 'ϱ' - else # if t.id === :λ - 'λ' - end - print(io, id, subscriptify(t.i), '.', subscriptify(t.j)) + print(io, t.id, subscriptify(t.i), '.', subscriptify(t.j)) return t.inv && print(io, "^-1") end diff --git a/src/hashing.jl b/src/hashing.jl index 48593e9..642c6f2 100644 --- a/src/hashing.jl +++ b/src/hashing.jl @@ -37,6 +37,7 @@ function _update_savedhash!(g::AbstractFPGroupElement, data) end function Base.hash(g::AbstractFPGroupElement, h::UInt) + g = normalform!(g) _isvalidhash(g) || _update_savedhash!(g, equality_data(g)) return hash(g.savedhash >> count_ones(__BITFLAGS_MASK), h) end diff --git a/src/matrix_groups/eltary_symplectic.jl b/src/matrix_groups/eltary_symplectic.jl index 1f70a5c..fb5ada7 100644 --- a/src/matrix_groups/eltary_symplectic.jl +++ b/src/matrix_groups/eltary_symplectic.jl @@ -23,7 +23,7 @@ end function Base.show(io::IO, s::ElementarySymplectic) i, j = Groups.subscriptify(s.i), Groups.subscriptify(s.j) - print(io, s.symbol, i, j) + print(io, s.symbol, i, '.', j) return !isone(s.val) && print(io, "^$(s.val)") end diff --git a/src/types.jl b/src/types.jl index b2482d9..d6a567e 100644 --- a/src/types.jl +++ b/src/types.jl @@ -88,6 +88,9 @@ end abstract type AbstractFPGroupElement{Gr} <: GroupElement end +Base.copy(g::AbstractFPGroupElement) = one(g) * g +word(f::AbstractFPGroupElement) = f.word + mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <: AbstractFPGroupElement{Gr} word::W @@ -111,7 +114,9 @@ function Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr} return print(io, FPGroupElement, "{$Gr, …}") end -word(f::AbstractFPGroupElement) = f.word +function Base.copy(f::FPGroupElement) + return FPGroupElement(copy(word(f)), parent(f), f.savedhash) +end #convenience KnuthBendix.alphabet(g::AbstractFPGroupElement) = alphabet(parent(g)) @@ -134,7 +139,13 @@ function Base.:(==)(g::AbstractFPGroupElement, h::AbstractFPGroupElement) end function Base.deepcopy_internal(g::FPGroupElement, stackdict::IdDict) - return FPGroupElement(copy(word(g)), parent(g), g.savedhash) + haskey(stackdict, objectid(g)) && return stackdict[objectid(g)] + cw = if haskey(stackdict, objectid(word(g))) + stackdict[objectid(word(g))] + else + copy(word(g)) + end + return FPGroupElement(cw, parent(g), g.savedhash) end function Base.inv(g::GEl) where {GEl<:AbstractFPGroupElement} diff --git a/src/wl_ball.jl b/src/wl_ball.jl index 96b5984..5834b58 100644 --- a/src/wl_ball.jl +++ b/src/wl_ball.jl @@ -26,8 +26,7 @@ function wlmetric_ball( new = collect( op(o, s) for o in @view(ball[sizes[end-1]:end]) for s in S ) - append!(ball, new) - unique!(ball) + ball = union!(ball, new) push!(sizes, length(ball)) end end diff --git a/test/fp_groups.jl b/test/fp_groups.jl index 5e98dd5..87e6ef7 100644 --- a/test/fp_groups.jl +++ b/test/fp_groups.jl @@ -14,7 +14,8 @@ G = FPGroup(F, [a * b => b * a, a * c => c * a, b * c => c * b]) @test G isa FPGroup - @test sprint(show, G) == "⟨ a b c | \n\t a*b => b*a a*c => c*a b*c => c*b ⟩" + @test sprint(show, G) == + "⟨ a b c | \n\t a*b => b*a a*c => c*a b*c => c*b ⟩" @test rand(G) isa FPGroupElement f = a * c * b @@ -40,7 +41,7 @@ end # quotient of G - H = FPGroup(G, [aG^2 => cG, bG * cG => aG], max_rules=200) + H = FPGroup(G, [aG^2 => cG, bG * cG => aG]; max_rules = 200) h = H(word(g)) @@ -48,15 +49,21 @@ @test_throws AssertionError h == g @test_throws MethodError h * g - H′ = FPGroup(G, [aG^2 => cG, bG * cG => aG], max_rules=200) + H′ = FPGroup(G, [aG^2 => cG, bG * cG => aG]; max_rules = 200) @test_throws AssertionError one(H) == one(H′) Groups.normalform!(h) @test h == H([5]) - @test_logs (:warn, "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong") isfiniteorder(h) + @test_logs ( + :warn, + "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong", + ) isfiniteorder(h) - @test_logs (:warn, "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong") isfinite(H) + @test_logs ( + :warn, + "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong", + ) isfinite(H) Logging.with_logger(Logging.NullLogger()) do @testset "GroupsCore conformance: H" begin @@ -64,4 +71,24 @@ test_GroupElement_interface(rand(H, 2)...) end end + + @testset "hash/normalform #28" begin + function cyclic_group(n::Integer) + A = Alphabet([:a, :A], [2, 1]) + F = FreeGroup(A) + a, = Groups.gens(F) + e = one(F) + Cₙ = FPGroup(F, [a^n => e]) + + return Cₙ + end + + n = 15 + G = cyclic_group(n) + ball, sizes = Groups.wlmetric_ball(gens(G); radius = n) + @test first(sizes) == 2 + @test last(sizes) == n + + @test Set(ball) == Set([first(gens(G))^i for i in 0:n-1]) + end end