mirror of
https://github.com/kalmarek/PropertyT.jl.git
synced 2024-11-14 14:15:28 +01:00
256 lines
7.4 KiB
Julia
256 lines
7.4 KiB
Julia
module Projections
|
|
|
|
using AbstractAlgebra
|
|
using Groups
|
|
using GroupRings
|
|
using Markdown
|
|
|
|
export PermCharacter, DirectProdCharacter, rankOne_projections
|
|
|
|
###############################################################################
|
|
#
|
|
# Characters of Symmetric Group and DirectProduct
|
|
#
|
|
###############################################################################
|
|
|
|
abstract type AbstractCharacter end
|
|
|
|
struct PermCharacter <: AbstractCharacter
|
|
p::Generic.Partition
|
|
end
|
|
|
|
struct DirectProdCharacter{N, T<:AbstractCharacter} <: AbstractCharacter
|
|
chars::NTuple{N, T}
|
|
end
|
|
|
|
function (chi::DirectProdCharacter)(g::DirectPowerGroupElem)
|
|
res = 1
|
|
for (χ, elt) in zip(chi.chars, g.elts)
|
|
res *= χ(elt)
|
|
end
|
|
return res
|
|
end
|
|
|
|
function (chi::PermCharacter)(g::Generic.perm)
|
|
R = AbstractAlgebra.partitionseq(chi.p)
|
|
p = Partition(Generic.permtype(g))
|
|
return Int(Generic.MN1inner(R, p, 1, Generic._charvalsTable))
|
|
end
|
|
|
|
AbstractAlgebra.dim(χ::PermCharacter) = dim(YoungTableau(χ.p))
|
|
|
|
for T in [PermCharacter, DirectProdCharacter]
|
|
@eval begin
|
|
function (chi::$T)(X::GroupRingElem)
|
|
RG = parent(X)
|
|
z = zero(eltype(X))
|
|
result = z
|
|
for i in 1:length(X.coeffs)
|
|
if X.coeffs[i] != z
|
|
result += chi(RG.basis[i])*X.coeffs[i]
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
|
|
characters(G::Generic.PermGroup) = (PermCharacter(p) for p in AllParts(G.n))
|
|
|
|
function characters(G::DirectPowerGroup{N}) where N
|
|
nfold_chars = Iterators.repeated(characters(G.group), N)
|
|
return (DirectProdCharacter(idx) for idx in Iterators.product(nfold_chars...))
|
|
end
|
|
|
|
###############################################################################
|
|
#
|
|
# Projections
|
|
#
|
|
###############################################################################
|
|
|
|
function central_projection(RG::GroupRing, chi::AbstractCharacter, T::Type=Rational{Int})
|
|
result = RG(zeros(T, length(RG.basis)))
|
|
dim = chi(RG.group())
|
|
ord = Int(order(RG.group))
|
|
|
|
for g in RG.basis
|
|
result[g] = convert(T, (dim//ord)*chi(g))
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
function alternating_emb(RG::GroupRing{Gr,T}, V::Vector{T}, S::Type=Rational{Int}) where {Gr<:Generic.PermGroup, T<:GroupElem}
|
|
res = RG(S)
|
|
for g in V
|
|
res[g] += sign(g)
|
|
end
|
|
return res
|
|
end
|
|
|
|
function idempotents(RG::GroupRing{Generic.PermGroup{S}}, T::Type=Rational{Int}) where S<:Integer
|
|
if RG.group.n == 1
|
|
return GroupRingElem{T}[one(RG,T)]
|
|
elseif RG.group.n == 2
|
|
Id = one(RG,T)
|
|
transp = RG(perm"(1,2)", T)
|
|
return GroupRingElem{T}[1//2*(Id + transp), 1//2*(Id - transp)]
|
|
end
|
|
|
|
projs = Vector{Vector{Generic.perm{S}}}()
|
|
for l in 2:RG.group.n
|
|
u = RG.group([circshift([i for i in 1:l], -1); [i for i in l+1:RG.group.n]])
|
|
i = 0
|
|
while (l-1)*i <= RG.group.n
|
|
v = RG.group(circshift(collect(1:RG.group.n), i))
|
|
k = inv(v)*u*v
|
|
push!(projs, generateGroup([k], RG.group.n))
|
|
i += 1
|
|
end
|
|
end
|
|
|
|
idems = Vector{GroupRingElem{T}}()
|
|
|
|
for p in projs
|
|
append!(idems, [RG(p, T)//length(p), alternating_emb(RG, p, T)//length(p)])
|
|
end
|
|
|
|
return unique(idems)
|
|
end
|
|
|
|
function rankOne_projection(chi::PermCharacter, idems::Vector{T}) where {T<:GroupRingElem}
|
|
|
|
RG = parent(first(idems))
|
|
S = eltype(first(idems))
|
|
|
|
ids = [one(RG, S); idems]
|
|
zzz = zero(S)
|
|
|
|
for (i,j,k) in Base.product(ids, ids, ids)
|
|
if chi(i) == zzz || chi(j) == zzz || chi(k) == zzz
|
|
continue
|
|
else
|
|
elt = i*j*k
|
|
if elt^2 != elt
|
|
continue
|
|
elseif chi(elt) == one(S)
|
|
return elt
|
|
# return (i,j,k)
|
|
end
|
|
end
|
|
end
|
|
throw("Couldn't find rank-one projection for $chi")
|
|
end
|
|
|
|
function rankOne_projections(RG::GroupRing{G}, T::Type=Rational{Int}) where G<:Generic.PermGroup
|
|
if RG.group.n == 1
|
|
return [GroupRingElem([one(T)], RG)]
|
|
end
|
|
|
|
RGidems = idempotents(RG, T)
|
|
|
|
min_projs = [central_projection(RG,chi)*rankOne_projection(chi,RGidems) for chi in characters(RG.group)]
|
|
|
|
return min_projs
|
|
end
|
|
|
|
function ifelsetuple(a,b, k, n)
|
|
x = [repeat([a], k); repeat([b], n-k)]
|
|
return tuple(x...)
|
|
end
|
|
|
|
function orbit_selector(n::Integer, k::Integer,
|
|
chi::AbstractCharacter, psi::AbstractCharacter)
|
|
return Projections.DirectProdCharacter(ifelsetuple(chi, psi, k, n))
|
|
end
|
|
|
|
function rankOne_projections(RBn::GroupRing{G}, T::Type=Rational{Int}) where {G<:WreathProduct}
|
|
|
|
Bn = RBn.group
|
|
N = Bn.P.n
|
|
# projections as elements of the group rings RSₙ
|
|
Sn_rankOnePr = [rankOne_projections(
|
|
GroupRing(PermGroup(i), collect(PermGroup(i))))
|
|
for i in typeof(N)(1):N]
|
|
|
|
# embedding into group ring of BN
|
|
RN = GroupRing(Bn.N, collect(Bn.N))
|
|
|
|
sign, id = collect(characters(Bn.N.group))
|
|
# Bn.N = (Z/2Z)ⁿ characters corresponding to the first k coordinates:
|
|
BnN_orbits = Dict(i => orbit_selector(N, i, sign, id) for i in 0:N)
|
|
|
|
Q = Dict(i => RBn(g -> Bn(g), central_projection(RN, BnN_orbits[i], T)) for i in 0:N)
|
|
Q = Dict(key => GroupRings.dense(val) for (key, val) in Q)
|
|
|
|
all_projs = [Q[0]*RBn(g->Bn(g), p) for p in Sn_rankOnePr[N]]
|
|
|
|
r = collect(1:N)
|
|
for i in 1:N-1
|
|
first_emb = g->Bn(Generic.emb!(Bn.P(), g, view(r, 1:i)))
|
|
last_emb = g->Bn(Generic.emb!(Bn.P(), g, view(r, (i+1):N)))
|
|
|
|
Sk_first = (RBn(first_emb, p) for p in Sn_rankOnePr[i])
|
|
Sk_last = (RBn(last_emb, p) for p in Sn_rankOnePr[N-i])
|
|
|
|
append!(all_projs,
|
|
[Q[i]*p1*p2 for (p1,p2) in Base.product(Sk_first,Sk_last)])
|
|
end
|
|
|
|
append!(all_projs, [Q[N]*RBn(g->Bn(g), p) for p in Sn_rankOnePr[N]])
|
|
|
|
return all_projs
|
|
end
|
|
|
|
##############################################################################
|
|
#
|
|
# General Groups Misc
|
|
#
|
|
##############################################################################
|
|
|
|
@doc doc"""
|
|
products(X::Vector{GroupElem}, Y::Vector{GroupElem}, op=*)
|
|
> Returns a vector of all possible products (or `op(x,y)`), where $x\in X$ and
|
|
> $y\in Y$ are group elements. You may specify which operation is used when
|
|
> forming 'products' by adding `op` (which is `*` by default).
|
|
"""
|
|
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
|
|
|
|
@doc doc"""
|
|
generateGroup(gens::Vector{GroupElem}, r=2, Id=parent(first(gens))(), op=*)
|
|
> Produces all elements of a group generated by elements in `gens` in ball of
|
|
> radius `r` (word-length metric induced by `gens`).
|
|
> If `r(=2)` is specified the procedure will terminate after generating ball
|
|
> of radius `r` in the word-length metric induced by `gens`.
|
|
> The identity element `Id` and binary operation function `op` can be supplied
|
|
> to e.g. take advantage of additive group structure.
|
|
"""
|
|
function generateGroup(gens::Vector{T}, r=2, Id::T=parent(first(gens))(), op=*) where {T<:GroupElem}
|
|
n = 0
|
|
R = 1
|
|
elts = gens
|
|
gens = [Id; gens]
|
|
while n ≠ length(elts) && R < r
|
|
# @show elts
|
|
R += 1
|
|
n = length(elts)
|
|
elts = products(elts, gens, op)
|
|
end
|
|
return elts
|
|
end
|
|
|
|
end # of module Projections
|