diff --git a/.travis.yml b/.travis.yml index 47a23da..ef4adb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ matrix: ## uncomment the following lines to override the default test script script: - - julia -e 'Pkg.clone("https://github.com/Nemocas/Nemo.jl"); Pkg.build("Nemo")' +# - julia -e 'Pkg.clone("https://github.com/Nemocas/Nemo.jl"); Pkg.build("Nemo")' - julia -e 'Pkg.clone(pwd()); Pkg.build("Groups"); Pkg.test("Groups"; coverage=true)' after_success: diff --git a/src/AutGroup.jl b/src/AutGroup.jl index 3bc63ae..c48a28c 100644 --- a/src/AutGroup.jl +++ b/src/AutGroup.jl @@ -7,8 +7,7 @@ struct AutSymbol <: GSymbol str::String pow::Int - ex::Expr - func::Function + typ::Union{RTransvect, LTransvect, FlipAut, PermAut, Identity} end AutGroupElem = GWord{AutSymbol} @@ -36,21 +35,23 @@ parent_type(::AutGroupElem) = AutGroup # ############################################################################### -function ϱ(i,j, pow=1) - # @assert i ≠ j - return v -> [(k==i ? v[i]*v[j]^pow : v[k]) for k in eachindex(v)] +function (ϱ::RTransvect)(v, pow=1::Int) + return [(k==ϱ.i ? v[ϱ.i]*v[ϱ.j]^pow : v[k]) for k in eachindex(v)] end -function λ(i,j, pow=1) - # @assert i ≠ j - return v -> [(k==i ? v[j]^pow*v[i] : v[k]) for k in eachindex(v)] +function (λ::LTransvect)(v, pow=1::Int) + return [(k==λ.i ? v[λ.j]^pow*v[λ.i] : v[k]) for k in eachindex(v)] end -function σ(p::Generic.perm, pow=1) - return v -> [v[(p^pow)[k]] for k in eachindex(v)] +function (σ::PermAut)(v, pow=1::Int) + return v[(σ.p^pow).d] end -ɛ(i, pow=1) = v -> [(k==i ? v[k]^(-1*(2+pow%2)%2) : v[k]) for k in eachindex(v)] +function (ɛ::FlipAut)(v, pow=1::Int) + return [(k==ɛ.i ? v[k]^(-1^pow) : v[k]) for k in eachindex(v)] +end + +(::Identity)(v, pow=1::Int) = v # taken from ValidatedNumerics, under under the MIT "Expat" License: # https://github.com/JuliaIntervals/ValidatedNumerics.jl/blob/master/LICENSE.md @@ -60,32 +61,36 @@ function subscriptify(n::Int) end function id_autsymbol() - return AutSymbol("(id)", 0, :(id()), identity) + return AutSymbol("(id)", 0, Identity()) end function rmul_autsymbol(i, j; pow::Int=1) str = "ϱ"*subscriptify(i)*subscriptify(j) - return AutSymbol(str, pow, :(ϱ($i, $j, $pow)), ϱ(i, j, pow)) + return AutSymbol(str, pow, RTransvect(i, j)) end function lmul_autsymbol(i, j; pow::Int=1) str = "λ"*subscriptify(i)*subscriptify(j) - return AutSymbol(str, pow, :(λ($i, $j, $pow)), λ(i, j, pow)) + return AutSymbol(str, pow, LTransvect(i, j)) end function flip_autsymbol(i; pow::Int=1) - str = "ɛ"*subscriptify(i) pow = (2+pow%2)%2 - return AutSymbol(str, pow, :(ɛ($i, $pow)), ɛ(i, pow)) + if pow == 0 + return id_autsymbol() + else + str = "ɛ"*subscriptify(i) + return AutSymbol(str, pow, FlipAut(i)) + end end function perm_autsymbol(p::Generic.perm; pow::Int=1) + p = p^pow if p == parent(p)() - return id_autsymbol() + return id_autsymbol() else - p = p^pow - str = "σ"*join([subscriptify(i) for i in p.d]) - return AutSymbol(str, 1, :(σ($(p.d), 1)), σ(p, 1)) + str = "σ"*join([subscriptify(i) for i in p.d]) + return AutSymbol(str, 1, PermAut(p)) end end @@ -94,38 +99,30 @@ function perm_autsymbol(a::Vector{Int}) return perm_autsymbol(G(a)) end -function getperm(s::AutSymbol) - if s.ex.args[1] == :σ - p = s.ex.args[2] - return PermutationGroup(length(p))(p) - else - throw(ArgumentError("$s is not a permutation automorphism!")) - end -end - ############################################################################### # # AutGroup / AutGroupElem constructors # ############################################################################### -function AutGroup(G::FreeGroup; outer=false, special=false) +function AutGroup(G::FreeGroup; special=false) n = length(G.gens) n == 0 && return AutGroup(G, AutSymbol[]) S = AutSymbol[] + indexing = [[i,j] for i in 1:n for j in 1:n if i≠j] + rmuls = [rmul_autsymbol(i,j) for (i,j) in indexing] - append!(S, rmuls) lmuls = [lmul_autsymbol(i,j) for (i,j) in indexing] - append!(S, lmuls) + + append!(S, [rmuls; lmuls]) + if !special flips = [flip_autsymbol(i) for i in 1:n] - append!(S, flips) - end - if !outer - perms = collect(elements(PermutationGroup(n))) - perms = [perm_autsymbol(p) for p in perms[2:end]] # leave the identity - append!(S, perms) + syms = [perm_autsymbol(p) for p in elements(PermutationGroup(n))][2:end] + + append!(S, [flips; syms]) + end return AutGroup(G, S) end @@ -160,10 +157,12 @@ end ############################################################################### function (f::AutSymbol){T}(v::Vector{GWord{T}}) - if f.pow == 0 - return v - end - return f.func(v) + if f.pow == 0 + nothing + else + v = f.typ(v, f.pow) + end + return v end function (F::AutGroupElem)(v::Vector) @@ -182,30 +181,31 @@ end hash(s::AutSymbol, h::UInt) = hash(s.str, hash(s.pow, hash(:AutSymbol, h))) function hash(g::AutGroupElem, h::UInt) - gs = gens(parent(g).objectGroup) - return hash(g(gs), hash(typeof(g), hash(parent(g), h))) + if g.modified + g.savedhash = hash(g(gens(parent(g).objectGroup)), hash(typeof(g), hash(parent(g), h))) + g.modified = false + end + return g.savedhash end function change_pow(s::AutSymbol, n::Int) if n == 0 return id_autsymbol() end - symbol = s.ex.args[1] - if symbol == :ɛ - return flip_autsymbol(s.ex.args[2], pow=n) - elseif symbol == :σ - G = PermutationGroup(length(s.ex.args[2])) - return perm_autsymbol(G(s.ex.args[2]), pow=n) - elseif symbol == :ϱ - s.ex.args[2:end-1] - return rmul_autsymbol(s.ex.args[2:end-1]..., pow=n) - elseif symbol == :λ - return lmul_autsymbol(s.ex.args[2:end-1]..., pow=n) - elseif symbol == :id + symbol = s.typ + if isa(symbol, FlipAut) + return flip_autsymbol(symbol.i, pow=n) + elseif isa(symbol, PermAut) + return perm_autsymbol(symbol.p, pow=n) + elseif isa(symbol, RTransvect) + return rmul_autsymbol(symbol.i, symbol.j, pow=n) + elseif isa(symbol, LTransvect) + return lmul_autsymbol(symbol.i, symbol.j, pow=n) + elseif isa(symbol, Identity) return s else warn("Changing power of an unknown type of symbol! $s") - return AutSymbol(s.str, n, s.ex, s.func) + return AutSymbol(s.str, n, s.typ) end end @@ -257,18 +257,22 @@ inv(f::AutSymbol) = change_pow(f, -f.pow) # ############################################################################### -ispermauto(s::AutSymbol) = s.ex.args[1] == :σ +function getperm(s::AutSymbol) + isa(s.typ, PermAut) || throw("$s is not a permutation automorphism") + return s.typ.p +end function simplify_perms!(W::AutGroupElem) reduced = true for i in 1:length(W.symbols) - 1 current = W.symbols[i] - if ispermauto(current) - if current.pow != 1 - current = perm_autsymbol(perm(current), pow=current.pow) - end + if isa(current.typ, PermAut) next_s = W.symbols[i+1] - if ispermauto(next_s) + if isa(next_s.typ, PermAut) + if current.pow != 1 + current = perm_autsymbol(perm(current), pow=current.pow) + end + reduced = false if next_s.pow != 1 next_s = perm_autsymbol(perm(next_s), pow=next_s.pow) @@ -295,7 +299,7 @@ function reduce!(W::AutGroupElem) end end - W.modified = false - W.savedhash = hash(W.symbols,hash(typeof(W))) + W.modified = true + return W end diff --git a/src/Groups.jl b/src/Groups.jl index cb2c78a..d324a2b 100644 --- a/src/Groups.jl +++ b/src/Groups.jl @@ -1,3 +1,4 @@ +__precompile__() module Groups using Nemo @@ -376,30 +377,23 @@ end # ############################################################################### -function products(X::AbstractVector{T}, Y::AbstractVector{T}, op=*) where {T<:GroupElem} - - result = Vector{T}() - seen = Set{T}() - for x in X - for y in Y - z = op(x,y) - if !in(z, seen) - push!(seen, z) - push!(result, z) - end - end - end - return result -end - -function generate_balls(S::Vector{T}, Id::T; radius=2, op=*) where {T<:GroupElem} - - sizes = Vector{Int}() - S = deepcopy(S) - S = unshift!(S, Id) +function generate_balls{T<:GroupElem}(S::Vector{T}, Id::T=parent(first(S))(); radius=2, op=*) + sizes = Int[] B = [Id] for i in 1:radius - B = products(B, S, op); + BB = [op(i,j) for (i,j) in Base.product(B,S)] + B = unique([B; vec(BB)]) + push!(sizes, length(B)) + end + return B, sizes +end + +function generate_balls{T<:RingElem}(S::Vector{T}, Id::T=one(parent(first(S))); radius=2, op=*) + sizes = Int[] + B = [Id] + for i in 1:radius + BB = [op(i,j) for (i,j) in Base.product(B,S)] + B = unique([B; vec(BB)]) push!(sizes, length(B)) end return B, sizes diff --git a/test/AutGroup-tests.jl b/test/AutGroup-tests.jl index 98aaae9..ea0d6cb 100644 --- a/test/AutGroup-tests.jl +++ b/test/AutGroup-tests.jl @@ -5,7 +5,7 @@ @testset "AutSymbol" begin @test_throws MethodError Groups.AutSymbol("a") @test_throws MethodError Groups.AutSymbol("a", 1) - f = Groups.AutSymbol("a", 1, :(a()), v -> v) + f = Groups.AutSymbol("a", 1, Groups.FlipAut(2)) @test isa(f, Groups.GSymbol) @test isa(f, Groups.AutSymbol) @test isa(Groups.perm_autsymbol(G([1,2,3,4])), Groups.AutSymbol) @@ -83,7 +83,7 @@ end @testset "AutGroup/AutGroupElem constructors" begin - f = Groups.AutSymbol("a", 1, :(a()), v -> v) + f = Groups.AutSymbol("a", 1, Groups.FlipAut(1)) @test isa(AutGroupElem(f), Groups.GWord) @test isa(AutGroupElem(f), AutGroupElem) @test isa(AutGroup(FreeGroup(3)), Nemo.Group) @@ -129,7 +129,6 @@ @test (Groups.change_pow(f, -2)).pow == 1 @test (inv(f)).pow == 1 - f = Groups.perm_autsymbol(G([2,1,4,3])) @test isa(inv(f), Groups.AutSymbol) @@ -150,6 +149,16 @@ b = Groups.flip_autsymbol(2)*A(inv(Groups.rmul_autsymbol(1,2))) @test a*b == b*a @test a^3 * b^3 == A() + g,h = Nemo.gens(A)[[1,8]] + domain = Nemo.gens(A.objectGroup) + @test (g*h)(domain) == (h*g)(domain) + @test (g*h).savedhash != (h*g).savedhash + a = g*h + b = h*g + @test hash(a) == hash(b) + @test a.savedhash == b.savedhash + @test length(unique([a,b])) == 1 + @test length(unique([g*h, h*g])) == 1 end @testset "specific Aut(F4) tests" begin @@ -164,7 +173,7 @@ S_inv = [S..., [inv(s) for s in S]...] @test length(unique(S_inv)) == 75 - G = AutGroup(FreeGroup(N), special=true, outer=true) + G = AutGroup(FreeGroup(N), special=true) S = Nemo.gens(G) S_inv = [G(), S..., [inv(s) for s in S]...] S_inv = unique(S_inv)