Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ const _PAGES = [
"API Reference" => "submodules/Test/reference.md",
],
],
"Developer Docs" =>
["developer/checklists.md", "developer/contributing.md"],
"Developer Docs" => [
"developer/checklists.md",
"developer/contributing.md",
"developer/defining_a_new_set.md",
],
"Release notes" => "release_notes.md",
]

Expand Down
1 change: 1 addition & 0 deletions docs/src/developer/checklists.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Use this checklist when adding a new set to the MathOptInterface repository.
- [ ] If `isbitstype(S) == false`, implement `Base.:(==)(x::S, y::S)`
- [ ] If an `AbstractVectorSet`, implement `dimension(set::S)`, unless the
dimension is given by `set.dimension`.
- [ ] Ensure the set does not contain references to any variables or constraints

## Utilities

Expand Down
84 changes: 84 additions & 0 deletions docs/src/developer/defining_a_new_set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
```@meta
CurrentModule = MathOptInterface
DocTestSetup = quote
import MathOptInterface as MOI
end
DocTestFilters = [r"MathOptInterface|MOI"]
```

# Defining a new set

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:
```math
t = \max(f_1(x), f_2(x), \ldots, f_N(x))
```

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_ $f(x) \in S$.

Your initial thought for representing the _LinMax_ constraint in MathOptInterface
may be to represent it as:
```math
F(x) \in LinMax(t)
```
where $F(x)$ is the vector-valued function created by concatenating the $f_i$
functions. This formulation violates a basic rule of MathOptInterface:

!!! rule
Sets cannot contain references to decision variables or other constraints.

Instead, we could model the _LinMax_ constraint as:
```math
[t, f_1(x), f_2(x), \ldots, f_N(x)] \in LinMax(N+1)
```

In the language of MathOptInterface, this is a [`AbstractVectorFunction`](@ref)
in the `LinMax` set of dimension $N+1$. The type of the function depends on the
types of the component scalar functions, with a special convention that the
first element in the function is interpretable as a [`VariableIndex`](@ref)
`t`.

Now `LinMax` can be trivially defined as a new [`AbstractVectorSet`](@ref):
```jldoctest define_new_set
julia> import MathOptInterface as MOI

julia> struct LinMax <: MOI.AbstractVectorSet
dimension::Int
end
```
and it can immediately be used in MathOptInterface:
```jldoctest define_new_set
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)
```
5 changes: 3 additions & 2 deletions docs/src/manual/standard_form.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ where:
* the sets ``\mathcal{S}_1, \ldots, \mathcal{S}_m`` are specified by
[`AbstractSet`](@ref) objects

An important design consideration is that the sets are independent of the
decision variables.

!!! tip
For more information on this standard form, read [our paper](https://arxiv.org/abs/2002.03447).

Expand All @@ -43,8 +46,6 @@ The function types implemented in MathOptInterface.jl are:
| [`VectorQuadraticFunction`](@ref) | A vector of scalar-valued quadratic functions. |
| [`VectorNonlinearFunction`](@ref) | ``f(x)``, where ``f`` is a vector-valued nonlinear function. |

Extensions for nonlinear programming are present but not yet well documented.

## One-dimensional sets

The one-dimensional set types implemented in MathOptInterface.jl are:
Expand Down
Loading