Skip to content

Commit 0e52542

Browse files
committed
Add decomposition and fix test
1 parent bc2310a commit 0e52542

File tree

4 files changed

+100
-13
lines changed

4 files changed

+100
-13
lines changed

src/RelativeEntropy/RelativeEntropy.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,61 @@ function JuMP.build_constraint(
125125
)
126126
end
127127

128+
const APL{T} = MP.AbstractPolynomialLike{T}
129+
130+
"""
131+
struct Decomposition{T, PT}
132+
133+
Represents a SAGE decomposition.
134+
"""
135+
struct Decomposition{T,P<:APL{T}} <: APL{T}
136+
polynomials::Vector{P}
137+
function Decomposition(ps::Vector{P}) where {T,P<:APL{T}}
138+
return new{T,P}(ps)
139+
end
140+
end
141+
142+
function Base.show(io::IO, p::Decomposition)
143+
for (i, q) in enumerate(p.polynomials)
144+
print(io, "(")
145+
print(io, q)
146+
print(io, ")")
147+
if i != length(p.polynomials)
148+
print(io, " + ")
149+
end
150+
end
151+
end
152+
153+
function MP.polynomial(d::Decomposition)
154+
return sum(d.polynomials)
155+
end
156+
157+
"""
158+
struct DecompositionAttribute{T} <: MOI.AbstractConstraintAttribute
159+
tol::T
160+
end
161+
162+
A constraint attribute for the [`Decomposition`](@ref) of a constraint.
163+
"""
164+
struct DecompositionAttribute{T} <: MOI.AbstractConstraintAttribute
165+
tol::T
166+
result_index::Int
167+
end
168+
function DecompositionAttribute(tol::Real)
169+
return DecompositionAttribute(tol, 1)
170+
end
171+
172+
function decomposition(con_ref::JuMP.ConstraintRef; tol::Real, result_index::Int = 1)
173+
monos = con_ref.shape.monomials
174+
attr = DecompositionAttribute(tol, result_index)
175+
return Decomposition(
176+
[MP.polynomial(a, monos)
177+
for a in MOI.get(JuMP.owner_model(con_ref), attr, con_ref)]
178+
)
179+
end
180+
181+
MOI.is_set_by_optimize(::DecompositionAttribute) = true
182+
128183
include("bridges/sage.jl")
129184

130185
function PolyJuMP.bridges(

src/RelativeEntropy/bridges/sage.jl

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ function MOI.Bridges.Constraint.bridge_constraint(
1515
m = size(set.α, 1)
1616
ν = Matrix{MOI.VariableIndex}(undef, m, m)
1717
A = SignomialAGECone
18-
c = Vector{MOI.ConstraintIndex{MOI.VectorOfVariables,A}}(undef, m)
18+
age_constraints =
19+
Vector{MOI.ConstraintIndex{MOI.VectorOfVariables,A}}(undef, m)
1920
for k in 1:m
20-
ν[k, :], c[k] = MOI.add_constrained_variables(model, A(set.α, k))
21+
ν[k, :], age_constraints[k] =
22+
MOI.add_constrained_variables(model, A(set.α, k))
2123
end
2224
scalars = MOI.Utilities.eachscalar(func)
23-
n = size(set.α, 2)
24-
equality_constraints = map(1:n) do i
25+
equality_constraints = map(1:m) do i
2526
f = MOI.ScalarAffineFunction(
2627
MOI.ScalarAffineTerm.(one(T), ν[:, i]),
2728
zero(T),
@@ -32,7 +33,7 @@ function MOI.Bridges.Constraint.bridge_constraint(
3233
MOI.EqualTo(zero(T)),
3334
)
3435
end
35-
return SAGEBridge{T,F,G}(ν, c, equality_constraints)
36+
return SAGEBridge{T,F,G}(ν, age_constraints, equality_constraints)
3637
end
3738

3839
function MOI.supports_constraint(
@@ -67,3 +68,20 @@ function MOI.Bridges.Constraint.concrete_bridge_type(
6768
)
6869
return SAGEBridge{T,F,G}
6970
end
71+
72+
function MOI.get(
73+
model::MOI.ModelLike,
74+
attr::DecompositionAttribute,
75+
bridge::SAGEBridge,
76+
)
77+
return filter!(
78+
!isempty,
79+
[
80+
filter(
81+
x -> !isapprox(x, zero(x), atol=attr.tol),
82+
MOI.get(model, MOI.VariablePrimal(attr.result_index), bridge.ν[k, :])
83+
)
84+
for k in axes(bridge.ν, 1)
85+
]
86+
)
87+
end

src/RelativeEntropy/bridges/signomial.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Mathematical Programming Computation 13 (2021): 257-295.
1212
https://arxiv.org/pdf/1907.00814.pdf
1313
"""
1414
struct SignomialBridge{T,S,P,F} <: MOI.Bridges.Constraint.AbstractBridge
15-
constraints::MOI.ConstraintIndex{F,S}
15+
constraint::MOI.ConstraintIndex{F,S}
1616
end
1717

1818
_signomial(set::PolynomialSAGECone) = SignomialSAGECone(set.α)
@@ -36,7 +36,6 @@ function MOI.Bridges.Constraint.bridge_constraint(
3636
g[i] = vi
3737
end
3838
end
39-
@show g
4039
constraint = MOI.add_constraint(model, MOI.Utilities.vectorize(g), _signomial(set))
4140
return SignomialBridge{T,S,P,F}(constraint)
4241
end
@@ -67,3 +66,11 @@ function MOI.Bridges.Constraint.concrete_bridge_type(
6766
S = _signomial(P)
6867
return SignomialBridge{T,S,P,F}
6968
end
69+
70+
function MOI.get(
71+
model::MOI.ModelLike,
72+
attr::DecompositionAttribute,
73+
bridge::SignomialBridge,
74+
)
75+
return MOI.get(model, attr, bridge.constraint)
76+
end

test/relative_entropy.jl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,23 @@ function _test_motzkin(x, y, T, solver, set, feasible, square, neg)
2121
else
2222
motzkin = a^2 * b + a * b^2 + one(T) - 3a * b
2323
end
24-
@show motzkin
25-
@constraint(model, motzkin in set)
24+
con_ref = @constraint(model, motzkin in set)
2625
optimize!(model)
27-
inner = model.moi_backend.optimizer.model
28-
println(inner)
29-
vis = MOI.get(inner, MOI.ListOfVariableIndices())
30-
@show MOI.get(inner, MOI.VariablePrimal(), vis)
3126
if feasible
3227
@test termination_status(model) == MOI.OPTIMAL
3328
@test primal_status(model) == MOI.FEASIBLE_POINT
29+
if set isa Union{PolyJuMP.RelativeEntropy.SignomialSAGESet,
30+
PolyJuMP.RelativeEntropy.PolynomialSAGESet}
31+
d = PolyJuMP.RelativeEntropy.decomposition(con_ref; tol = 1e-6)
32+
p = MP.polynomial(d)
33+
if set isa PolyJuMP.RelativeEntropy.SignomialSAGESet
34+
@test p motzkin atol = 1e-6
35+
else
36+
for m in MP.monomials(p - motzkin)
37+
@test MP.coefficient(p, m) MP.coefficient(motzkin, m) atol = 1e-6
38+
end
39+
end
40+
end
3441
else
3542
@test termination_status(model) == MOI.INFEASIBLE
3643
end

0 commit comments

Comments
 (0)