1
0
mirror of https://github.com/kalmarek/PropertyT.jl.git synced 2024-07-12 01:35:29 +02:00
PropertyT.jl/src/PropertyT.jl

198 lines
5.9 KiB
Julia
Raw Normal View History

2018-08-19 20:05:45 +02:00
__precompile__()
2017-03-13 15:56:07 +01:00
module PropertyT
2017-03-13 14:49:55 +01:00
2018-07-31 10:21:54 +02:00
using AbstractAlgebra
2017-06-22 15:15:43 +02:00
using Groups
2017-05-28 20:03:57 +02:00
using GroupRings
2017-03-15 17:48:52 +01:00
2018-07-31 10:21:54 +02:00
import AbstractAlgebra: Group, GroupElem, Ring, perm
2017-06-22 15:15:43 +02:00
using JLD
using JuMP
2018-01-01 14:06:33 +01:00
exists(fname::String) = isfile(fname) || islink(fname)
2018-01-02 02:55:53 +01:00
filename(prefix, s::Symbol) = filename(prefix, Val{s})
2018-09-05 08:55:13 +02:00
import MathProgBase.SolverInterface.AbstractMathProgSolver
2018-01-02 02:55:53 +01:00
@eval begin
for (s,n) in [
2018-08-20 03:52:16 +02:00
[:fulllog, "full_$(string(now())).log"],
[:solverlog, "solver_$(string(now())).log"],
[:pm, "pm.jld"],
[, "delta.jld"],
[, "lambda.jld"],
[:P, "SDPmatrix.jld"],
[:warm, "warmstart.jld"],
[:Uπs, "U_pis.jld"],
[:orbits,"orbits.jld"],
[:preps, "preps.jld"],
2018-01-02 02:55:53 +01:00
]
2017-03-13 14:49:55 +01:00
2018-01-02 02:55:53 +01:00
filename(prefix::String, ::Type{Val{$:(s)}}) = joinpath(prefix, :($n))
end
end
2017-03-13 14:49:55 +01:00
function loadLaplacian(name::String, G::Group)
if exists(filename(name, )) && exists(filename(name, :pm))
info("Loading precomputed Δ...")
RG = GroupRing(G, load(filename(name, :pm), "pm"))
Δ = GroupRingElem(load(filename(name, ), "Δ")[:, 1], RG)
else
throw("You need to precompute $(filename(name, :pm)) and $(filename(name, )) to load it!")
end
return Δ
2017-03-13 14:49:55 +01:00
end
2018-09-05 08:55:13 +02:00
###############################################################################
#
# Settings and filenames
#
###############################################################################
2017-03-13 14:49:55 +01:00
function computeLaplacian(S::Vector{E}, radius) where E<:AbstractAlgebra.RingElem
R = parent(first(S))
return computeLaplacian(S, one(R), radius)
end
function computeLaplacian(S::Vector{E}, radius) where E<:AbstractAlgebra.GroupElem
G = parent(first(S))
return computeLaplacian(S, G(), radius)
end
2018-09-05 08:55:13 +02:00
mutable struct Settings{Gr<:Group, GEl<:GroupElem, Sol<:AbstractMathProgSolver}
name::String
G::Gr
S::Vector{GEl}
radius::Int
2017-03-13 14:49:55 +01:00
function computeLaplacian(S, Id, radius)
2018-08-19 20:05:45 +02:00
info("Generating metric ball of radius $radius...")
@time E_R, sizes = Groups.generate_balls(S, Id, radius=2radius)
2018-08-19 20:05:45 +02:00
info("Generated balls of sizes $sizes.")
2018-09-05 08:55:13 +02:00
solver::Sol
upper_bound::Float64
tol::Float64
warmstart::Bool
2018-08-19 20:05:45 +02:00
info("Creating product matrix...")
@time pm = GroupRings.create_pm(E_R, GroupRings.reverse_dict(E_R), sizes[radius]; twisted=true)
2018-09-05 08:55:13 +02:00
autS::Group
RG = GroupRing(parent(Id), E_R, pm)
2018-01-02 03:02:22 +01:00
Δ = spLaplacian(RG, S)
return Δ
end
function loadλandP(name::String)
2018-01-01 23:57:03 +01:00
λ_fname = filename(name, )
P_fname = filename(name, :P)
2018-09-05 08:55:13 +02:00
function Settings(name, G::Gr, S::Vector{GEl}, r::Int,
sol::Sol, ub, tol, ws) where {Gr, GEl, Sol}
return new{Gr, GEl, Sol}(name, G, S, r, sol, ub, tol, ws)
end
2017-04-01 15:21:57 +02:00
2018-01-01 23:57:03 +01:00
if exists(λ_fname) && exists(P_fname)
info("Loading precomputed λ, P...")
2017-04-01 15:21:57 +02:00
λ = load(λ_fname, "λ")
2018-01-01 23:57:03 +01:00
P = load(P_fname, "P")
2017-03-13 14:49:55 +01:00
else
2018-01-01 23:57:03 +01:00
throw("You need to precompute $λ_fname and $P_fname to load it!")
2018-09-05 08:55:13 +02:00
function Settings(name, G::Gr, S::Vector{GEl}, r::Int,
sol::Sol, ub, tol, ws, autS) where {Gr, GEl, Sol}
return new{Gr, GEl, Sol}(name, G, S, r, sol, ub, tol, ws, autS)
2017-03-13 14:49:55 +01:00
end
2017-04-01 15:21:57 +02:00
return λ, P
end
function computeλandP(Δ::GroupRingElem, upper_bound::AbstractFloat, solver, ws=nothing; solverlog=tempname()*".log")
2018-08-20 03:45:50 +02:00
info("Creating SDP problem...")
SDP_problem, varλ, varP = SOS_problem(Δ^2, Δ, upper_bound=upper_bound)
JuMP.setsolver(SDP_problem, solver)
info(Base.repr(SDP_problem))
2018-08-20 03:45:50 +02:00
@time λ, P, ws = solve_SDP(SDP_problem, varλ, varP, ws, solverlog=solverlog)
2018-01-02 02:52:45 +01:00
2018-08-20 03:45:50 +02:00
return λ, P, ws
end
2018-09-05 08:55:13 +02:00
prefix(s::Settings) = s.name
suffix(s::Settings) = "$(s.upper_bound)"
prepath(s::Settings) = prefix(s)
fullpath(s::Settings) = joinpath(prefix(s), suffix(s))
function saveλandP(name, λ, P, ws)
save(filename(name, ), "λ", λ)
save(filename(name, :P), "P", P)
save(filename(name, :warm), "warmstart", ws)
end
2018-09-05 08:55:13 +02:00
exists(fname::String) = isfile(fname) || islink(fname)
2017-03-16 09:35:32 +01:00
Kazhdan(λ::Number,N::Integer) = sqrt(2*λ/N)
2018-01-02 03:22:46 +01:00
2018-08-20 03:50:56 +02:00
function check_property_T(name::String, S, solver, upper_bound, tol, radius, warm::Bool=false)
2017-03-13 14:49:55 +01:00
2018-01-01 23:57:03 +01:00
if exists(filename(name, :pm)) && exists(filename(name, ))
2017-06-05 13:48:44 +02:00
# cached
Δ = loadLaplacian(name, parent(S[1]))
2017-06-05 13:17:49 +02:00
else
2017-06-05 13:48:44 +02:00
# compute
Δ = computeLaplacian(S, radius)
2018-01-02 03:02:22 +01:00
save(filename(name, :pm), "pm", parent(Δ).pm)
save(filename(name, ), "Δ", Δ.coeffs)
2017-06-05 13:23:10 +02:00
end
fullpath = joinpath(name, string(upper_bound))
isdir(fullpath) || mkdir(fullpath)
2018-08-19 20:05:45 +02:00
files_exist = exists(filename(fullpath, )) && exists(filename(fullpath, :P))
2018-01-25 21:38:38 +01:00
2018-08-19 20:05:45 +02:00
if !(warm) && files_exist
λ, P = loadλandP(fullpath)
2018-01-01 14:06:33 +01:00
else
warmfile = filename(fullpath, :warm)
if warm && isfile(warmfile)
ws = load(warmfile, "warmstart")
2018-08-19 20:05:45 +02:00
else
ws = nothing
end
λ, P, ws = computeλandP(Δ, upper_bound, solver, ws,
solverlog=filename(fullpath, :solverlog))
saveλandP(fullpath, λ, P, ws)
if λ < 0
warn("Solver did not produce a valid solution!")
2018-08-19 20:05:45 +02:00
end
2018-01-01 14:06:33 +01:00
end
2018-08-19 20:05:45 +02:00
info("λ = ")
info("sum(P) = $(sum(P))")
info("maximum(P) = $(maximum(P))")
info("minimum(P) = $(minimum(P))")
2018-01-01 14:06:33 +01:00
2018-01-02 03:22:46 +01:00
isapprox(eigvals(P), abs.(eigvals(P)), atol=tol) ||
warn("The solution matrix doesn't seem to be positive definite!")
2018-01-01 14:06:33 +01:00
return interpret_results(name, Δ, radius,length(S), λ, P)
end
function interpret_results(name::String, Δ::GroupRingElem, radius::Integer, length_S::Integer, λ::AbstractFloat, P)
2018-08-19 20:05:45 +02:00
@time Q = real(sqrtm(Symmetric(P)))
2018-08-19 20:05:45 +02:00
sgap = distance_to_cone(Δ, λ, Q, wlen=2*radius)
if sgap > 0
Kazhdan_κ = Kazhdan(sgap, length_S)
if Kazhdan_κ > 0
2018-08-19 20:05:45 +02:00
info("κ($name, S) ≥ $Kazhdan_κ: Group HAS property (T)!")
return true
end
2018-01-01 14:06:33 +01:00
end
2018-08-19 20:05:45 +02:00
info("λ($name, S) ≥ $sgap < 0: Tells us nothing about property (T)")
2018-01-01 14:06:33 +01:00
return false
2017-03-13 14:49:55 +01:00
end
2017-06-22 15:15:55 +02:00
include("SDPs.jl")
include("CheckSolution.jl")
include("Orbit-wise.jl")
2017-03-13 14:49:55 +01:00
end # module Property(T)