2017-03-13 15:56:07 +01:00
|
|
|
module PropertyT
|
2017-03-13 14:49:55 +01:00
|
|
|
|
2017-06-22 15:15:43 +02:00
|
|
|
using Nemo
|
|
|
|
using Groups
|
2017-05-28 20:03:57 +02:00
|
|
|
using GroupRings
|
2017-03-15 17:48:52 +01:00
|
|
|
|
2017-06-22 15:15:43 +02:00
|
|
|
import Nemo: Group, GroupElem, Ring
|
|
|
|
|
|
|
|
using JLD
|
|
|
|
using JuMP
|
|
|
|
|
|
|
|
using Memento
|
2017-06-06 11:48:52 +02:00
|
|
|
|
2017-04-17 15:20:58 +02:00
|
|
|
const logger = Memento.config("info", fmt="{msg}")
|
|
|
|
const solver_logger = Memento.config("info", fmt="{msg}")
|
2017-03-13 14:49:55 +01:00
|
|
|
|
2017-07-21 17:12:27 +02:00
|
|
|
function setup_logging(name::String)
|
|
|
|
isdir(name) || mkdir(name)
|
|
|
|
|
|
|
|
Memento.add_handler(logger,
|
|
|
|
Memento.DefaultHandler(joinpath(name,"full_$(string((now()))).log"),
|
|
|
|
Memento.DefaultFormatter("{date}| {msg}")), "full_log")
|
|
|
|
|
2017-08-03 11:34:38 +02:00
|
|
|
e = redirect_stderr(logger.handlers["full_log"].io)
|
2017-07-21 17:12:27 +02:00
|
|
|
|
|
|
|
return logger
|
|
|
|
end
|
|
|
|
|
2017-09-06 16:02:46 +02:00
|
|
|
function exists(fname::String)
|
|
|
|
return isfile(fname) || islink(fname)
|
|
|
|
end
|
|
|
|
|
2017-10-09 19:44:54 +02:00
|
|
|
function pmΔfilenames(prefix::String)
|
|
|
|
isdir(prefix) || mkdir(prefix)
|
|
|
|
pm_filename = joinpath(prefix, "pm.jld")
|
|
|
|
Δ_coeff_filename = joinpath(prefix, "delta.jld")
|
|
|
|
return pm_filename, Δ_coeff_filename
|
2017-03-13 14:49:55 +01:00
|
|
|
end
|
|
|
|
|
2017-10-09 19:44:54 +02:00
|
|
|
function λSDPfilenames(prefix::String)
|
|
|
|
isdir(prefix) || mkdir(prefix)
|
|
|
|
λ_filename = joinpath(prefix, "lambda.jld")
|
|
|
|
SDP_filename = joinpath(prefix, "SDPmatrix.jld")
|
|
|
|
return λ_filename, SDP_filename
|
2017-03-13 14:49:55 +01:00
|
|
|
end
|
|
|
|
|
2017-10-09 19:44:54 +02:00
|
|
|
function ΔandSDPconstraints(prefix::String, G::Group)
|
2017-06-05 13:17:49 +02:00
|
|
|
info(logger, "Loading precomputed pm, Δ, sdp_constraints...")
|
2017-10-09 19:44:54 +02:00
|
|
|
pm_fname, Δ_fname = pmΔfilenames(prefix)
|
2017-06-05 13:48:02 +02:00
|
|
|
|
2017-06-05 13:17:49 +02:00
|
|
|
product_matrix = load(pm_fname, "pm")
|
|
|
|
sdp_constraints = constraints_from_pm(product_matrix)
|
2017-06-05 13:48:02 +02:00
|
|
|
|
|
|
|
RG = GroupRing(G, product_matrix)
|
|
|
|
Δ = GroupRingElem(load(Δ_fname, "Δ")[:, 1], RG)
|
|
|
|
|
2017-03-13 14:49:55 +01:00
|
|
|
return Δ, sdp_constraints
|
|
|
|
end
|
|
|
|
|
2017-06-05 17:26:55 +02:00
|
|
|
function ΔandSDPconstraints{T<:GroupElem}(name::String, S::Vector{T}, Id::T; radius::Int=2)
|
2017-06-05 13:17:49 +02:00
|
|
|
info(logger, "Computing pm, Δ, sdp_constraints...")
|
2017-06-05 17:26:55 +02:00
|
|
|
Δ, sdp_constraints = ΔandSDPconstraints(S, Id, radius=radius)
|
2017-06-05 13:17:49 +02:00
|
|
|
pm_fname, Δ_fname = pmΔfilenames(name)
|
|
|
|
save(pm_fname, "pm", parent(Δ).pm)
|
|
|
|
save(Δ_fname, "Δ", Δ.coeffs)
|
2017-06-05 17:26:55 +02:00
|
|
|
return Δ, sdp_constraints
|
2017-03-13 14:49:55 +01:00
|
|
|
end
|
|
|
|
|
2017-06-05 17:26:55 +02:00
|
|
|
function ΔandSDPconstraints{T<:GroupElem}(S::Vector{T}, Id::T; radius::Int=2)
|
|
|
|
B, sizes = Groups.generate_balls(S, Id, radius=2*radius)
|
2017-06-05 13:20:32 +02:00
|
|
|
info(logger, "Generated balls of sizes $sizes")
|
|
|
|
|
|
|
|
info(logger, "Creating product matrix...")
|
2017-06-05 17:26:55 +02:00
|
|
|
t = @timed pm = GroupRings.create_pm(B, GroupRings.reverse_dict(B), sizes[radius]; twisted=true)
|
2017-06-05 13:20:32 +02:00
|
|
|
info(logger, timed_msg(t))
|
|
|
|
|
|
|
|
info(logger, "Creating sdp_constratints...")
|
|
|
|
t = @timed sdp_constraints = PropertyT.constraints_from_pm(pm)
|
|
|
|
info(logger, timed_msg(t))
|
|
|
|
|
|
|
|
RG = GroupRing(parent(Id), B, pm)
|
|
|
|
|
2017-10-27 18:36:59 +02:00
|
|
|
Δ = splaplacian(RG, S)
|
2017-06-05 13:20:32 +02:00
|
|
|
return Δ, sdp_constraints
|
|
|
|
end
|
|
|
|
|
2017-08-27 19:56:35 +02:00
|
|
|
macro logtime(logger, ex)
|
|
|
|
quote
|
|
|
|
local stats = Base.gc_num()
|
|
|
|
local elapsedtime = Base.time_ns()
|
|
|
|
local val = $(esc(ex))
|
|
|
|
elapsedtime = Base.time_ns() - elapsedtime
|
|
|
|
local diff = Base.GC_Diff(Base.gc_num(), stats)
|
|
|
|
local ts = time_string(elapsedtime, diff.allocd, diff.total_time,
|
|
|
|
Base.gc_alloc_count(diff))
|
|
|
|
esc(warn($(esc(logger)), ts))
|
|
|
|
val
|
|
|
|
end
|
|
|
|
end
|
2017-06-05 13:20:32 +02:00
|
|
|
|
2017-06-04 20:34:12 +02:00
|
|
|
function timed_msg(t)
|
|
|
|
elapsed = t[2]
|
|
|
|
bytes_alloc = t[3]
|
|
|
|
gc_time = t[4]
|
|
|
|
gc_diff = t[5]
|
|
|
|
|
|
|
|
return "took: $elapsed s, allocated: $bytes_alloc bytes ($(gc_diff.poolalloc) allocations)."
|
|
|
|
end
|
|
|
|
|
2017-04-01 15:21:57 +02:00
|
|
|
function λandP(name::String)
|
|
|
|
λ_fname, SDP_fname = λSDPfilenames(name)
|
2017-09-06 16:02:46 +02:00
|
|
|
f₁ = exists(λ_fname)
|
|
|
|
f₂ = exists(SDP_fname)
|
2017-04-01 15:21:57 +02:00
|
|
|
|
2017-03-13 14:49:55 +01:00
|
|
|
if f₁ && f₂
|
2017-04-01 15:21:57 +02:00
|
|
|
info(logger, "Loading precomputed λ, P...")
|
|
|
|
λ = load(λ_fname, "λ")
|
|
|
|
P = load(SDP_fname, "P")
|
2017-03-13 14:49:55 +01:00
|
|
|
else
|
2017-04-01 15:21:57 +02:00
|
|
|
throw(ArgumentError("You need to precompute λ and SDP matrix P to load it!"))
|
2017-03-13 14:49:55 +01:00
|
|
|
end
|
2017-04-01 15:21:57 +02:00
|
|
|
return λ, P
|
2017-03-15 17:49:39 +01:00
|
|
|
end
|
|
|
|
|
2017-06-05 12:15:34 +02:00
|
|
|
function λandP(name::String, SDP_problem::JuMP.Model, varλ, varP)
|
2017-09-06 16:02:46 +02:00
|
|
|
if exists(joinpath(name, "solver.log"))
|
2017-06-04 20:37:02 +02:00
|
|
|
rm(joinpath(name, "solver.log"))
|
|
|
|
end
|
2017-03-31 16:07:08 +02:00
|
|
|
|
2017-06-05 12:48:13 +02:00
|
|
|
add_handler(solver_logger,
|
|
|
|
DefaultHandler(joinpath(name, "solver_$(string(now())).log"),
|
|
|
|
DefaultFormatter("{date}| {msg}")),
|
|
|
|
"solver_log")
|
2017-03-31 16:07:08 +02:00
|
|
|
|
2017-06-04 20:37:02 +02:00
|
|
|
λ, P = compute_λandP(SDP_problem, varλ, varP)
|
2017-03-31 16:07:08 +02:00
|
|
|
|
2017-06-04 20:37:02 +02:00
|
|
|
remove_handler(solver_logger, "solver_log")
|
2017-03-31 16:07:08 +02:00
|
|
|
|
2017-06-04 20:37:02 +02:00
|
|
|
λ_fname, P_fname = λSDPfilenames(name)
|
2017-03-31 16:07:08 +02:00
|
|
|
|
2017-06-04 20:37:02 +02:00
|
|
|
if λ > 0
|
|
|
|
save(λ_fname, "λ", λ)
|
|
|
|
save(P_fname, "P", P)
|
|
|
|
else
|
2017-10-27 14:28:01 +02:00
|
|
|
throw(ErrorException("Solver did not produce a valid solution!: λ = $λ"))
|
2017-06-04 20:37:02 +02:00
|
|
|
end
|
|
|
|
return λ, P
|
2017-03-31 16:07:08 +02:00
|
|
|
|
|
|
|
end
|
2017-03-16 09:35:32 +01:00
|
|
|
|
2017-06-04 20:32:40 +02:00
|
|
|
function compute_λandP(m, varλ, varP)
|
2017-04-01 15:21:57 +02:00
|
|
|
λ = 0.0
|
2017-10-27 18:20:28 +02:00
|
|
|
P = nothing
|
2017-04-01 15:21:57 +02:00
|
|
|
while λ == 0.0
|
2017-04-01 08:32:34 +02:00
|
|
|
try
|
2017-06-04 20:32:40 +02:00
|
|
|
solve_SDP(m)
|
|
|
|
λ = JuMP.getvalue(varλ)
|
|
|
|
P = JuMP.getvalue(varP)
|
2017-03-20 21:48:22 +01:00
|
|
|
catch y
|
2017-04-01 08:32:34 +02:00
|
|
|
warn(solver_logger, y)
|
2017-03-20 21:48:22 +01:00
|
|
|
end
|
|
|
|
end
|
2017-04-01 15:21:57 +02:00
|
|
|
return λ, P
|
2017-03-13 14:49:55 +01:00
|
|
|
end
|
|
|
|
|
2017-04-01 14:22:30 +02:00
|
|
|
Kazhdan_from_sgap(λ,N) = sqrt(2*λ/N)
|
|
|
|
|
2017-06-05 17:26:55 +02:00
|
|
|
function check_property_T(name::String, S, Id, solver, upper_bound, tol, radius)
|
2017-03-13 14:49:55 +01:00
|
|
|
|
2017-06-05 17:29:05 +02:00
|
|
|
isdir(name) || mkdir(name)
|
2017-03-13 14:49:55 +01:00
|
|
|
|
2017-09-06 16:02:46 +02:00
|
|
|
if all(exists.(pmΔfilenames(name)))
|
2017-06-05 13:48:44 +02:00
|
|
|
# cached
|
|
|
|
Δ, sdp_constraints = ΔandSDPconstraints(name, parent(S[1]))
|
2017-06-05 13:17:49 +02:00
|
|
|
else
|
2017-06-05 13:48:44 +02:00
|
|
|
# compute
|
2017-06-05 17:26:55 +02:00
|
|
|
Δ, sdp_constraints = ΔandSDPconstraints(name, S, Id, radius=radius)
|
2017-06-05 13:23:10 +02:00
|
|
|
end
|
2017-03-31 16:07:08 +02:00
|
|
|
|
2017-06-05 13:49:43 +02:00
|
|
|
info(logger, "|S| = $(length(S))")
|
2017-03-15 17:51:13 +01:00
|
|
|
info(logger, "length(Δ) = $(length(Δ))")
|
2017-06-05 13:49:57 +02:00
|
|
|
info(logger, "|R[G]|.pm = $(size(parent(Δ).pm))")
|
2017-03-13 14:49:55 +01:00
|
|
|
|
2017-09-06 16:02:46 +02:00
|
|
|
if all(exists.(λSDPfilenames(name)))
|
2017-06-05 12:48:33 +02:00
|
|
|
λ, P = λandP(name)
|
|
|
|
else
|
|
|
|
info(logger, "Creating SDP problem...")
|
2017-10-27 18:36:32 +02:00
|
|
|
SDP_problem, λ, P = create_SDP_problem(Δ, sdp_constraints, upper_bound=upper_bound)
|
2017-06-05 12:48:33 +02:00
|
|
|
JuMP.setsolver(SDP_problem, solver)
|
2017-04-08 13:49:57 +02:00
|
|
|
|
2017-06-05 12:48:33 +02:00
|
|
|
λ, P = λandP(name, SDP_problem, λ, P)
|
2017-06-04 20:37:52 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
info(logger, "λ = $λ")
|
|
|
|
info(logger, "sum(P) = $(sum(P))")
|
|
|
|
info(logger, "maximum(P) = $(maximum(P))")
|
|
|
|
info(logger, "minimum(P) = $(minimum(P))")
|
|
|
|
|
|
|
|
if λ > 0
|
2017-10-27 18:36:32 +02:00
|
|
|
pm_fname, Δ_fname = pmΔfilenames(name)
|
|
|
|
RG = GroupRing(parent(first(S)), load(pm_fname, "pm"))
|
|
|
|
Δ = GroupRingElem(load(Δ_fname, "Δ")[:, 1], RG)
|
2017-06-22 11:56:46 +02:00
|
|
|
|
|
|
|
isapprox(eigvals(P), abs(eigvals(P)), atol=tol) ||
|
2017-08-04 20:33:21 +02:00
|
|
|
warn("The solution matrix doesn't seem to be positive definite!")
|
2017-06-22 11:56:46 +02:00
|
|
|
# @assert P == Symmetric(P)
|
|
|
|
Q = real(sqrtm(Symmetric(P)))
|
|
|
|
|
2017-10-27 18:35:50 +02:00
|
|
|
sgap = distance_to_positive_cone(Δ, λ, Q, 2*radius)
|
2017-06-04 20:37:52 +02:00
|
|
|
if isa(sgap, Interval)
|
2017-08-04 20:33:21 +02:00
|
|
|
sgap = sgap.lo
|
2017-06-04 20:37:52 +02:00
|
|
|
end
|
|
|
|
if sgap > 0
|
2017-08-04 20:33:21 +02:00
|
|
|
info(logger, "λ ≥ $(Float64(trunc(sgap,12)))")
|
|
|
|
Kazhdan_κ = Kazhdan_from_sgap(sgap, length(S))
|
|
|
|
Kazhdan_κ = Float64(trunc(Kazhdan_κ, 12))
|
|
|
|
info(logger, "κ($name, S) ≥ $Kazhdan_κ: Group HAS property (T)!")
|
|
|
|
return true
|
2017-06-04 20:37:52 +02:00
|
|
|
else
|
2017-08-04 20:33:21 +02:00
|
|
|
sgap = Float64(trunc(sgap, 12))
|
|
|
|
info(logger, "λ($name, S) ≥ $sgap: Group may NOT HAVE property (T)!")
|
|
|
|
return false
|
2017-06-04 20:37:52 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
info(logger, "κ($name, S) ≥ $λ < 0: Tells us nothing about property (T)")
|
|
|
|
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)
|