Help understanding MOI bridges, Even Proof-of-concept doesn't work

Hi, I’ve been playing around with MOI bridges, but I can’t get even the simplest thing to work.
Let’s imagine I want to create a bridge that simply ignores any PSD constraints:

module MWE
using MathOptInterface
const MOI = MathOptInterface

struct RemovePSDBridge <: MOI.Bridges.Constraint.AbstractBridge end

function MOI.supports_constraint(::Type{<:RemovePSDBridge},
	::Type{<:MOI.AbstractVectorFunction},
	::Type{<:MOI.PositiveSemidefiniteConeTriangle})
	return true
end

function MOI.Bridges.added_constrained_variable_types(::Type{<:RemovePSDBridge}) 
	Tuple{DataType}[]
end
function MOI.Bridges.added_constraint_types(::Type{<:RemovePSDBridge})
	[]
end

function bridge_constraint(::Type{RemovePSDBridge}, model::MOI.ModelLike, f::MOI.AbstractVectorFunction, s::MathOptInterface.PositiveSemidefiniteConeTriangle)
end
end

Then the obvious proof of concept is whether an LP solver accepts it:


using JuMP
using Clp
using MWE


m = Model(Clp.Optimizer)
MOI.Bridges.add_bridge(m.moi_backend.optimizer, MWE.RemovePSDBridge)

@variable m x[1:3]
@objective m Min x[1]
@constraint(m,[x[1] x[2];x[2] x[3]] in JuMP.PSDCone())

optimize!(m)

But it does not work. What am I doing wrong?

You’re close, but you need something like

struct RemovePSDBridge{T} <: MOI.Bridges.Constraint.AbstractBridge 
end

function MOI.Bridges.Constraint.concrete_bridge_type(
    ::Type{<:RemovePSDBridge}, 
    F::Type{<:MOI.AbstractVectorFunction},
    S::Type{<:MOI.PositiveSemidefiniteConeTriangle},
)
    return RemovePSDBridge{Float64}
end

function MOI.supports_constraint(
    ::Type{<:RemovePSDBridge},
	::Type{<:MOI.AbstractVectorFunction},
	::Type{<:MOI.PositiveSemidefiniteConeTriangle},
)
	return true
end

function MOI.Bridges.added_constrained_variable_types(::Type{<:RemovePSDBridge}) 
	return Tuple{DataType}[]
end

function MOI.Bridges.added_constraint_types(::Type{<:RemovePSDBridge})
	return []
end

function MOI.Bridges.Constraint.bridge_constraint(
    ::Type{<:RemovePSDBridge}, 
    ::MOI.ModelLike, 
    f::MOI.AbstractVectorFunction, 
    s::MOI.PositiveSemidefiniteConeTriangle,
)
    return RemovePSDBridge{Float64}()
end

# Wrap the optimizer in a single bridge optimizer
opt = () -> MOI.Bridges.Constraint.SingleBridgeOptimizer{RemovePSDBridge{Float64}}(
    # Clp doesn't support incremental modification, so we need to wrap it in a cache
    MOI.Utilities.CachingOptimizer(
        MOI.Utilities.Model{Float64}(),
        Clp.Optimizer()
    )
)
m = Model(opt)
@variable m x[1:3]
@objective m Min x[1]
@constraint(m,[x[1] x[2];x[2] x[3]] in JuMP.PSDCone())
optimize!(m)

If you’re interested in understanding the bridging system, I suggest you read: http://www.optimization-online.org/DB_HTML/2020/02/7609.html

Implementing this is definitely nontrivial and not well documented, short of following examples.

@rtwalker did a great job implementing a bridge recently: https://github.com/jump-dev/MathOptInterface.jl/pull/1099. Reading through the comments is probably a good way to learn the thought process.

3 Likes

Thanks.
Additional question: instead of creating the model/bridge/cache/model/solver hierarchy, would this do the same?

	m = SOSModel(Clp.Optimizer)
	JuMP.add_bridge(m, RemovePSDBridge)

BTW: Is it possible / worthwhile adding such external resources to the MOI wiki? With the wiki as is, MOI is fairly impenetrable.

1 Like

Woah! I forgot we had add_bridge! Yes, you can go

m = Model(Clp.Optimizer)
add_bridge(m, RemovePSDBridge)
@variable m x[1:3]
@objective m Min x[1]
@constraint(m,[x[1] x[2];x[2] x[3]] in JuMP.PSDCone())
optimize!(m)

Much simpler.

creating the model/bridge/cache/model/solver hierarchy

You seem well on your way to understanding what is happening. It is pretty complicated…

the wiki as is, MOI is fairly impenetrable.

Pull requests to improve the documentation (e.g., adding a link to the paper) would be great! We’ve focused on building functionality, and documentation has fallen behind, unfortunately.

1 Like