Groups.jl/src/AutGroup.jl

398 lines
10 KiB
Julia
Raw Normal View History

2017-05-12 20:11:10 +02:00
###############################################################################
#
# AutSymbol/ AutGroup / Automorphism
2017-05-12 20:11:10 +02:00
#
###############################################################################
2019-01-03 03:37:02 +01:00
struct RTransvect
i::Int8
j::Int8
2017-11-15 20:43:09 +01:00
end
2019-01-03 03:37:02 +01:00
struct LTransvect
i::Int8
j::Int8
2017-11-15 20:43:09 +01:00
end
2019-01-03 03:37:02 +01:00
struct FlipAut
i::Int8
2017-11-15 20:43:09 +01:00
end
2019-01-03 03:37:02 +01:00
struct PermAut
perm::Generic.perm{Int8}
2017-11-15 20:43:09 +01:00
end
2018-03-25 19:13:30 +02:00
struct Identity end
2017-11-15 20:43:09 +01:00
2018-03-25 19:13:30 +02:00
struct AutSymbol <: GSymbol
2019-01-03 03:37:37 +01:00
id::Symbol
pow::Int8
fn::Union{LTransvect, RTransvect, PermAut, FlipAut, Identity}
end
2018-03-17 05:01:21 +01:00
mutable struct AutGroup{N} <: AbstractFPGroup
objectGroup::FreeGroup
gens::Vector{AutSymbol}
end
mutable struct Automorphism{N} <: GWord{AutSymbol}
symbols::Vector{AutSymbol}
modified::Bool
savedhash::UInt
parent::AutGroup{N}
2019-01-03 03:37:02 +01:00
function Automorphism{N}(f::Vector{AutSymbol}) where {N}
return new{N}(f, true, zero(UInt))
end
end
export Automorphism, AutGroup, Aut, SAut
2017-05-12 20:11:10 +02:00
###############################################################################
#
# Type and parent object methods
#
###############################################################################
elem_type(::AutGroup{N}) where N = Automorphism{N}
parent_type(::Automorphism{N}) where N = AutGroup{N}
2017-05-12 20:11:10 +02:00
###############################################################################
#
# AutSymbol defining functions
#
###############################################################################
2019-01-03 03:37:02 +01:00
function (ϱ::RTransvect)(v, pow::Integer=1)
2018-03-21 19:23:13 +01:00
@inbounds Groups.r_multiply!(v[ϱ.i], (v[ϱ.j]^pow).symbols, reduced=false)
return v
end
2019-01-03 03:37:02 +01:00
function (λ::LTransvect)(v, pow::Integer=1)
2018-03-21 19:23:13 +01:00
@inbounds Groups.l_multiply!(v[λ.i], (v[λ.j]^pow).symbols, reduced=false)
return v
end
2019-01-03 03:37:02 +01:00
function (σ::PermAut)(v, pow::Integer=1)
2018-03-21 19:23:13 +01:00
w = deepcopy(v)
2019-01-03 03:37:02 +01:00
if pow == 1
@inbounds for k in eachindex(v)
v[k].symbols = w[σ.perm.d[k]].symbols
end
else
s = (σ.perm^pow).d
@inbounds for k in eachindex(v)
v[k].symbols = w[s[k]].symbols
end
2018-03-21 19:23:13 +01:00
end
return v
end
2019-01-03 03:37:02 +01:00
function (ɛ::FlipAut)(v, pow::Integer=1)
2018-03-21 19:23:13 +01:00
@inbounds if isodd(pow)
v[ɛ.i].symbols = inv(v[ɛ.i]).symbols
end
return v
end
2019-01-03 03:37:02 +01:00
(::Identity)(v, pow::Integer=1) = v
2017-05-12 20:06:42 +02:00
# taken from ValidatedNumerics, under under the MIT "Expat" License:
# https://github.com/JuliaIntervals/ValidatedNumerics.jl/blob/master/LICENSE.md
function subscriptify(n::Integer)
2017-05-12 20:06:42 +02:00
subscript_0 = Int(0x2080) # Char(0x2080) -> subscript 0
2019-01-03 03:37:02 +01:00
@assert 0 <= n <= 9
return Char(subscript_0 + n)
# return [Char(subscript_0 + i) for i in reverse(digits(n))])
2017-04-18 13:17:48 +02:00
end
function id_autsymbol()
2019-01-03 03:37:37 +01:00
return AutSymbol(Symbol("(id)"), 0, Identity())
end
2019-01-03 03:37:37 +01:00
function rmul_autsymbol(i::Integer, j::Integer; pow::Integer=1)
id = Symbol("ϱ", subscriptify(i), subscriptify(j))
return AutSymbol(id, pow, RTransvect(i, j))
end
2019-01-03 03:37:37 +01:00
function lmul_autsymbol(i::Integer, j::Integer; pow::Integer=1)
id = Symbol("λ", subscriptify(i), subscriptify(j))
return AutSymbol(id, pow, LTransvect(i, j))
end
2019-01-03 03:37:37 +01:00
function flip_autsymbol(i::Integer; pow::Integer=1)
if iseven(pow)
2017-10-27 16:10:37 +02:00
return id_autsymbol()
else
2019-01-03 03:37:37 +01:00
id = Symbol("ɛ", subscriptify(i))
return AutSymbol(id, 1, FlipAut(i))
2017-10-27 16:10:37 +02:00
end
end
function perm_autsymbol(p::Generic.perm{I}; pow::Integer=one(I)) where I<:Integer
2019-01-03 03:37:02 +01:00
if pow != 1
p = p^pow
end
for i in eachindex(p.d)
if p.d[i] != i
2019-01-03 03:37:37 +01:00
id = Symbol("σ", [subscriptify(i) for i in p.d]...)
return AutSymbol(id, 1, PermAut(p))
end
end
return id_autsymbol()
end
function perm_autsymbol(a::Vector{T}) where T<:Integer
return perm_autsymbol(perm(Vector{Int8}(a), false))
end
2018-08-07 23:51:15 +02:00
function domain(G::AutGroup{N}) where N
F = G.objectGroup
gg = gens(F)
2018-09-21 18:08:44 +02:00
return ntuple(i->gg[i], Val(N))
2018-08-07 23:51:15 +02:00
end
2017-05-12 20:11:10 +02:00
###############################################################################
#
# AutGroup / Automorphism constructors
2017-05-12 20:11:10 +02:00
#
###############################################################################
2017-10-04 21:34:59 +02:00
function AutGroup(G::FreeGroup; special=false)
2017-05-15 09:51:03 +02:00
S = AutSymbol[]
n = length(gens(G))
n == 0 && return AutGroup{n}(G, S)
2019-01-03 03:37:02 +01:00
indexing = [[i,j] for i in 1:n for j in 1:n if i≠j]
2017-10-24 15:27:43 +02:00
2017-05-12 19:55:50 +02:00
rmuls = [rmul_autsymbol(i,j) for (i,j) in indexing]
lmuls = [lmul_autsymbol(i,j) for (i,j) in indexing]
2017-10-24 15:27:43 +02:00
append!(S, [rmuls; lmuls])
2017-05-15 09:51:03 +02:00
if !special
2017-05-12 19:55:50 +02:00
flips = [flip_autsymbol(i) for i in 1:n]
syms = [perm_autsymbol(p) for p in PermutationGroup(n)][2:end]
2017-10-24 15:27:43 +02:00
append!(S, [flips; syms])
2017-05-12 19:55:50 +02:00
end
2019-01-03 03:37:02 +01:00
return AutGroup{n}(G, S)
2017-05-12 19:55:50 +02:00
end
Aut(G::Group) = AutGroup(G)
SAut(G::Group) = AutGroup(G, special=true)
2017-05-12 20:11:10 +02:00
###############################################################################
#
# Types call overloads
#
###############################################################################
2017-05-12 19:55:50 +02:00
2018-09-21 18:09:13 +02:00
Automorphism{N}(s::AutSymbol) where N = Automorphism{N}(AutSymbol[s])
2018-03-26 00:45:02 +02:00
function (G::AutGroup{N})() where N
id = Automorphism{N}(id_autsymbol())
id.parent = G
return id
end
function (G::AutGroup{N})(f::AutSymbol) where N
g = Automorphism{N}([f])
g.parent = G
return g
end
function (G::AutGroup{N})(g::Automorphism{N}) where N
g.parent = G
return g
end
###############################################################################
#
# Functional call overloads for evaluation of AutSymbol and Automorphism
#
###############################################################################
2018-03-17 05:08:42 +01:00
function (f::AutSymbol)(v::NTuple{N, T}) where {N, T}
if f.pow != 0
v = f.fn(v, f.pow)::NTuple{N, T}
end
return v
2017-05-12 19:52:27 +02:00
end
function (F::Automorphism{N})(v::NTuple{N, T}) where {N, T}
for f in F.symbols
2018-03-17 05:08:42 +01:00
v = f(v)::NTuple{N, T}
end
return v
end
2017-05-12 20:11:10 +02:00
###############################################################################
#
# Comparison
2017-05-12 20:11:10 +02:00
#
###############################################################################
const HASHINGCONST = 0x7d28276b01874b19 # hash(Automorphism)
2019-01-03 03:37:37 +01:00
hash(s::AutSymbol, h::UInt) = hash(s.id, hash(s.pow, hash(:AutSymbol, h)))
2017-05-12 20:04:03 +02:00
function hash(g::Automorphism, h::UInt)
if g.modified
g_im = reduce!.(g(domain(parent(g))))
g.savedhash = hash(g_im, hash(typeof(g), hash(parent(g), HASHINGCONST)))
g.modified = false
end
return xor(g.savedhash, h)
end
function (==)(g::Automorphism{N}, h::Automorphism{N}) where N
parent(g) == parent(h) || return false
if !g.modified && !h.modified
if g.savedhash != h.savedhash
return false
end
end
# expensive:
g_im = reduce!.(g(domain(parent(g))))
h_im = reduce!.(h(domain(parent(h))))
# cheap:
g.savedhash = hash(g_im, hash(typeof(g), hash(parent(g), HASHINGCONST)))
g.modified = false
h.savedhash = hash(h_im, hash(typeof(h), hash(parent(h), HASHINGCONST)))
h.modified = false
return g_im == h_im
end
###############################################################################
#
# Basic manipulation
#
###############################################################################
function change_pow(s::AutSymbol, n::Integer)
if n == zero(n)
return id_autsymbol()
2017-05-12 20:04:03 +02:00
end
symbol = s.fn
if symbol isa FlipAut
2017-10-27 16:14:28 +02:00
return flip_autsymbol(symbol.i, pow=n)
elseif symbol isa PermAut
2018-03-28 12:19:18 +02:00
return perm_autsymbol(symbol.perm, pow=n)
elseif symbol isa RTransvect
2017-10-27 16:14:28 +02:00
return rmul_autsymbol(symbol.i, symbol.j, pow=n)
elseif symbol isa LTransvect
2017-10-27 16:14:28 +02:00
return lmul_autsymbol(symbol.i, symbol.j, pow=n)
elseif symbol isa Identity
2017-05-12 20:04:03 +02:00
return s
else
2017-05-15 09:50:26 +02:00
warn("Changing power of an unknown type of symbol! $s")
2019-01-03 03:37:37 +01:00
return AutSymbol(s.id, n, s.fn)
2017-05-12 20:04:03 +02:00
end
end
2017-05-15 09:54:08 +02:00
length(s::AutSymbol) = abs(s.pow)
2017-05-12 20:11:10 +02:00
###############################################################################
#
# String I/O
#
###############################################################################
2017-05-15 17:29:12 +02:00
function show(io::IO, G::AutGroup)
print(io, "Automorphism Group of $(G.objectGroup)\n")
print(io, "Generated by $(join(G.gens, ","))")
end
2017-05-12 20:11:10 +02:00
###############################################################################
#
# Binary operators
#
###############################################################################
###############################################################################
#
# Inversion
#
###############################################################################
2017-05-12 20:04:03 +02:00
inv(f::AutSymbol) = change_pow(f, -f.pow)
2017-05-12 20:11:10 +02:00
###############################################################################
#
# Misc
#
###############################################################################
2017-10-27 16:13:45 +02:00
function getperm(s::AutSymbol)
2018-03-28 12:19:18 +02:00
if s.pow != 1
2018-09-26 20:03:07 +02:00
@warn("Power for perm_symbol should be never 0!")
return s.fn.perm^s.pow
2018-03-28 12:19:18 +02:00
else
return s.fn.perm
2018-03-28 12:19:18 +02:00
end
2017-10-27 16:13:45 +02:00
end
2017-05-15 17:21:48 +02:00
function simplifyperms!(W::Automorphism{N}) where N
reduced = true
to_delete = Int[]
2018-03-28 12:20:03 +02:00
for i in 1:length(W.symbols)-1
if W.symbols[i].pow == 0
continue
elseif W.symbols[i].fn isa PermAut && W.symbols[i+1].fn isa PermAut
2018-03-28 12:20:03 +02:00
reduced = false
c = W.symbols[i]
n = W.symbols[i+1]
W.symbols[i+1] = perm_autsymbol(getperm(c)*getperm(n))
push!(to_delete, i)
end
end
deleteat!(W.symbols, to_delete)
2018-04-02 18:14:08 +02:00
deleteids!(W)
return reduced
end
2017-01-31 16:59:10 +01:00
function reduce!(W::Automorphism)
if length(W) == 0
2018-03-28 12:20:03 +02:00
return W
elseif length(W.symbols) == 1
2018-04-02 18:14:08 +02:00
deleteids!(W)
2017-01-31 16:59:10 +01:00
else
reduced = false
while !reduced
2018-04-02 18:19:55 +02:00
reduced = simplifyperms!(W) && freereduce!(W)
2017-01-31 16:59:10 +01:00
end
end
W.modified = true
2017-01-31 16:59:10 +01:00
return W
end
function linear_repr(A::Automorphism{N}, hom=matrix_repr) where N
2018-09-21 18:08:44 +02:00
return reduce(*, linear_repr.(A.symbols, N, hom), init=hom(Identity(),N,1))
end
linear_repr(a::AutSymbol, n::Int, hom) = hom(a.fn, n, a.pow)
function matrix_repr(a::Union{RTransvect, LTransvect}, n::Int, pow)
2018-09-21 18:08:44 +02:00
x = Matrix{Int}(I, n, n)
x[a.i,a.j] = pow
return x
end
function matrix_repr(a::FlipAut, n::Int, pow)
2018-09-21 18:08:44 +02:00
x = Matrix{Int}(I, n, n)
x[a.i,a.i] = -1^pow
return x
end
2018-09-21 18:08:44 +02:00
matrix_repr(a::PermAut, n::Int, pow) = Matrix{Int}(I, n, n)[(a.perm^pow).d, :]
2018-09-21 18:08:44 +02:00
matrix_repr(a::Identity, n::Int, pow) = Matrix{Int}(I, n, n)