Skip to content

Commit

Permalink
Certificate API: get -> function (#229)
Browse files Browse the repository at this point in the history
* Certificate API: get -> function

* Update certificate example
  • Loading branch information
blegat authored Dec 1, 2021
1 parent 98fc3af commit 919ded6
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 102 deletions.
18 changes: 9 additions & 9 deletions docs/src/tutorials/Extension/certificate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,37 +51,37 @@ struct Schmüdgen{IC <: SOSC.AbstractIdealCertificate, CT <: SOS.SOSLikeCone, BT
maxdegree::Int
end

SOSC.get(certificate::Schmüdgen, ::SOSC.Cone) = certificate.cone
SOSC.cone(certificate::Schmüdgen) = certificate.cone

function SOSC.get(::Schmüdgen, ::SOSC.PreprocessedDomain, domain::BasicSemialgebraicSet, p)
function SOSC.preprocessed_domain(::Schmüdgen, domain::BasicSemialgebraicSet, p)
return SOSC.DomainWithVariables(domain, variables(p))
end

function SOSC.get(::Schmüdgen, ::SOSC.PreorderIndices, domain::SOSC.DomainWithVariables)
function SOSC.preorder_indices(::Schmüdgen, domain::SOSC.DomainWithVariables)
n = length(domain.domain.p)
if n >= Sys.WORD_SIZE
error("There are $(2^n - 1) products in Schmüdgen's certificate, they cannot even be indexed with `$Int`.")
end
return map(SOSC.PreorderIndex, 1:(2^n-1))
end

function SOSC.get(certificate::Schmüdgen, ::SOSC.MultiplierBasis, index::SOSC.PreorderIndex, domain::SOSC.DomainWithVariables)
q = SOSC.get(certificate, SOSC.Generator(), index, domain)
function SOSC.multiplier_basis(certificate::Schmüdgen, index::SOSC.PreorderIndex, domain::SOSC.DomainWithVariables)
q = SOSC.generator(certificate, index, domain)
vars = sort!([domain.variables..., variables(q)...], rev = true)
unique!(vars)
return SOSC.maxdegree_gram_basis(certificate.basis, vars, SOSC.multiplier_maxdegree(certificate.maxdegree, q))
end
function SOSC.get(::Type{Schmüdgen{IC, CT, BT}}, ::SOSC.MultiplierBasisType) where {IC, CT, BT}
function SOSC.multiplier_basis_type(::Type{Schmüdgen{IC, CT, BT}}) where {IC, CT, BT}
return BT
end

function SOSC.get(::Schmüdgen, ::SOSC.Generator, index::SOSC.PreorderIndex, domain::SOSC.DomainWithVariables)
function SOSC.generator(::Schmüdgen, index::SOSC.PreorderIndex, domain::SOSC.DomainWithVariables)
I = [i for i in eachindex(domain.domain.p) if !iszero(index.value & (1 << (i - 1)))]
return prod([domain.domain.p[i] for i in eachindex(domain.domain.p) if !iszero(index.value & (1 << (i - 1)))])
end

SOSC.get(certificate::Schmüdgen, ::SOSC.IdealCertificate) = certificate.ideal_certificate
SOSC.get(::Type{<:Schmüdgen{IC}}, ::SOSC.IdealCertificate) where {IC} = IC
SOSC.ideal_certificate(certificate::Schmüdgen) = certificate.ideal_certificate
SOSC.ideal_certificate(::Type{<:Schmüdgen{IC}}) where {IC} = IC

SOS.matrix_cone_type(::Type{<:Schmüdgen{IC, CT}}) where {IC, CT} = SOS.matrix_cone_type(CT)

Expand Down
9 changes: 4 additions & 5 deletions src/Bridges/Constraint/sos_polynomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ function MOI.Bridges.Constraint.bridge_constraint(
# `Float64` when used with JuMP and the coefficient type is often `Int` if
# `set.domain.V` is `FullSpace` or `FixedPolynomialsSet`.
# FIXME convert needed because the coefficient type of `r` is `Any` otherwise if `domain` is `AlgebraicSet`
r = SOS.Certificate.get(s.certificate, SOS.Certificate.ReducedPolynomial(), p, MP.changecoefficienttype(s.domain, T))
gram_basis = SOS.Certificate.get(s.certificate, SOS.Certificate.GramBasis(), r)
r = SOS.Certificate.reduced_polynomial(s.certificate, p, MP.changecoefficienttype(s.domain, T))
gram_basis = SOS.Certificate.gram_basis(s.certificate, r)
g, Q, cQ = SOS.add_gram_matrix(model, MCT, gram_basis, T)
# MOI does not modify the coefficients of the functions so we can modify `r`.
# without altering `f`.
Expand Down Expand Up @@ -73,7 +73,7 @@ function MOIB.Constraint.concrete_bridge_type(
MCT = SOS.matrix_cone_type(CT)
UMCT = union_constraint_types(MCT)
UMST = union_set_types(MCT)
GB = SOS.Certificate.get(CT, SOS.Certificate.GramBasisType())
GB = SOS.Certificate.gram_basis_type(CT)
ZB = SOS.Certificate.zero_basis_type(CT)
return SOSPolynomialBridge{T, G, DT, UMCT, UMST, MCT, GB, ZB, CT, MT, MVT}
end
Expand Down Expand Up @@ -150,8 +150,7 @@ function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintDual,
function reduced(mono)
p = MP.polynomial(mono, T)
domain = MP.changecoefficienttype(bridge.domain, T)
return SOS.Certificate.get(
bridge.certificate, SOS.Certificate.ReducedPolynomial(), p, domain)
return SOS.Certificate.reduced_polynomial(bridge.certificate, p, domain)
end
return [dot(reduced(mono), μ) for mono in bridge.monomials]
end
Expand Down
14 changes: 7 additions & 7 deletions src/Bridges/Constraint/sos_polynomial_in_semialgebraic_set.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function lagrangian_multiplier(model::MOI.ModelLike, certificate, index, preprocessed, T::Type)
basis = Certificate.get(certificate, Certificate.MultiplierBasis(), index, preprocessed)
basis = Certificate.multiplier_basis(certificate, index, preprocessed)
MCT = SOS.matrix_cone_type(typeof(certificate))
return SOS.add_gram_matrix(model, MCT, basis, T)..., basis
end
Expand Down Expand Up @@ -33,8 +33,8 @@ function MOI.Bridges.Constraint.bridge_constraint(
λ_bases = B[]
λ_variables = Union{Vector{MOI.VariableIndex}, Vector{Vector{MOI.VariableIndex}}}[]
λ_constraints = UMCT[]
preprocessed = Certificate.get(set.certificate, Certificate.PreprocessedDomain(), set.domain, p)
for index in Certificate.get(set.certificate, Certificate.PreorderIndices(), preprocessed)
preprocessed = Certificate.preprocessed_domain(set.certificate, set.domain, p)
for index in Certificate.preorder_indices(set.certificate, preprocessed)
λ, λ_variable, λ_constraint, λ_basis = lagrangian_multiplier(
model, set.certificate, index, preprocessed, T)
push!(λ_variables, λ_variable)
Expand All @@ -44,13 +44,13 @@ function MOI.Bridges.Constraint.bridge_constraint(
# need to call `changecoefficienttype`. This is critical since `T` is
# `Float64` when used with JuMP and the coefficient type is often `Int` if
# `set.domain.V` is `FullSpace` or `FixedPolynomialsSet`.
g = Certificate.get(set.certificate, Certificate.Generator(), index, preprocessed)
g = Certificate.generator(set.certificate, index, preprocessed)
# TODO replace with `MA.sub_mul` when it works.
p = MA.operate!!(MA.add_mul, p, -one(T), λ, MP.changecoefficienttype(g, T))
end
new_set = SOS.SOSPolynomialSet(
set.domain.V, MP.monomials(p),
Certificate.get(set.certificate, Certificate.IdealCertificate()))
Certificate.ideal_certificate(set.certificate))
constraint = MOI.add_constraint(model, MOIU.vectorize(MP.coefficients(p)),
new_set)

Expand Down Expand Up @@ -79,10 +79,10 @@ function MOIB.Constraint.concrete_bridge_type(
# for most use cases
G = MOIU.promote_operation(-, T, F, MOI.VectorOfVariables)
MCT = SOS.matrix_cone_type(CT)
B = Certificate.get(CT, Certificate.MultiplierBasisType())
B = Certificate.multiplier_basis_type(CT)
UMCT = union_constraint_types(MCT)
UMST = union_set_types(MCT)
IC = Certificate.get(CT, Certificate.IdealCertificate())
IC = Certificate.ideal_certificate(CT)
return SOSPolynomialInSemialgebraicSetBridge{T, G, AT, IC, B, UMCT, UMST, MCT, MT, MVT}
end

Expand Down
68 changes: 32 additions & 36 deletions src/Certificate/Certificate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,19 @@ const Index = Union{PreorderIndex, IdealIndex}
abstract type Attribute end

# For get
struct Cone <: Attribute end
struct GramBasis <: Attribute end
function cone end
function gram_basis end
# FIXME currently, this returns `MB.MonomialBasis` instead of `MB.MonomialBasis{MT, MVT}`
struct GramBasisType <: Attribute end
struct ReducedPolynomial <: Attribute end
struct IdealCertificate <: Attribute end
struct PreprocessedDomain <: Attribute end
function gram_basis_type end
function reduced_polynomial end
function ideal_certificate end
function preprocessed_domain end

# Only for PreorderIndex
struct PreorderIndices <: Attribute end
struct Generator <: Attribute end
struct MultiplierBasis <: Attribute end
struct MultiplierBasisType <: Attribute end

# For set
#struct Monomials <: Attribute end

function preorder_indices end
function generator end
function multiplier_basis end
function multiplier_basis_type end

# PreorderCertificate
# IdealCertificate
Expand Down Expand Up @@ -80,40 +76,40 @@ struct Putinar{IC <: AbstractIdealCertificate, CT <: SumOfSquares.SOSLikeCone, B
maxdegree::Int
end

get(certificate::Putinar, ::Cone) = certificate.cone
cone(certificate::Putinar) = certificate.cone

struct DomainWithVariables{S, V}
domain::S
variables::V
end
function get(::Putinar, ::PreprocessedDomain, domain::BasicSemialgebraicSet, p)
function preprocessed_domain(::Putinar, domain::BasicSemialgebraicSet, p)
return DomainWithVariables(domain, MP.variables(p))
end

function get(::Putinar, ::PreorderIndices, domain::DomainWithVariables)
function preorder_indices(::Putinar, domain::DomainWithVariables)
return map(PreorderIndex, eachindex(domain.domain.p))
end

function maxdegree_gram_basis(B::Type, variables, maxdegree::Int)
return MB.maxdegree_basis(B, variables, div(maxdegree, 2))
end
multiplier_maxdegree(maxdegree, q) = maxdegree - MP.maxdegree(q)
function get(certificate::Putinar, ::MultiplierBasis, index::PreorderIndex, domain::DomainWithVariables)
function multiplier_basis(certificate::Putinar, index::PreorderIndex, domain::DomainWithVariables)
q = domain.domain.p[index.value]
vars = sort!([domain.variables..., MP.variables(q)...], rev = true)
unique!(vars)
return maxdegree_gram_basis(certificate.basis, vars, multiplier_maxdegree(certificate.maxdegree, q))
end
function get(::Type{Putinar{IC, CT, BT}}, ::MultiplierBasisType) where {IC, CT, BT}
function multiplier_basis_type(::Type{Putinar{IC, CT, BT}}) where {IC, CT, BT}
return BT
end

function get(::Putinar, ::Generator, index::PreorderIndex, domain::DomainWithVariables)
function generator(::Putinar, index::PreorderIndex, domain::DomainWithVariables)
return domain.domain.p[index.value]
end

get(certificate::Putinar, ::IdealCertificate) = certificate.ideal_certificate
get(::Type{<:Putinar{IC}}, ::IdealCertificate) where {IC} = IC
ideal_certificate(certificate::Putinar) = certificate.ideal_certificate
ideal_certificate(::Type{<:Putinar{IC}}) where {IC} = IC

SumOfSquares.matrix_cone_type(::Type{<:Putinar{IC, CT}}) where {IC, CT} = SumOfSquares.matrix_cone_type(CT)

Expand All @@ -122,9 +118,9 @@ SumOfSquares.matrix_cone_type(::Type{<:Putinar{IC, CT}}) where {IC, CT} = SumOfS
######################

abstract type SimpleIdealCertificate{CT, BT} <: AbstractIdealCertificate end
get(::SimpleIdealCertificate, ::ReducedPolynomial, poly, domain) = poly
reduced_polynomial(::SimpleIdealCertificate, poly, domain) = poly

get(certificate::SimpleIdealCertificate, ::Cone) = certificate.cone
cone(certificate::SimpleIdealCertificate) = certificate.cone
SumOfSquares.matrix_cone_type(::Type{<:SimpleIdealCertificate{CT}}) where {CT} = SumOfSquares.matrix_cone_type(CT)

# TODO return something else when `PolyJuMP` support other bases.
Expand All @@ -150,10 +146,10 @@ struct MaxDegree{CT <: SumOfSquares.SOSLikeCone, BT <: MB.AbstractPolynomialBasi
basis::Type{BT}
maxdegree::Int
end
function get(certificate::MaxDegree, ::GramBasis, poly) where CT
function gram_basis(certificate::MaxDegree, poly) where CT
return maxdegree_gram_basis(certificate.basis, MP.variables(poly), certificate.maxdegree)
end
function get(::Type{MaxDegree{CT, BT}}, ::GramBasisType) where {CT, BT}
function gram_basis_type(::Type{MaxDegree{CT, BT}}) where {CT, BT}
return BT
end

Expand All @@ -173,10 +169,10 @@ struct FixedBasis{CT <: SumOfSquares.SOSLikeCone, BT <: MB.AbstractPolynomialBas
cone::CT
basis::BT
end
function get(certificate::FixedBasis, ::GramBasis, poly) where CT
function gram_basis(certificate::FixedBasis, poly) where CT
return certificate.basis
end
function get(::Type{FixedBasis{CT, BT}}, ::GramBasisType) where {CT, BT}
function gram_basis_type(::Type{FixedBasis{CT, BT}}) where {CT, BT}
return BT
end

Expand All @@ -201,10 +197,10 @@ struct Newton{CT <: SumOfSquares.SOSLikeCone, BT <: MB.AbstractPolynomialBasis,
basis::Type{BT}
variable_groups::NPT
end
function get(certificate::Newton{CT, B}, ::GramBasis, poly) where {CT, B}
function gram_basis(certificate::Newton{CT, B}, poly) where {CT, B}
return MB.basis_covering_monomials(B, monomials_half_newton_polytope(MP.monomials(poly), certificate.variable_groups))
end
function get(::Type{<:Newton{CT, BT}}, ::GramBasisType) where {CT, BT}
function gram_basis_type(::Type{<:Newton{CT, BT}}) where {CT, BT}
return BT
end

Expand All @@ -228,18 +224,18 @@ struct Remainder{GCT<:AbstractIdealCertificate} <: AbstractIdealCertificate
gram_certificate::GCT
end

function get(::Remainder, ::ReducedPolynomial, poly, domain)
function reduced_polynomial(::Remainder, poly, domain)
return convert(typeof(poly), rem(poly, ideal(domain)))
end

function get(certificate::Remainder, attr::GramBasis, poly)
return get(certificate.gram_certificate, attr, poly)
function gram_basis(certificate::Remainder, poly)
return gram_basis(certificate.gram_certificate, poly)
end
function get(::Type{Remainder{GCT}}, attr::GramBasisType) where GCT
return get(GCT, attr)
function gram_basis_type(::Type{Remainder{GCT}}) where GCT
return gram_basis_type(GCT)
end

get(certificate::Remainder, attr::Cone) = get(certificate.gram_certificate, attr)
cone(certificate::Remainder) = cone(certificate.gram_certificate)
SumOfSquares.matrix_cone_type(::Type{Remainder{GCT}}) where {GCT} = SumOfSquares.matrix_cone_type(GCT)
zero_basis(certificate::Remainder) = zero_basis(certificate.gram_certificate)
zero_basis_type(::Type{Remainder{GCT}}) where {GCT} = zero_basis_type(GCT)
Expand Down
16 changes: 8 additions & 8 deletions src/Certificate/Sparsity/ideal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ function sparsity(monos, sp::Union{SignSymmetry, Monomial}, gram_basis::MB.Monom
return MB.MonomialBasis.(sparsity(monos, sp, gram_basis.monomials))
end
function sparsity(poly::MP.AbstractPolynomial, sp::Union{SignSymmetry, Monomial}, certificate::SumOfSquares.Certificate.AbstractIdealCertificate)
return sparsity(MP.monomials(poly), sp, SumOfSquares.Certificate.get(certificate, SumOfSquares.Certificate.GramBasis(), poly))
return sparsity(MP.monomials(poly), sp, SumOfSquares.Certificate.gram_basis(certificate, poly))
end
function SumOfSquares.Certificate.get(certificate::Ideal, ::SumOfSquares.Certificate.GramBasis, poly)
function SumOfSquares.Certificate.gram_basis(certificate::Ideal, poly)
return sparsity(poly, certificate.sparsity, certificate.certificate)
end
function SumOfSquares.Certificate.get(::Type{Ideal{S, C}}, attr::SumOfSquares.Certificate.GramBasisType) where {S, C}
return Vector{<:SumOfSquares.Certificate.get(C, attr)}
function SumOfSquares.Certificate.gram_basis_type(::Type{Ideal{S, C}}) where {S, C}
return Vector{<:SumOfSquares.Certificate.gram_basis_type(C)}
end
function SumOfSquares.Certificate.get(certificate::Ideal, attr::SumOfSquares.Certificate.ReducedPolynomial, poly, domain)
return SumOfSquares.Certificate.get(certificate.certificate, attr, poly, domain)
function SumOfSquares.Certificate.reduced_polynomial(certificate::Ideal, poly, domain)
return SumOfSquares.Certificate.reduced_polynomial(certificate.certificate, poly, domain)
end
function SumOfSquares.Certificate.get(certificate::Ideal, attr::SumOfSquares.Certificate.Cone)
return SumOfSquares.Certificate.get(certificate.certificate, attr)
function SumOfSquares.Certificate.cone(certificate::Ideal)
return SumOfSquares.Certificate.cone(certificate.certificate)
end
SumOfSquares.matrix_cone_type(::Type{Ideal{S, C}}) where {S, C} = SumOfSquares.matrix_cone_type(C)

Expand Down
10 changes: 5 additions & 5 deletions src/Certificate/Sparsity/monomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@ function sparsity(poly::MP.AbstractPolynomial, domain::SemialgebraicSets.BasicSe
gram_monos = _gram_monos(
reduce((v, q) -> unique!(sort!([v..., MP.variables(q)...], rev=true)),
domain.p, init = MP.variables(poly)),
SumOfSquares.Certificate.get(certificate, SumOfSquares.Certificate.IdealCertificate())
SumOfSquares.Certificate.ideal_certificate(certificate)
)
processed = SumOfSquares.Certificate.get(certificate, SumOfSquares.Certificate.PreprocessedDomain(), domain, poly)
processed = SumOfSquares.Certificate.preprocessed_domain(certificate, domain, poly)
multiplier_generator_monos = [
(_monos(SumOfSquares.Certificate.get(certificate, SumOfSquares.Certificate.MultiplierBasis(), index, processed)),
MP.monomials(SumOfSquares.Certificate.get(certificate, SumOfSquares.Certificate.Generator(), index, processed)))
for index in SumOfSquares.Certificate.get(certificate, SumOfSquares.Certificate.PreorderIndices(), processed)
(_monos(SumOfSquares.Certificate.multiplier_basis(certificate, index, processed)),
MP.monomials(SumOfSquares.Certificate.generator(certificate, index, processed)))
for index in SumOfSquares.Certificate.preorder_indices(certificate, processed)
]
cliques, multiplier_cliques = sparsity(MP.monomials(poly), sp, gram_monos, multiplier_generator_monos)
return MB.MonomialBasis.(cliques), [MB.MonomialBasis.(clique) for clique in multiplier_cliques]
Expand Down
Loading

0 comments on commit 919ded6

Please sign in to comment.