mirror of
https://github.com/kalmarek/Groups.jl.git
synced 2024-12-25 02:05:30 +01:00
Merge branch 'master' into cosmetics
This commit is contained in:
commit
c3ee520521
12
.travis.yml
12
.travis.yml
@ -6,12 +6,18 @@ os:
|
|||||||
julia:
|
julia:
|
||||||
- release
|
- release
|
||||||
- nightly
|
- nightly
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
allow_failures:
|
||||||
|
julia: nightly
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
# uncomment the following lines to override the default test script
|
# uncomment the following lines to override the default test script
|
||||||
#script:
|
script:
|
||||||
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||||
# - julia -e 'Pkg.clone(pwd()); Pkg.build("Groups"); Pkg.test("Groups"; coverage=true)'
|
- julia -e 'Pkg.clone("https://github.com/scheinerman/Permutations.jl.git")'
|
||||||
|
- julia -e 'Pkg.clone(pwd()); Pkg.build("Groups"); Pkg.test("Groups"; coverage=true)'
|
||||||
after_success:
|
after_success:
|
||||||
# push coverage results to Coveralls
|
# push coverage results to Coveralls
|
||||||
- julia -e 'cd(Pkg.dir("Groups")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
|
- julia -e 'cd(Pkg.dir("Groups")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
module Groups
|
module Groups
|
||||||
|
|
||||||
import Base: length, ==, hash, show
|
import Base: length, ==, hash, show, convert
|
||||||
import Base: one, inv, reduce, *, ^
|
import Base: one, inv, reduce, *, ^
|
||||||
|
import Base: findfirst, findnext
|
||||||
|
|
||||||
export GSymbol, GWord
|
export GSymbol, GWord
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ type GWord{T<:GSymbol} <: Word
|
|||||||
end
|
end
|
||||||
|
|
||||||
GWord{T<:GSymbol}(s::T) = GWord{T}([s])
|
GWord{T<:GSymbol}(s::T) = GWord{T}([s])
|
||||||
|
convert{T<:GSymbol, W<:Word}(::Type{W}, s::T) = GWord{T}(s)
|
||||||
|
|
||||||
IDWord{T<:GSymbol}(::Type{T}) = GWord(one(T))
|
IDWord{T<:GSymbol}(::Type{T}) = GWord(one(T))
|
||||||
IDWord{T<:GSymbol}(W::GWord{T}) = IDWord(T)
|
IDWord{T<:GSymbol}(W::GWord{T}) = IDWord(T)
|
||||||
@ -94,7 +96,10 @@ end
|
|||||||
|
|
||||||
freegroup_reduce(W::GWord) = freegroup_reduce!(deepcopy(W))
|
freegroup_reduce(W::GWord) = freegroup_reduce!(deepcopy(W))
|
||||||
|
|
||||||
hash{T}(W::GWord{T}) = (W.modified && freegroup_reduce!(W); W.savedhash)
|
function hash{T}(W::GWord{T}, h::UInt)
|
||||||
|
W.modified && freegroup_reduce!(W)
|
||||||
|
return W.savedhash + h
|
||||||
|
end
|
||||||
|
|
||||||
function (==){T}(W::GWord{T}, Z::GWord{T})
|
function (==){T}(W::GWord{T}, Z::GWord{T})
|
||||||
W.modified && freegroup_reduce!(W) # reduce clears the flag and recalculate the hash
|
W.modified && freegroup_reduce!(W) # reduce clears the flag and recalculate the hash
|
||||||
@ -172,6 +177,72 @@ end
|
|||||||
(^)(x::GWord, n::Integer) = power_by_squaring(x,n)
|
(^)(x::GWord, n::Integer) = power_by_squaring(x,n)
|
||||||
(^){T<:GSymbol}(x::T, n::Integer) = GWord(x)^n
|
(^){T<:GSymbol}(x::T, n::Integer) = GWord(x)^n
|
||||||
|
|
||||||
|
is_subsymbol(s::GSymbol, t::GSymbol) =
|
||||||
|
s.gen == t.gen && (0 ≤ s.pow ≤ t.pow || 0 ≥ s.pow ≥ t.pow)
|
||||||
|
|
||||||
|
function findfirst(W::GWord, Z::GWord)
|
||||||
|
n = length(Z.symbols)
|
||||||
|
|
||||||
|
@assert n > 1
|
||||||
|
for (idx,a) in enumerate(W.symbols)
|
||||||
|
if idx + n - 1 > length(W.symbols)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
first = is_subsymbol(Z.symbols[1],a)
|
||||||
|
if first
|
||||||
|
middle = W.symbols[idx+1:idx+n-2] == Z.symbols[2:end-1]
|
||||||
|
last = is_subsymbol(Z.symbols[end], W.symbols[idx+n-1])
|
||||||
|
if middle && last
|
||||||
|
return idx
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function findnext(W::GWord, Z::GWord, i::Integer)
|
||||||
|
t = findfirst(GWord{eltype(W.symbols)}(W.symbols[i:end]), Z)
|
||||||
|
if t > 0
|
||||||
|
return t+i-1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function replace!(W::GWord, index, toreplace::GWord, replacement::GWord; asserts=true)
|
||||||
|
n = length(toreplace.symbols)
|
||||||
|
if asserts
|
||||||
|
@assert is_subsymbol(toreplace.symbols[1], W.symbols[index])
|
||||||
|
@assert W.symbols[index+1:index+n-2] == toreplace.symbols[2:end-1]
|
||||||
|
@assert is_subsymbol(toreplace.symbols[end], W.symbols[index+n-1])
|
||||||
|
end
|
||||||
|
|
||||||
|
first = W.symbols[index]*inv(toreplace.symbols[1])
|
||||||
|
last = W.symbols[index+n-1]*inv(toreplace.symbols[end])
|
||||||
|
replacement = first*replacement*last
|
||||||
|
splice!(W.symbols, index:index+n-1, replacement.symbols)
|
||||||
|
Groups.freegroup_reduce!(W)
|
||||||
|
return W
|
||||||
|
end
|
||||||
|
|
||||||
|
function replace(W::GWord, index, toreplace::GWord, replacement::GWord)
|
||||||
|
replace!(deepcopy(W), index, toreplace, replacement)
|
||||||
|
end
|
||||||
|
|
||||||
|
function replace_all!{T}(W::GWord{T}, subst_dict::Dict{GWord{T}, GWord{T}})
|
||||||
|
for toreplace in reverse!(sort!(collect(keys(subst_dict)),by=length))
|
||||||
|
replacement = subst_dict[toreplace]
|
||||||
|
i = findfirst(W, toreplace)
|
||||||
|
while i ≠ 0
|
||||||
|
replace!(W,i,toreplace, replacement)
|
||||||
|
i = findnext(W, toreplace, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return W
|
||||||
|
end
|
||||||
|
|
||||||
|
replace_all(W::GWord, subst_dict::Dict{GWord, GWord}) = replace_all!(deepcopy(W), subst_dict)
|
||||||
|
|
||||||
include("free_groups.jl")
|
include("free_groups.jl")
|
||||||
include("automorphism_groups.jl")
|
include("automorphism_groups.jl")
|
||||||
|
|
||||||
|
@ -7,19 +7,31 @@ immutable AutSymbol <: GSymbol
|
|||||||
gen::String
|
gen::String
|
||||||
pow::Int
|
pow::Int
|
||||||
ex::Expr
|
ex::Expr
|
||||||
|
fmap::Function
|
||||||
|
imap::Function
|
||||||
|
end
|
||||||
|
|
||||||
|
function (f::AutSymbol){T}(v::Vector{GWord{T}})
|
||||||
|
if f.pow > 0
|
||||||
|
map = f.fmap
|
||||||
|
else
|
||||||
|
map = f.imap
|
||||||
|
end
|
||||||
|
for i in 1:abs(f.pow)
|
||||||
|
v::Vector{GWord{T}} = map(v)
|
||||||
|
end
|
||||||
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
(==)(s::AutSymbol, t::AutSymbol) = s.gen == t.gen && s.pow == t.pow
|
(==)(s::AutSymbol, t::AutSymbol) = s.gen == t.gen && s.pow == t.pow
|
||||||
hash(s::AutSymbol, h::UInt) = hash(s.gen, hash(s.pow, hash(:AutSymbol, h)))
|
hash(s::AutSymbol, h::UInt) = hash(s.gen, hash(s.pow, hash(:AutSymbol, h)))
|
||||||
|
|
||||||
IdSymbol(::Type{AutSymbol}) = AutSymbol("(id)", 0, :(IdAutomorphism(N)))
|
IdSymbol(::Type{AutSymbol}) = AutSymbol("(id)", 0, :(Id(N)), v -> Vector{GWord}(v), v -> Vector{GWord}(v))
|
||||||
|
|
||||||
function change_pow(s::AutSymbol, n::Int)
|
function change_pow(s::AutSymbol, n::Int)
|
||||||
|
|
||||||
if n == 0
|
if n == 0
|
||||||
return one(s)
|
return one(s)
|
||||||
end
|
end
|
||||||
|
|
||||||
symbol = s.ex.args[1]
|
symbol = s.ex.args[1]
|
||||||
if symbol == :ɛ
|
if symbol == :ɛ
|
||||||
return flip_AutSymbol(s.ex.args[2], pow=n)
|
return flip_AutSymbol(s.ex.args[2], pow=n)
|
||||||
@ -29,29 +41,58 @@ function change_pow(s::AutSymbol, n::Int)
|
|||||||
return rmul_AutSymbol(s.ex.args[2], s.ex.args[3], pow=n)
|
return rmul_AutSymbol(s.ex.args[2], s.ex.args[3], pow=n)
|
||||||
elseif symbol == :λ
|
elseif symbol == :λ
|
||||||
return lmul_AutSymbol(s.ex.args[2], s.ex.args[3], pow=n)
|
return lmul_AutSymbol(s.ex.args[2], s.ex.args[3], pow=n)
|
||||||
elseif symbol == :IdAutomorphism
|
elseif symbol == :Id
|
||||||
return s
|
return s
|
||||||
else
|
else
|
||||||
warn("Changing an unknown type of symbol! $s")
|
warn("Changing an unknown type of symbol! $s")
|
||||||
return AutSymbol(s.gen, n, s.ex)
|
return AutSymbol(s.gen, n, s.ex, s.fmap, s.imap)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
inv(f::AutSymbol) = change_pow(f, -f.pow)
|
inv(f::AutSymbol) = change_pow(f, -f.pow)
|
||||||
|
|
||||||
|
function ϱ(i,j)
|
||||||
|
# @assert i ≠ j
|
||||||
|
return v -> [(k!=i ? GWord(v[k]) : v[i]*v[j]) for k in eachindex(v)]
|
||||||
|
end
|
||||||
|
|
||||||
|
function ϱ_inv(i,j)
|
||||||
|
# @assert i ≠ j
|
||||||
|
return v -> [(k!=i ? GWord(v[k]) : v[i]*v[j]^-1) for k in eachindex(v)]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function λ(i,j)
|
||||||
|
# @assert i ≠ j
|
||||||
|
return v -> ([(k!=i ? GWord(v[k]) : v[j]*v[i]) for k in eachindex(v)])
|
||||||
|
end
|
||||||
|
|
||||||
|
function λ_inv(i,j)
|
||||||
|
# @assert i ≠ j
|
||||||
|
return v -> ([(k!=i ? GWord(v[k]) : v[j]^-1*v[i]) for k in eachindex(v)])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ɛ(i) = v -> [(k!=i ? GWord(v[k]) : v[k]^-1) for k in eachindex(v)]
|
||||||
|
|
||||||
|
function σ(perm)
|
||||||
|
# @assert sort(perm) == collect(1:length(perm))
|
||||||
|
return v -> [GWord(v[perm[k]]) for k in eachindex(v)]
|
||||||
|
end
|
||||||
|
|
||||||
function rmul_AutSymbol(i,j; pow::Int=1)
|
function rmul_AutSymbol(i,j; pow::Int=1)
|
||||||
gen = string('ϱ',Char(8320+i), Char(8320+j)...)
|
gen = string('ϱ',Char(8320+i), Char(8320+j)...)
|
||||||
return AutSymbol(gen, pow, :(ϱ($i,$j)))
|
return AutSymbol(gen, pow, :(ϱ($i,$j)), ϱ(i,j), ϱ_inv(i,j))
|
||||||
end
|
end
|
||||||
|
|
||||||
function lmul_AutSymbol(i,j; pow::Int=1)
|
function lmul_AutSymbol(i,j; pow::Int=1)
|
||||||
gen = string('λ',Char(8320+i), Char(8320+j)...)
|
gen = string('λ',Char(8320+i), Char(8320+j)...)
|
||||||
return AutSymbol(gen, pow, :(λ($i,$j)))
|
return AutSymbol(gen, pow, :(λ($i,$j)), λ(i,j), λ_inv(i,j))
|
||||||
end
|
end
|
||||||
|
|
||||||
function flip_AutSymbol(j; pow::Int=1)
|
function flip_AutSymbol(j; pow::Int=1)
|
||||||
gen = string('ɛ', Char(8320 + j))
|
gen = string('ɛ', Char(8320 + j))
|
||||||
return AutSymbol(gen, (2+ pow%2)%2, :(ɛ($j)))
|
return AutSymbol(gen, (2+ pow%2)%2, :(ɛ($j)), ɛ(j), ɛ(j))
|
||||||
end
|
end
|
||||||
|
|
||||||
function symmetric_AutSymbol(perm::Vector{Int}; pow::Int=1)
|
function symmetric_AutSymbol(perm::Vector{Int}; pow::Int=1)
|
||||||
@ -59,11 +100,12 @@ function symmetric_AutSymbol(perm::Vector{Int}; pow::Int=1)
|
|||||||
ord = order(perm)
|
ord = order(perm)
|
||||||
pow = pow % ord
|
pow = pow % ord
|
||||||
perm = perm^pow
|
perm = perm^pow
|
||||||
if array(perm) == collect(1:length(perm))
|
p = array(perm)
|
||||||
|
if p == collect(1:length(p))
|
||||||
return one(AutSymbol)
|
return one(AutSymbol)
|
||||||
else
|
else
|
||||||
gen = string('σ', [Char(8320 + i) for i in array(perm)]...)
|
gen = string('σ', [Char(8320 + i) for i in p]...)
|
||||||
return AutSymbol(gen, 1, :(σ($(array(perm)))))
|
return AutSymbol(gen, 1, :(σ($p)), σ(p), σ(array(inv(perm))))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -77,6 +119,13 @@ end
|
|||||||
|
|
||||||
typealias AutWord GWord{AutSymbol}
|
typealias AutWord GWord{AutSymbol}
|
||||||
|
|
||||||
|
function (F::AutWord)(v)
|
||||||
|
for f in F.symbols
|
||||||
|
v = f(v)
|
||||||
|
end
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
convert(::Type{AutWord}, s::AutSymbol) = GWord(s)
|
convert(::Type{AutWord}, s::AutSymbol) = GWord(s)
|
||||||
|
|
||||||
function simplify_perms!(W::AutWord)
|
function simplify_perms!(W::AutWord)
|
||||||
@ -100,5 +149,6 @@ function simplify_perms!(W::AutWord)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
deleteat!(W.symbols, find(x -> x.pow == 0, W.symbols))
|
||||||
return reduced
|
return reduced
|
||||||
end
|
end
|
||||||
|
@ -40,9 +40,15 @@ end
|
|||||||
@test isa(Groups.GWord(s), Groups.GWord)
|
@test isa(Groups.GWord(s), Groups.GWord)
|
||||||
@test isa(Groups.GWord(s), FGWord)
|
@test isa(Groups.GWord(s), FGWord)
|
||||||
@test isa(FGWord(s), Groups.GWord)
|
@test isa(FGWord(s), Groups.GWord)
|
||||||
|
@test isa(convert(FGWord, s), GWord)
|
||||||
|
@test isa(convert(FGWord, s), FGWord)
|
||||||
|
@test isa(Vector{FGWord}([s,t]), Vector{FGWord})
|
||||||
|
@test Vector{GWord{FGSymbol}}([s,t]) == Vector{FGWord}([s,t])
|
||||||
@test isa(s*s, FGWord)
|
@test isa(s*s, FGWord)
|
||||||
@test s*s == s^2
|
@test s*s == s^2
|
||||||
@test t*s ≠ s*t
|
@test t*s ≠ s*t
|
||||||
|
@test Vector{GWord}([s,t]) == [s^2*s^-1, t]
|
||||||
|
@test hash([t^1,s^1]) == hash([t^2*inv(t),s*inv(s)*s])
|
||||||
end
|
end
|
||||||
@testset "eltary functions" begin
|
@testset "eltary functions" begin
|
||||||
@test length(FGWord(s)) == 1
|
@test length(FGWord(s)) == 1
|
||||||
@ -56,6 +62,7 @@ end
|
|||||||
@test isa(one(w), FGWord)
|
@test isa(one(w), FGWord)
|
||||||
@test inv(s*t) == t^-1*s^-1
|
@test inv(s*t) == t^-1*s^-1
|
||||||
@test inv(w) == s*t^-1*s^-1
|
@test inv(w) == s*t^-1*s^-1
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@testset "reductions" begin
|
@testset "reductions" begin
|
||||||
@ -80,11 +87,33 @@ end
|
|||||||
@test (t*s*t^-1)^10 == t*s^10*t^-1
|
@test (t*s*t^-1)^10 == t*s^10*t^-1
|
||||||
@test (t*s*t^-1)^-10 == t*s^-10*t^-1
|
@test (t*s*t^-1)^-10 == t*s^-10*t^-1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@testset "replacements" begin
|
||||||
|
@test Groups.is_subsymbol(s, Groups.change_pow(s,2)) == true
|
||||||
|
@test Groups.is_subsymbol(s, Groups.change_pow(s,-2)) == false
|
||||||
|
@test Groups.is_subsymbol(t, Groups.change_pow(s,-2)) == false
|
||||||
|
@test Groups.is_subsymbol(inv(t), Groups.change_pow(t,-2)) == true
|
||||||
|
c = s*t*s^-1*t^-1
|
||||||
|
@test findfirst(c, s^-1*t^-1) == 3
|
||||||
|
@test findnext(c*s^-1, s^-1*t^-1,3) == 3
|
||||||
|
@test findnext(c*s^-1*t^-1, s^-1*t^-1,4) == 5
|
||||||
|
@test findfirst(c*t, c) == 0
|
||||||
|
w = s*t*s^-1
|
||||||
|
subst = Dict{FGWord, FGWord}(w => s^1, s*t^-1 => t^4)
|
||||||
|
@test Groups.replace(c, 1, s*t, one(FGWord)) == s^-1*t^-1
|
||||||
|
|
||||||
|
@test Groups.replace(c, 1, w, subst[w]) == s*t^-1
|
||||||
|
@test Groups.replace(s*c*t^-1, 1, w, subst[w]) == s^2*t^-2
|
||||||
|
@test Groups.replace(t*c*t, 2, w, subst[w]) == t*s
|
||||||
|
@test Groups.replace_all!(s*c*s*c*s, subst) == s*t^4*s*t^4*s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@testset "Automorphisms" begin
|
@testset "Automorphisms" begin
|
||||||
@testset "AutSymbol" begin
|
@testset "AutSymbol" begin
|
||||||
@test_throws MethodError AutSymbol("a")
|
@test_throws MethodError AutSymbol("a")
|
||||||
@test_throws MethodError AutSymbol("a", 1)
|
@test_throws MethodError AutSymbol("a", 1)
|
||||||
f = AutSymbol("a", 1, :(a(0)))
|
f = AutSymbol("a", 1, :(a(0)), v -> v, v -> v)
|
||||||
@test isa(f, GSymbol)
|
@test isa(f, GSymbol)
|
||||||
@test isa(f, AutSymbol)
|
@test isa(f, AutSymbol)
|
||||||
@test isa(symmetric_AutSymbol([1,2,3,4]), AutSymbol)
|
@test isa(symmetric_AutSymbol([1,2,3,4]), AutSymbol)
|
||||||
@ -94,7 +123,7 @@ end
|
|||||||
end
|
end
|
||||||
|
|
||||||
@testset "AutWords" begin
|
@testset "AutWords" begin
|
||||||
f = AutSymbol("a", 1, :(a(0)))
|
f = AutSymbol("a", 1, :(a(0)), v -> v, v -> v)
|
||||||
@test isa(GWord(f), GWord)
|
@test isa(GWord(f), GWord)
|
||||||
@test isa(GWord(f), AutWord)
|
@test isa(GWord(f), AutWord)
|
||||||
@test isa(AutWord(f), AutWord)
|
@test isa(AutWord(f), AutWord)
|
||||||
@ -120,4 +149,30 @@ end
|
|||||||
@test a*b == b*a
|
@test a*b == b*a
|
||||||
@test a^3 * b^3 == one(a)
|
@test a^3 * b^3 == one(a)
|
||||||
end
|
end
|
||||||
|
@testset "specific Aut(𝔽₄) tests" begin
|
||||||
|
N = 4
|
||||||
|
import Combinatorics.nthperm
|
||||||
|
SymmetricGroup(n) = [nthperm(collect(1:n), k) for k in 1:factorial(n)]
|
||||||
|
indexing = [[i,j] for i in 1:N for j in 1:N if i≠j]
|
||||||
|
|
||||||
|
σs = [symmetric_AutSymbol(perm) for perm in SymmetricGroup(N)[2:end]];
|
||||||
|
ϱs = [rmul_AutSymbol(i,j) for (i,j) in indexing]
|
||||||
|
λs = [lmul_AutSymbol(i,j) for (i,j) in indexing]
|
||||||
|
ɛs = [flip_AutSymbol(i) for i in 1:N];
|
||||||
|
|
||||||
|
S = vcat(ϱs, λs, σs, ɛs)
|
||||||
|
S = vcat(S, [inv(s) for s in S])
|
||||||
|
@test isa(S, Vector{AutSymbol})
|
||||||
|
@test length(S) == 102
|
||||||
|
@test length(unique(S)) == 75
|
||||||
|
S₁ = [GWord(s) for s in unique(S)]
|
||||||
|
@test isa(S₁, Vector{AutWord})
|
||||||
|
p = prod(S₁)
|
||||||
|
@test length(p) == 75
|
||||||
|
@test Groups.simplify_perms!(p) == false
|
||||||
|
@test length(p) == 53
|
||||||
|
@test Groups.join_free_symbols!(p) == true
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user