mirror of
https://github.com/kalmarek/PropertyT.jl.git
synced 2024-10-19 09:05:36 +02:00
220 lines
6.3 KiB
Julia
220 lines
6.3 KiB
Julia
include("Projections.jl")
|
|
|
|
###############################################################################
|
|
#
|
|
# Iterator protocol for Nemo.FinField
|
|
#
|
|
###############################################################################
|
|
|
|
mutable struct FFEltsIter{T<:Generic.FinField}
|
|
all::Int
|
|
field::T
|
|
|
|
function FFEltsIter{T}(F::T) where {T}
|
|
return new(Int(characteristic(F)^degree(F)), F)
|
|
end
|
|
end
|
|
FFEltsIter(F::T) where {T<:Nemo.FinField} = FFEltsIter{T}(F)
|
|
|
|
import Base: start, next, done, eltype, length
|
|
|
|
Base.start(A::FFEltsIter) = (zero(A.field), 0)
|
|
Base.next(A::FFEltsIter, state) = next_ffelem(state...)
|
|
Base.done(A::FFEltsIter, state) = state[2] >= A.all
|
|
Base.eltype(::Type{FFEltsIter}) = elem_type(A.field)
|
|
Base.length(A::FFEltsIter) = A.all
|
|
|
|
function next_ffelem(f::Nemo.FinFieldElem, c::Int)
|
|
if c == 0
|
|
return (f, (f, 1))
|
|
elseif c == 1
|
|
f = one(parent(f))
|
|
return (f, (f, 2))
|
|
else
|
|
f = gen(parent(f))*f
|
|
return (f, (f, c+1))
|
|
end
|
|
end
|
|
|
|
import Nemo.elements
|
|
elements(F::Nemo.FinField) = FFEltsIter(F)
|
|
|
|
###############################################################################
|
|
#
|
|
# Orbit stuff
|
|
#
|
|
###############################################################################
|
|
|
|
function orbit_decomposition(G::Nemo.Group, E::Vector, rdict=GroupRings.reverse_dict(E))
|
|
|
|
elts = collect(elements(G))
|
|
|
|
tovisit = trues(E);
|
|
orbits = Vector{Vector{Int}}()
|
|
|
|
for i in 1:endof(E)
|
|
if tovisit[i]
|
|
orbit = zeros(Int, length(elts))
|
|
a = E[i]
|
|
Threads.@threads for i in 1:length(elts)
|
|
orbit[i] = rdict[elts[i](a)]
|
|
end
|
|
tovisit[orbit] = false
|
|
push!(orbits, unique(orbit))
|
|
end
|
|
end
|
|
return orbits
|
|
end
|
|
|
|
function orbit_spvector(vect::AbstractVector, orbits)
|
|
orb_vector = spzeros(length(orbits))
|
|
|
|
for (i,o) in enumerate(orbits)
|
|
k = vect[collect(o)]
|
|
val = k[1]
|
|
@assert all(k .== val)
|
|
orb_vector[i] = val
|
|
end
|
|
|
|
return orb_vector
|
|
end
|
|
|
|
function orbit_constraint(constraints::Vector{Vector{Tuple{Int,Int}}}, n)
|
|
result = spzeros(n,n)
|
|
for cnstr in constraints
|
|
for p in cnstr
|
|
result[p[2], p[1]] += 1.0/length(constraints)
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
###############################################################################
|
|
#
|
|
# Matrix-, Permutation- and C*-representations
|
|
#
|
|
###############################################################################
|
|
|
|
function matrix_repr(p::perm)
|
|
N = parent(p).n
|
|
return sparse(1:N, p.d, [1.0 for _ in 1:N])
|
|
end
|
|
|
|
function matrix_reps{T<:GroupElem}(preps::Dict{T,perm})
|
|
kk = collect(keys(preps))
|
|
mreps = Vector{SparseMatrixCSC{Float64, Int}}(length(kk))
|
|
Threads.@threads for i in 1:length(kk)
|
|
mreps[i] = matrix_repr(preps[kk[i]])
|
|
end
|
|
return Dict(kk[i] => mreps[i] for i in 1:length(kk))
|
|
end
|
|
|
|
function perm_repr(g::GroupElem, E::Vector, E_dict)
|
|
p = Vector{Int}(length(E))
|
|
for (i,elt) in enumerate(E)
|
|
p[i] = E_dict[g(elt)]
|
|
end
|
|
return p
|
|
end
|
|
|
|
function perm_reps(G::Group, E::Vector, E_rdict=GroupRings.reverse_dict(E))
|
|
elts = collect(elements(G))
|
|
l = length(elts)
|
|
preps = Vector{Generic.perm}(l)
|
|
|
|
permG = Nemo.PermutationGroup(length(E))
|
|
|
|
Threads.@threads for i in 1:l
|
|
preps[i] = permG(PropertyT.perm_repr(elts[i], E, E_rdict))
|
|
end
|
|
|
|
return Dict(elts[i]=>preps[i] for i in 1:l)
|
|
end
|
|
|
|
function perm_reps(S::Vector, autS::Group, radius::Int)
|
|
E, _ = Groups.generate_balls(S, radius=radius)
|
|
return perm_reps(autS, E)
|
|
end
|
|
|
|
function reconstruct_sol{T<:GroupElem, S<:perm}(preps::Dict{T, S},
|
|
Us::Vector, Ps::Vector, dims::Vector)
|
|
|
|
l = length(Us)
|
|
transfP = [dims[π].*Us[π]*Ps[π]*Us[π]' for π in 1:l]
|
|
tmp = [zeros(Float64, size(first(transfP))) for _ in 1:l]
|
|
perms = collect(keys(preps))
|
|
|
|
@inbounds Threads.@threads for π in 1:l
|
|
for p in perms
|
|
BLAS.axpy!(1.0, view(transfP[π], preps[p].d, preps[p].d), tmp[π])
|
|
end
|
|
end
|
|
|
|
recP = 1/length(perms) .* sum(tmp)
|
|
recP[abs.(recP) .< eps(eltype(recP))] = zero(eltype(recP))
|
|
return recP
|
|
end
|
|
|
|
function Cstar_repr(x::GroupRingElem{T}, mreps::Dict) where {T}
|
|
return sum(x[i].*mreps[parent(x).basis[i]] for i in findn(x.coeffs))
|
|
end
|
|
|
|
function orthSVD{T}(M::AbstractMatrix{T})
|
|
M = full(M)
|
|
fact = svdfact(M)
|
|
M_rank = sum(fact[:S] .> maximum(size(M))*eps(T))
|
|
return fact[:U][:,1:M_rank]
|
|
end
|
|
|
|
function compute_orbit_data{T<:GroupElem}(logger, name::String, G::Nemo.Group, S::Vector{T}, autS::Nemo.Group; radius=2)
|
|
isdir(name) || mkdir(name)
|
|
|
|
info(logger, "Generating ball of radius $(2*radius)")
|
|
|
|
# TODO: Fix that by multiple dispatch?
|
|
Id = (isa(G, Nemo.Ring) ? one(G) : G())
|
|
|
|
@logtime logger E_2R, sizes = Groups.generate_balls(S, Id, radius=2*radius);
|
|
info(logger, "Balls of sizes $sizes.")
|
|
info(logger, "Reverse dict")
|
|
@logtime logger E_rdict = GroupRings.reverse_dict(E_2R)
|
|
|
|
info(logger, "Product matrix")
|
|
@logtime logger pm = GroupRings.create_pm(E_2R, E_rdict, sizes[radius], twisted=true)
|
|
RG = GroupRing(G, E_2R, E_rdict, pm)
|
|
Δ = PropertyT.spLaplacian(RG, S)
|
|
@assert GroupRings.augmentation(Δ) == 0
|
|
save(filename(name, :Δ), "Δ", Δ.coeffs)
|
|
save(filename(name, :pm), "pm", pm)
|
|
|
|
info(logger, "Decomposing E into orbits of $(autS)")
|
|
@logtime logger orbs = orbit_decomposition(autS, E_2R, E_rdict)
|
|
@assert sum(length(o) for o in orbs) == length(E_2R)
|
|
info(logger, "E consists of $(length(orbs)) orbits!")
|
|
save(joinpath(name, "orbits.jld"), "orbits", orbs)
|
|
|
|
info(logger, "Action matrices")
|
|
@logtime logger reps = perm_reps(autS, E_2R[1:sizes[radius]], E_rdict)
|
|
save_preps(filename(name, :preps), reps)
|
|
reps = matrix_reps(reps)
|
|
|
|
info(logger, "Projections")
|
|
@logtime logger autS_mps = rankOne_projections(autS);
|
|
|
|
@logtime logger π_E_projections = [Cstar_repr(p, reps) for p in autS_mps]
|
|
|
|
info(logger, "Uπs...")
|
|
@logtime logger Uπs = orthSVD.(π_E_projections)
|
|
|
|
multiplicities = size.(Uπs,2)
|
|
info(logger, "multiplicities = $multiplicities")
|
|
dimensions = [Int(p[autS()]*Int(order(autS))) for p in autS_mps];
|
|
info(logger, "dimensions = $dimensions")
|
|
@assert dot(multiplicities, dimensions) == sizes[radius]
|
|
|
|
save(joinpath(name, "U_pis.jld"),
|
|
"Uπs", Uπs,
|
|
"dims", dimensions)
|
|
return 0
|
|
end
|