1
0
mirror of https://github.com/kalmarek/PropertyT.jl.git synced 2024-10-15 08:05:35 +02:00
PropertyT.jl/src/PropertyT.jl

242 lines
7.2 KiB
Julia
Raw Normal View History

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-11-17 15:28:11 +01:00
import Nemo: Group, GroupElem, Ring, Generic.perm
2017-06-22 15:15:43 +02:00
using JLD
using JuMP
2017-12-01 17:03:24 +01:00
using MathProgBase
2017-06-22 15:15:43 +02:00
using Memento
2017-06-06 11:48:52 +02:00
function setup_logging(name::String)
isdir(name) || mkdir(name)
2018-01-02 02:59:10 +01:00
L = Memento.config("info", fmt="{date}| {msg}")
handler = Memento.DefaultHandler(
2018-01-02 02:59:10 +01:00
filename(name, :logall), Memento.DefaultFormatter("{date}| {msg}"))
handler.levels.x = L.levels
L.handlers["all"] = handler
# e = redirect_stderr(L.handlers["all"].io)
return L
end
2018-01-02 02:59:10 +01:00
function solverlogger(name)
logger = Memento.config("info", fmt="{msg}")
2018-01-02 02:59:10 +01:00
handler = DefaultHandler(
filename(name, :logsolver), DefaultFormatter("{date}| {msg}"))
handler.levels.x = logger.levels
logger.handlers["solver_log"] = handler
return logger
end
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))
2018-01-01 23:54:36 +01:00
$(esc(info))($(esc(logger)), ts)
val
end
end
function time_string(elapsedtime, bytes, gctime, allocs)
str = @sprintf("%10.6f seconds", elapsedtime/1e9)
if bytes != 0 || allocs != 0
bytes, mb = Base.prettyprint_getunits(bytes, length(Base._mem_units), Int64(1024))
allocs, ma = Base.prettyprint_getunits(allocs, length(Base._cnt_units), Int64(1000))
if ma == 1
str*= @sprintf(" (%d%s allocation%s: ", allocs, Base._cnt_units[ma], allocs==1 ? "" : "s")
else
str*= @sprintf(" (%.2f%s allocations: ", allocs, Base._cnt_units[ma])
end
if mb == 1
str*= @sprintf("%d %s%s", bytes, Base._mem_units[mb], bytes==1 ? "" : "s")
else
str*= @sprintf("%.3f %s", bytes, Base._mem_units[mb])
end
if gctime > 0
str*= @sprintf(", %.2f%% gc time", 100*gctime/elapsedtime)
end
str*=")"
elseif gctime > 0
str*= @sprintf(", %.2f%% gc time", 100*gctime/elapsedtime)
end
return str
end
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})
@eval begin
for (s,n) in [
[:pm, "pm.jld"],
[, "delta.jld"],
[, "lambda.jld"],
[:P, "SDPmatrix.jld"],
[:warm, "warmstart.jld"],
[:Uπs, "U_pis.jld"],
[:orb, "orbits.jld"],
[:preps,"preps.jld"],
[:logall, "full_$(string(now())).log"],
[:logsolver,"solver_$(string(now())).log"]
]
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 Laplacian(name::String, G::Group)
info(LOGGER, "Loading precomputed Δ...")
if exists(filename(name, )) && exists(filename(name, :pm))
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
function Laplacian{T<:GroupElem}(name::String, S::Vector{T}, Id::T; radius::Int=2)
info(LOGGER, "Computing multiplication table, Δ...")
Δ = Laplacian(S, Id, radius=radius)
save(filename(name, :pm), "pm", parent(Δ).pm)
save(filename(name, ), "Δ", Δ.coeffs)
return Δ
2017-03-13 14:49:55 +01:00
end
function Laplacian{T<:GroupElem}(S::Vector{T}, Id::T; radius::Int=2)
info(LOGGER, "Generating metric ball of radius $radius...")
@logtime LOGGER E_R, sizes = Groups.generate_balls(S, Id, radius=2*radius)
info(LOGGER, "Generated balls of sizes $sizes.")
info(LOGGER, "Creating product matrix...")
@logtime LOGGER pm = GroupRings.create_pm(E_R, GroupRings.reverse_dict(E_R), sizes[radius]; twisted=true)
RG = GroupRing(parent(Id), E_R, pm)
2017-10-27 18:36:59 +02:00
Δ = splaplacian(RG, S)
return Δ
end
2017-04-01 15:21:57 +02:00
function λandP(name::String)
2018-01-01 23:57:03 +01:00
λ_fname = filename(name, )
P_fname = filename(name, :P)
2017-04-01 15:21:57 +02:00
2018-01-01 23:57:03 +01:00
if exists(λ_fname) && exists(P_fname)
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!")
2017-03-13 14:49:55 +01:00
end
2017-04-01 15:21:57 +02:00
return λ, P
end
2018-01-02 02:52:45 +01:00
function λandP(name::String, SDP::JuMP.Model, varλ, varP, warmstart=true)
2018-01-02 02:52:45 +01:00
if warmstart && isfile(filename(name, :warm))
ws = load(filename(name, :warm), "warmstart")
2018-01-01 14:06:33 +01:00
else
ws = nothing
end
2018-01-02 02:52:45 +01:00
solver_log = solverlogger(name)
Base.Libc.flush_cstdio()
o = redirect_stdout(solver_log.handlers["solver_log"].io)
Base.Libc.flush_cstdio()
λ, P, warmstart = solve_SDP(SDP, varλ, varP, warmstart=ws)
Base.Libc.flush_cstdio()
redirect_stdout(o)
2018-01-02 02:52:45 +01:00
delete!(solver_log.handlers, "solver_log")
2018-01-01 14:06:33 +01:00
if λ > 0
2018-01-01 23:57:03 +01:00
save(filename(name, ), "λ", λ)
save(filename(name, :P), "P", P)
2018-01-02 02:52:45 +01:00
save(filename(name, :warm), "warmstart", warmstart)
2018-01-01 14:06:33 +01:00
else
2018-01-01 23:57:03 +01:00
throw(ErrorException("Solver did not produce a valid solution: λ = "))
2018-01-01 14:06:33 +01:00
end
return λ, P
end
2017-03-16 09:35:32 +01:00
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)
2018-01-02 02:59:10 +01:00
LOGGER = Memento.getlogger()
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
Δ = Laplacian(name, parent(S[1]))
2017-06-05 13:17:49 +02:00
else
2017-06-05 13:48:44 +02:00
# compute
Δ = Laplacian(name, S, Id, radius=radius)
2017-06-05 13:23:10 +02:00
end
2018-01-01 23:57:03 +01:00
if exists(filename(name, )) && exists(filename(name, :P))
info(LOGGER, "Loading precomputed λ, P...")
2018-01-01 14:06:33 +01:00
λ, P = λandP(name)
else
info(LOGGER, "Creating SDP problem...")
SDP_problem, λ_var, P_var = create_SDP_problem(Δ, PropertyT.constraints(parent(Δ).pm), upper_bound=upper_bound)
2018-01-01 14:06:33 +01:00
JuMP.setsolver(SDP_problem, solver)
λ, P = λandP(name, SDP_problem, λ_var, P_var)
2018-01-01 14:06:33 +01:00
end
info(LOGGER, "λ = ")
info(LOGGER, "sum(P) = $(sum(P))")
info(LOGGER, "maximum(P) = $(maximum(P))")
info(LOGGER, "minimum(P) = $(minimum(P))")
if λ > 0
2018-01-01 23:57:03 +01:00
RG = GroupRing(parent(first(S)), load(filename(name, :pm), "pm"))
Δ = GroupRingElem(load(filename(name, ), "Δ")[:, 1], RG)
2018-01-01 14:06:33 +01:00
isapprox(eigvals(P), abs(eigvals(P)), atol=tol) ||
warn("The solution matrix doesn't seem to be positive definite!")
@logtime LOGGER Q = real(sqrtm(Symmetric(P)))
sgap = check_distance_to_cone(Δ, λ, Q, 2*radius, LOGGER)
2018-01-01 14:06:33 +01:00
if sgap > 0
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
else
sgap = Float64(trunc(sgap, 12))
info(LOGGER, "λ($name, S) ≥ $sgap: Group may NOT HAVE property (T)!")
return false
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)