CurrentModule = MathOptInterface
DocTestSetup = quote
import MathOptInterface as MOI
end
DocTestFilters = [r"MathOptInterface|MOI"]
The easiest way to extend the behavior of MathOptInterface is to design a new set. The purpose of this tutorial is to explain how to define a new set and some of the associated nuances.
Defining a new function is an order of magnitude (if not two) harder than defining a new set. Don't consider it as an option unless you have already tried to support your behavior as a set.
As a motivation for this tutorial, we consider the LinMax constraint type, which appears often in constraint programming:
The first step to design a new set for MathOptInterface is to define the
mathematical relationship you want to model as a function-in-set
Your initial thought for representing the LinMax constraint in MathOptInterface may be to represent it as:
where
!!! rule Sets cannot contain references to decision variables or other constraints.
Instead, we could model the LinMax constraint as:
In the language of MathOptInterface, this is a AbstractVectorFunction
in the LinMax set of dimension VariableIndex
t.
Now LinMax can be trivially defined as a new AbstractVectorSet:
julia> import MathOptInterface as MOI
julia> struct LinMax <: MOI.AbstractVectorSet
dimension::Int
end
and it can immediately be used in MathOptInterface:
julia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}());
julia> t = MOI.VariableIndex(1);
julia> x = MOI.VariableIndex.(2:3);
julia> F = 1.0 .* x .+ 2.0;
julia> g = MOI.Utilities.operate(vcat, Float64, t, F...);
julia> MOI.add_constraint(model, g, LinMax(3))
MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, LinMax}(1)
julia> print(model)
Feasibility
Subject to:
VectorAffineFunction{Float64}-in-LinMax
┌ ┐
│0.0 + 1.0 v[1]│
│2.0 + 1.0 v[2]│
│2.0 + 1.0 v[3]│
└ ┘ ∈ LinMax(3)