Conventions for interfacing between JuMP and MathOptInterface
The purpose of this guide is to document the conventions that we have developed for interfacing between JuMP and MathOptInterface.
Attributes
JuMP provides get_attribute
and set_attribute
as thin shims for MOI.get
and MOI.set
. However, there are two common cases where the thin shims are not sufficient:
- when the value of the attribute is an
AbstractJuMPScalar
that needs to be mapped to and fromMOI.AbstractFunction
- when the value of the attribute depends on the shape of the constraint, for example, when getting
MOI.ConstraintDualStart
of matrix-valued constraints.
In these two cases, the convention is to keep get_attribute
as a thin shim that does not modify the attribute value, and to develop new functions that modify or reshape the value as appropriate.
As an example, JuMP provides dual_start_value
and set_dual_start_value
to get and set the MOI.ConstraintDualStart
in the original matrix shape, while get_attribute
and set_attribute
can be used to get and set the value in the vectorized shape:
julia> using JuMP
julia> model = Model();
julia> @variable(model, x[1:2, 1:2], PSD);
julia> c = VariableInSetRef(x);
julia> set_dual_start_value(c, [1 0; 0 1])
julia> dual_start_value(c)
2×2 LinearAlgebra.Symmetric{Float64, Matrix{Float64}}: 1.0 0.0 0.0 1.0
julia> get_attribute(c, MOI.ConstraintDualStart())
3-element Vector{Float64}: 1.0 0.0 1.0
julia> set_attribute(c, MOI.ConstraintDualStart(), [2.0, -1.0, 1.0])
julia> dual_start_value(c)
2×2 LinearAlgebra.Symmetric{Float64, Matrix{Float64}}: 2.0 -1.0 -1.0 1.0
unset_
methods
There are a variety of attributes in JuMP and MOI that can be "set" and "unset." For example, there is MOI.Silent
, and the corresponding set_silent
and unset_silent
.
Note how set_silent
and unset_silent
take a single argument (the model), where set_silent(model)
corresponds to MOI.set(model, MOI.Silent(), true)
and unset_silent(model)
corresponds to MOI.set(model, MOI.Silent(), false)
. We could have instead implemented a single method set_silent(model, flag::Bool)
that corresponded to MOI.set(model, MOI.Silent(), flag)
. Another example is unset_time_limit_sec
, which is equivalent to set_time_limit_sec(model, nothing)
.
We have come to regard the unset_
design as a mistake, because it leads to a proliferation of unique function names instead of leveraging Julia's strength for multiple dispatch.
The existing unset_
names are retained for backwards compatibility, but, going forward, provide a single set_
method and document what value type should be provided to restore the model to the default setting. Thus, we have set_string_names_on_creation
, but no corresponding unset_string_names_on_creation
.