From c0c688ed2dbe5e2b0712f5d64638b44ac47baa46 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Wed, 26 May 2021 12:08:31 +0200 Subject: [PATCH] add tests for automorphisms and iteration benchmarks --- Project.toml | 3 +- test/automorphisms.jl | 184 ++++++++++++++++++++++++++++++++++++++++++ test/benchmarks.jl | 72 +++++++++++++++++ test/free_groups.jl | 8 +- test/runtests.jl | 2 + 5 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 test/automorphisms.jl create mode 100644 test/benchmarks.jl diff --git a/Project.toml b/Project.toml index cf37737..3906ff5 100644 --- a/Project.toml +++ b/Project.toml @@ -20,6 +20,7 @@ julia = "1.3, 1.4, 1.5" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" [targets] -test = ["Test"] +test = ["Test", "BenchmarkTools"] diff --git a/test/automorphisms.jl b/test/automorphisms.jl new file mode 100644 index 0000000..ecd469e --- /dev/null +++ b/test/automorphisms.jl @@ -0,0 +1,184 @@ +@testset "Automorphisms" begin + + @testset "Transvections" begin + + @test New.Transvection(:ϱ, 1, 2) isa New.GSymbol + @test New.Transvection(:ϱ, 1, 2) isa New.Transvection + @test New.Transvection(:λ, 1, 2) isa New.GSymbol + @test New.Transvection(:λ, 1, 2) isa New.Transvection + t = New.Transvection(:ϱ, 1, 2) + @test inv(t) isa New.GSymbol + @test inv(t) isa New.Transvection + + @test t != inv(t) + + s = New.Transvection(:ϱ, 1, 2) + @test t == s + @test hash(t) == hash(s) + + s_ = New.Transvection(:ϱ, 1, 3) + @test s_ != s + @test hash(s_) != hash(s) + + @test New.gersten_alphabet(3) isa Alphabet + A = New.gersten_alphabet(3) + @test length(A) == 12 + end + + A4 = Alphabet( + [:a,:A,:b,:B,:c,:C,:d,:D], + [ 2, 1, 4, 3, 6, 5, 8, 7] + ) + + A5 = Alphabet( + [:a,:A,:b,:B,:c,:C,:d,:D,:e,:E], + [ 2, 1, 4, 3, 6, 5, 8, 7,10, 9] + ) + + F4 = New.FreeGroup([:a, :b, :c, :d], A4) + A = New.SpecialAutomorphismGroup(F4, maxrules=1000) + + a,b,c,d = gens(F4) + D = ntuple(i->gens(F4, i), 4) + + @testset "Transvection action correctness" begin + i,j = 1,2 + r = New.Transvection(:ϱ,i,j) + l = New.Transvection(:λ,i,j) + + (t::New.Transvection)(v::Tuple) = New.evaluate!(v, t, A4) + + @test r(deepcopy(D)) == (a*b, b, c, d) + @test inv(r)(deepcopy(D)) == (a*b^-1,b, c, d) + @test l(deepcopy(D)) == (b*a, b, c, d) + @test inv(l)(deepcopy(D)) == (b^-1*a,b, c, d) + + i,j = 3,1 + r = New.Transvection(:ϱ,i,j) + l = New.Transvection(:λ,i,j) + @test r(deepcopy(D)) == (a, b, c*a, d) + @test inv(r)(deepcopy(D)) == (a, b, c*a^-1,d) + @test l(deepcopy(D)) == (a, b, a*c, d) + @test inv(l)(deepcopy(D)) == (a, b, a^-1*c,d) + + i,j = 4,3 + r = New.Transvection(:ϱ,i,j) + l = New.Transvection(:λ,i,j) + @test r(deepcopy(D)) == (a, b, c, d*c) + @test inv(r)(deepcopy(D)) == (a, b, c, d*c^-1) + @test l(deepcopy(D)) == (a, b, c, c*d) + @test inv(l)(deepcopy(D)) == (a, b, c, c^-1*d) + + i,j = 2,4 + r = New.Transvection(:ϱ,i,j) + l = New.Transvection(:λ,i,j) + @test r(deepcopy(D)) == (a, b*d, c, d) + @test inv(r)(deepcopy(D)) == (a, b*d^-1,c, d) + @test l(deepcopy(D)) == (a, d*b, c, d) + @test inv(l)(deepcopy(D)) == (a, d^-1*b,c, d) + end + + @testset "AutomorphismGroup constructors" begin + @test A isa New.AbstractFPGroup + @test A isa New.AutomorphismGroup + @test KnuthBendix.alphabet(A) isa Alphabet + @test New.relations(A) isa Vector{<:Pair} + + end + + @testset "Automorphisms: hash and evaluate" begin + @test New.domain(gens(A, 1)) == D + g, h = gens(A, 1), gens(A, 8) + + @test New.evaluate(g*h) == New.evaluate(h*g) + @test (g*h).savedhash == zero(UInt) + + a = g*h + b = h*g + @test hash(a) != zero(UInt) + @test hash(a) == hash(b) + @test a.savedhash == b.savedhash + + @test length(unique([a,b])) == 1 + @test length(unique([g*h, h*g])) == 1 + + # Not so simple arithmetic: applying starting on the left: + # ϱ₁₂*ϱ₂₁⁻¹*λ₁₂*ε₂ == σ₂₁₃₄ + + g = gens(A, 1) + x1, x2, x3, x4 = New.domain(g) + @test New.evaluate(g) == (x1*x2, x2, x3, x4) + + g = g*inv(gens(A, 4)) # ϱ₂₁ + @test New.evaluate(g) == (x1*x2, x1^-1, x3, x4) + + g = g*gens(A, 13) + @test New.evaluate(g) == (x2, x1^-1, x3, x4) + end + + @testset "Automorphisms: SAut(F₄)" begin + N = 4 + G = New.SpecialAutomorphismGroup(New.FreeGroup(N)) + + S = gens(G) + @test S isa Vector{<:New.FPGroupElement{<:New.AutomorphismGroup{<:New.FreeGroup}}} + + @test length(S) == 2*N*(N-1) + @test length(unique(S)) == length(S) + + S_sym = [S; inv.(S)] + @test length(S_sym) == length(unique(S_sym)) + + pushfirst!(S_sym, one(G)) + + B_2 = [i*j for (i,j) in Base.product(S_sym, S_sym)] + @test length(B_2) == 2401 + @test length(unique(B_2)) == 1777 + + @test all(g->isone(inv(g)*g), B_2) + @test all(g->isone(g*inv(g)), B_2) + end + + @testset "GroupsCore conformance" begin + test_Group_interface(A) + g = A(rand(1:length(KnuthBendix.alphabet(A)), 10)) + h = A(rand(1:length(KnuthBendix.alphabet(A)), 10)) + + test_GroupElement_interface(g, h) + end + +end + +# using Random +# using GroupsCore +# +# A = New.SpecialAutomorphismGroup(New.FreeGroup(4), maxrules=2000, ordering=KnuthBendix.RecursivePathOrder) +# +# # for seed in 1:1000 +# let seed = 68 +# N = 14 +# Random.seed!(seed) +# g = A(rand(1:length(KnuthBendix.alphabet(A)), N)) +# h = A(rand(1:length(KnuthBendix.alphabet(A)), N)) +# @info "seed=$seed" g h +# @time isone(g*inv(g)) +# @time isone(inv(g)*g) +# @info "" length(New.word(New.normalform!(g*inv(g)))) length(New.word(New.normalform!(inv(g)*g))) +# a = commutator(g, h, g) +# b = conj(inv(g), h) * conj(conj(g, h), g) +# +# @info length(New.word(a)) +# @info length(New.word(b)) +# +# w = a*inv(b) +# @info length(New.word(w)) +# New.normalform!(w) +# @info length(New.word(w)) +# +# +# # +# # @time ima = New.evaluate(a) +# # @time imb = New.evaluate(b) +# # @info "" a b ima imb +# # @time a == b +# end diff --git a/test/benchmarks.jl b/test/benchmarks.jl new file mode 100644 index 0000000..0505cda --- /dev/null +++ b/test/benchmarks.jl @@ -0,0 +1,72 @@ +using BenchmarkTools +using Test + +using Groups +using Groups.New + +function wl_ball(F; radius::Integer) + g, state = iterate(F) + while length(New.word(g)) <= radius + res = iterate(F, state) + isnothing(res) && break + g, state = res + end + elts = collect(state.seen) + elts = resize!(elts, length(elts)-1) + return elts +end + +@testset "Benchmarks" begin + N = 4 + + @testset "iteration: FreeGroup" begin + FN = New.FreeGroup(N) + R = 8 + + let G = FN + S = unique([gens(G); inv.(gens(G))]) + + sizes1 = last(Groups.wlmetric_ball(S, radius=R, threading=false)) + sizes2 = last(Groups.wlmetric_ball(S, radius=R, threading=true)) + + l = length(wl_ball(G, radius=R)) + + @test sizes1 == sizes2 + @test last(sizes1) == l + + @info "Ball of radius $R in $(parent(first(S)))" sizes=sizes1 + @info "serial" + @time Groups.wlmetric_ball(S, radius=R, threading=false) + @info "threaded" + @time Groups.wlmetric_ball(S, radius=R, threading=true) + @info "iteration" + @time wl_ball(G, radius=R) + end + end + + @testset "iteration: SAut(F_n)" begin + R = 4 + FN = New.FreeGroup(N) + SAutFN = New.SpecialAutomorphismGroup(FN) + + let G = SAutFN + S = unique([gens(G); inv.(gens(G))]) + + sizes1 = last(Groups.wlmetric_ball(S, radius=R, threading=false)) + sizes2 = last(Groups.wlmetric_ball(S, radius=R, threading=true)) + + l = length(wl_ball(G, radius=R)) + + @test sizes1 == sizes2 + @test last(sizes1) == l + + @info "Ball of radius $R in $(parent(first(S)))" sizes=sizes1 + @info "serial" + @time Groups.wlmetric_ball(S, radius=R, threading=false) + @info "threaded" + @time Groups.wlmetric_ball(S, radius=R, threading=true) + @info "iteration" + @time wl_ball(G, radius=R) + end + end +end diff --git a/test/free_groups.jl b/test/free_groups.jl index de5d1fa..181c789 100644 --- a/test/free_groups.jl +++ b/test/free_groups.jl @@ -33,12 +33,11 @@ return w end - @time k = test_iteration(F3, 10) + k = test_iteration(F3, 10) @test k == a*b^-1 - k = test_iteration(F3, 1000) - @test k == (a^2)*c^2*a^-1 @time k = test_iteration(F3, 1000) + @test k == (a^2)*c^2*a^-1 end @testset "wl_ball" begin @@ -58,9 +57,10 @@ @test length(E4) == 937 @test New.word(last(E4)) == Word([6])^4 - @time E8 = wl_ball(F3, radius=8) + E8, t, _ = @timed wl_ball(F3, radius=8) @test length(E8) == 585937 @test New.word(last(E8)) == Word([6])^8 + @test t/10^9 < 1 end @testset "GroupsCore conformance" begin diff --git a/test/runtests.jl b/test/runtests.jl index 21e9a9d..49e864d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -33,5 +33,7 @@ using LinearAlgebra include("free_groups.jl") include("fp_groups.jl") + include("automorphisms.jl") + include("benchmarks.jl") end end