|
| 1 | +# # Certificate |
| 2 | + |
| 3 | +#md # [](@__BINDER_ROOT_URL__/generated/Extension/certificate.ipynb) |
| 4 | +#md # [](@__NBVIEWER_ROOT_URL__/generated/Extension/certificate.ipynb) |
| 5 | +# **Contributed by**: Benoît Legat |
| 6 | + |
| 7 | +# ## Introduction |
| 8 | + |
| 9 | +# Consider the polynomial optimization problem (a variation from [L09, Example 2.2]) of |
| 10 | +# minimizing the polynomial $x^3 - x^2 + 2xy - y^2 + y^3$ |
| 11 | +# over the polyhedron defined by the inequalities $x \ge 0, y \ge 0$ and $x + y \geq 1$. |
| 12 | + |
| 13 | +# [L09] Lasserre, J. B. |
| 14 | +# *Moments, positive polynomials and their applications*. |
| 15 | +# World Scientific, **2009**. |
| 16 | + |
| 17 | +using Test #src |
| 18 | +using DynamicPolynomials |
| 19 | +@polyvar x y |
| 20 | +p = x^3 - x^2 + 2x*y -y^2 + y^3 + x^3 * y |
| 21 | +using SumOfSquares |
| 22 | +S = @set x >= 0 && y >= 0 && x^2 + y^2 >= 2 |
| 23 | + |
| 24 | +# We will now see how to find the optimal solution using Sum of Squares Programming. |
| 25 | +# We first need to pick an SDP solver, see [here](https://jump.dev/JuMP.jl/v0.21.6/installation/#Supported-solvers) for a list of the available choices. |
| 26 | + |
| 27 | +import CSDP |
| 28 | +solver = optimizer_with_attributes(CSDP.Optimizer, MOI.Silent() => true) |
| 29 | + |
| 30 | +# A Sum-of-Squares certificate that $p \ge \alpha$ over the domain `S`, ensures that $\alpha$ is a lower bound to the polynomial optimization problem. |
| 31 | +# The following program searches for the largest upper bound and finds zero. |
| 32 | + |
| 33 | +model = SOSModel(solver) |
| 34 | +@variable(model, α) |
| 35 | +@objective(model, Max, α) |
| 36 | +@constraint(model, c, p >= α, domain = S) |
| 37 | +optimize!(model) |
| 38 | +@show termination_status(model) |
| 39 | +@show objective_value(model) |
| 40 | + |
| 41 | +# We now define the Schmüdgen's certificate: |
| 42 | + |
| 43 | +using MultivariateBases |
| 44 | +const MB = MultivariateBases |
| 45 | +const SOS = SumOfSquares |
| 46 | +const SOSC = SOS.Certificate |
| 47 | +struct Schmüdgen{IC <: SOSC.AbstractIdealCertificate, CT <: SOS.SOSLikeCone, BT <: SOS.AbstractPolynomialBasis} <: SOSC.AbstractPreorderCertificate |
| 48 | + ideal_certificate::IC |
| 49 | + cone::CT |
| 50 | + basis::Type{BT} |
| 51 | + maxdegree::Int |
| 52 | +end |
| 53 | + |
| 54 | +SOSC.get(certificate::Schmüdgen, ::SOSC.Cone) = certificate.cone |
| 55 | + |
| 56 | +function SOSC.get(::Schmüdgen, ::SOSC.PreprocessedDomain, domain::BasicSemialgebraicSet, p) |
| 57 | + return SOSC.DomainWithVariables(domain, variables(p)) |
| 58 | +end |
| 59 | + |
| 60 | +function SOSC.get(::Schmüdgen, ::SOSC.PreorderIndices, domain::SOSC.DomainWithVariables) |
| 61 | + n = length(domain.domain.p) |
| 62 | + if n >= Sys.WORD_SIZE |
| 63 | + error("There are $(2^n - 1) products in Schmüdgen's certificate, they cannot even be indexed with `$Int`.") |
| 64 | + end |
| 65 | + return map(SOSC.PreorderIndex, 1:(2^n-1)) |
| 66 | +end |
| 67 | + |
| 68 | +function SOSC.get(certificate::Schmüdgen, ::SOSC.MultiplierBasis, index::SOSC.PreorderIndex, domain::SOSC.DomainWithVariables) |
| 69 | + q = SOSC.get(certificate, SOSC.Generator(), index, domain) |
| 70 | + vars = sort!([domain.variables..., variables(q)...], rev = true) |
| 71 | + unique!(vars) |
| 72 | + return SOSC.maxdegree_gram_basis(certificate.basis, vars, SOSC.multiplier_maxdegree(certificate.maxdegree, q)) |
| 73 | +end |
| 74 | +function SOSC.get(::Type{Schmüdgen{IC, CT, BT}}, ::SOSC.MultiplierBasisType) where {IC, CT, BT} |
| 75 | + return BT |
| 76 | +end |
| 77 | + |
| 78 | +function SOSC.get(::Schmüdgen, ::SOSC.Generator, index::SOSC.PreorderIndex, domain::SOSC.DomainWithVariables) |
| 79 | + I = [i for i in eachindex(domain.domain.p) if !iszero(index.value & (1 << (i - 1)))] |
| 80 | + return prod([domain.domain.p[i] for i in eachindex(domain.domain.p) if !iszero(index.value & (1 << (i - 1)))]) |
| 81 | +end |
| 82 | + |
| 83 | +SOSC.get(certificate::Schmüdgen, ::SOSC.IdealCertificate) = certificate.ideal_certificate |
| 84 | +SOSC.get(::Type{<:Schmüdgen{IC}}, ::SOSC.IdealCertificate) where {IC} = IC |
| 85 | + |
| 86 | +SOS.matrix_cone_type(::Type{<:Schmüdgen{IC, CT}}) where {IC, CT} = SOS.matrix_cone_type(CT) |
| 87 | + |
| 88 | +# Let's try again with our the Schmüdgen certificate: |
| 89 | + |
| 90 | +model = SOSModel(solver) |
| 91 | +@variable(model, α) |
| 92 | +@objective(model, Max, α) |
| 93 | +ideal_certificate = SOSC.Newton(SOSCone(), MB.MonomialBasis, tuple()) |
| 94 | +certificate = Schmüdgen(ideal_certificate, SOSCone(), MB.MonomialBasis, maxdegree(p)) |
| 95 | +@constraint(model, c, p >= α, domain = S, certificate = certificate) |
| 96 | +optimize!(model) |
| 97 | +@show termination_status(model) |
| 98 | +@show objective_value(model) |
| 99 | +@test length(lagrangian_multipliers(c)) == 7 #src |
0 commit comments