/
certificate.jl
97 lines (89 loc) · 2.8 KB
/
certificate.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# Inspired from SOSTools
export getmonomialsforcertificate, randpsd, randsos
function map_extrema(f::Function, itr::AbstractVector)
state = start(itr)
it1, state = next(itr, state)
mini = maxi = f(it1)
while !done(itr, state)
it, state = next(itr, state)
fit = f(it)
if fit < mini
mini = fit
end
if fit > maxi
maxi = fit
end
end
mini, maxi
end
# Cheap approximation of the convex hull as the approximation of:
#
# z such that mindeg < sum(z) < maxdeg
# |\
# |#\ <-------- sum(z) = maxdeg
# |##\
# |\<-\-------- sum(z) = mindeg
# | \##\
# +---------
cfld(x::NTuple{2,Int}, n) = (cld(x[1], 2), fld(x[2], 2))
# and:
#
# z such that minmultideg < z < maxmultideg
# | +----+ <--- maxmultideg
# | |####|
# | |####|
# | +----+
# | ^---------- minmultideg
# +---------
struct CheapOuterLibrary <: PolyhedraLibrary end
struct CheapOuterPolytope{N, T} <: Polyhedron{N, T}
minmultideg::Vector{Int}
maxmultideg::Vector{Int}
end
function newtonpolytope(Z::MonomialVector, lib::CheapOuterLibrary)
n = length(Z.Z[1])
minmultideg, maxmultideg = Vector{Int}(n), Vector{Int}(n)
for i in 1:n
a, b = map_extrema(z->z[i], Z.Z)
minmultideg[i], maxmultideg[i] = cfld(map_extrema(z->z[i], Z.Z), 2)
end
CheapOuterPolytope{n, Int}(minmultideg, maxmultideg)
end
function Base.in(z::Vector{Int}, p::CheapOuterPolytope)
reduce(&, true, p.minmultideg .<= z .<= p.maxmultideg)
end
function newtonpolytope(Z::MonomialVector, lib::PolyhedraLibrary)
V = reduce(vcat, Matrix{Int}(0, 2), Z.Z.')
vr = SimpleVRepresentation(V)
polyhedron(vr, lib)
end
# TODO sparse with Newton polytope (Polyhedra.jl for convex hull)
function getmonomialsforcertificate(Z::MonomialVector, lib::PolyhedraLibrary)
p = newtonpolytope(Z, lib)
mindeg, maxdeg = cfld(extdeg(Z), 2)
MonomialVector(vars(Z), mindeg:maxdeg, z -> z in p)
end
getmonomialsforcertificate(Z::Vector, libs...) = getmonomialsforcertificate(MonomialVector(Z), libs...)
getmonomialsforcertificate(p::Polynomial, libs...) = getmonomialsforcertificate(monomials(p), libs...)
getmonomialsforcertificate(porZ) = getmonomialsforcertificate(porZ, CheapOuterLibrary())
function randpsd(n; r=n, eps=0.1)
Q = randn(n,n)
d = zeros(Float64, n)
d[1:r] = eps + abs.(randn(r))
Q' * Diagonal(d) * Q
end
function randsos(Z::MonomialVector; r=-1, monotype=:Classic, eps=0.1)
if monotype == :Classic
x = getmonomialsforcertificate(Z)
elseif monotype == :Gram
x = Z
else
throw(ArgumentError("Monotype $monotype not known"))
end
n = length(x)
if r < 0
r = n
end
MatPolynomial(randpsd(n, r=r, eps=eps), x)
end
randsos(Z::Vector; r=-1, monotype=:Classic, eps=0.1) = randsos(MonomialVector(Z), r=r, monotype=monotype, eps=eps)