diff --git a/docs/make.jl b/docs/make.jl index 8e68e2677b..d7862fb8d9 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -25,13 +25,24 @@ makedocs( ], "Manual" => [ "manual/standard_form.md", + "manual/models.md", + "manual/variables.md", "manual/constraints.md", - "manual/status.md", + "manual/solutions.md", "manual/modification.md", - "manual/basic_usage.md", + "manual/example.md", "manual/implementing.md", ], - "API Reference" => "reference/reference.md", + "API Reference" => [ + "reference/standard_form.md", + "reference/models.md", + "reference/variables.md", + "reference/constraints.md", + "reference/modification.md", + "reference/nonlinear.md", + "reference/callbacks.md", + "reference/errors.md", + ], "Submodules" => [ "Benchmarks" => [ "Overview" => "submodules/Benchmarks/overview.md", diff --git a/docs/src/index.md b/docs/src/index.md index 2f28e12af1..aaf24d6cae 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,11 +1,13 @@ -# MathOptInterface - !!! warning This documentation is still under construction. If you need help with JuMP, read the [JuMP documentation](https://jump.dev/JuMP.jl/stable/) instead. If you are writing a solver interface and need help with MOI, join the [developer chatroom](https://gitter.im/JuliaOpt/JuMP-dev) and ask away! +# MathOptInterface + +# What is MathOptInterface? + [MathOptInterface.jl](https://github.com/jump-dev/MathOptInterface.jl) (MOI) is an abstraction layer designed to provide a unified interface to mathematical optimization solvers so that users do not need to understand multiple @@ -36,7 +38,7 @@ you know where to look for certain things. submodules within MOI. These submodules are not required to interface a solver with MOI, but they make the job much easier. -## Citing JuMP +## Citing MathOptInterface A [paper describing the design and features of MathOptInterface](https://arxiv.org/abs/2002.03447) is available on [arXiv](https://arxiv.org). diff --git a/docs/src/manual/basic_usage.md b/docs/src/manual/basic_usage.md deleted file mode 100644 index d2d2210237..0000000000 --- a/docs/src/manual/basic_usage.md +++ /dev/null @@ -1,361 +0,0 @@ -```@meta -CurrentModule = MathOptInterface -DocTestSetup = quote - using MathOptInterface - const MOI = MathOptInterface -end -DocTestFilters = [r"MathOptInterface|MOI"] -``` - -# Basic usage - -!!! note - MOI does not export functions, but for brevity we often omit qualifying - names with the MOI module. Best practice is to have - ```julia - using MathOptInterface - const MOI = MathOptInterface - ``` - and prefix all MOI methods with `MOI.` in user code. If a name is also - available in base Julia, we always explicitly use the module prefix, for - example, with `MOI.get`. - -## The ModelLike and AbstractOptimizer APIs - -The most significant part of MOI is the definition of the **model API** that is -used to specify an instance of an optimization problem (e.g., by adding -variables and constraints). Objects that implement the model API should inherit -from the [`ModelLike`](@ref) abstract type. - -Notably missing from the model API is the method to solve an optimization -problem. `ModelLike` objects may store an instance (e.g., in memory or backed by -a file format) without being linked to a particular solver. In addition to the -model API, MOI defines [`AbstractOptimizer`](@ref). - -*Optimizers* (or solvers) implement the model API (inheriting from `ModelLike`) -and additionally provide methods to solve the model. - -!!! info - Throughout the rest of the manual, `model` is used as a generic `ModelLike`, - and `optimizer` is used as a generic `AbstractOptimizer`. - -Models are constructed by -* adding variables using [`add_variable`](@ref) (or [`add_variables`](@ref)), - see [Add a variable](@ref); -* setting an objective sense and function using [`set`](@ref), - see [Setting an objective](@ref); -* and adding constraints using [`add_constraint`](@ref) (or - [`add_constraints`](@ref)), see [Constraints](@ref). - -The way the problem is solved by the optimimizer is controlled by -[`AbstractOptimizerAttribute`](@ref)s, see [Solver-specific attributes](@ref). - -## Add a variable - -All variables in MOI are scalar variables. New scalar variables are created with -[`add_variable`](@ref) or [`add_variables`](@ref), which return a [`VariableIndex`](@ref) -or `Vector{VariableIndex}` respectively. [`VariableIndex`](@ref) objects are -type-safe wrappers around integers that refer to a variable in a particular -model. - -!!! note - The integer does not necessarily corresond to the column inside an - optimizer! - -One uses [`VariableIndex`](@ref) objects to set and get variable attributes. For -example, the [`VariablePrimalStart`](@ref) attribute is used to provide an -initial starting point for a variable or collection of variables: -```julia -v = MOI.add_variable(model) -MOI.set(model, MOI.VariablePrimalStart(), v, 10.5) -v2 = MOI.add_variables(model, 3) -MOI.set(model, MOI.VariablePrimalStart(), v2, [1.3, 6.8, -4.6]) -``` - -## Delete a variable - -Delete a variable using -[`delete(::ModelLike, ::VariableIndex)`](@ref MathOptInterface.delete(::MathOptInterface.ModelLike, ::MathOptInterface.Index)). - -!!! warning - Not all `ModelLike` models support deleting variables. A - [`DeleteNotAllowed`](@ref) error is thrown if this is not supported. - -## Functions - -MOI defines six functions as listed in the definition of the [Standard form problem](@ref). -The simplest function is [`SingleVariable`](@ref), defined as: -```julia -struct SingleVariable <: AbstractFunction - variable::VariableIndex -end -``` - -If `v` is a [`VariableIndex`](@ref) object, then `SingleVariable(v)` is simply -the scalar-valued function from the complete set of variables in a model that -returns the value of variable `v`. One may also call this function a coordinate -projection, which is more useful for defining constraints than as an objective -function. - -A more interesting function is [`ScalarAffineFunction`](@ref), defined as: -```julia -struct ScalarAffineFunction{T} <: AbstractScalarFunction - terms::Vector{ScalarAffineTerm{T}} - constant::T -end -``` - -The [`ScalarAffineTerm`](@ref) struct defines a variable-coefficient pair: -```julia -struct ScalarAffineTerm{T} - coefficient::T - variable_index::VariableIndex -end -``` - -If `x` is a vector of `VariableIndex` objects, then -```julia -MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([5.0, -2.3], [x[1], x[2]]), 1.0) -``` -represents the function ``5 x_1 - 2.3 x_2 + 1``. - -!!! note - `MOI.ScalarAffineTerm.([5.0, -2.3], [x[1], x[2]])` is a shortcut for - `[MOI.ScalarAffineTerm(5.0, x[1]), MOI.ScalarAffineTerm(-2.3, x[2])]`. This - is Julia's broadcast syntax in action, and is used quite often. - -### Setting an objective - -Objective functions are assigned to a model by setting the [`ObjectiveFunction`](@ref) -attribute. The [`ObjectiveSense`](@ref) attribute is used for setting the -optimization sense. For example, -```julia -x = MOI.add_variables(model, 2) -MOI.set( - model, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), - MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([5.0, -2.3], [x[1], x[2]]), 1.0), - ) -MOI.set(model, MOI.ObjectiveSense(), MIN_SENSE) -``` -sets the objective to the function just discussed in the minimization sense. - -See [Functions and function modifications](@ref) for the complete list of -functions. - -## Solving and retrieving the results - -Once an optimizer is loaded with the objective function and all of the -constraints, we can ask the solver to solve the model by calling -[`optimize!`](@ref). -```julia -MOI.optimize!(optimizer) -``` - -The optimization procedure may terminate for a number of reasons. The -[`TerminationStatus`](@ref) attribute of the optimizer returns a -[`TerminationStatusCode`](@ref) object which explains why the solver stopped. -The termination statuses distinguish between proofs of optimality, -infeasibility, local convergence, limits, and termination because of something -unexpected like invalid problem data or failure to converge. A typical usage of -the [`TerminationStatus`](@ref) attribute is as follows: -```julia -status = MOI.get(optimizer, TerminationStatus()) -if status == MOI.OPTIMAL - # Ok, we solved the problem! -else - # Handle other cases. -end -``` - -After checking the [`TerminationStatus`](@ref), one should typically check -[`ResultCount`](@ref). This attribute returns the number of results that the -solver has available to return. *A result is defined as a primal-dual pair, -but either the primal or the dual may be missing from the result.* While the -`OPTIMAL` termination status normally implies that at least one result is -available, other statuses do not. For example, in the case of infeasiblity, a -solver may return no result or a proof of infeasibility. The [`ResultCount`](@ref) -attribute distinguishes between these two cases. - -The [`PrimalStatus`](@ref) and [`DualStatus`](@ref) attributes return a -[`ResultStatusCode`](@ref) that indicates if that component of the result -is present (i.e., not `NO_SOLUTION`) and explains how to interpret the result. - -If `PrimalStatus` is not `NO_SOLUTION`, then the primal may be retrieved with -the [`VariablePrimal`](@ref) attribute: -```julia -MOI.get(optimizer, VariablePrimal(), x) -``` - -If `x` is a [`VariableIndex`](@ref) then the function call returns a scalar, and -if `x` is a `Vector{VariableIndex}` then the call returns a vector of scalars. -`VariablePrimal()` is equivalent to `VariablePrimal(1)`, i.e., the variable -primal vector of the first result. Use `VariablePrimal(N)` to access the `N`th -result. - -See also the attributes [`ConstraintPrimal`](@ref), and [`ConstraintDual`](@ref). - -See [Duality](@ref) for a discussion of the MOI conventions for primal-dual -pairs and certificates. - -!!! note - We omit discussion of how to handle multiple results, i.e., when - `ResultCount` is greater than 1. This is supported in the API but not yet - implemented in any solver. - -### Common status situations - -The sections below describe how to interpret typical or interesting status cases -for three common classes of solvers. The example cases are illustrative, not -comprehensive. Solver wrappers may provide additional information on -how the solver's statuses map to MOI statuses. - -`?` in the tables indicate that multiple different values are possible. - -#### Primal-dual convex solver - -Linear programming and conic optimization solvers fall into this category. - -| What happened? | `TerminationStatus()` | `ResultCount()` | `PrimalStatus()` | `DualStatus()` | -| --------------------------------------- | --------------------- | --------------- | ------------------------------------------- | ------------------------------------------- | -| Proved optimality | `OPTIMAL` | 1 | `FEASIBLE_POINT` | `FEASIBLE_POINT` | -| Proved infeasible | `INFEASIBLE` | 1 | `NO_SOLUTION` | `INFEASIBILITY_CERTIFICATE` | -| Optimal within relaxed tolerances | `ALMOST_OPTIMAL` | 1 | `FEASIBLE_POINT` or `ALMOST_FEASIBLE_POINT` | `FEASIBLE_POINT` or `ALMOST_FEASIBLE_POINT` | -| Detected an unbounded ray of the primal | `DUAL_INFEASIBLE` | 1 | `INFEASIBILITY_CERTIFICATE` | `NO_SOLUTION` | -| Stall | `SLOW_PROGRESS` | 1 | ? | ? | - -#### Global branch-and-bound solvers - -Mixed-integer programming solvers fall into this category. - -| What happened? | `TerminationStatus()` | `ResultCount()` | `PrimalStatus()` | `DualStatus()` | -| ------------------------------------------------ | ------------------------- | --------------- | ------------------ | -------------- | -| Proved optimality | `OPTIMAL` | 1 | `FEASIBLE_POINT` | `NO_SOLUTION` | -| Presolve detected infeasibility or unboundedness | `INFEASIBLE_OR_UNBOUNDED` | 0 | `NO_SOLUTION` | `NO_SOLUTION` | -| Proved infeasibility | `INFEASIBLE` | 0 | `NO_SOLUTION` | `NO_SOLUTION` | -| Timed out (no solution) | `TIME_LIMIT` | 0 | `NO_SOLUTION` | `NO_SOLUTION` | -| Timed out (with a solution) | `TIME_LIMIT` | 1 | `FEASIBLE_POINT` | `NO_SOLUTION` | -| `CPXMIP_OPTIMAL_INFEAS` | `ALMOST_OPTIMAL` | 1 | `INFEASIBLE_POINT` | `NO_SOLUTION` | - -[`CPXMIP_OPTIMAL_INFEAS`](https://www.ibm.com/support/knowledgecenter/en/SSSA5P_12.6.1/ilog.odms.cplex.help/refcallablelibrary/macros/CPXMIP_OPTIMAL_INFEAS.html) -is a CPLEX status that indicates that a preprocessed problem was solved to -optimality, but the solver was unable to recover a feasible solution to the -original problem. - -#### Local search solvers - -Nonlinear programming solvers fall into this category. It also includes -non-global tree search solvers like -[Juniper](https://github.com/lanl-ansi/Juniper.jl). - -| What happened? | `TerminationStatus()` | `ResultCount()` | `PrimalStatus()` | `DualStatus()` | -| ------------------------------------------------------ | --------------------------------- | --------------- | ------------------ | ---------------- | -| Converged to a stationary point | `LOCALLY_SOLVED` | 1 | `FEASIBLE_POINT` | `FEASIBLE_POINT` | -| Completed a non-global tree search (with a solution) | `LOCALLY_SOLVED` | 1 | `FEASIBLE_POINT` | `FEASIBLE_POINT` | -| Converged to an infeasible point | `LOCALLY_INFEASIBLE` | 1 | `INFEASIBLE_POINT` | ? | -| Completed a non-global tree search (no solution found) | `LOCALLY_INFEASIBLE` | 0 | `NO_SOLUTION` | `NO_SOLUTION` | -| Iteration limit | `ITERATION_LIMIT` | 1 | ? | ? | -| Diverging iterates | `NORM_LIMIT` or `OBJECTIVE_LIMIT` | 1 | ? | ? | - - -## A complete example: solving a knapsack problem - -We first need to select a solver supporting the given problem (see -[`supports`](@ref) and [`supports_constraint`](@ref)). In this example, we -want to solve a binary-constrained knapsack problem: -`max c'x: w'x <= C, x binary`. Suppose we choose GLPK: -```julia -using GLPK -optimizer = GLPK.Optimizer() -``` -We first define the constants of the problem: -```jldoctest knapsack; setup = :(optimizer = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}()); MOI.Utilities.set_mock_optimize!(optimizer, mock -> MOI.Utilities.mock_optimize!(mock, ones(3)))) -c = [1.0, 2.0, 3.0] -w = [0.3, 0.5, 1.0] -C = 3.2 - -# output - -3.2 -``` -We create the variables of the problem and set the objective function: -```jldoctest knapsack -x = MOI.add_variables(optimizer, length(c)) -MOI.set( - optimizer, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(c, x), 0.0), -) -MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE) - -# output - -``` - -We add the knapsack constraint and integrality constraints: -```jldoctest knapsack -MOI.add_constraint( - optimizer, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(w, x), 0.0), - MOI.LessThan(C), -) -for x_i in x - MOI.add_constraint(optimizer, MOI.SingleVariable(x_i), MOI.ZeroOne()) -end - -# output - -``` - -We are all set! We can now call [`optimize!`](@ref) and wait for the solver to -find the solution: -```jldoctest knapsack -MOI.optimize!(optimizer) - -# output - -``` - -The first thing to check after optimization is why the solver stopped, e.g., -did it stop because of a time limit or did it stop because it found the optimal -solution? -```jldoctest knapsack -MOI.get(optimizer, MOI.TerminationStatus()) - -# output - - -OPTIMAL::TerminationStatusCode = 1 -``` - -It found the optimal solution! Now let's see what is that solution. -```jldoctest knapsack -MOI.get(optimizer, MOI.PrimalStatus()) - -# output - -FEASIBLE_POINT::ResultStatusCode = 1 -``` - -What is its objective value? -```jldoctest knapsack -MOI.get(optimizer, MOI.ObjectiveValue()) - -# output - -6.0 -``` - -And what is the value of the variables `x`? -```jldoctest knapsack -MOI.get(optimizer, MOI.VariablePrimal(), x) - -# output - -3-element Array{Float64,1}: - 1.0 - 1.0 - 1.0 -``` - diff --git a/docs/src/manual/constraints.md b/docs/src/manual/constraints.md index eccd33d5d8..2b89a3c8f7 100644 --- a/docs/src/manual/constraints.md +++ b/docs/src/manual/constraints.md @@ -9,83 +9,85 @@ DocTestFilters = [r"MathOptInterface|MOI"] # Constraints -All constraints are specified with [`add_constraint`](@ref) by restricting the -output of some function to a set. The interface allows an arbitrary combination -of functions and sets, but of course solvers may decide to support only a small -number of combinations. - -For example, linear programming solvers should support, at least, combinations -of affine functions with the [`LessThan`](@ref) and [`GreaterThan`](@ref) sets. -These are simply linear constraints. [`SingleVariable`](@ref) functions combined -with these same sets are used to specify upper- and lower-bounds on variables. - -The code example below encodes the linear optimization problem: -```math -\begin{align} -& \max_{x \in \mathbb{R}^2} & 3x_1 + 2x_2 & -\\ -& \;\;\text{s.t.} & x_1 + x_2 &\le 5 -\\ -&& x_1 & \ge 0 -\\ -&&x_2 & \ge -1 -\end{align} +## Add a constraint + +Use [`add_constraint`](@ref) to add a single constraint. + +```jldoctest constraints; setup=:(model = MOI.Utilities.Model{Float64}(); x = MOI.add_variables(model, 2)) +julia> c = MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonnegatives(2)) +MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables,MathOptInterface.Nonnegatives}(1) ``` -```julia -x = MOI.add_variables(model, 2) -MOI.set( - model, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 2.0], x), 0.0), -) -MOI.set(model, MOI.ObjectiveSense(), MAX_SENSE) -MOI.add_constraint( - model, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(1.0, x), 0.0), - MOI.LessThan(5.0), -) -MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.GreaterThan(0.0)) -MOI.add_constraint(model, MOI.SingleVariable(x[2]), MOI.GreaterThan(-1.0)) +[`add_constraint`](@ref) returns a [`ConstraintIndex`](@ref) type, which should +be used to refer to the added constraint in other calls. + +Check if a [`ConstraintIndex`](@ref) is valid using [`is_valid`](@ref). + +```jldoctest constraints +julia> MOI.is_valid(model, c) +true ``` -Besides scalar-valued functions in scalar-valued sets, it's also possible to use -vector-valued functions and sets. - -The code example below encodes the convex optimization problem: -```math -\begin{align} -& \max_{x,y,z \in \mathbb{R}} & y + z & -\\ -& \;\;\text{s.t.} & 3x &= 2 -\\ -&& x & \ge \lVert (y,z) \rVert_2 -\end{align} +Use [`add_constraints`](@ref) to add a number of constraints of the same type. + +```jldoctest; setup=:(model = MOI.Utilities.Model{Float64}(); x = MOI.add_variables(model, 2)) +julia> c = MOI.add_constraints( + model, + [MOI.SingleVariable(x[1]), MOI.SingleVariable(x[2])], + [MOI.GreaterThan(0.0), MOI.GreaterThan(1.0)] + ) +2-element Array{MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.GreaterThan{Float64}},1}: + MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.GreaterThan{Float64}}(1) + MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.GreaterThan{Float64}}(2) ``` +This time, a vector of [`ConstraintIndex`](@ref) are returned. + +Use [`supports_constraint`](@ref) to check if the model supports adding a +constraint type. +```jldoctest; setup=:(model = MOI.Utilities.Model{Float64}()) +julia> MOI.supports_constraint( + model, + MOI.SingleVariable, + MOI.GreaterThan{Float64}, + ) +true +``` + +## Delete a constraint + +Use [`delete`](@ref) to delete a constraint. + +```jldoctest constraints +julia> MOI.delete(model, c) -```julia -x,y,z = MOI.add_variables(model, 3) -MOI.set( - model, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(1.0, [y, z]), 0.0), -) -MOI.set(model, ObjectiveSense(), MAX_SENSE) -MOI.add_constraint( - model, - MOI.VectorAffineFunction( - [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(3.0, x))], [-2.0] - ), - MOI.Zeros(1), -) -MOI.add_constraint( - model, MOI.VectorOfVariables([x, y, z]), MOI.SecondOrderCone(3) -) +julia> MOI.is_valid(model, c) +false ``` -[TODO Describe ConstraintIndex objects.] +## Constraint attributes -### Constraints by function-set pairs +The following attributes are available for constraints: + +* [`ConstraintName`](@ref) +* [`ConstraintPrimalStart`](@ref) +* [`ConstraintDualStart`](@ref) +* [`ConstraintPrimal`](@ref) +* [`ConstraintDual`](@ref) +* [`ConstraintBasisStatus`](@ref) +* [`ConstraintFunction`](@ref) +* [`CanonicalConstraintFunction`](@ref) +* [`ConstraintSet`](@ref) + +Get and set these attributes using [`get`](@ref) and [`set`](@ref). + +```jldoctest constraints +julia> MOI.set(model, MOI.ConstraintName(), c, "con_c") + +julia> MOI.get(model, MOI.ConstraintName(), c) +"con_c" +``` + +## Constraints by function-set pairs Below is a list of common constraint types and how they are represented as function-set pairs in MOI. In the notation below, ``x`` is a vector of @@ -94,7 +96,7 @@ scalar constants, ``a, b`` are constant vectors, `A` is a constant matrix and ``\mathbb{R}_+`` (resp. ``\mathbb{R}_-``) is the set of nonnegative (resp. nonpositive) real numbers. -#### Linear constraints +### Linear constraints | Mathematical Constraint | MOI Function | MOI Set | |-------------------------------|------------------------------|----------------| @@ -133,7 +135,7 @@ allow the solver to return separate dual multipliers for the two bounds, while the former will allow the solver to return only a single dual for the interval constraint. -#### Conic constraints +### Conic constraints | Mathematical Constraint | MOI Function | MOI Set | |---------------------------------------------------------------|------------------------------|------------------------------------| @@ -151,7 +153,7 @@ where ``\mathcal{E}`` is the exponential cone (see [`ExponentialCone`](@ref)), ``A`` is an affine map that outputs symmetric matrices and ``B`` is an affine map that outputs square matrices. -#### Quadratic constraints +### Quadratic constraints | Mathematical Constraint | MOI Function | MOI Set | |-------------------------------|------------------------------|-------------------------------| @@ -160,8 +162,7 @@ where ``\mathcal{E}`` is the exponential cone (see [`ExponentialCone`](@ref)), | ``x^TQx + a^Tx + b = 0`` | `ScalarQuadraticFunction` | `EqualTo` | | Bilinear matrix inequality | `VectorQuadraticFunction` | `PositiveSemidefiniteCone...` | - -#### Discrete and logical constraints +### Discrete and logical constraints | Mathematical Constraint | MOI Function | MOI Set | |--------------------------------------------------------------------------------------------|------------------------|------------------------------------| diff --git a/docs/src/manual/example.md b/docs/src/manual/example.md new file mode 100644 index 0000000000..c6cf54e65c --- /dev/null +++ b/docs/src/manual/example.md @@ -0,0 +1,136 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# A complete example: solving a knapsack problem + +In this example, we want to solve a binary-constrained knapsack problem: +```math +\begin{aligned} +\max \; & c^\top x \\ +s.t. \; & w^\top x \le C \\ + & x_i \in \{0,1\},\quad \forall i=1,\ldots,n +\end{aligned} +``` + +As an optimizer, we choose GLPK: +```julia +using GLPK +optimizer = GLPK.Optimizer() +``` + +## Define the data + +We first define the constants of the problem: +```jldoctest knapsack; setup = :(optimizer = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}()); MOI.Utilities.set_mock_optimize!(optimizer, mock -> MOI.Utilities.mock_optimize!(mock, ones(3)))) +julia> c = [1.0, 2.0, 3.0] +3-element Array{Float64,1}: + 1.0 + 2.0 + 3.0 + +julia> w = [0.3, 0.5, 1.0] +3-element Array{Float64,1}: + 0.3 + 0.5 + 1.0 + +julia> C = 3.2 +3.2 +``` + +## Add the variables + +```jldoctest knapsack +julia> x = MOI.add_variables(optimizer, length(c)); +``` + +## [Set the objective](@id set_objective_example) + +```jldoctest knapsack +julia> MOI.set( + optimizer, + MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(c, x), 0.0), + ); + +julia> MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE) +``` + +!!! tip + `MOI.ScalarAffineTerm.(c, x)` is a shortcut for + `[MOI.ScalarAffineTerm(c[i], x[i]) for i = 1:3]`. This is Julia's broadcast + syntax in action, and is used quite often throughout MOI. + +## Add the constraints + +We add the knapsack constraint and integrality constraints: +```jldoctest knapsack +julia> MOI.add_constraint( + optimizer, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(w, x), 0.0), + MOI.LessThan(C), + ); +``` + +Add integrality constraints: +```jldoctest knapsack +julia> for x_i in x + MOI.add_constraint(optimizer, MOI.SingleVariable(x_i), MOI.ZeroOne()) + end +``` + +## Optimize the model + +```jldoctest knapsack +julia> MOI.optimize!(optimizer) +``` + +## Understand why the solver stopped + +The first thing to check after optimization is why the solver stopped, e.g., +did it stop because of a time limit or did it stop because it found the optimal +solution? +```jldoctest knapsack +julia> MOI.get(optimizer, MOI.TerminationStatus()) +OPTIMAL::TerminationStatusCode = 1 +``` +Looks like we found an optimal solution! + +## Understand what solution was returned + + +```jldoctest knapsack +julia> MOI.get(optimizer, MOI.ResultCount()) +1 + +julia> MOI.get(optimizer, MOI.PrimalStatus()) +FEASIBLE_POINT::ResultStatusCode = 1 + +julia> MOI.get(optimizer, MOI.DualStatus()) +NO_SOLUTION::ResultStatusCode = 0 +``` + +## Query the objective + +What is its objective value? +```jldoctest knapsack +julia> MOI.get(optimizer, MOI.ObjectiveValue()) +6.0 +``` + +## Query the primal solution + +And what is the value of the variables `x`? +```jldoctest knapsack +julia> MOI.get(optimizer, MOI.VariablePrimal(), x) +3-element Array{Float64,1}: + 1.0 + 1.0 + 1.0 +``` diff --git a/docs/src/manual/models.md b/docs/src/manual/models.md new file mode 100644 index 0000000000..346b6881ba --- /dev/null +++ b/docs/src/manual/models.md @@ -0,0 +1,52 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Models + +The most significant part of MOI is the definition of the **model API** that is +used to specify an instance of an optimization problem (e.g., by adding +variables and constraints). Objects that implement the model API should inherit +from the [`ModelLike`](@ref) abstract type. + +Notably missing from the model API is the method to solve an optimization +problem. `ModelLike` objects may store an instance (e.g., in memory or backed by +a file format) without being linked to a particular solver. In addition to the +model API, MOI defines [`AbstractOptimizer`](@ref). + +*Optimizers* (or solvers) implement the model API (inheriting from `ModelLike`) +and additionally provide methods to solve the model. + +!!! info + Throughout the rest of the manual, `model` is used as a generic `ModelLike`, + and `optimizer` is used as a generic `AbstractOptimizer`. + +!!! tip + MOI does not export functions, but for brevity we often omit qualifying + names with the MOI module. Best practice is to have + ```julia + using MathOptInterface + const MOI = MathOptInterface + ``` + and prefix all MOI methods with `MOI.` in user code. If a name is also + available in base Julia, we always explicitly use the module prefix, for + example, with `MOI.get`. + +## Attributes + +Attributes can be set in different ways: + +* it is either set when the model is created like [`SolverName`](@ref) and + [`RawSolver`](@ref), +* or explicitly when the model is copied like [`ObjectiveSense`](@ref), +* or implicitly, e.g., [`NumberOfVariables`](@ref) is implicitly set by + [`add_variable`](@ref) and [`ConstraintFunction`](@ref) is implicitly set by + [`add_constraint`](@ref). +* or it is set to contain the result of the optimization during + [`optimize!`](@ref) like [`VariablePrimal`](@ref). + diff --git a/docs/src/manual/status.md b/docs/src/manual/solutions.md similarity index 84% rename from docs/src/manual/status.md rename to docs/src/manual/solutions.md index 6cdeb63272..620d921ee7 100644 --- a/docs/src/manual/status.md +++ b/docs/src/manual/solutions.md @@ -7,7 +7,16 @@ end DocTestFilters = [r"MathOptInterface|MOI"] ``` -# Statuses +# Solutions + +## Solving and retrieving the results + +Once an optimizer is loaded with the objective function and all of the +constraints, we can ask the solver to solve the model by calling +[`optimize!`](@ref). +```julia +MOI.optimize!(optimizer) +``` ## Why did the solver stop? @@ -38,33 +47,32 @@ available, other statuses do not. For example, in the case of infeasiblity, a solver may return no result or a proof of infeasibility. The [`ResultCount`](@ref) attribute distinguishes between these two cases. -## What solution did the solver return? +## Primal solutions -The [`PrimalStatus`](@ref) and [`DualStatus`](@ref) attributes return a -[`ResultStatusCode`](@ref) that indicates if that component of the result -is present (i.e., not `NO_SOLUTION`) and explains how to interpret the result. +Use the [`PrimalStatus`](@ref) optimizer attribute to return a +[`ResultStatusCode`](@ref) describing the status of the primal solution. -If `PrimalStatus` is not `NO_SOLUTION`, then the primal may be retrieved with -the [`VariablePrimal`](@ref) attribute: -```julia -MOI.get(optimizer, VariablePrimal(), x) -``` +Common returns are described below in the [Common status situations](@ref) +section. + +Query the primal solution using the [`VariablePrimal`](@ref) and +[`ConstraintPrimal`](@ref) attributes. + +Query the objective function value using the [`ObjectiveValue`](@ref) attribute. + +## Dual solutions -If `x` is a [`VariableIndex`](@ref) then the function call returns a scalar, and -if `x` is a `Vector{VariableIndex}` then the call returns a vector of scalars. -`VariablePrimal()` is equivalent to `VariablePrimal(1)`, i.e., the variable -primal vector of the first result. Use `VariablePrimal(N)` to access the `N`th -result. +!!! warning + See [Duality](@ref) for a discussion of the MOI conventions for primal-dual + pairs and certificates. -See also the attributes [`ConstraintPrimal`](@ref), and [`ConstraintDual`](@ref). +Use the [`DualStatus`](@ref) optimizer attribute to return a +[`ResultStatusCode`](@ref) describing the status of the dual solution. -See [Duality](@ref) for a discussion of the MOI conventions for primal-dual -pairs and certificates. +Query the dual solution using the [`ConstraintDual`](@ref) attribute. -!!! note - We omit discussion of how to handle multiple results, i.e., when - `ResultCount` is greater than 1. This is supported in the API but not yet - implemented in any solver. +Query the dual objective function value using the [`DualObjectiveValue`](@ref) +attribute. ## Common status situations diff --git a/docs/src/manual/variables.md b/docs/src/manual/variables.md new file mode 100644 index 0000000000..d57b2e2f56 --- /dev/null +++ b/docs/src/manual/variables.md @@ -0,0 +1,71 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Variables + +## Add a variable + +Use [`add_variable`](@ref) to add a single variable. + +```jldoctest variables; setup=:(model = MOI.Utilities.Model{Float64}(); ) +julia> x = MOI.add_variable(model) +MathOptInterface.VariableIndex(1) +``` +[`add_variable`](@ref) returns a [`VariableIndex`](@ref) type, which should be +used to refer to the added variable in other calls. + +Check if a [`VariableIndex`](@ref) is valid using [`is_valid`](@ref). +```jldoctest variables +julia> MOI.is_valid(model, x) +true +``` + +Use [`add_variables`](@ref) to add a number of variables. +```jldoctest variables +julia> y = MOI.add_variables(model, 2) +2-element Array{MathOptInterface.VariableIndex,1}: + MathOptInterface.VariableIndex(2) + MathOptInterface.VariableIndex(3) +``` + +!!! warning + The integer does not necessarily corresond to the column inside an + optimizer! + +## Delete a variable + +Delete a variable using [`delete`](@ref). + +```jldoctest variables +julia> MOI.delete(model, x) + +julia> MOI.is_valid(model, x) +false +``` + +!!! warning + Not all `ModelLike` models support deleting variables. A + [`DeleteNotAllowed`](@ref) error is thrown if this is not supported. + +## Variable attributes + +The following attributes are available for variables: + +* [`VariableName`](@ref) +* [`VariablePrimalStart`](@ref) +* [`VariablePrimal`](@ref) + +Get and set these attributes using [`get`(@ref) and [`set`](@ref). + +```jldoctest variables +julia> MOI.set(model, MOI.VariableName(), x, "var_x") + +julia> MOI.get(model, MOI.VariableName(), x) +"var_x" +``` diff --git a/docs/src/reference/callbacks.md b/docs/src/reference/callbacks.md new file mode 100644 index 0000000000..435c79a46e --- /dev/null +++ b/docs/src/reference/callbacks.md @@ -0,0 +1,46 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Callbacks + +```@docs +AbstractCallback +AbstractSubmittable +submit +``` + +## Attributes + +```@docs +CallbackNodeStatus +CallbackNodeStatusCode +CallbackVariablePrimal +``` + +## Lazy constraints + +```@docs +LazyConstraintCallback +LazyConstraint +``` + +## User cuts + +```@docs +UserCutCallback +UserCut +``` + +## Heuristic solutions + +```@docs +HeuristicCallback +HeuristicSolutionStatus +HeuristicSolution +``` diff --git a/docs/src/reference/constraints.md b/docs/src/reference/constraints.md new file mode 100644 index 0000000000..c2122ea6dc --- /dev/null +++ b/docs/src/reference/constraints.md @@ -0,0 +1,42 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# [Constraints](@id constraints_ref) + +## Types + +```@docs +ConstraintIndex +``` + +## Functions + +```@docs +is_valid(::ModelLike,::ConstraintIndex) +add_constraint +add_constraints +transform +supports_constraint +``` + +## Attributes + +```@docs +AbstractConstraintAttribute +ConstraintName +ConstraintPrimalStart +ConstraintDualStart +ConstraintPrimal +ConstraintDual +ConstraintBasisStatus +BasisStatusCode +ConstraintFunction +CanonicalConstraintFunction +ConstraintSet +``` diff --git a/docs/src/reference/errors.md b/docs/src/reference/errors.md new file mode 100644 index 0000000000..ea9818a763 --- /dev/null +++ b/docs/src/reference/errors.md @@ -0,0 +1,78 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Errors + +When an MOI call fails on a model, precise errors should be thrown when possible +instead of simply calling `error` with a message. The docstrings for the +respective methods describe the errors that the implementation should thrown in +certain situations. This error-reporting system allows code to distinguish +between internal errors (that should be shown to the user) and unsupported +operations which may have automatic workarounds. + +When an invalid index is used in an MOI call, an [`InvalidIndex`](@ref) should +be thrown: +```@docs +InvalidIndex +``` + +As discussed in [JuMP mapping](@ref), for scalar constraint with a nonzero +function constant, a [`ScalarFunctionConstantNotZero`](@ref) exception may be +thrown: +```@docs +ScalarFunctionConstantNotZero +``` + +Some [`SingleVariable`](@ref) constraints cannot be combined on the same +variable: +```@docs +LowerBoundAlreadySet +UpperBoundAlreadySet +``` + +As discussed in [`AbstractCallback`](@ref), trying to [`get`](@ref) attributes +inside a callback may throw: +```@docs +OptimizeInProgress +``` + +Trying to submit the wrong type of [`AbstractSubmittable`](@ref) inside an +[`AbstractCallback`](@ref) (e.g., a [`UserCut`](@ref) inside a +[`LazyConstraintCallback`](@ref)) will throw: +```@docs +InvalidCallbackUsage +``` + +The rest of the errors defined in MOI fall in two categories represented by the +following two abstract types: +```@docs +UnsupportedError +NotAllowedError +``` + +The different [`UnsupportedError`](@ref) and [`NotAllowedError`](@ref) are the +following errors: +```@docs +UnsupportedAttribute +SetAttributeNotAllowed +AddVariableNotAllowed +UnsupportedConstraint +AddConstraintNotAllowed +ModifyConstraintNotAllowed +ModifyObjectiveNotAllowed +DeleteNotAllowed +UnsupportedSubmittable +SubmitNotAllowed +``` + +Note that setting the [`ConstraintFunction`](@ref) of a [`SingleVariable`] +constraint is not allowed: +```@docs +SettingSingleVariableFunctionNotAllowed +``` diff --git a/docs/src/reference/models.md b/docs/src/reference/models.md new file mode 100644 index 0000000000..a8009726c2 --- /dev/null +++ b/docs/src/reference/models.md @@ -0,0 +1,102 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Models + +## Attribute interface + +```@docs +is_set_by_optimize +is_copyable +get +get! +set +supports +``` + +## Model interface + +```@docs +ModelLike +is_empty +empty! +write_to_file +read_from_file +copy_to +``` + +## Model attributes + +```@docs +AbstractModelAttribute +Name +ObjectiveFunction +ObjectiveFunctionType +ObjectiveSense +NumberOfVariables +ListOfVariableIndices +ListOfConstraints +NumberOfConstraints +ListOfConstraintIndices +ListOfOptimizerAttributesSet +ListOfModelAttributesSet +ListOfVariableAttributesSet +ListOfConstraintAttributesSet +``` + +## Optimizer interface + +```@docs +AbstractOptimizer +OptimizerWithAttributes +optimize! +instantiate +``` + +## Optimizer attributes + +```@docs +AbstractOptimizerAttribute +SolverName +Silent +TimeLimitSec +RawParameter +NumberOfThreads +RawSolver +``` + +List of attributes useful for optimizers + +```@docs +TerminationStatus +TerminationStatusCode +PrimalStatus +DualStatus +ResultStatusCode +RawStatusString +ResultCount +ObjectiveValue +DualObjectiveValue +ObjectiveBound +RelativeGap +SolveTime +SimplexIterations +BarrierIterations +NodeCount +``` + +### Conflict Status + +```@docs +compute_conflict! +ConflictStatus +ConflictStatusCode +ConstraintConflictStatus +ConflictParticipationStatusCode +``` diff --git a/docs/src/reference/modification.md b/docs/src/reference/modification.md new file mode 100644 index 0000000000..abb08f534c --- /dev/null +++ b/docs/src/reference/modification.md @@ -0,0 +1,19 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Modifications + +```@docs +modify +AbstractFunctionModification +ScalarConstantChange +VectorConstantChange +ScalarCoefficientChange +MultirowChange +``` diff --git a/docs/src/reference/nonlinear.md b/docs/src/reference/nonlinear.md new file mode 100644 index 0000000000..04a954f470 --- /dev/null +++ b/docs/src/reference/nonlinear.md @@ -0,0 +1,44 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Nonlinear programming + +## Types +```@docs +AbstractNLPEvaluator +NLPBoundsPair +NLPBlockData +``` + +## Attributes + +```@docs +NLPBlock +NLPBlockDual +NLPBlockDualStart +``` + +## Functions + +```@docs +initialize +features_available +eval_objective +eval_constraint +eval_objective_gradient +jacobian_structure +hessian_lagrangian_structure +eval_constraint_jacobian +eval_constraint_jacobian_product +eval_constraint_jacobian_transpose_product +eval_hessian_lagrangian +eval_hessian_lagrangian_product +objective_expr +constraint_expr +``` diff --git a/docs/src/reference/reference.md b/docs/src/reference/reference.md deleted file mode 100644 index 8909b730e4..0000000000 --- a/docs/src/reference/reference.md +++ /dev/null @@ -1,509 +0,0 @@ -```@meta -CurrentModule = MathOptInterface -DocTestSetup = quote - using MathOptInterface - const MOI = MathOptInterface - - # For compatibility with both Julia 1.0.5 and 1.5.2 - # Upon the Julia LTS version becoming 1.6, these imports could be dropped, - # and all ScalarAffineTerm and VariableIndex instances in doctests below - # could be replaced with MOI.ScalarAffineTerm and MOI.VariableIndex - # Check discussion at PR 1184: https://github.com/jump-dev/MathOptInterface.jl/pull/1184#discussion_r515300914 - import MathOptInterface.ScalarAffineTerm - import MathOptInterface.VariableIndex -end -DocTestFilters = [r"MathOptInterface|MOI"] -``` - -# API Reference - -[Some introduction to API. List basic standalone methods.] - -## Attributes - -List of attribute categories. - -```@docs -AbstractOptimizerAttribute -AbstractModelAttribute -AbstractVariableAttribute -AbstractConstraintAttribute -``` - -Attributes can be set in different ways: - -* it is either set when the model is created like [`SolverName`](@ref) and - [`RawSolver`](@ref), -* or explicitly when the model is copied like [`ObjectiveSense`](@ref), -* or implicitly, e.g., [`NumberOfVariables`](@ref) is implicitly set by - [`add_variable`](@ref) and [`ConstraintFunction`](@ref) is implicitly set by - [`add_constraint`](@ref). -* or it is set to contain the result of the optimization during - [`optimize!`](@ref) like [`VariablePrimal`](@ref). - -The following functions allow to distinguish between some of these different -categories: -```@docs -is_set_by_optimize -is_copyable -``` - -Functions for getting and setting attributes. - -```@docs -get -get! -set -supports -``` - -### Submit - -Objects may be submitted to an optimizer using [`submit`](@ref). -```@docs -AbstractSubmittable -submit -``` - -List of submittables - -```@docs -LazyConstraint -HeuristicSolutionStatus -HeuristicSolution -UserCut -``` - -## Model Interface - -```@docs -ModelLike -is_empty -empty! -write_to_file -read_from_file -``` - -Copying - -```@docs -copy_to -``` - -List of model attributes - -```@docs -Name -ObjectiveSense -NumberOfVariables -ListOfVariableIndices -ListOfConstraints -NumberOfConstraints -ListOfConstraintIndices -ListOfOptimizerAttributesSet -ListOfModelAttributesSet -ListOfVariableAttributesSet -ListOfConstraintAttributesSet -``` - -## Optimizers - -```@docs -AbstractOptimizer -optimize! -OptimizerWithAttributes -instantiate -``` - -List of optimizers attributes - -```@docs -SolverName -Silent -TimeLimitSec -RawParameter -NumberOfThreads -``` - -List of attributes useful for optimizers - - -```@docs -RawSolver -ResultCount -ObjectiveFunction -ObjectiveFunctionType -ObjectiveValue -DualObjectiveValue -ObjectiveBound -RelativeGap -SolveTime -SimplexIterations -BarrierIterations -NodeCount -TerminationStatus -RawStatusString -PrimalStatus -DualStatus -``` - -Attributes relating to solver callbacks: - -```@docs -AbstractCallback -LazyConstraintCallback -HeuristicCallback -UserCutCallback -CallbackNodeStatus -CallbackNodeStatusCode -CallbackVariablePrimal -``` -### Termination Status - -The `TerminationStatus` attribute indicates why the optimizer stopped executing. -The value of the attribute is of type `TerminationStatusCode`. - -```@docs -TerminationStatusCode -``` - -### Conflict Status - -The `ConflictStatus` attribute indicates why the conflict finder stopped executing. -The value of the attribute is of type `ConflictStatusCode`. - -```@docs -compute_conflict! -ConflictStatus -ConflictStatusCode -ConstraintConflictStatus -ConflictParticipationStatusCode -``` - -### Result Status - -The `PrimalStatus` and `DualStatus` attributes indicate how to interpret the result returned by the solver. -The value of the attribute is of type `ResultStatusCode`. - -```@docs -ResultStatusCode -``` - -## Variables and Constraints - -### Basis Status - -The `BasisStatus` attribute of a constraint describes its status with respect to -a basis, if one is known. The value of the attribute is of type -`BasisStatusCode`. - -```@docs -BasisStatusCode -``` - -### Index types - -```@docs -VariableIndex -ConstraintIndex -is_valid -throw_if_not_valid -delete(::ModelLike, ::Index) -delete(::ModelLike, ::Vector{<:Index}) -``` - -### Variables - -*Free variables* are the variables created with [`add_variable`](@ref) or -[`add_variables`](@ref) while *constrained variables* are -the variables created with [`add_constrained_variable`](@ref) or -[`add_constrained_variables`](@ref). Adding constrained variables instead of -constraining free variables with [`add_constraint`](@ref) allows -[variable bridges](@ref variable_bridges) to be used. -Note further that free variables that are constrained with -[`add_constraint`](@ref) may be copied by [`copy_to`](@ref) with -[`add_constrained_variable`](@ref) or [`add_constrained_variables`](@ref) by the -[`Utilities.CachingOptimizer`](@ref). -More precisely, the attributes do not distinguish constraints on variables -created with `add_constrained_variable(s)` or `add_variable(s)`/`add_constraint`. -When the model is copied, if a variable is constrained in several sets, -the implementation of [`copy_to`](@ref) can determine whether it is added -using [`add_variable`](@ref) or [`add_constrained_variable`](@ref) with one -of the sets. The rest of the constraints on the variables are added -with [`add_constraint`](@ref). For deleting, see [Index types](@ref). - -```@docs -add_variable -add_variables -add_constrained_variable -add_constrained_variables -supports_add_constrained_variable -supports_add_constrained_variables -``` - -List of attributes associated with variables. [category AbstractVariableAttribute] -Calls to `get` and `set` should include as an argument a single `VariableIndex` or a vector of `VariableIndex` objects. - -```@docs -VariableName -VariablePrimalStart -VariablePrimal -``` - -### [Constraints](@id constraints_ref) - -Functions for adding and modifying constraints. - -```@docs -is_valid(::ModelLike,::ConstraintIndex) -add_constraint -add_constraints -transform -supports_constraint -``` - -List of attributes associated with constraints. [category AbstractConstraintAttribute] -Calls to `get` and `set` should include as an argument a single `ConstraintIndex` or a vector of `ConstraintIndex{F,S}` objects. - -```@docs -ConstraintName -ConstraintPrimalStart -ConstraintDualStart -ConstraintPrimal -ConstraintDual -ConstraintBasisStatus -ConstraintFunction -CanonicalConstraintFunction -ConstraintSet -``` - -Note that setting the [`ConstraintFunction`](@ref) of a [`SingleVariable`] -constraint is not allowed: -```@docs -SettingSingleVariableFunctionNotAllowed -``` - -## Functions and function modifications - -List of recognized functions. -```@docs -AbstractFunction -AbstractVectorFunction -SingleVariable -VectorOfVariables -ScalarAffineTerm -ScalarAffineFunction -VectorAffineTerm -VectorAffineFunction -ScalarQuadraticTerm -ScalarQuadraticFunction -VectorQuadraticTerm -VectorQuadraticFunction -``` - -Functions for getting and setting properties of functions. - -```@docs -output_dimension -constant(f::Union{ScalarAffineFunction, ScalarQuadraticFunction}) -constant(f::Union{VectorAffineFunction, VectorQuadraticFunction}) -constant(f::SingleVariable, ::DataType) -constant(f::VectorOfVariables, T::DataType) -``` - -## Sets - -All sets are subtypes of [`AbstractSet`](@ref) and they should either be scalar -or vector sets. -```@docs -AbstractSet -AbstractScalarSet -AbstractVectorSet -``` - -Functions for getting properties of sets. -```@docs -dimension -dual_set -dual_set_type -constant(s::EqualTo) -supports_dimension_update -update_dimension -``` - -### Scalar sets - -List of recognized scalar sets. -```@docs -GreaterThan -LessThan -EqualTo -Interval -Integer -ZeroOne -Semicontinuous -Semiinteger -``` - -### Vector sets - -List of recognized vector sets. -```@docs -Reals -Zeros -Nonnegatives -Nonpositives -NormInfinityCone -NormOneCone -SecondOrderCone -RotatedSecondOrderCone -GeometricMeanCone -ExponentialCone -DualExponentialCone -PowerCone -DualPowerCone -RelativeEntropyCone -NormSpectralCone -NormNuclearCone -SOS1 -SOS2 -IndicatorSet -Complements -``` - -### Matrix sets - -Matrix sets are vectorized in order to be subtypes of -[`AbstractVectorSet`](@ref). For sets of symmetric matrices, storing both the -`(i, j)` and `(j, i)` elements is redundant so there exists the -[`AbstractSymmetricMatrixSetTriangle`](@ref) set to represent only the -vectorization of the upper triangular part of the matrix. When the matrix -of expressions constrained to be in the set is not symmetric and hence -the `(i, j)` and `(j, i)` elements should be constrained to be symmetric, -the [`AbstractSymmetricMatrixSetSquare`](@ref) set can be used. The -[`Bridges.Constraint.SquareBridge`](@ref) can transform a set from the square -form to the [`triangular_form`](@ref) by adding appropriate constraints if -the `(i, j)` and `(j, i)` expressions are different. -```@docs -AbstractSymmetricMatrixSetTriangle -AbstractSymmetricMatrixSetSquare -side_dimension -triangular_form -``` -List of recognized matrix sets. -```@docs -PositiveSemidefiniteConeTriangle -PositiveSemidefiniteConeSquare -LogDetConeTriangle -LogDetConeSquare -RootDetConeTriangle -RootDetConeSquare -``` - -## Modifications - -Functions for modifying objective and constraint functions. - -```@docs -modify -AbstractFunctionModification -ScalarConstantChange -VectorConstantChange -ScalarCoefficientChange -MultirowChange -``` - -## Nonlinear programming (NLP) - -### Attributes - -```@docs -NLPBlock -NLPBoundsPair -NLPBlockData -NLPBlockDual -NLPBlockDualStart -``` -### NLP evaluator methods - -```@docs -AbstractNLPEvaluator -initialize -features_available -eval_objective -eval_constraint -eval_objective_gradient -jacobian_structure -hessian_lagrangian_structure -eval_constraint_jacobian -eval_constraint_jacobian_product -eval_constraint_jacobian_transpose_product -eval_hessian_lagrangian -eval_hessian_lagrangian_product -objective_expr -constraint_expr -``` - -## Errors - -When an MOI call fails on a model, precise errors should be thrown when possible -instead of simply calling `error` with a message. The docstrings for the -respective methods describe the errors that the implementation should thrown in -certain situations. This error-reporting system allows code to distinguish -between internal errors (that should be shown to the user) and unsupported -operations which may have automatic workarounds. - -When an invalid index is used in an MOI call, an [`InvalidIndex`](@ref) should -be thrown: -```@docs -InvalidIndex -``` - -As discussed in [JuMP mapping](@ref), for scalar constraint with a nonzero -function constant, a [`ScalarFunctionConstantNotZero`](@ref) exception may be -thrown: -```@docs -ScalarFunctionConstantNotZero -``` - -Some [`SingleVariable`](@ref) constraints cannot be combined on the same -variable: -```@docs -LowerBoundAlreadySet -UpperBoundAlreadySet -``` - -As discussed in [`AbstractCallback`](@ref), trying to [`get`](@ref) attributes -inside a callback may throw: -```@docs -OptimizeInProgress -``` - -Trying to submit the wrong type of [`AbstractSubmittable`](@ref) inside an -[`AbstractCallback`](@ref) (e.g., a [`UserCut`](@ref) inside a -[`LazyConstraintCallback`](@ref)) will throw: -```@docs -InvalidCallbackUsage -``` - -The rest of the errors defined in MOI fall in two categories represented by the -following two abstract types: -```@docs -UnsupportedError -NotAllowedError -``` - -The different [`UnsupportedError`](@ref) and [`NotAllowedError`](@ref) are the -following errors: -```@docs -UnsupportedAttribute -SetAttributeNotAllowed -AddVariableNotAllowed -UnsupportedConstraint -AddConstraintNotAllowed -ModifyConstraintNotAllowed -ModifyObjectiveNotAllowed -DeleteNotAllowed -UnsupportedSubmittable -SubmitNotAllowed -``` diff --git a/docs/src/reference/standard_form.md b/docs/src/reference/standard_form.md new file mode 100644 index 0000000000..d3ad803b4f --- /dev/null +++ b/docs/src/reference/standard_form.md @@ -0,0 +1,127 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Standard form + +## Functions + +```@docs +AbstractFunction +AbstractVectorFunction +SingleVariable +VectorOfVariables +ScalarAffineTerm +ScalarAffineFunction +VectorAffineTerm +VectorAffineFunction +ScalarQuadraticTerm +ScalarQuadraticFunction +VectorQuadraticTerm +VectorQuadraticFunction +``` + +### Utilities + +```@docs +output_dimension +constant(f::Union{ScalarAffineFunction, ScalarQuadraticFunction}) +constant(f::Union{VectorAffineFunction, VectorQuadraticFunction}) +constant(f::SingleVariable, ::DataType) +constant(f::VectorOfVariables, T::DataType) +``` + +## Sets + +```@docs +AbstractSet +AbstractScalarSet +AbstractVectorSet +``` + +### Utilities + +```@docs +dimension +dual_set +dual_set_type +constant(s::EqualTo) +supports_dimension_update +update_dimension +``` + +## Scalar sets + +List of recognized scalar sets. +```@docs +GreaterThan +LessThan +EqualTo +Interval +Integer +ZeroOne +Semicontinuous +Semiinteger +``` + +## Vector sets + +List of recognized vector sets. +```@docs +Reals +Zeros +Nonnegatives +Nonpositives +NormInfinityCone +NormOneCone +SecondOrderCone +RotatedSecondOrderCone +GeometricMeanCone +ExponentialCone +DualExponentialCone +PowerCone +DualPowerCone +RelativeEntropyCone +NormSpectralCone +NormNuclearCone +SOS1 +SOS2 +IndicatorSet +Complements +``` + +## Matrix sets + +Matrix sets are vectorized in order to be subtypes of +[`AbstractVectorSet`](@ref). For sets of symmetric matrices, storing both the +`(i, j)` and `(j, i)` elements is redundant so there exists the +[`AbstractSymmetricMatrixSetTriangle`](@ref) set to represent only the +vectorization of the upper triangular part of the matrix. When the matrix +of expressions constrained to be in the set is not symmetric and hence +the `(i, j)` and `(j, i)` elements should be constrained to be symmetric, +the [`AbstractSymmetricMatrixSetSquare`](@ref) set can be used. The +[`Bridges.Constraint.SquareBridge`](@ref) can transform a set from the square +form to the [`triangular_form`](@ref) by adding appropriate constraints if +the `(i, j)` and `(j, i)` expressions are different. + +```@docs +AbstractSymmetricMatrixSetTriangle +AbstractSymmetricMatrixSetSquare +side_dimension +triangular_form +``` + +List of recognized matrix sets. +```@docs +PositiveSemidefiniteConeTriangle +PositiveSemidefiniteConeSquare +LogDetConeTriangle +LogDetConeSquare +RootDetConeTriangle +RootDetConeSquare +``` diff --git a/docs/src/reference/variables.md b/docs/src/reference/variables.md new file mode 100644 index 0000000000..6e0d8a5bc9 --- /dev/null +++ b/docs/src/reference/variables.md @@ -0,0 +1,39 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Variables + +## Types + +```@docs +VariableIndex +``` + +## Functions + +```@docs +add_variable +add_variables +add_constrained_variable +add_constrained_variables +supports_add_constrained_variable +supports_add_constrained_variables +is_valid(::ModelLike,::VariableIndex) +delete(::ModelLike, ::VariableIndex) +delete(::ModelLike, ::Vector{VariableIndex}) +``` + +## Attributes + +```@docs +AbstractVariableAttribute +VariableName +VariablePrimalStart +VariablePrimal +```