# API Reference

[Some introduction to API. List basic standalone methods.]

## Attributes

List of attribute categories.

`AbstractOptimizerAttribute`

Abstract supertype for attribute objects that can be used to set or get attributes (properties) of the optimizer.

**Note**

The difference between `AbstractOptimizerAttribute`

and `AbstractModelAttribute`

lies in the behavior of `is_empty`

, `empty!`

and `copy_to`

. Typically optimizer attributes only affect how the model is solved.

`AbstractModelAttribute`

Abstract supertype for attribute objects that can be used to set or get attributes (properties) of the model.

`AbstractVariableAttribute`

Abstract supertype for attribute objects that can be used to set or get attributes (properties) of variables in the model.

`AbstractConstraintAttribute`

Abstract supertype for attribute objects that can be used to set or get attributes (properties) of constraints in the model.

Attributes can be set in different ways:

- it is either set when the model is created like
`SolverName`

and`RawSolver`

, - or explicitly when the model is copied like
`ObjectiveSense`

, - or implicitly, e.g.,
`NumberOfVariables`

is implicitly set by`add_variable`

and`ConstraintFunction`

is implicitly set by`add_constraint`

. - or it is set to contain the result of the optimization during
`optimize!`

like`VariablePrimal`

.

The following functions allow to distinguish between some of these different categories:

`MathOptInterface.is_set_by_optimize`

— Function.`is_set_by_optimize(::AnyAttribute)`

Return a `Bool`

indicating whether the value of the attribute is modified during an `optimize!`

call, that is, the attribute is used to query the result of the optimization.

**Important note when defining new attributes**

This function returns `false`

by default so it should be implemented for attributes that are modified by `optimize!`

.

`MathOptInterface.is_copyable`

— Function.`is_copyable(::AnyAttribute)`

Return a `Bool`

indicating whether the value of the attribute may be copied during `copy_to`

using `set`

.

**Important note when defining new attributes**

By default `is_copyable(attr)`

returns `!is_set_by_optimize(attr)`

. A specific method should be defined for attributes which are copied indirectly during `copy_to`

. For instance, both `is_copyable`

and `is_set_by_optimize`

return `false`

for the following attributes:

`ListOfOptimizerAttributesSet`

,`ListOfModelAttributesSet`

,`ListOfConstraintAttributesSet`

and`ListOfVariableAttributesSet`

.`SolverName`

and`RawSolver`

: these attributes cannot be set.`NumberOfVariables`

and`ListOfVariableIndices`

: these attributes are set indirectly by`add_variable`

and`add_variables`

.`ObjectiveFunctionType`

: this attribute is set indirectly when setting the`ObjectiveFunction`

attribute.`NumberOfConstraints`

,`ListOfConstraintIndices`

,`ListOfConstraints`

,`ConstraintFunction`

and`ConstraintSet`

: these attributes are set indirectly by`add_constraint`

and`add_constraints`

.

Functions for getting and setting attributes.

`MathOptInterface.get`

— Function.`get(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute)`

Return an attribute `attr`

of the optimizer `optimizer`

.

`get(model::ModelLike, attr::AbstractModelAttribute)`

Return an attribute `attr`

of the model `model`

.

`get(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex)`

If the attribute `attr`

is set for the variable `v`

in the model `model`

, return its value, return `nothing`

otherwise. If the attribute `attr`

is not supported by `model`

then an error should be thrown instead of returning `nothing`

.

`get(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex})`

Return a vector of attributes corresponding to each variable in the collection `v`

in the model `model`

.

`get(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex)`

If the attribute `attr`

is set for the constraint `c`

in the model `model`

, return its value, return `nothing`

otherwise. If the attribute `attr`

is not supported by `model`

then an error should be thrown instead of returning `nothing`

.

`get(model::ModelLike, attr::AbstractConstraintAttribute, c::Vector{ConstraintIndex{F,S}})`

Return a vector of attributes corresponding to each constraint in the collection `c`

in the model `model`

.

`get(model::ModelLike, ::Type{VariableIndex}, name::String)`

If a variable with name `name`

exists in the model `model`

, return the corresponding index, otherwise return `nothing`

. Errors if two variables have the same name.

`get(model::ModelLike, ::Type{ConstraintIndex{F,S}}, name::String) where {F<:AbstractFunction,S<:AbstractSet}`

If an `F`

-in-`S`

constraint with name `name`

exists in the model `model`

, return the corresponding index, otherwise return `nothing`

. Errors if two constraints have the same name.

`get(model::ModelLike, ::Type{ConstraintIndex}, name::String)`

If *any* constraint with name `name`

exists in the model `model`

, return the corresponding index, otherwise return `nothing`

. This version is available for convenience but may incur a performance penalty because it is not type stable. Errors if two constraints have the same name.

**Examples**

```
get(model, ObjectiveValue())
get(model, VariablePrimal(), ref)
get(model, VariablePrimal(5), [ref1, ref2])
get(model, OtherAttribute("something specific to cplex"))
get(model, VariableIndex, "var1")
get(model, ConstraintIndex{ScalarAffineFunction{Float64},LessThan{Float64}}, "con1")
get(model, ConstraintIndex, "con1")
```

`MathOptInterface.get!`

— Function.`get!(output, model::ModelLike, args...)`

An in-place version of `get`

. The signature matches that of `get`

except that the the result is placed in the vector `output`

.

`MathOptInterface.set`

— Function.`set(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute, value)`

Assign `value`

to the attribute `attr`

of the optimizer `optimizer`

.

`set(model::ModelLike, attr::AbstractModelAttribute, value)`

Assign `value`

to the attribute `attr`

of the model `model`

.

`set(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex, value)`

Assign `value`

to the attribute `attr`

of variable `v`

in model `model`

.

`set(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex}, vector_of_values)`

Assign a value respectively to the attribute `attr`

of each variable in the collection `v`

in model `model`

.

`set(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex, value)`

Assign a value to the attribute `attr`

of constraint `c`

in model `model`

.

`set(model::ModelLike, attr::AbstractConstraintAttribute, c::Vector{ConstraintIndex{F,S}}, vector_of_values)`

Assign a value respectively to the attribute `attr`

of each constraint in the collection `c`

in model `model`

.

An `UnsupportedAttribute`

error is thrown if `model`

does not support the attribute `attr`

(see `supports`

) and a `SetAttributeNotAllowed`

error is thrown if it supports the attribute `attr`

but it cannot be set.

**Replace set in a constraint**

`set(model::ModelLike, ::ConstraintSet, c::ConstraintIndex{F,S}, set::S)`

Change the set of constraint `c`

to the new set `set`

which should be of the same type as the original set.

**Examples**

If `c`

is a `ConstraintIndex{F,Interval}`

```
set(model, ConstraintSet(), c, Interval(0, 5))
set(model, ConstraintSet(), c, GreaterThan(0.0)) # Error
```

**Replace function in a constraint**

`set(model::ModelLike, ::ConstraintFunction, c::ConstraintIndex{F,S}, func::F)`

Replace the function in constraint `c`

with `func`

. `F`

must match the original function type used to define the constraint.

**Note**

Setting the constraint function is not allowed if `F`

is `SingleVariable`

, it throws a `SettingSingleVariableFunctionNotAllowed`

error. Indeed, it would require changing the index `c`

as the index of `SingleVariable`

constraints should be the same as the index of the variable.

**Examples**

If `c`

is a `ConstraintIndex{ScalarAffineFunction,S}`

and `v1`

and `v2`

are `VariableIndex`

objects,

```
set(model, ConstraintFunction(), c,
ScalarAffineFunction(ScalarAffineTerm.([1.0, 2.0], [v1, v2]), 5.0))
set(model, ConstraintFunction(), c, SingleVariable(v1)) # Error
```

`MathOptInterface.supports`

— Function.`supports(model::ModelLike, sub::AbstractSubmittable)::Bool`

Return a `Bool`

indicating whether `model`

supports the submittable `sub`

.

`supports(model::ModelLike, attr::AbstractOptimizerAttribute)::Bool`

Return a `Bool`

indicating whether `model`

supports the optimizer attribute `attr`

. That is, it returns `false`

if `copy_to(model, src)`

shows a warning in case `attr`

is in the `ListOfOptimizerAttributesSet`

of `src`

; see `copy_to`

for more details on how unsupported optimizer attributes are handled in copy.

`supports(model::ModelLike, attr::AbstractModelAttribute)::Bool`

Return a `Bool`

indicating whether `model`

supports the model attribute `attr`

. That is, it returns `false`

if `copy_to(model, src)`

cannot be performed in case `attr`

is in the `ListOfModelAttributesSet`

of `src`

.

`supports(model::ModelLike, attr::AbstractVariableAttribute, ::Type{VariableIndex})::Bool`

Return a `Bool`

indicating whether `model`

supports the variable attribute `attr`

. That is, it returns `false`

if `copy_to(model, src)`

cannot be performed in case `attr`

is in the `ListOfVariableAttributesSet`

of `src`

.

`supports(model::ModelLike, attr::AbstractConstraintAttribute, ::Type{ConstraintIndex{F,S}})::Bool where {F,S}`

Return a `Bool`

indicating whether `model`

supports the constraint attribute `attr`

applied to an `F`

-in-`S`

constraint. That is, it returns `false`

if `copy_to(model, src)`

cannot be performed in case `attr`

is in the `ListOfConstraintAttributesSet`

of `src`

.

For all five methods, if the attribute is only not supported in specific circumstances, it should still return `true`

.

Note that `supports`

is only defined for attributes for which `is_copyable`

returns `true`

as other attributes do not appear in the list of attributes set obtained by `ListOf...AttributesSet`

.

### Fallbacks

The value of some attributes can be inferred from the value of other attributes. For instance, the value of `ObjectiveValue`

can be computed using `ObjectiveFunction`

and `VariablePrimal`

. When a solver gives access to the objective value, it is better to return this value but otherwise, `Utilities.get_fallback`

can be used.

```
function MOI.get(optimizer::Optimizer, attr::MOI.ObjectiveValue)
return MOI.Utilities.get_fallback(optimizer, attr)
end
```

`MathOptInterface.Utilities.get_fallback`

— Function.`get_fallback(model::MOI.ModelLike, ::MOI.ObjectiveValue)`

Compute the objective function value using the `VariablePrimal`

results and the `ObjectiveFunction`

value.

`get_fallback(model::MOI.ModelLike, ::MOI.DualObjectiveValue, T::Type)::T`

Compute the dual objective value of type `T`

using the `ConstraintDual`

results and the `ConstraintFunction`

and `ConstraintSet`

values. Note that the nonlinear part of the model is ignored.

```
get_fallback(model::MOI.ModelLike, ::MOI.ConstraintPrimal,
constraint_index::MOI.ConstraintIndex)
```

Compute the value of the function of the constraint of index `constraint_index`

using the `VariablePrimal`

results and the `ConstraintFunction`

values.

```
get_fallback(model::MOI.ModelLike, attr::MOI.ConstraintDual,
ci::MOI.ConstraintIndex{Union{MOI.SingleVariable,
MOI.VectorOfVariables}})
```

Compute the dual of the constraint of index `ci`

using the `ConstraintDual`

of other constraints and the `ConstraintFunction`

values. Throws an error if some constraints are quadratic or if there is one another `MOI.SingleVariable`

-in-`S`

or `MOI.VectorOfVariables`

-in-`S`

constraint with one of the variables in the function of the constraint `ci`

.

### Submit

Objects may be submitted to an optimizer using `submit`

.

`AbstractSubmittable`

Abstract supertype for objects that can be submitted to the model.

`MathOptInterface.submit`

— Function.```
submit(optimizer::AbstractOptimizer, sub::AbstractSubmittable,
values...)::Nothing
```

Submit `values`

to the submittable `sub`

of the optimizer `optimizer`

.

An `UnsupportedSubmittable`

error is thrown if `model`

does not support the attribute `attr`

(see `supports`

) and a `SubmitNotAllowed`

error is thrown if it supports the submittable `sub`

but it cannot be submitted.

## Model Interface

`MathOptInterface.ModelLike`

— Type.`ModelLike`

Abstract supertype for objects that implement the "Model" interface for defining an optimization problem.

`Base.isempty`

— Function.`isempty(collection) -> Bool`

Determine whether a collection is empty (has no elements).

**Examples**

```
julia> isempty([])
true
julia> isempty([1 2 3])
false
```

`MathOptInterface.empty!`

— Function.`empty!(model::ModelLike)`

Empty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes.

`MathOptInterface.write_to_file`

— Function.`write_to_file(model::ModelLike, filename::String)`

Writes the current model data to the given file. Supported file types depend on the model type.

`MathOptInterface.read_from_file`

— Function.`read_from_file(model::ModelLike, filename::String)`

Read the file `filename`

into the model `model`

. If `model`

is non-empty, this may throw an error.

Supported file types depend on the model type.

**Note**

Once the contents of the file are loaded into the model, users can query the variables via `get(model, ListOfVariableIndices())`

. However, some filetypes, such as LP files, do not maintain an explicit ordering of the variables. Therefore, the returned list may be in an arbitrary order. To avoid depending on the order of the indices, users should look up each variable index by name: `get(model, VariableIndex, "name")`

.

Copying

`MathOptInterface.copy_to`

— Function.`copy_to(dest::ModelLike, src::ModelLike; copy_names=true, warn_attributes=true)`

Copy the model from `src`

into `dest`

. The target `dest`

is emptied, and all previous indices to variables or constraints in `dest`

are invalidated. Returns a dictionary-like object that translates variable and constraint indices from the `src`

model to the corresponding indices in the `dest`

model.

If `copy_names`

is `false`

, the `Name`

, `VariableName`

and `ConstraintName`

attributes are not copied even if they are set in `src`

. If a constraint that is copied from `src`

is not supported by `dest`

then an `UnsupportedConstraint`

error is thrown. Similarly, if a model, variable or constraint attribute that is copied from `src`

is not supported by `dest`

then an `UnsupportedAttribute`

error is thrown. Unsupported *optimizer* attributes are treated differently:

- If
`warn_attributes`

is`true`

, a warning is displayed, otherwise, - the attribute is silently ignored.

**Example**

```
# Given empty `ModelLike` objects `src` and `dest`.
x = add_variable(src)
is_valid(src, x) # true
is_valid(dest, x) # false (`dest` has no variables)
index_map = copy_to(dest, src)
is_valid(dest, x) # false (unless index_map[x] == x)
is_valid(dest, index_map[x]) # true
```

List of model attributes

`MathOptInterface.Name`

— Type.`Name()`

A model attribute for the string identifying the model. It has a default value of `""`

if not set`.

`MathOptInterface.ObjectiveSense`

— Type.`ObjectiveSense()`

A model attribute for the objective sense of the objective function, which must be an `OptimizationSense`

: `MIN_SENSE`

, `MAX_SENSE`

, or `FEASIBILITY_SENSE`

. The default is `FEASIBILITY_SENSE`

.

`NumberOfVariables()`

A model attribute for the number of variables in the model.

`ListOfVariableIndices()`

A model attribute for the `Vector{VariableIndex}`

of all variable indices present in the model (i.e., of length equal to the value of `NumberOfVariables()`

) in the order in which they were added.

`ListOfConstraints()`

A model attribute for the list of tuples of the form `(F,S)`

, where `F`

is a function type and `S`

is a set type indicating that the attribute `NumberOfConstraints{F,S}()`

has value greater than zero.

`NumberOfConstraints{F,S}()`

A model attribute for the number of constraints of the type `F`

-in-`S`

present in the model.

`ListOfConstraintIndices{F,S}()`

A model attribute for the `Vector{ConstraintIndex{F,S}}`

of all constraint indices of type `F`

-in-`S`

in the model (i.e., of length equal to the value of `NumberOfConstraints{F,S}()`

) in the order in which they were added.

`ListOfOptimizerAttributesSet()`

An optimizer attribute for the `Vector{AbstractOptimizerAttribute}`

of all optimizer attributes that were set.

`ListOfModelAttributesSet()`

A model attribute for the `Vector{AbstractModelAttribute}`

of all model attributes `attr`

such that 1) `is_copyable(attr)`

returns `true`

and 2) the attribute was set to the model.

`ListOfVariableAttributesSet()`

A model attribute for the `Vector{AbstractVariableAttribute}`

of all variable attributes `attr`

such that 1) `is_copyable(attr)`

returns `true`

and 2) the attribute was set to variables.

`ListOfConstraintAttributesSet{F, S}()`

A model attribute for the `Vector{AbstractConstraintAttribute}`

of all constraint attributes `attr`

such that 1) `is_copyable(attr)`

returns `true`

and

- the attribute was set to
`F`

-in-`S`

constraints.

**Note**

The attributes `ConstraintFunction`

and `ConstraintSet`

should not be included in the list even if then have been set with `set`

.

## Optimizers

`AbstractOptimizer`

Abstract supertype for objects representing an instance of an optimization problem tied to a particular solver. This is typically a solver's in-memory representation. In addition to `ModelLike`

, `AbstractOptimizer`

objects let you solve the model and query the solution.

`MathOptInterface.optimize!`

— Function.`optimize!(optimizer::AbstractOptimizer)`

Start the solution procedure.

List of optimizers attributes

`MathOptInterface.SolverName`

— Type.`SolverName()`

An optimizer attribute for the string identifying the solver/optimizer.

`MathOptInterface.Silent`

— Type.`Silent()`

An optimizer attribute for silencing the output of an optimizer. When `set`

to `true`

, it takes precedence over any other attribute controlling verbosity and requires the solver to produce no output. The default value is `false`

which has no effect. In this case the verbosity is controlled by other attributes.

**Note**

Every optimizer should have verbosity on by default. For instance, if a solver has a solver-specific log level attribute, the MOI implementation should set it to `1`

by default. If the user sets `Silent`

to `true`

, then the log level should be set to `0`

, even if the user specifically sets a value of log level. If the value of `Silent`

is `false`

then the log level set to the solver is the value given by the user for this solver-specific parameter or `1`

if none is given.

`MathOptInterface.TimeLimitSec`

— Type.`TimeLimitSec()`

An optimizer attribute for setting a time limit for an optimization. When `set`

to `nothing`

, it deactivates the solver time limit. The default value is `nothing`

. The time limit is in seconds.

`MathOptInterface.RawParameter`

— Type.`RawParameter(name)`

An optimizer attribute for the solver-specific parameter identified by `name`

which is typically an `Enum`

or a `String`

.

List of attributes useful for optimizers

`MathOptInterface.RawSolver`

— Type.`RawSolver()`

A model attribute for the object that may be used to access a solver-specific API for this optimizer.

`MathOptInterface.ResultCount`

— Type.`ResultCount()`

A model attribute for the number of results available.

`ObjectiveFunction{F<:AbstractScalarFunction}()`

A model attribute for the objective function which has a type `F<:AbstractScalarFunction`

. `F`

should be guaranteed to be equivalent but not necessarily identical to the function type provided by the user. Throws an `InexactError`

if the objective function cannot be converted to `F`

, e.g. the objective function is quadratic and `F`

is `ScalarAffineFunction{Float64}`

or it has non-integer coefficient and `F`

is `ScalarAffineFunction{Int}`

.

`ObjectiveFunctionType()`

A model attribute for the type `F`

of the objective function set using the `ObjectiveFunction{F}`

attribute.

**Examples**

In the following code, `attr`

should be equal to `MOI.SingleVariable`

:

```
x = MOI.add_variable(model)
MOI.set(model, MOI.ObjectiveFunction{MOI.SingleVariable}(),
MOI.SingleVariable(x))
attr = MOI.get(model, MOI.ObjectiveFunctionType())
```

`MathOptInterface.ObjectiveValue`

— Type.`ObjectiveValue(resultidx::Int=1)`

A model attribute for the objective value of the `result_index`

th primal result.

`DualObjectiveValue(result_index::Int=1)`

A model attribute for the value of the objective function of the dual problem for the `result_index`

th dual result.

`MathOptInterface.ObjectiveBound`

— Type.`ObjectiveBound()`

A model attribute for the best known bound on the optimal objective value.

`MathOptInterface.RelativeGap`

— Type.`RelativeGap()`

A model attribute for the final relative optimality gap, defined as $\frac{|b-f|}{|f|}$, where $b$ is the best bound and $f$ is the best feasible objective value.

`MathOptInterface.SolveTime`

— Type.`SolveTime()`

A model attribute for the total elapsed solution time (in seconds) as reported by the optimizer.

`SimplexIterations()`

A model attribute for the cumulative number of simplex iterations during the optimization process. In particular, for a mixed-integer program (MIP), the total simplex iterations for all nodes.

`BarrierIterations()`

A model attribute for the cumulative number of barrier iterations while solving a problem.

`MathOptInterface.NodeCount`

— Type.`NodeCount()`

A model attribute for the total number of branch-and-bound nodes explored while solving a mixed-integer program (MIP).

`TerminationStatus()`

A model attribute for the `TerminationStatusCode`

explaining why the optimizer stopped.

`MathOptInterface.RawStatusString`

— Type.`RawStatusString()`

A model attribute for a solver specific string explaining why the optimizer stopped.

`MathOptInterface.PrimalStatus`

— Type.```
PrimalStatus(N)
PrimalStatus()
```

A model attribute for the `ResultStatusCode`

of the primal result `N`

. If `N`

is omitted, it defaults to 1.

`MathOptInterface.DualStatus`

— Type.```
DualStatus(N)
DualStatus()
```

A model attribute for the `ResultStatusCode`

of the dual result `N`

. If `N`

is omitted, it defaults to 1.

### Termination Status

The `TerminationStatus`

attribute indicates why the optimizer stopped executing. The value of the attribute is of type `TerminationStatusCode`

.

`TerminationStatusCode`

An Enum of possible values for the `TerminationStatus`

attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to `optimize!`

.

If no call has been made to `optimize!`

, then the `TerminationStatus`

is:

`OPTIMIZE_NOT_CALLED`

: The algorithm has not started.

**OK**

These are generally OK statuses, i.e., the algorithm ran to completion normally.

`OPTIMAL`

: The algorithm found a globally optimal solution.`INFEASIBLE`

: The algorithm concluded that no feasible solution exists.`DUAL_INFEASIBLE`

: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.`LOCALLY_SOLVED`

: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.`LOCALLY_INFEASIBLE`

: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.`INFEASIBLE_OR_UNBOUNDED`

: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.

**Solved to relaxed tolerances**

`ALMOST_OPTIMAL`

: The algorithm found a globally optimal solution to relaxed tolerances.`ALMOST_INFEASIBLE`

: The algorithm concluded that no feasible solution exists within relaxed tolerances.`ALMOST_DUAL_INFEASIBLE`

: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.`ALMOST_LOCALLY_SOLVED`

: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.

**Limits**

The optimizer stopped because of some user-defined limit.

`ITERATION_LIMIT`

: An iterative algorithm stopped after conducting the maximum number of iterations.`TIME_LIMIT`

: The algorithm stopped after a user-specified computation time.`NODE_LIMIT`

: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.`SOLUTION_LIMIT`

: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.`MEMORY_LIMIT`

: The algorithm stopped because it ran out of memory.`OBJECTIVE_LIMIT`

: The algorthm stopped because it found a solution better than a minimum limit set by the user.`NORM_LIMIT`

: The algorithm stopped because the norm of an iterate became too large.`OTHER_LIMIT`

: The algorithm stopped due to a limit not covered by one of the above.

**Problematic**

This group of statuses means that something unexpected or problematic happened.

`SLOW_PROGRESS`

: The algorithm stopped because it was unable to continue making progress towards the solution.`NUMERICAL_ERROR`

: The algorithm stopped because it encountered unrecoverable numerical error.`INVALID_MODEL`

: The algorithm stopped because the model is invalid.`INVALID_OPTION`

: The algorithm stopped because it was provided an invalid option.`INTERRUPTED`

: The algorithm stopped because of an interrupt signal.`OTHER_ERROR`

: The algorithm stopped because of an error not covered by one of the statuses defined above.

### 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`

.

`ResultStatusCode`

An Enum of possible values for the `PrimalStatus`

and `DualStatus`

attributes. The values indicate how to interpret the result vector.

`NO_SOLUTION`

: the result vector is empty.`FEASIBLE_POINT`

: the result vector is a feasible point.`NEARLY_FEASIBLE_POINT`

: the result vector is feasible if some constraint tolerances are relaxed.`INFEASIBLE_POINT`

: the result vector is an infeasible point.`INFEASIBILITY_CERTIFICATE`

: the result vector is an infeasibility certificate. If the`PrimalStatus`

is`INFEASIBILITY_CERTIFICATE`

, then the primal result vector is a certificate of dual infeasibility. If the`DualStatus`

is`INFEASIBILITY_CERTIFICATE`

, then the dual result vector is a proof of primal infeasibility.`NEARLY_INFEASIBILITY_CERTIFICATE`

: the result satisfies a relaxed criterion for a certificate of infeasibility.`REDUCTION_CERTIFICATE`

: the result vector is an ill-posed certificate; see this article for details. If the`PrimalStatus`

is`REDUCTION_CERTIFICATE`

, then the primal result vector is a proof that the dual problem is ill-posed. If the`DualStatus`

is`REDUCTION_CERTIFICATE`

, then the dual result vector is a proof that the primal is ill-posed.`NEARLY_REDUCTION_CERTIFICATE`

: the result satisfies a relaxed criterion for an ill-posed certificate.`UNKNOWN_RESULT_STATUS`

: the result vector contains a solution with an unknown interpretation.`OTHER_RESULT_STATUS`

: the result vector contains a solution with an interpretation not covered by one of the statuses defined above.

## 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`

.

`MathOptInterface.BasisStatusCode`

— Type.`BasisStatusCode`

An Enum of possible values for the `ConstraintBasisStatus`

attribute. This explains the status of a given element with respect to an optimal solution basis. Possible values are:

`BASIC`

: element is in the basis`NONBASIC`

: element is not in the basis`NONBASIC_AT_LOWER`

: element is not in the basis and is at its lower bound`NONBASIC_AT_UPPER`

: element is not in the basis and is at its upper bound`SUPER_BASIC`

: element is not in the basis but is also not at one of its bounds

Note: `NONBASIC_AT_LOWER`

and `NONBASIC_AT_UPPER`

should be used only for constraints with the `Interval`

. In this case cases they are necessary to distinguish which side of the constraint. One-sided constraints (e.g., `LessThan`

and `GreaterThan`

) should use `NONBASIC`

instead of the `NONBASIC_AT_*`

values.

### Index types

`MathOptInterface.VariableIndex`

— Type.`VariableIndex`

A type-safe wrapper for `Int64`

for use in referencing variables in a model. To allow for deletion, indices need not be consecutive.

`MathOptInterface.ConstraintIndex`

— Type.`ConstraintIndex{F, S}`

A type-safe wrapper for `Int64`

for use in referencing `F`

-in-`S`

constraints in a model. The parameter `F`

is the type of the function in the constraint, and the parameter `S`

is the type of set in the constraint. To allow for deletion, indices need not be consecutive. Indices within a constraint type (i.e. `F`

-in-`S`

) must be unique, but non-unique indices across different constraint types are allowed. If `F`

is `SingleVariable`

then the index is equal to the index of the variable. That is for an `index::ConstraintIndex{SingleVariable}`

, we always have

`index.value == MOI.get(model, MOI.ConstraintFunction(), index).variable.value`

`MathOptInterface.is_valid`

— Function.`is_valid(model::ModelLike, index::Index)::Bool`

Return a `Bool`

indicating whether this index refers to a valid object in the model `model`

.

`MathOptInterface.throw_if_not_valid`

— Function.`throw_if_not_valid(model::ModelLike, index::Index)`

Throw an `InvalidIndex(index)`

error if `MOI.is_valid(model, index)`

returns `false`

.

`MathOptInterface.delete`

— Method.`delete(model::ModelLike, index::Index)`

Delete the referenced object from the model. Throw `DeleteNotAllowed`

if if `index`

cannot be deleted.

The following modifications also take effect if `Index`

is `VariableIndex`

:

- If
`index`

used in the objective function, it is removed from the function, i.e., it is substituted for zero. - For each
`func`

-in-`set`

constraint of the model:- If
`func isa SingleVariable`

and`func.variable == index`

then the constraint is deleted. - If
`func isa VectorOfVariables`

and`index in func.variable`

then- if
`length(func.variable) == 1`

is one, the constraint is deleted; - if
`length(func.variable) > 1`

and`supports_dimension_update(set)`

then then the variable is removed from`func`

and`set`

is replaced by`update_dimension(set, MOI.dimension(set) - 1)`

. - Otherwise, a
`DeleteNotAllowed`

error is thrown.

- if
- Otherwise, the variable is removed from
`func`

, i.e., it is substituted for zero.

- If

### Variables

*Free variables* are the variables created with `add_variable`

or `add_variables`

while *constrained variables* are the variables created with `add_constrained_variable`

or `add_constrained_variables`

. Adding constrained variables instead of constraining free variables with `add_constraint`

allows variable bridges to be used. Note further that free variables that are constrained with `add_constraint`

may be copied by `copy_to`

with `add_constrained_variable`

or `add_constrained_variables`

by the `Utilities.CachingOptimizer`

. 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`

can determine whether it is added using `add_variable`

or `add_constrained_variable`

with one of the sets. The rest of the constraints on the variables are added with `add_constraint`

. For deleting, see Index types.

`MathOptInterface.add_variable`

— Function.`add_variable(model::ModelLike)::VariableIndex`

Add a scalar variable to the model, returning a variable index.

A `AddVariableNotAllowed`

error is thrown if adding variables cannot be done in the current state of the model `model`

.

`MathOptInterface.add_variables`

— Function.`add_variables(model::ModelLike, n::Int)::Vector{VariableIndex}`

Add `n`

scalar variables to the model, returning a vector of variable indices.

A `AddVariableNotAllowed`

error is thrown if adding variables cannot be done in the current state of the model `model`

.

`MathOptInterface.add_constrained_variable`

— Function.```
add_constrained_variable(
model::ModelLike,
set::AbstractScalarSet
)::Tuple{MOI.VariableIndex,
MOI.ConstraintIndex{MOI.SingleVariable, typeof(set)}}
```

Add to `model`

a scalar variable constrained to belong to `set`

, returning the index of the variable created and the index of the constraint constraining the variable to belong to `set`

.

By default, this function falls back to creating a free variable with `add_variable`

and then constraining it to belong to `set`

with `add_constraint`

.

`MathOptInterface.add_constrained_variables`

— Function.```
add_constrained_variables(
model::ModelLike,
sets:AbstractVector{<:AbstractScalarSet}
)::Tuple{Vector{MOI.VariableIndex},
Vector{MOI.ConstraintIndex{MOI.SingleVariable, eltype(sets)}}}
```

Add to `model`

scalar variables constrained to belong to `sets`

, returning the indices of the variables created and the indices of the constraints constraining the variables to belong to each set in `sets`

. That is, if it returns `variables`

and `constraints`

, `constraints[i]`

is the index of the constraint constraining `variable[i]`

to belong to `sets[i]`

.

By default, this function falls back to calling `add_constrained_variable`

on each set.

```
add_constrained_variables(
model::ModelLike,
set::AbstractVectorSet
)::Tuple{Vector{MOI.VariableIndex},
MOI.ConstraintIndex{MOI.VectorOfVariables, typeof(set)}}
```

Add to `model`

a vector of variables constrained to belong to `set`

, returning the indices of the variables created and the index of the constraint constraining the vector of variables to belong to `set`

.

By default, this function falls back to creating free variables with `add_variables`

and then constraining it to belong to `set`

with `add_constraint`

.

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.

`MathOptInterface.VariableName`

— Type.`VariableName()`

A variable attribute for a string identifying the variable. It is *valid* for two variables to have the same name; however, variables with duplicate names cannot be looked up using `get`

. It has a default value of `""`

if not set`.

`VariablePrimalStart()`

A variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve.

`MathOptInterface.VariablePrimal`

— Type.```
VariablePrimal(N)
VariablePrimal()
```

A variable attribute for the assignment to some primal variable's value in result `N`

. If `N`

is omitted, it is 1 by default.

### Constraints

Functions for adding and modifying constraints.

`MathOptInterface.is_valid`

— Method.`is_valid(model::ModelLike, index::Index)::Bool`

Return a `Bool`

indicating whether this index refers to a valid object in the model `model`

.

`MathOptInterface.add_constraint`

— Function.`add_constraint(model::ModelLike, func::F, set::S)::ConstraintIndex{F,S} where {F,S}`

Add the constraint $f(x) \in \mathcal{S}$ where $f$ is defined by `func`

, and $\mathcal{S}$ is defined by `set`

.

```
add_constraint(model::ModelLike, v::VariableIndex, set::S)::ConstraintIndex{SingleVariable,S} where {S}
add_constraint(model::ModelLike, vec::Vector{VariableIndex}, set::S)::ConstraintIndex{VectorOfVariables,S} where {S}
```

Add the constraint $v \in \mathcal{S}$ where $v$ is the variable (or vector of variables) referenced by `v`

and $\mathcal{S}$ is defined by `set`

.

- An
`UnsupportedConstraint`

error is thrown if`model`

does not support`F`

-in-`S`

constraints, - a
`AddConstraintNotAllowed`

error is thrown if it supports`F`

-in-`S`

constraints but it cannot add the constraint(s) in its current state and - a
`ScalarFunctionConstantNotZero`

error may be thrown if`func`

is an`AbstractScalarFunction`

with nonzero constant and`set`

is`EqualTo`

,`GreaterThan`

,`LessThan`

or`Interval`

. - a
`LowerBoundAlreadySet`

error is thrown if`F`

is a`SingleVariable`

and a constraint was already added to this variable that sets a lower bound. - a
`UpperBoundAlreadySet`

error is thrown if`F`

is a`SingleVariable`

and a constraint was already added to this variable that sets an upper bound.

`MathOptInterface.add_constraints`

— Function.`add_constraints(model::ModelLike, funcs::Vector{F}, sets::Vector{S})::Vector{ConstraintIndex{F,S}} where {F,S}`

Add the set of constraints specified by each function-set pair in `funcs`

and `sets`

. `F`

and `S`

should be concrete types. This call is equivalent to `add_constraint.(model, funcs, sets)`

but may be more efficient.

`MathOptInterface.transform`

— Function.**Transform Constraint Set**

`transform(model::ModelLike, c::ConstraintIndex{F,S1}, newset::S2)::ConstraintIndex{F,S2}`

Replace the set in constraint `c`

with `newset`

. The constraint index `c`

will no longer be valid, and the function returns a new constraint index with the correct type.

Solvers may only support a subset of constraint transforms that they perform efficiently (for example, changing from a `LessThan`

to `GreaterThan`

set). In addition, set modification (where `S1 = S2`

) should be performed via the `modify`

function.

Typically, the user should delete the constraint and add a new one.

**Examples**

If `c`

is a `ConstraintIndex{ScalarAffineFunction{Float64},LessThan{Float64}}`

,

```
c2 = transform(model, c, GreaterThan(0.0))
transform(model, c, LessThan(0.0)) # errors
```

`MathOptInterface.supports_constraint`

— Function.`MOI.supports_constraint(BT::Type{<:AbstractBridge}, F::Type{<:MOI.AbstractFunction}, S::Type{<:MOI.AbstractSet})::Bool`

Return a `Bool`

indicating whether the bridges of type `BT`

support bridging `F`

-in-`S`

constraints.

`supports_constraint(model::ModelLike, ::Type{F}, ::Type{S})::Bool where {F<:AbstractFunction,S<:AbstractSet}`

Return a `Bool`

indicating whether `model`

supports `F`

-in-`S`

constraints, that is, `copy_to(model, src)`

does not throw `UnsupportedConstraint`

when `src`

contains `F`

-in-`S`

constraints. If `F`

-in-`S`

constraints are only not supported in specific circumstances, e.g. `F`

-in-`S`

constraints cannot be combined with another type of constraint, it should still return `true`

.

`supports_constraint(model::ModelLike, ::Type{VectorOfVariables}, ::Type{Reals})::Bool`

Return a `Bool`

indicating whether `model`

supports free variables. That is, `copy_to(model, src)`

does not error when `src`

contains variables that are not constrained by any `SingleVariable`

or `VectorOfVariables`

constraint. By default, this method returns `true`

so it should only be implemented if `model`

does not support free variables. For instance, if a solver requires all variables to be nonnegative, it should implement this method and return `false`

because free variables cannot be copied to the solver.

Note that free variables are not explicitly set to be free by calling `add_constraint`

with the set `Reals`

, instead, free variables are created with `add_variable`

and `add_variables`

. If `model`

does not support free variables, it should not implement `add_variable`

nor `add_variables`

but should implement this method and return `false`

. This allows free variables to be bridged as the sum of a nonnegative and a nonpositive variables.

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.

`MathOptInterface.ConstraintName`

— Type.`ConstraintName()`

A constraint attribute for a string identifying the constraint. It is *valid* for constraints variables to have the same name; however, constraints with duplicate names cannot be looked up using `get`

regardless of if they have the same `F`

-in-`S`

type. It has a default value of `""`

if not set.

`ConstraintPrimalStart()`

A constraint attribute for the initial assignment to some constraint's primal value(s) that the optimizer may use to warm-start the solve.

`ConstraintDualStart()`

A constraint attribute for the initial assignment to some constraint's dual value(s) that the optimizer may use to warm-start the solve.

```
ConstraintPrimal(N)
ConstraintPrimal()
```

A constraint attribute for the assignment to some constraint's primal value(s) in result `N`

. If `N`

is omitted, it is 1 by default.

Given a constraint `function-in-set`

, the `ConstraintPrimal`

is the value of the function evaluated at the primal solution of the variables. For example, given the constraint `ScalarAffineFunction([x,y], [1, 2], 3)`

-in-`Interval(0, 20)`

and a primal solution of `(x,y) = (4,5)`

, the `ConstraintPrimal`

solution of the constraint is `1 * 4 + 2 * 5 + 3 = 17`

.

`MathOptInterface.ConstraintDual`

— Type.```
ConstraintDual(N)
ConstraintDual()
```

A constraint attribute for the assignment to some constraint's dual value(s) in result `N`

. If `N`

is omitted, it is 1 by default.

`ConstraintBasisStatus()`

A constraint attribute for the `BasisStatusCode`

of some constraint, with respect to an available optimal solution basis.

**For the basis status of a variable, query the corresponding SingleVariable constraint that enforces the variable's bounds.**

`ConstraintFunction()`

A constraint attribute for the `AbstractFunction`

object used to define the constraint. It is guaranteed to be equivalent but not necessarily identical to the function provided by the user.

`MathOptInterface.ConstraintSet`

— Type.`ConstraintSet()`

A constraint attribute for the `AbstractSet`

object used to define the constraint.

Note that setting the `ConstraintFunction`

of a [`SingleVariable`

] constraint is not allowed:

`SettingSingleVariableFunctionNotAllowed()`

Error type that should be thrown when the user `set`

the `ConstraintFunction`

of a `SingleVariable`

constraint.

## Functions and function modifications

List of recognized functions.

`AbstractFunction`

Abstract supertype for function objects.

`MathOptInterface.SingleVariable`

— Type.`SingleVariable(variable)`

The function that extracts the scalar variable referenced by `variable`

, a `VariableIndex`

. This function is naturally be used for single variable bounds or integrality constraints.

`VectorOfVariables(variables)`

The function that extracts the vector of variables referenced by `variables`

, a `Vector{VariableIndex}`

. This function is naturally be used for constraints that apply to groups of variables, such as an "all different" constraint, an indicator constraint, or a complementarity constraint.

```
struct ScalarAffineTerm{T}
coefficient::T
variable_index::VariableIndex
end
```

Represents $c x_i$ where $c$ is `coefficient`

and $x_i$ is the variable identified by `variable_index`

.

`ScalarAffineFunction{T}(terms, constant)`

The scalar-valued affine function $a^T x + b$, where:

- $a$ is a sparse vector specified by a list of
`ScalarAffineTerm`

structs. - $b$ is a scalar specified by
`constant::T`

Duplicate variable indices in `terms`

are accepted, and the corresponding coefficients are summed together.

```
struct VectorAffineTerm{T}
output_index::Int64
scalar_term::ScalarAffineTerm{T}
end
```

A `ScalarAffineTerm`

plus its index of the output component of a `VectorAffineFunction`

or `VectorQuadraticFunction`

. `output_index`

can also be interpreted as a row index into a sparse matrix, where the `scalar_term`

contains the column index and coefficient.

`VectorAffineFunction{T}(terms, constants)`

The vector-valued affine function $A x + b$, where:

- $A$ is a sparse matrix specified by a list of
`VectorAffineTerm`

objects. - $b$ is a vector specified by
`constants`

Duplicate indices in the $A$ are accepted, and the corresponding coefficients are summed together.

```
struct ScalarQuadraticTerm{T}
coefficient::T
variable_index_1::VariableIndex
variable_index_2::VariableIndex
end
```

Represents $c x_i x_j$ where $c$ is `coefficient`

, $x_i$ is the variable identified by `variable_index_1`

and $x_j$ is the variable identified by `variable_index_2`

.

`ScalarQuadraticFunction{T}(affine_terms, quadratic_terms, constant)`

The scalar-valued quadratic function $\frac{1}{2}x^TQx + a^T x + b$, where:

- $a$ is a sparse vector specified by a list of
`ScalarAffineTerm`

structs. - $b$ is a scalar specified by
`constant`

. - $Q$ is a symmetric matrix specified by a list of
`ScalarQuadraticTerm`

structs.

Duplicate indices in $a$ or $Q$ are accepted, and the corresponding coefficients are summed together. "Mirrored" indices `(q,r)`

and `(r,q)`

(where `r`

and `q`

are `VariableIndex`

es) are considered duplicates; only one need be specified.

For example, for two scalar variables $y, z$, the quadratic expression $yz + y^2$ is represented by the terms `ScalarQuadraticTerm.([1.0, 2.0], [y, y], [z, y])`

.

```
struct VectorQuadraticTerm{T}
output_index::Int64
scalar_term::ScalarQuadraticTerm{T}
end
```

A `ScalarQuadraticTerm`

plus its index of the output component of a `VectorQuadraticFunction`

. Each output component corresponds to a distinct sparse matrix $Q_i$.

`VectorQuadraticFunction{T}(affine_terms, quadratic_terms, constant)`

The vector-valued quadratic function with i`th`

component ("output index") defined as $\frac{1}{2}x^TQ_ix + a_i^T x + b_i$, where:

- $a_i$ is a sparse vector specified by the
`VectorAffineTerm`

s with`output_index == i`

. - $b_i$ is a scalar specified by
`constants[i]`

- $Q_i$ is a symmetric matrix specified by the
`VectorQuadraticTerm`

with`output_index == i`

.

Duplicate indices in $a_i$ or $Q_i$ are accepted, and the corresponding coefficients are summed together. "Mirrored" indices `(q,r)`

and `(r,q)`

(where `r`

and `q`

are `VariableIndex`

es) are considered duplicates; only one need be specified.

Functions for getting and setting properties of functions.

`MathOptInterface.output_dimension`

— Function.`output_dimension(f::AbstractFunction)`

Return 1 if `f`

has a scalar output and the number of output components if `f`

has a vector output.

`MathOptInterface.constant`

— Method.`constant(f::Union{ScalarAffineFunction, ScalarQuadraticFunction})`

Returns the constant term of the scalar function

`MathOptInterface.constant`

— Method.`constant(f::Union{VectorAffineFunction, VectorQuadraticFunction})`

Returns the vector of constant terms of the vector function

`MathOptInterface.constant`

— Method.`constant(f::SingleVariable, T::DataType)`

The constant term of a `SingleVariable`

function is the zero value of the specified type `T`

.

`MathOptInterface.constant`

— Method.`constant(f::VectorOfVariables, T::DataType)`

The constant term of a `VectorOfVariables`

function is a vector of zero values of the specified type `T`

.

## Sets

All sets are subtypes of `AbstractSet`

and they should either be scalar or vector sets.

`MathOptInterface.AbstractSet`

— Type.`AbstractSet`

Abstract supertype for set objects used to encode constraints. A set object should not contain any `VariableIndex`

or `ConstraintIndex`

as the set is passed unmodifed during `copy_to`

.

`AbstractScalarSet`

Abstract supertype for subsets of $\mathbb{R}$.

`AbstractVectorSet`

Abstract supertype for subsets of $\mathbb{R}^n$ for some $n$.

Functions for getting properties of sets.

`MathOptInterface.dimension`

— Function.`dimension(s::AbstractSet)`

Return the `output_dimension`

that an `AbstractFunction`

should have to be used with the set `s`

.

**Examples**

```
julia> dimension(Reals(4))
4
julia> dimension(LessThan(3.0))
1
julia> dimension(PositiveSemidefiniteConeTriangle(2))
3
```

`MathOptInterface.dual_set`

— Function.`dual_set(s::AbstractSet)`

Return the dual set of `s`

, that is the dual cone of the set. This follows the definition of duality discussed in Duals. See Dual cone for more information. If the dual cone is not defined it returns an error.

**Examples**

```
julia> dual_set(Reals(4))
Zeros(4)
julia> dual_set(SecondOrderCone(5))
SecondOrderCone(5)
julia> dual_set(ExponentialCone())
DualExponentialCone()
```

`MathOptInterface.constant`

— Method.`constant(s::Union{EqualTo, GreaterThan, LessThan})`

Returns the constant of the set.

`MathOptInterface.supports_dimension_update`

— Function.`supports_dimension_update(S::Type{<:MOI.AbstractVectorSet})`

Return a `Bool`

indicating whether the elimination of any dimension of `n`

-dimensional sets of type `S`

give an `n-1`

-dimensional set `S`

. By default, this function returns `false`

so it should only be implemented for sets that supports dimension update.

For instance, `supports_dimension_update(MOI.Nonnegatives}`

is `true`

because the elimination of any dimension of the `n`

-dimensional nonnegative orthant gives the `n-1`

-dimensional nonnegative orthant. However `supports_dimension_update(MOI.ExponentialCone}`

is `false`

.

`MathOptInterface.update_dimension`

— Function.`update_dimension(s::AbstractVectorSet, new_dim)`

Returns a set with the dimension modified to `new_dim`

.

### Scalar sets

List of recognized scalar sets.

`MathOptInterface.GreaterThan`

— Type.`GreaterThan{T <: Real}(lower::T)`

The set $[lower,\infty) \subseteq \mathbb{R}$.

`MathOptInterface.LessThan`

— Type.`LessThan{T <: Real}(upper::T)`

The set $(-\infty,upper] \subseteq \mathbb{R}$.

`MathOptInterface.EqualTo`

— Type.`EqualTo{T <: Number}(value::T)`

The set containing the single point $x \in \mathbb{R}$ where $x$ is given by `value`

.

`MathOptInterface.Interval`

— Type.`Interval{T <: Real}(lower::T,upper::T)`

The interval $[lower, upper] \subseteq \mathbb{R}$. If `lower`

or `upper`

is `-Inf`

or `Inf`

, respectively, the set is interpreted as a one-sided interval.

`Interval(s::GreaterThan{<:AbstractFloat})`

Construct a (right-unbounded) `Interval`

equivalent to the given `GreaterThan`

set.

`Interval(s::LessThan{<:AbstractFloat})`

Construct a (left-unbounded) `Interval`

equivalent to the given `LessThan`

set.

`Interval(s::EqualTo{<:Real})`

Construct a (degenerate) `Interval`

equivalent to the given `EqualTo`

set.

`MathOptInterface.Integer`

— Type.`Integer()`

The set of integers $\mathbb{Z}$.

`MathOptInterface.ZeroOne`

— Type.`ZeroOne()`

The set $\{ 0, 1 \}$.

`MathOptInterface.Semicontinuous`

— Type.`Semicontinuous{T <: Real}(lower::T,upper::T)`

The set $\{0\} \cup [lower,upper]$.

`MathOptInterface.Semiinteger`

— Type.`Semiinteger{T <: Real}(lower::T,upper::T)`

The set $\{0\} \cup \{lower,lower+1,\ldots,upper-1,upper\}$.

### Vector sets

List of recognized vector sets.

`MathOptInterface.Reals`

— Type.`Reals(dimension)`

The set $\mathbb{R}^{dimension}$ (containing all points) of dimension `dimension`

.

`MathOptInterface.Zeros`

— Type.`Zeros(dimension)`

The set $\{ 0 \}^{dimension}$ (containing only the origin) of dimension `dimension`

.

`MathOptInterface.Nonnegatives`

— Type.`Nonnegatives(dimension)`

The nonnegative orthant $\{ x \in \mathbb{R}^{dimension} : x \ge 0 \}$ of dimension `dimension`

.

`MathOptInterface.Nonpositives`

— Type.`Nonpositives(dimension)`

The nonpositive orthant $\{ x \in \mathbb{R}^{dimension} : x \le 0 \}$ of dimension `dimension`

.

`MathOptInterface.SecondOrderCone`

— Type.`SecondOrderCone(dimension)`

The second-order cone (or Lorenz cone or $\ell_2$-norm cone) $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \lVert x \rVert_2 \}$ of dimension `dimension`

.

`RotatedSecondOrderCone(dimension)`

The rotated second-order cone $\{ (t,u,x) \in \mathbb{R}^{dimension} : 2tu \ge \lVert x \rVert_2^2, t,u \ge 0 \}$ of dimension `dimension`

.

`GeometricMeanCone(dimension)`

The geometric mean cone $\{ (t,x) \in \mathbb{R}^{n+1} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}$ of dimension `dimension`

${}=n+1$.

`MathOptInterface.ExponentialCone`

— Type.`ExponentialCone()`

The 3-dimensional exponential cone $\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}$.

`DualExponentialCone()`

The 3-dimensional dual exponential cone $\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}$.

`MathOptInterface.PowerCone`

— Type.`PowerCone{T <: Real}(exponent::T)`

The 3-dimensional power cone $\{ (x,y,z) \in \mathbb{R}^3 : x^{exponent} y^{1-exponent} \ge |z|, x \ge 0, y \ge 0 \}$ with parameter `exponent`

.

`MathOptInterface.DualPowerCone`

— Type.`DualPowerCone{T <: Real}(exponent::T)`

The 3-dimensional power cone $\{ (u,v,w) \in \mathbb{R}^3 : (\frac{u}{exponent})^{exponent} (\frac{v}{1-exponent})^{1-exponent} \ge |w|, u \ge 0, v \ge 0 \}$ with parameter `exponent`

.

`MathOptInterface.SOS1`

— Type.`SOS1{T <: Real}(weights::Vector{T})`

The set corresponding to the special ordered set (SOS) constraint of type 1. Of the variables in the set, at most one can be nonzero. The `weights`

induce an ordering of the variables; as such, they should be unique values. The *k*th element in the set corresponds to the *k*th weight in `weights`

. See here for a description of SOS constraints and their potential uses.

`MathOptInterface.SOS2`

— Type.`SOS2{T <: Real}(weights::Vector{T})`

The set corresponding to the special ordered set (SOS) constraint of type 2. Of the variables in the set, at most two can be nonzero, and if two are nonzero, they must be adjacent in the ordering of the set. The `weights`

induce an ordering of the variables; as such, they should be unique values. The *k*th element in the set corresponds to the *k*th weight in `weights`

. See here for a description of SOS constraints and their potential uses.

`MathOptInterface.IndicatorSet`

— Type.`IndicatorSet{A, S <: AbstractScalarSet}(set::S)`

$\{((y, x) \in \{0, 1\} \times \mathbb{R}^n : y = 0 \implies x \in set\}$ when `A`

is `ACTIVATE_ON_ZERO`

and $\{((y, x) \in \{0, 1\} \times \mathbb{R}^n : y = 1 \implies x \in set\}$ when `A`

is `ACTIVATE_ON_ONE`

.

`S`

has to be a sub-type of `AbstractScalarSet`

. `A`

is one of the value of the `ActivationCond`

enum. `IndicatorSet`

is used with a `VectorAffineFunction`

holding the indicator variable first.

Example: $\{(y, x) \in \{0, 1\} \times \mathbb{R}^2 : y = 1 \implies x_1 + x_2 \leq 9 \}$

```
f = MOI.VectorAffineFunction(
[MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z)),
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(0.2, x1)),
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x2)),
],
[0.0, 0.0],
)
indicator_set = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(9.0))
MOI.add_constraint(model, f, indicator_set)
```

### Matrix sets

Matrix sets are vectorized in order to be subtypes of `AbstractVectorSet`

. For sets of symmetric matrices, storing both the `(i, j)`

and `(j, i)`

elements is redundant so there exists the `AbstractSymmetricMatrixSetTriangle`

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`

set can be used. The `Bridges.Constraint.SquareBridge`

can transform a set from the square form to the `triangular_form`

by adding appropriate constraints if the `(i, j)`

and `(j, i)`

expressions are different.

`abstract type AbstractSymmetricMatrixSetTriangle <: AbstractVectorSet end`

Abstract supertype for subsets of the (vectorized) cone of symmetric matrices, with `side_dimension`

rows and columns. The entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row). A vectorized cone of `dimension`

$n$ corresponds to a square matrix with side dimension $\sqrt{1/4 + 2 n} - 1/2$. (Because a $d \times d$ matrix has $d(d + 1) / 2$ elements in the upper or lower triangle.)

**Examples**

The matrix

has `side_dimension`

3 and vectorization $(1, 2, 3, 4, 5, 6)$.

**Note**

Two packed storage formats exist for symmetric matrices, the respective orders of the entries are:

- upper triangular column by column (or lower triangular row by row);
- lower triangular column by column (or upper triangular row by row).

The advantage of the first format is the mapping between the `(i, j)`

matrix indices and the `k`

index of the vectorized form. It is simpler and does not depend on the side dimension of the matrix. Indeed,

- the entry of matrix indices
`(i, j)`

has vectorized index`k = div((j - 1) * j, 2) + i`

if $i \leq j$ and`k = div((i - 1) * i, 2) + j`

if $j \leq i$; - and the entry with vectorized index
`k`

has matrix indices`i = div(1 + isqrt(8k - 7), 2)`

and`j = k - div((i - 1) * i, 2)`

or`j = div(1 + isqrt(8k - 7), 2)`

and`i = k - div((j - 1) * j, 2)`

.

**Duality note**

The scalar product for the symmetric matrix in its vectorized form is the sum of the pairwise product of the diagonal entries plus twice the sum of the pairwise product of the upper diagonal entries; see [p. 634, 1]. This has important consequence for duality.

Consider for example the following problem (`PositiveSemidefiniteConeTriangle`

is a subtype of `AbstractSymmetricMatrixSetTriangle`

)

The dual is the following problem

Why do we use $2y_2$ in the dual constraint instead of $y_2$ ? The reason is that $2y_2$ is the scalar product between $y$ and the symmetric matrix whose vectorized form is $(0, 1, 0)$. Indeed, with our modified scalar products we have

**References**

[1] Boyd, S. and Vandenberghe, L.. *Convex optimization*. Cambridge university press, 2004.

`abstract type AbstractSymmetricMatrixSetSquare <: AbstractVectorSet end`

Abstract supertype for subsets of the (vectorized) cone of symmetric matrices, with `side_dimension`

rows and columns. The entries of the matrix are given column by column (or equivalently, row by row). The matrix is both constrained to be symmetric and to have its `triangular_form`

belong to the corresponding set. That is, if the functions in entries $(i, j)$ and $(j, i)$ are different, then a constraint will be added to make sure that the entries are equal.

**Examples**

`PositiveSemidefiniteConeSquare`

is a subtype of `AbstractSymmetricMatrixSetSquare`

and constraining the matrix

to be symmetric positive semidefinite can be achieved by constraining the vector $(1, -z, -y, 0)$ (or $(1, -y, -z, 0)$) to belong to the `PositiveSemidefiniteConeSquare(2)`

. It both constrains $y = z$ and $(1, -y, 0)$ (or $(1, -z, 0)$) to be in `PositiveSemidefiniteConeTriangle(2)`

, since `triangular_form(PositiveSemidefiniteConeSquare)`

is `PositiveSemidefiniteConeTriangle`

.

`MathOptInterface.side_dimension`

— Function.```
side_dimension(set::Union{AbstractSymmetricMatrixSetTriangle,
AbstractSymmetricMatrixSetSquare})
```

Side dimension of the matrices in `set`

. By convention, it should be stored in the `side_dimension`

field but if it is not the case for a subtype of `AbstractSymmetricMatrixSetTriangle`

, the method should be implemented for this subtype.

`MathOptInterface.triangular_form`

— Function.```
triangular_form(S::Type{<:AbstractSymmetricMatrixSetSquare})
triangular_form(set::AbstractSymmetricMatrixSetSquare)
```

Return the `AbstractSymmetricMatrixSetTriangle`

corresponding to the vectorization of the upper triangular part of matrices in the `AbstractSymmetricMatrixSetSquare`

set.

List of recognized matrix sets.

`PositiveSemidefiniteConeTriangle(side_dimension) <: AbstractSymmetricMatrixSetTriangle`

The (vectorized) cone of symmetric positive semidefinite matrices, with `side_dimension`

rows and columns. See `AbstractSymmetricMatrixSetTriangle`

for more details on the vectorized form.

`PositiveSemidefiniteConeSquare(side_dimension) <: AbstractSymmetricMatrixSetSquare`

The cone of symmetric positive semidefinite matrices, with side length `side_dimension`

. See `AbstractSymmetricMatrixSetSquare`

for more details on the vectorized form.

The entries of the matrix are given column by column (or equivalently, row by row). The matrix is both constrained to be symmetric and to be positive semidefinite. That is, if the functions in entries $(i, j)$ and $(j, i)$ are different, then a constraint will be added to make sure that the entries are equal.

**Examples**

Constraining the matrix

to be symmetric positive semidefinite can be achieved by constraining the vector $(1, -z, -y, 0)$ (or $(1, -y, -z, 0)$) to belong to the `PositiveSemidefiniteConeSquare(2)`

. It both constrains $y = z$ and $(1, -y, 0)$ (or $(1, -z, 0)$) to be in `PositiveSemidefiniteConeTriangle(2)`

.

`LogDetConeTriangle(side_dimension)`

The log-determinant cone $\{ (t, u, X) \in \mathbb{R}^{2 + d(d+1)/2} : t \le u \log(\det(X/u)), u > 0 \}$ where the matrix `X`

is represented in the same symmetric packed format as in the `PositiveSemidefiniteConeTriangle`

. The argument `side_dimension`

is the side dimension of the matrix `X`

, i.e., its number of rows or columns.

`LogDetConeSquare(side_dimension)`

The log-determinant cone $\{ (t, u, X) \in \mathbb{R}^{2 + d^2} : t \le u \log(\det(X/u)), X \text{ symmetric}, u > 0 \}$ where the matrix `X`

is represented in the same format as in the `PositiveSemidefiniteConeSquare`

. Similarly to `PositiveSemidefiniteConeSquare`

, constraints are added to ensures that `X`

is symmetric. The argument `side_dimension`

is the side dimension of the matrix `X`

, i.e., its number of rows or columns.

`RootDetConeTriangle(side_dimension)`

The root-determinant cone $\{ (t, X) \in \mathbb{R}^{1 + d(d+1)/2} : t \le \det(X)^{1/d} \}$ where the matrix `X`

is represented in the same symmetric packed format as in the `PositiveSemidefiniteConeTriangle`

. The argument `side_dimension`

is the side dimension of the matrix `X`

, i.e., its number of rows or columns.

`RootDetConeSquare(side_dimension)`

The root-determinant cone $\{ (t, X) \in \mathbb{R}^{1 + d^2} : t \le \det(X)^{1/d}, X \text{ symmetric} \}$ where the matrix `X`

is represented in the same format as in the `PositiveSemidefiniteConeSquare`

. Similarly to `PositiveSemidefiniteConeSquare`

, constraints are added to ensure that `X`

is symmetric. The argument `side_dimension`

is the side dimension of the matrix `X`

, i.e., its number of rows or columns.

## Modifications

Functions for modifying objective and constraint functions.

`MathOptInterface.modify`

— Function.**Constraint Function**

`modify(model::ModelLike, ci::ConstraintIndex, change::AbstractFunctionModification)`

Apply the modification specified by `change`

to the function of constraint `ci`

.

An `ModifyConstraintNotAllowed`

error is thrown if modifying constraints is not supported by the model `model`

.

**Examples**

`modify(model, ci, ScalarConstantChange(10.0))`

**Objective Function**

`modify(model::ModelLike, ::ObjectiveFunction, change::AbstractFunctionModification)`

Apply the modification specified by `change`

to the objective function of `model`

. To change the function completely, call `set`

instead.

An `ModifyObjectiveNotAllowed`

error is thrown if modifying objectives is not supported by the model `model`

.

**Examples**

`modify(model, ObjectiveFunction{ScalarAffineFunction{Float64}}(), ScalarConstantChange(10.0))`

`AbstractFunctionModification`

An abstract supertype for structs which specify partial modifications to functions, to be used for making small modifications instead of replacing the functions entirely.

`ScalarConstantChange{T}(new_constant::T)`

A struct used to request a change in the constant term of a scalar-valued function. Applicable to `ScalarAffineFunction`

and `ScalarQuadraticFunction`

.

`VectorConstantChange{T}(new_constant::Vector{T})`

A struct used to request a change in the constant vector of a vector-valued function. Applicable to `VectorAffineFunction`

and `VectorQuadraticFunction`

.

`ScalarCoefficientChange{T}(variable::VariableIndex, new_coefficient::T)`

A struct used to request a change in the linear coefficient of a single variable in a scalar-valued function. Applicable to `ScalarAffineFunction`

and `ScalarQuadraticFunction`

.

`MathOptInterface.MultirowChange`

— Type.`MultirowChange{T}(variable::VariableIndex, new_coefficients::Vector{Tuple{Int64, T}})`

A struct used to request a change in the linear coefficients of a single variable in a vector-valued function. New coefficients are specified by `(output_index, coefficient)`

tuples. Applicable to `VectorAffineFunction`

and `VectorQuadraticFunction`

.

## Nonlinear programming (NLP)

### Attributes

`MathOptInterface.NLPBlock`

— Type.`NLPBlock()`

Holds the `NLPBlockData`

that represents a set of nonlinear constraints, and optionally a nonlinear objective.

`MathOptInterface.NLPBoundsPair`

— Type.`NLPBoundsPair(lower,upper)`

A struct holding a pair of lower and upper bounds. `-Inf`

and `Inf`

can be used to indicate no lower or upper bound, respectively.

`MathOptInterface.NLPBlockData`

— Type.```
struct NLPBlockData
constraint_bounds::Vector{NLPBoundsPair}
evaluator::AbstractNLPEvaluator
has_objective::Bool
end
```

A `struct`

encoding a set of nonlinear constraints of the form $lb \le g(x) \le ub$ and, if `has_objective == true`

, a nonlinear objective function $f(x)$. `constraint_bounds`

holds the pairs of $lb$ and $ub$ elements. Nonlinear objectives *override* any objective set by using the `ObjectiveFunction`

attribute. The `evaluator`

is a callback object that is used to query function values, derivatives, and expression graphs. If `has_objective == false`

, then it is an error to query properties of the objective function, and in Hessian-of-the-Lagrangian queries, `σ`

must be set to zero. Throughout the evaluator, all variables are ordered according to ListOfVariableIndices().

`MathOptInterface.NLPBlockDual`

— Type.```
NLPBlockDual(N)
NLPBlockDual()
```

The Lagrange multipliers on the constraints from the `NLPBlock`

in result `N`

. If `N`

is omitted, it is 1 by default.

`NLPBlockDualStart()`

An initial assignment of the Lagrange multipliers on the constraints from the `NLPBlock`

that the solver may use to warm-start the solve.

### NLP evaluator methods

`AbstractNLPEvaluator`

Abstract supertype for the callback object used in `NLPBlock`

.

`MathOptInterface.initialize`

— Function.`initialize(d::AbstractNLPEvaluator, requested_features::Vector{Symbol})`

Must be called before any other methods. The vector `requested_features`

lists features requested by the solver. These may include `:Grad`

for gradients of $f$, `:Jac`

for explicit Jacobians of $g$, `:JacVec`

for Jacobian-vector products, `:HessVec`

for Hessian-vector and Hessian-of-Lagrangian-vector products, `:Hess`

for explicit Hessians and Hessian-of-Lagrangians, and `:ExprGraph`

for expression graphs.

`MathOptInterface.features_available`

— Function.`features_available(d::AbstractNLPEvaluator)`

Returns the subset of features available for this problem instance, as a list of symbols in the same format as in `initialize`

.

`MathOptInterface.eval_objective`

— Function.`eval_objective(d::AbstractNLPEvaluator, x)`

Evaluate the objective $f(x)$, returning a scalar value.

`MathOptInterface.eval_constraint`

— Function.`eval_constraint(d::AbstractNLPEvaluator, g, x)`

Evaluate the constraint function $g(x)$, storing the result in the vector `g`

which must be of the appropriate size.

`MathOptInterface.eval_objective_gradient`

— Function.`eval_objective_gradient(d::AbstractNLPEvaluator, g, x)`

Evaluate $\nabla f(x)$ as a dense vector, storing the result in the vector `g`

which must be of the appropriate size.

`MathOptInterface.jacobian_structure`

— Function.`jacobian_structure(d::AbstractNLPEvaluator)::Vector{Tuple{Int64,Int64}}`

Returns the sparsity structure of the Jacobian matrix $J_g(x) = \left[ \begin{array}{c} \nabla g_1(x) \\ \nabla g_2(x) \\ \vdots \\ \nabla g_m(x) \end{array}\right]$ where $g_i$ is the $i\text{th}$ component of $g$. The sparsity structure is assumed to be independent of the point $x$. Returns a vector of tuples, `(row, column)`

, where each indicates the position of a structurally nonzero element. These indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

`MathOptInterface.hessian_lagrangian_structure`

— Function.`hessian_lagrangian_structure(d::AbstractNLPEvaluator)::Vector{Tuple{Int64,Int64}}`

Returns the sparsity structure of the Hessian-of-the-Lagrangian matrix $\nabla^2 f + \sum_{i=1}^m \nabla^2 g_i$ as a vector of tuples, where each indicates the position of a structurally nonzero element. These indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together. Any mix of lower and upper-triangular indices is valid. Elements `(i,j)`

and `(j,i)`

, if both present, should be treated as duplicates.

`MathOptInterface.eval_constraint_jacobian`

— Function.`eval_constraint_jacobian(d::AbstractNLPEvaluator, J, x)`

Evaluates the sparse Jacobian matrix $J_g(x) = \left[ \begin{array}{c} \nabla g_1(x) \\ \nabla g_2(x) \\ \vdots \\ \nabla g_m(x) \end{array}\right]$. The result is stored in the vector `J`

in the same order as the indices returned by `jacobian_structure`

.

`eval_constraint_jacobian_product(d::AbstractNLPEvaluator, y, x, w)`

Computes the Jacobian-vector product $J_g(x)w$, storing the result in the vector `y`

.

`eval_constraint_jacobian_transpose_product(d::AbstractNLPEvaluator, y, x, w)`

Computes the Jacobian-transpose-vector product $J_g(x)^Tw$, storing the result in the vector `y`

.

`MathOptInterface.eval_hessian_lagrangian`

— Function.`eval_hessian_lagrangian(d::AbstractNLPEvaluator, H, x, σ, μ)`

Given scalar weight `σ`

and vector of constraint weights `μ`

, computes the sparse Hessian-of-the-Lagrangian matrix $\sigma\nabla^2 f(x) + \sum_{i=1}^m \mu_i \nabla^2 g_i(x)$, storing the result in the vector `H`

in the same order as the indices returned by `hessian_lagrangian_structure`

.

`MathOptInterface.eval_hessian_lagrangian_product`

— Function.`eval_hessian_lagrangian_prod(d::AbstractNLPEvaluator, h, x, v, σ, μ)`

Given scalar weight `σ`

and vector of constraint weights `μ`

, computes the Hessian-of-the-Lagrangian-vector product $\left(\sigma\nabla^2 f(x) + \sum_{i=1}^m \mu_i \nabla^2 g_i(x)\right)v$, storing the result in the vector `h`

.

`MathOptInterface.objective_expr`

— Function.`objective_expr(d::AbstractNLPEvaluator)`

Returns an expression graph for the objective function as a standard Julia `Expr`

object. All sums and products are flattened out as simple `Expr(:+,...)`

and `Expr(:*,...)`

objects. The symbol `x`

is used as a placeholder for the vector of decision variables. No other undefined symbols are permitted; coefficients are embedded as explicit values. For example, the expression $x_1+\sin(x_2/\exp(x_3))$ would be represented as the Julia object `:(x[1] + sin(x[2]/exp(x[3])))`

. Each integer index is wrapped in a `VariableIndex`

. See the Julia manual for more information on the structure of `Expr`

objects. There are currently no restrictions on recognized functions; typically these will be built-in Julia functions like `^`

, `exp`

, `log`

, `cos`

, `tan`

, `sqrt`

, etc., but modeling interfaces may choose to extend these basic functions.

`MathOptInterface.constraint_expr`

— Function.`constraint_expr(d::AbstractNLPEvaluator, i)`

Returns an expression graph for the $i\text{th}$ constraint in the same format as described above, with an additional comparison operator indicating the sense of and bounds on the constraint. The right-hand side of the comparison must be a constant; that is, `:(x[1]^3 <= 1)`

is allowed, while `:(1 <= x[1]^3)`

is not valid. Double-sided constraints are allowed, in which case both the lower bound and upper bounds should be constants; for example, `:(-1 <= cos(x[1]) + sin(x[2]) <= 1)`

is valid.

## 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`

should be thrown:

`MathOptInterface.InvalidIndex`

— Type.```
struct InvalidIndex{IndexType<:Index} <: Exception
index::IndexType
end
```

An error indicating that the index `index`

is invalid.

As discussed in JuMP mapping, for scalar constraint with a nonzero function constant, a `ScalarFunctionConstantNotZero`

exception may be thrown:

```
struct ScalarFunctionConstantNotZero{T, F, S} <: Exception
constant::T
end
```

An error indicating that the constant part of the function in the constraint `F`

-in-`S`

is nonzero.

Some `SingleVariable`

constraints cannot be combined on the same variable:

`LowerBoundAlreadySet{S1, S2}`

Error thrown when setting a `SingleVariable`

-in-`S2`

when a `SingleVariable`

-in-`S1`

has already been added and the sets `S1`

, `S2`

both set a lower bound, i.e. they are `EqualTo`

, `GreaterThan`

, `Interval`

, `Semicontinuous`

or `Semiinteger`

.

`UpperBoundAlreadySet{S1, S2}`

Error thrown when setting a `SingleVariable`

-in-`S2`

when a `SingleVariable`

-in-`S1`

has already been added and the sets `S1`

, `S2`

both set an upper bound, i.e. they are `EqualTo`

, `LessThan`

, `Interval`

, `Semicontinuous`

or `Semiinteger`

.

The rest of the errors defined in MOI fall in two categories represented by the following two abstract types:

`UnsupportedError <: Exception`

Abstract type for error thrown when an element is not supported by the model.

`MathOptInterface.NotAllowedError`

— Type.`NotAllowedError <: Exception`

Abstract type for error thrown when an operation is supported but cannot be applied in the current state of the model.

The different `UnsupportedError`

and `NotAllowedError`

are the following errors:

```
struct UnsupportedAttribute{AttrType} <: UnsupportedError
attr::AttrType
message::String
end
```

An error indicating that the attribute `attr`

is not supported by the model, i.e. that `supports`

returns `false`

.

```
struct SetAttributeNotAllowed{AttrType} <: NotAllowedError
attr::AttrType
message::String # Human-friendly explanation why the attribute cannot be set
end
```

An error indicating that the attribute `attr`

is supported (see `supports`

) but cannot be set for some reason (see the error string).

```
struct AddVariableNotAllowed <: NotAllowedError
message::String # Human-friendly explanation why the attribute cannot be set
end
```

An error indicating that variables cannot be added to the model.

```
struct UnsupportedConstraint{F<:AbstractFunction, S<:AbstractSet} <: UnsupportedError
message::String # Human-friendly explanation why the attribute cannot be set
end
```

An error indicating that constraints of type `F`

-in-`S`

are not supported by the model, i.e. that `supports_constraint`

returns `false`

.

```
struct AddConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet} <: NotAllowedError
message::String # Human-friendly explanation why the attribute cannot be set
end
```

An error indicating that constraints of type `F`

-in-`S`

are supported (see `supports_constraint`

) but cannot be added.

```
struct ModifyConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet,
C<:AbstractFunctionModification} <: NotAllowedError
constraint_index::ConstraintIndex{F, S}
change::C
message::String
end
```

An error indicating that the constraint modification `change`

cannot be applied to the constraint of index `ci`

.

```
struct ModifyObjectiveNotAllowed{C<:AbstractFunctionModification} <: NotAllowedError
change::C
message::String
end
```

An error indicating that the objective modification `change`

cannot be applied to the objective.

```
struct DeleteNotAllowed{IndexType <: Index} <: NotAllowedError
index::IndexType
message::String
end
```

An error indicating that the index `index`

cannot be deleted.

```
struct UnsupportedSubmittable{SubmitType} <: UnsupportedError
sub::SubmitType
message::String
end
```

An error indicating that the submittable `sub`

is not supported by the model, i.e. that `supports`

returns `false`

.

```
struct SubmitNotAllowed{SubmitTyp<:AbstractSubmittable} <: NotAllowedError
sub::SubmitType
message::String # Human-friendly explanation why the attribute cannot be set
end
```

An error indicating that the submittable `sub`

is supported (see `supports`

) but cannot be added for some reason (see the error string).

## Models

`Utilities.Model`

provides an implementation of a `ModelLike`

that efficiently supports all functions and sets defined within MOI. However, given the extensibility of MOI, this might not over all use cases.

`Utilities.UniversalFallback`

is a layer that sits on top of any `ModelLike`

and provides non-specialized (slower) fallbacks for constraints and attributes that the underlying `ModeLike`

does not support.

For advanced use cases that need efficient support for functions and sets defined outside of MOI (but still known at compile time), we provide the `Utilities.@model`

macro.

`MathOptInterface.Utilities.Model`

— Type.An implementation of `ModelLike`

that supports all functions and sets defined in MOI. It is parameterized by the coefficient type.

**Examples**

```
model = Model{Float64}()
x = add_variable(model)
```

`UniversalFallback`

The `UniversalFallback`

can be applied on a `MathOptInterface.ModelLike`

`model`

to create the model `UniversalFallback(model)`

supporting *any* constaint and attribute. This allows to have a specialized implementation in `model`

for performance critical constraints and attributes while still supporting other attributes with a small performance penalty. Note that `model`

is unaware of constraints and attributes stored by `UniversalFallback`

so this is not appropriate if `model`

is an optimizer (for this reason, `MathOptInterface.optimize!`

has not been implemented). In that case, optimizer bridges should be used instead.

`MathOptInterface.Utilities.@model`

— Macro.`macro model(model_name, scalar_sets, typed_scalar_sets, vector_sets, typed_vector_sets, scalar_functions, typed_scalar_functions, vector_functions, typed_vector_functions)`

Creates a type `model_name`

implementing the MOI model interface and containing `scalar_sets`

scalar sets `typed_scalar_sets`

typed scalar sets, `vector_sets`

vector sets, `typed_vector_sets`

typed vector sets, `scalar_functions`

scalar functions, `typed_scalar_functions`

typed scalar functions, `vector_functions`

vector functions and `typed_vector_functions`

typed vector functions. To give no set/function, write `()`

, to give one set `S`

, write `(S,)`

.

The function `MathOptInterface.SingleVariable`

should not be given in `scalar_functions`

. The model supports `MathOptInterface.SingleVariable`

-in-`F`

constraints where `F`

is `MathOptInterface.EqualTo`

, `MathOptInterface.GreaterThan`

, `MathOptInterface.LessThan`

, `MathOptInterface.Interval`

, `MathOptInterface.Integer`

, `MathOptInterface.ZeroOne`

, `MathOptInterface.Semicontinuous`

or `MathOptInterface.Semiinteger`

. The sets supported with the `MathOptInterface.SingleVariable`

cannot be controlled from the macro, use the `UniversalFallback`

to support more sets.

This macro creates a model specialized for specific types of constraint, by defining specialized structures and methods. To create a model that, in addition to be optimized for specific constraints, also support arbitrary constraints and attributes, use `UniversalFallback`

.

This implementation of the MOI model certifies that the constraint indices, in addition to being different between constraints `F`

-in-`S`

for the same types `F`

and `S`

, are also different between constraints for different types `F`

and `S`

. This means that for constraint indices `ci1`

, `ci2`

of this model, `ci1 == ci2`

if and only if `ci1.value == ci2.value`

. This fact can be used to use the the value of the index directly in a dictionary representing a mapping between constraint indices and something else.

**Examples**

The model describing an linear program would be:

```
@model(LPModel, # Name of model
(), # untyped scalar sets
(MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), # typed scalar sets
(MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives), # untyped vector sets
(), # typed vector sets
(), # untyped scalar functions
(MOI.ScalarAffineFunction,), # typed scalar functions
(MOI.VectorOfVariables,), # untyped vector functions
(MOI.VectorAffineFunction,)) # typed vector functions
```

Let `MOI`

denote `MathOptInterface`

, `MOIU`

denote `MOI.Utilities`

and `MOIU.ConstraintEntry{F, S}`

be defined as `MOI.Tuple{MOI.ConstraintIndex{F, S}, F, S}`

. The macro would create the types:

```
struct LPModelScalarConstraints{T, F <: MOI.AbstractScalarFunction} <: MOIU.Constraints{F}
equalto::Vector{MOIU.ConstraintEntry{F, MOI.EqualTo{T}}}
greaterthan::Vector{MOIU.ConstraintEntry{F, MOI.GreaterThan{T}}}
lessthan::Vector{MOIU.ConstraintEntry{F, MOI.LessThan{T}}}
interval::Vector{MOIU.ConstraintEntry{F, MOI.Interval{T}}}
end
struct LPModelVectorConstraints{T, F <: MOI.AbstractVectorFunction} <: MOIU.Constraints{F}
zeros::Vector{MOIU.ConstraintEntry{F, MOI.Zeros}}
nonnegatives::Vector{MOIU.ConstraintEntry{F, MOI.Nonnegatives}}
nonpositives::Vector{MOIU.ConstraintEntry{F, MOI.Nonpositives}}
end
mutable struct LPModel{T} <: MOIU.AbstractModel{T}
name::String
sense::MOI.OptimizationSense
objective::Union{MOI.SingleVariable, MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}}
num_variables_created::Int64
# If nothing, no variable has been deleted so the indices of the
# variables are VI.(1:num_variables_created)
variable_indices::Union{Nothing, Set{MOI.VariableIndex}}
# Union of flags of `S` such that a `SingleVariable`-in-`S`
# constraint was added to the model and not deleted yet.
single_variable_mask::Vector{UInt8}
# Lower bound set by `SingleVariable`-in-`S` where `S`is
# `GreaterThan{T}`, `EqualTo{T}` or `Interval{T}`.
lower_bound::Vector{T}
# Lower bound set by `SingleVariable`-in-`S` where `S`is
# `LessThan{T}`, `EqualTo{T}` or `Interval{T}`.
upper_bound::Vector{T}
var_to_name::Dict{MOI.VariableIndex, String}
# If `nothing`, the dictionary hasn't been constructed yet.
name_to_var::Union{Dict{String, MOI.VariableIndex}, Nothing}
nextconstraintid::Int64
con_to_name::Dict{MOI.ConstraintIndex, String}
name_to_con::Union{Dict{String, MOI.ConstraintIndex}, Nothing}
constrmap::Vector{Int}
scalaraffinefunction::LPModelScalarConstraints{T, MOI.ScalarAffineFunction{T}}
vectorofvariables::LPModelVectorConstraints{T, MOI.VectorOfVariables}
vectoraffinefunction::LPModelVectorConstraints{T, MOI.VectorAffineFunction{T}}
end
```

The type `LPModel`

implements the MathOptInterface API except methods specific to solver models like `optimize!`

or `getattribute`

with `VariablePrimal`

.

## Bridges

Bridges can be used for automatic reformulation of constrained variables (i.e. variables added with `add_constrained_variable`

/`add_constrained_variables`

) or constraints into equivalent formulations using constrained variables and constraints of different types. There are two important concepts to distinguish:

`Bridges.AbstractBridge`

s are recipes implementing a specific reformulation. Bridges are not directly subtypes of`Bridges.AbstractBridge`

, they are either`Bridges.Variable.AbstractBridge`

or`Bridges.Constraint.AbstractBridge`

.`Bridges.AbstractBridgeOptimizer`

is a layer that can be applied to another`ModelLike`

to apply the reformulation. The`Bridges.LazyBridgeOptimizer`

automatically chooses the appropriate bridges to use when a constrained variable or constraint is not supported by using the list of bridges that were added to it by`Bridges.add_bridge`

.`Bridges.full_bridge_optimizer`

wraps a model in a`Bridges.LazyBridgeOptimizer`

where all the bridges defined in MOI are added. This is the recommended way to use bridges in the Testing guideline, and JuMP automatically calls`Bridges.full_bridge_optimizer`

when attaching an optimizer.

`AbstractBridge`

Represents a bridged constraint or variable in a `MathOptInterface.Bridges.AbstractBridgeOptimizer`

. It contains the indices of the variables and constraints that it has created in the model. These can be obtained using `MathOptInterface.NumberOfVariables`

, `MathOptInterface.ListOfVariableIndices`

, `MathOptInterface.NumberOfConstraints`

and `MathOptInterface.ListOfConstraintIndices`

using `MathOptInterface.get`

with the bridge in place of the `MathOptInterface.ModelLike`

. Attributes of the bridged model such as `MathOptInterface.ConstraintDual`

and `MathOptInterface.ConstraintPrimal`

, can be obtained using `MathOptInterface.get`

with the bridge in place of the constraint index. These calls are used by the `MathOptInterface.Bridges.AbstractBridgeOptimizer`

to communicate with the bridge so they should be implemented by the bridge.

`AbstractBridgeOptimizer`

A bridge optimizer applies given constraint bridges to a given optimizer thus extending the types of supported constraints. The attributes of the inner optimizer are automatically transformed to make the bridges transparent, e.g. the variables and constraints created by the bridges are hidden.

By convention, the inner optimizer should be stored in a `model`

field and the dictionary mapping constraint indices to bridges should be stored in a `bridges`

field. If a bridge optimizer deviates from these conventions, it should implement the functions `MOI.optimize!`

and `bridge`

respectively.

`LazyBridgeOptimizer{OT<:MOI.ModelLike} <: AbstractBridgeOptimizer`

The `LazyBridgeOptimizer`

combines several bridges, which are added using the `add_bridge`

function. Whenever a constraint is added, it only attempts to bridge it if it is not supported by the internal model (hence its name `Lazy`

). When bridging a constraint, it selects the minimal number of bridges needed. For instance, a constraint `F`

-in-`S`

can be bridged into a constraint `F1`

-in-`S1`

(supported by the internal model) using bridge 1 or bridged into a constraint `F2`

-in-`S2`

(unsupported by the internal model) using bridge 2 which can then be bridged into a constraint `F3`

-in-`S3`

(supported by the internal model) using bridge 3, it will choose bridge 1 as it allows to bridge `F`

-in-`S`

using only one bridge instead of two if it uses bridge 2 and 3.

`MathOptInterface.Bridges.add_bridge`

— Function.`add_bridge(b::LazyBridgeOptimizer, BT::Type{<:Variable.AbstractBridge})`

Enable the use of the variable bridges of type `BT`

by `b`

.

`add_bridge(b::LazyBridgeOptimizer, BT::Type{<:Constraint.AbstractBridge})`

Enable the use of the constraint bridges of type `BT`

by `b`

.

`MathOptInterface.Bridges.full_bridge_optimizer`

— Function.`full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where T`

Returns a `LazyBridgeOptimizer`

bridging `model`

for every bridge defined in this package and for the coefficient type `T`

.

### Variable bridges

When variables are added, either free with `add_variable`

/`add_variables`

, or constrained with `add_constrained_variable`

/`add_constrained_variables`

, variable bridges allow to return *bridged variables* that do not correspond to variables of the underlying model. These variables are parametrized by variables of the underlying model and this parametrization can be obtained with `Bridges.bridged_variable_function`

. Similarly, the variables of the underlying model that were created by the bridge can be expressed in terms of the bridged variables and this expression can be obtained with `Bridges.unbridged_variable_function`

. For instance, consider a model bridged by the `Bridges.Variable.VectorizeBridge`

:

```
model = MOI.Utilities.Model{Float64}()
bridged_model = MOI.Bridges.Variable.Vectorize{Float64}(model)
bridged_variable, bridged_constraint = MOI.add_constrained_variable(bridged_model, MOI.GreaterThan(1.0))
# output
(MOI.VariableIndex(-1), MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}(-1))
```

The constrained variable in `MOI.GreaterThan(1.0)`

returned is a bridged variable as its index in negative. In `model`

, a constrained variable in `MOI.Nonnegatives`

is created:

```
inner_variables = MOI.get(model, MOI.ListOfVariableIndices())
# output
1-element Array{MOI.VariableIndex,1}:
MOI.VariableIndex(1)
```

In the functions used for adding constraints or setting the objective to `bridged_model`

, `bridged_variable`

is substituted for `inner_variables[1]`

plus 1:

```
MOI.Bridges.bridged_variable_function(bridged_model, bridged_variable)
# output
MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(1))], 1.0)
```

When getting `ConstraintFunction`

or `ObjectiveFunction`

, `inner_variables[1]`

is substituted for `bridged_variable`

minus 1:

```
MOI.Bridges.unbridged_variable_function(bridged_model, inner_variables[1])
# output
MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(-1))], -1.0)
```

A notable exception is with `Bridges.Variable.ZerosBridge`

where no variable is created in the underlying model as the variables are simply transformed to zeros. When this bridge is used, it is not possible to recover functions with bridged variables from functions of the inner model. Consider for instance that we create two zero variables:

```
model = MOI.Utilities.Model{Float64}()
bridged_model = MOI.Bridges.Variable.Zeros{Float64}(model)
bridged_variables, bridged_constraint = MOI.add_constrained_variables(bridged_model, MOI.Zeros(2))
# output
(MOI.VariableIndex[VariableIndex(-1), VariableIndex(-2)], MOI.ConstraintIndex{MOI.VectorOfVariables,MOI.Zeros}(-1))
```

Consider the following functions in the variables of `bridged_model`

:

```
func = MOI.Utilities.operate(+, Float64, MOI.SingleVariable.(bridged_variables)...)
# output
MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(-1)), ScalarAffineTerm{Float64}(1.0, VariableIndex(-2))], 0.0)
```

We can obtain the equivalent function in the variables of `model`

as follows:

```
inner_func = MOI.Bridges.bridged_function(bridged_model, func)
# output
MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[], 0.0)
```

However, it's not possible to invert this operation. Indeed, since the bridged variables are substituted for zeros, we cannot deduce whether they were present in the initial function.

```
MOI.Bridges.unbridged_function(bridged_model, inner_func)
# output
ERROR: Cannot unbridge function because some variables are bridged by variable bridges that do not support reverse mapping, e.g., `ZerosBridge`.
Stacktrace:
[1] error(::String, ::String, ::String) at ./error.jl:42
[2] throw_if_cannot_unbridge at /home/blegat/.julia/dev/MathOptInterface/src/Bridges/Variable/map.jl:343 [inlined]
[3] unbridged_function(::MOI.Bridges.Variable.SingleBridgeOptimizer{MOI.Bridges.Variable.ZerosBridge{Float64},MOI.Utilities.Model{Float64}}, ::MOI.ScalarAffineFunction{Float64}) at /home/blegat/.julia/dev/MOI/src/Bridges/bridge_optimizer.jl:920
[4] top-level scope at none:0
```

`AbstractBridge`

Subtype of `MathOptInterface.Bridges.AbstractBridge`

for variable bridges.

```
bridged_variable_function(b::AbstractBridgeOptimizer,
vi::MOI.VariableIndex)
```

Return a `MOI.AbstractScalarFunction`

of variables of `b.model`

that equals `vi`

. That is, if the variable `vi`

is bridged, it returns its expression in terms of the variables of `b.model`

. Otherwise, it returns `MOI.SingleVariable(vi)`

.

```
unbridged_variable_function(b::AbstractBridgeOptimizer,
vi::MOI.VariableIndex)
```

Return a `MOI.AbstractScalarFunction`

of variables of `b`

that equals `vi`

. That is, if the variable `vi`

is an internal variable of `b.model`

created by a but not visible to the user, it returns its expression in terms of the variables of bridged variables. Otherwise, it returns `MOI.SingleVariable(vi)`

.

Below is the list of variable bridges implemented in this package.

`ZerosBridge{T} <: Bridges.Variable.AbstractBridge`

Transforms constrained variables in `MathOptInterface.Zeros`

to zeros, which ends up creating no variables in the underlying model. The bridged variables are therefore similar to parameters with zero values. Parameters with non-zero value can be created with constrained variables in `MOI.EqualTo`

by combining a `VectorizeBridge`

and this bridge. The functions cannot be unbridged, given a function, we cannot determine, if the bridged variables were used. The dual values cannot be determined by the bridge but they can be determined by the bridged optimizer using `MathOptInterface.Utilities.get_fallback`

if a `CachingOptimizer`

is used (since `ConstraintFunction`

cannot be got as functions cannot be unbridged).

`FreeBridge{T} <: Bridges.Variable.AbstractBridge`

Transforms constrained variables in `MOI.Reals`

to the difference of constrained variables in `MOI.Nonnegatives`

.

```
NonposToNonnegBridge{T, F<:MOI.AbstractVectorFunction, G<:MOI.AbstractVectorFunction} <:
FlipSignBridge{T, MOI.Nonpositives, MOI.Nonnegatives, F, G}
```

Transforms constrained variables in `Nonpositives`

into constrained variables in `Nonnegatives`

.

`VectorizeBridge{T, S}`

Transforms a constrained variable in `scalar_set_type(S, T)`

where `S <: VectorLinearSet`

into a constrained vector of one variable in `S`

. For instance, `VectorizeBridge{Float64, MOI.Nonnegatives}`

transforms a constrained variable in `MOI.GreaterThan{Float64}`

into a constrained vector of one variable in `MOI.Nonnegatives`

.

`RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge`

Transforms constrained variables in `MathOptInterface.RotatedSecondOrderCone`

to constrained variables in `MathOptInterface.PositiveSemidefiniteConeTriangle`

.

For each bridge defined in this package, a corresponding `Bridges.Variable.SingleBridgeOptimizer`

is available with the same name without the "Bridge" suffix, e.g., `SplitInterval`

is a `SingleBridgeOptimizer`

for the `SplitIntervalBridge`

. Moreover, they are all added in the `Bridges.LazyBridgeOptimizer`

returned by `Bridges.full_bridge_optimizer`

as it calls `Bridges.Variable.add_all_bridges`

.

`SingleBridgeOptimizer{BT<:AbstractBridge, OT<:MOI.ModelLike} <: AbstractBridgeOptimizer`

The `SingleBridgeOptimizer`

bridges any constrained variables supported by the bridge `BT`

. This is in contrast with the `MathOptInterface.Bridges.LazyBridgeOptimizer`

which only bridges the constrained variables that are unsupported by the internal model, even if they are supported by one of its bridges.

Two bridge optimizers using variable bridges cannot be used together as both of them assume that the underlying model only returns variable indices with nonnegative values.

`add_all_bridges(bridged_model, T::Type)`

Add all bridges defined in the `Bridges.Variable`

submodule to `bridged_model`

. The coefficient type used is `T`

.

### Constraint bridges

When constraints are added with `add_constraint`

, constraint bridges allow to return *bridged constraints* that do not correspond to constraints of the underlying model. These constraints were enforced by an equivalent formulation that added constraints (and possibly also variables) in the underlying model. For instance, consider a model bridged by the `Bridges.Constraint.SplitIntervalBridge`

:

```
model = MOI.Utilities.Model{Float64}()
bridged_model = MOI.Bridges.Constraint.SplitInterval{Float64}(model)
x, y = MOI.add_variables(bridged_model, 2)
func = MOI.Utilities.operate(+, Float64, MOI.SingleVariable(x), MOI.SingleVariable(y))
c = MOI.add_constraint(bridged_model, func, MOI.Interval(1.0, 2.0))
# output
MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.Interval{Float64}}(1)
```

We can see the constraint was bridged to two constraints, one for each bound, in the inner model.

```
MOI.get(model, MOI.ListOfConstraints())
# output
2-element Array{Tuple{DataType,DataType},1}:
(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64})
(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64})
```

However, `bridged_model`

transparently hides these constraints and creates the illusion that an interval constraint was created.

```
MOI.get(bridged_model, MOI.ListOfConstraints())
# output
1-element Array{Tuple{DataType,DataType},1}:
(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64})
```

It is nevertheless possible to differentiate this constraint from a constraint added to the inner model by asking whether it is bridged:

```
MOI.Bridges.is_bridged(bridged_model, c)
# output
true
```

`AbstractBridge`

Subtype of `MathOptInterface.Bridges.AbstractBridge`

for constraint bridges.

Below is the list of constraint bridges implemented in this package.

```
GreaterToLessBridge{T, F<:MOI.AbstractScalarFunction, G<:MOI.AbstractScalarFunction} <:
FlipSignBridge{T, MOI.GreaterThan{T}, MOI.LessThan{T}, F, G}
```

Transforms a `G`

-in-`GreaterThan{T}`

constraint into an `F`

-in-`LessThan{T}`

constraint.

```
LessToGreaterBridge{T, F<:MOI.AbstractScalarFunction, G<:MOI.AbstractScalarFunction} <:
FlipSignBridge{T, MOI.LessThan{T}, MOI.GreaterThan{T}, F, G}
```

Transforms a `G`

-in-`LessThan{T}`

constraint into an `F`

-in-`GreaterThan{T}`

constraint.

```
NonnegToNonposBridge{T, F<:MOI.AbstractVectorFunction, G<:MOI.AbstractVectorFunction} <:
FlipSignBridge{T, MOI.Nonnegatives, MOI.Nonpositives, F, G}
```

Transforms a `G`

-in-`Nonnegatives`

constraint into a `F`

-in-`Nonpositives`

constraint.

```
NonposToNonnegBridge{T, F<:MOI.AbstractVectorFunction, G<:MOI.AbstractVectorFunction} <:
FlipSignBridge{T, MOI.Nonpositives, MOI.Nonnegatives, F, G}
```

Transforms a `G`

-in-`Nonpositives`

constraint into a `F`

-in-`Nonnegatives`

constraint.

`VectorizeBridge{T, F, S, G}`

Transforms a constraint `G`

-in-`scalar_set_type(S, T)`

where `S <: VectorLinearSet`

to `F`

-in-`S`

.

`ScalarizeBridge{T, F, S}`

Transforms a constraint `AbstractVectorFunction`

-in-`vector_set_type(S)`

where `S <: LPCone{T}`

to `F`

-in-`S`

.

`ScalarSlackBridge{T, F, S}`

The `ScalarSlackBridge`

converts a constraint `G`

-in-`S`

where `G`

is a function different from `SingleVariable`

into the constraints `F`

-in-`EqualTo{T}`

and `SingleVariable`

-in-`S`

. `F`

is the result of subtracting a `SingleVariable`

from `G`

. Tipically `G`

is the same as `F`

, but that is not mandatory.

`VectorSlackBridge{T, F, S}`

The `VectorSlackBridge`

converts a constraint `G`

-in-`S`

where `G`

is a function different from `VectorOfVariables`

into the constraints `F`

in-`Zeros`

and `VectorOfVariables`

-in-`S`

. `F`

is the result of subtracting a `VectorOfVariables`

from `G`

. Tipically `G`

is the same as `F`

, but that is not mandatory.

`ScalarFunctionizeBridge{T, S}`

The `ScalarFunctionizeBridge`

converts a constraint `SingleVariable`

-in-`S`

into the constraint `ScalarAffineFunction{T}`

-in-`S`

.

`VectorFunctionizeBridge{T, S}`

The `VectorFunctionizeBridge`

converts a constraint `VectorOfVariables`

-in-`S`

into the constraint `VectorAffineFunction{T}`

-in-`S`

.

`SplitIntervalBridge{T}`

The `SplitIntervalBridge`

splits a constraint $l ≤ ⟨a, x⟩ + α ≤ u$ into the constraints $⟨a, x⟩ + α ≥ l$ and $⟨a, x⟩ + α ≤ u$.

`RSOCBridge{T, F, G}`

The `RotatedSecondOrderCone`

is `SecondOrderCone`

representable; see [1, p. 104]. Indeed, we have $2tu = (t/√2 + u/√2)^2 - (t/√2 - u/√2)^2$ hence

is equivalent to

We can therefore use the transformation $(t, u, x) \mapsto (t/√2+u/√2, t/√2-u/√2, x)$. Note that the linear transformation is a symmetric involution (i.e. it is its own transpose and its own inverse). That means in particular that the norm is of constraint primal and duals are preserved by the tranformation.

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. *Lectures on modern convex optimization: analysis, algorithms, and engineering applications*. Society for Industrial and Applied Mathematics, 2001.

`QuadtoSOCBridge{T}`

The set of points `x`

satisfying the constraint

is a convex set if `Q`

is positive semidefinite and is the union of two convex cones if `a`

and `b`

are zero (i.e. *homogeneous* case) and `Q`

has only one negative eigenvalue. Currently, only the non-homogeneous transformation is implemented, see the Note section below for more details.

**Non-homogeneous case**

If `Q`

is positive semidefinite, there exists `U`

such that $Q = U^T U$, the inequality can then be rewritten as

which is equivalent to the membership of `(1, -a^T x - b, Ux)`

to the rotated second-order cone.

**Homogeneous case**

If `Q`

has only one negative eigenvalue, the set of `x`

such that $x^T Q x \le 0$ is the union of a convex cone and its opposite. We can choose which one to model by checking the existence of bounds on variables as shown below.

**Second-order cone**

If `Q`

is diagonal and has eigenvalues `(1, 1, -1)`

, the inequality $x^2 + x^2 \le z^2$ combined with $z \ge 0$ defines the Lorenz cone (i.e. the second-order cone) but when combined with $z \le 0$, it gives the opposite of the second order cone. Therefore, we need to check if the variable `z`

has a lower bound 0 or an upper bound 0 in order to determine which cone is

**Rotated second-order cone**

The matrix `Q`

corresponding to the inequality $x^2 \le 2yz$ has one eigenvalue 1 with eigenvectors `(1, 0, 0)`

and `(0, 1, -1)`

and one eigenvalue `-1`

corresponding to the eigenvector `(0, 1, 1)`

. Hence if we intersect this union of two convex cone with the halfspace $x + y \ge 0$, we get the rotated second-order cone and if we intersect it with the halfspace $x + y \le 0$ we get the opposite of the rotated second-order cone. Note that `y`

and `z`

have the same sign since `yz`

is nonnegative hence $x + y \ge 0$ is equivalent to $x \ge 0$ and $y \ge 0$.

**Note**

The check for existence of bound can be implemented (but inefficiently) with the current interface but if bound is removed or transformed (e.g. `≤ 0`

transformed into `≥ 0`

) then the bridge is no longer valid. For this reason the homogeneous version of the bridge is not implemented yet.

`GeoMeanBridge{T}`

The `GeometricMeanCone`

is `SecondOrderCone`

representable; see [1, p. 105]. The reformulation is best described in an example. Consider the cone of dimension 4

This can be rewritten as $\exists x_{21} \ge 0$ such that

Note that we need to create $x_{21}$ and not use $t^4$ directly as $t$ is allowed to be negative. Now, this is equivalent to

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. *Lectures on modern convex optimization: analysis, algorithms, and engineering applications*. Society for Industrial and Applied Mathematics, 2001.

```
SquareBridge{T, F<:MOI.AbstractVectorFunction,
G<:MOI.AbstractScalarFunction,
TT<:MOI.AbstractSymmetricMatrixSetTriangle,
ST<:MOI.AbstractSymmetricMatrixSetSquare} <: AbstractBridge
```

The `SquareBridge`

reformulates the constraint of a square matrix to be in `ST`

to a list of equality constraints for pair or off-diagonal entries with different expressions and a `TT`

constraint the upper triangular part of the matrix.

For instance, the constraint for the matrix

to be PSD can be broken down to the constraint of the symmetric matrix

and the equality constraint between the off-diagonal entries (2, 3) and (3, 2) $2x == 1$. Note that now symmetrization constraint need to be added between the off-diagonal entries (1, 2) and (2, 1) or between (1, 3) and (3, 1) since the expressions are the same.

`RootDetBridge{T}`

The `RootDetConeTriangle`

is representable by a `PositiveSemidefiniteConeTriangle`

and an `GeometricMeanCone`

constraints; see [1, p. 149]. Indeed, $t \le \det(X)^{1/n}$ if and only if there exists a lower triangular matrix $Δ$ such that

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. *Lectures on modern convex optimization: analysis, algorithms, and engineering applications*. Society for Industrial and Applied Mathematics, 2001.

`LogDetBridge{T}`

The `LogDetConeTriangle`

is representable by a `PositiveSemidefiniteConeTriangle`

and `ExponentialCone`

constraints. Indeed, $\log\det(X) = \log(\delta_1) + \cdots + \log(\delta_n)$ where $\delta_1$, ..., $\delta_n$ are the eigenvalues of $X$. Adapting the method from [1, p. 149], we see that $t \le u \log(\det(X/u))$ for $u > 0$ if and only if there exists a lower triangular matrix $Δ$ such that

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. *Lectures on modern convex optimization: analysis, algorithms, and engineering applications*. Society for Industrial and Applied Mathematics, 2001. ```

The `SOCtoPSDBridge`

transforms the second order cone constraint $\lVert x \rVert \le t$ into the semidefinite cone constraints

Indeed by the Schur Complement, it is positive definite iff

which is equivalent to

The `RSOCtoPSDBridge`

transforms the second order cone constraint $\lVert x \rVert \le 2tu$ with $u \ge 0$ into the semidefinite cone constraints

Indeed by the Schur Complement, it is positive definite iff

which is equivalent to

`IndicatorActiveOnFalseBridge{T}`

The `IndicatorActiveOnFalseBridge`

replaces an indicator constraint activated on 0 with a variable $z_0$ with the constraint activated on 1, with a variable $z_1$. It stores the added `variable_index`

and added constraints:

- $z_1 \in \mathbb{B}$ in
`zero_one_cons`

- $z_0 + z_1 == 1$ in `
`in`

disjunction_cons` - The added
`ACTIVATE_ON_ONE`

indicator constraint in`indicator_cons_index`

.

For each bridge defined in this package, a corresponding `Bridges.Constraint.SingleBridgeOptimizer`

is available with the same name without the "Bridge" suffix, e.g., `SplitInterval`

is a `SingleBridgeOptimizer`

for the `SplitIntervalBridge`

. Moreover, they are all added in the `Bridges.LazyBridgeOptimizer`

returned by `Bridges.full_bridge_optimizer`

as it calls `Bridges.Constraint.add_all_bridges`

.

`SingleBridgeOptimizer{BT<:AbstractBridge, OT<:MOI.ModelLike} <: AbstractBridgeOptimizer`

The `SingleBridgeOptimizer`

bridges any constraint supported by the bridge `BT`

. This is in contrast with the `MathOptInterface.Bridges.LazyBridgeOptimizer`

which only bridges the constraints that are unsupported by the internal model, even if they are supported by one of its bridges.

`add_all_bridges(bridged_model, T::Type)`

Add all bridges defined in the `Bridges.Constraint`

submodule to `bridged_model`

. The coefficient type used is `T`

.

### Bridge interface

A bridge should implement the following functions to be usable by a bridge optimizer:

`added_constrained_variable_types(BT::Type{<:Variable.AbstractBridge})::Bool`

Return a list of the types of constrained variables that bridges of concrete type `BT`

add. This is used by the `LazyBridgeOptimizer`

.

`MathOptInterface.Bridges.added_constraint_types`

— Function.`added_constraint_types(BT::Type{<:Constraint.AbstractBridge})::Bool`

Return a list of the types of constraints that bridges of concrete type `BT`

add. This is used by the `LazyBridgeOptimizer`

.

Additionally, variable bridges should implement:

```
supports_constrained_variable(::Type{<:AbstractBridge},
::Type{<:MOI.AbstractSet})::Bool
```

Return a `Bool`

indicating whether the bridges of type `BT`

support bridging constrained variables in `S`

.

```
concrete_bridge_type(BT::Type{<:AbstractBridge},
S::Type{<:MOI.AbstractSet})::DataType
```

Return the concrete type of the bridge supporting variables in `S`

constraints. This function can only be called if `MOI.supports_constrained_variable(BT, S)`

is `true`

.

**Examples**

As a variable in `MathOptInterface.GreaterThan`

is bridged into variables in `MathOptInterface.Nonnegatives`

by the `VectorizeBridge`

,

```
BT = MOI.Bridges.Variable.VectorizeBridge{Float64}
S = MOI.GreaterThan{Float64}
MOI.Bridges.Variable.concrete_bridge_type(BT, S)
# output
MOI.Bridges.Variable.VectorizeBridge{Float64,MOI.Nonnegatives}
```

```
bridge_constrained_variable(BT::Type{<:AbstractBridge}, model::MOI.ModelLike,
set::MOI.AbstractSet)
```

Bridge the constrained variable in `set`

using bridge `BT`

to `model`

and returns a bridge object of type `BT`

. The bridge type `BT`

should be a concrete type, that is, all the type parameters of the bridge should be set. Use `concrete_bridge_type`

to obtain a concrete type for given set types.

and constraint bridges should implement

`MathOptInterface.supports_constraint`

— Method.`MOI.supports_constraint(BT::Type{<:AbstractBridge}, F::Type{<:MOI.AbstractFunction}, S::Type{<:MOI.AbstractSet})::Bool`

Return a `Bool`

indicating whether the bridges of type `BT`

support bridging `F`

-in-`S`

constraints.

```
concrete_bridge_type(BT::Type{<:AbstractBridge},
F::Type{<:MOI.AbstractFunction},
S::Type{<:MOI.AbstractSet})::DataType
```

Return the concrete type of the bridge supporting `F`

-in-`S`

constraints. This function can only be called if `MOI.supports_constraint(BT, F, S)`

is `true`

.

**Examples**

As a `MathOptInterface.SingleVariable`

-in-`MathOptInterface.Interval`

constraint is bridged into a `MathOptInterface.SingleVariable`

-in-`MathOptInterface.GreaterThan`

and a `MathOptInterface.SingleVariable`

-in-`MathOptInterface.LessThan`

by the `SplitIntervalBridge`

,

```
BT = MOI.Bridges.Constraint.SplitIntervalBridge{Float64}
F = MOI.SingleVariable
S = MOI.Interval{Float64}
MOI.Bridges.Constraint.concrete_bridge_type(BT, F, S)
# output
MOI.Bridges.Constraint.SplitIntervalBridge{Float64,MOI.SingleVariable}
```

```
bridge_constraint(BT::Type{<:AbstractBridge}, model::MOI.ModelLike,
func::AbstractFunction, set::MOI.AbstractSet)
```

Bridge the constraint `func`

-in-`set`

using bridge `BT`

to `model`

and returns a bridge object of type `BT`

. The bridge type `BT`

should be a concrete type, that is, all the type parameters of the bridge should be set. Use `concrete_bridge_type`

to obtain a concrete type for given function and set types.

When querying the `NumberOfVariables`

, `NumberOfConstraints`

and `ListOfConstraintIndices`

, the variables and constraints created by the bridges in the underlying model are hidden by the bridge optimizer. For this purpose, the bridge should provide access to the variables and constraints it has creates by implemented the following methods of `get`

:

`MathOptInterface.get`

— Method.`MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)`

The number of variables created by the bridge `b`

in the model.

`MathOptInterface.get`

— Method.`MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)`

The list of variables created by the bridge `b`

in the model.

`MathOptInterface.get`

— Method.`MOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F, S}) where {F, S}`

The number of constraints of the type `F`

-in-`S`

created by the bridge `b`

in the model.

`MathOptInterface.get`

— Method.`MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F, S}) where {F, S}`

A `Vector{ConstraintIndex{F,S}}`

with indices of all constraints of type `F`

-in`S`

created by the bride `b`

in the model (i.e., of length equal to the value of `NumberOfConstraints{F,S}()`

).

## Copy utilities

The following utilities can be used to implement `copy_to`

. See Implementing copy for more details.

`MathOptInterface.Utilities.automatic_copy_to`

— Function.```
automatic_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike;
copy_names::Bool=true)
```

Use `Utilities.supports_default_copy_to`

and `Utilities.supports_allocate_load`

to automatically choose between `Utilities.default_copy_to`

or `Utilities.allocate_load`

to apply the copy operation.

`MathOptInterface.Utilities.default_copy_to`

— Function.`default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike, copy_names::Bool)`

Implements `MOI.copy_to(dest, src)`

by adding the variables and then the constraints and attributes incrementally. The function `supports_default_copy_to`

can be used to check whether `dest`

supports the copying a model incrementally.

`supports_default_copy_to(model::ModelLike, copy_names::Bool)`

Return a `Bool`

indicating whether the model `model`

supports `default_copy_to(model, src, copy_names=copy_names)`

if all the attributes set to `src`

and constraints added to `src`

are supported by `model`

.

This function can be used to determine whether a model can be loaded into `model`

incrementally or whether it should be cached and copied at once instead. This is used by JuMP to determine whether to add a cache or not in two situations:

- A first cache can be used to store the model as entered by the user as well as the names of variables and constraints. This cache is created if this function returns
`false`

when`copy_names`

is`true`

. - If bridges are used, then a second cache can be used to store the bridged model with unnamed variables and constraints. This cache is created if this function returns
`false`

when`copy_names`

is`false`

.

**Examples**

If `MathOptInterface.set`

, `MathOptInterface.add_variable`

and `MathOptInterface.add_constraint`

are implemented for a model of type `MyModel`

and names are supported, then `MathOptInterface.copy_to`

can be implemented as

```
MOI.Utilities.supports_default_copy_to(model::MyModel, copy_names::Bool) = true
function MOI.copy_to(dest::MyModel, src::MOI.ModelLike; kws...)
return MOI.Utilities.automatic_copy_to(dest, src; kws...)
end
```

The `Utilities.automatic_copy_to`

function automatically redirects to `Utilities.default_copy_to`

.

If names are not supported, simply change the first line by

`MOI.supports_default_copy_to(model::MyModel, copy_names::Bool) = !copy_names`

The `Utilities.default_copy_to`

function automatically throws an helpful error in case `copy_to`

is called with `copy_names`

equal to `true`

.

### Allocate-Load API

The Allocate-Load API allows solvers that do not support loading the problem incrementally to implement `copy_to`

in a way that still allows transformations to be applied in the copy between the cache and the model if the transformations are implemented as MOI layers implementing the Allocate-Load API, see Implementing copy for more details.

Loading a model using the Allocate-Load interface consists of two passes through the model data:

- the allocate pass where the model typically records the necessary information about the constraints and attributes such as their number and size. This information may be used by the solver to allocate datastructures of appropriate size.
- the load pass where the model typically loads the constraint and attribute data to the model.

The description above only gives a suggestion of what to achieve in each pass. In fact the exact same constraint and attribute data is provided to each pass, so an implementation of the Allocate-Load API is free to do whatever is more convenient in each pass.

The main difference between each pass, apart from the fact that one is executed before the other during a copy, is that the allocate pass needs to create and return new variable and constraint indices, while during the load pass the appropriate constraint indices are provided.

The Allocate-Load API is **not** meant to be used outside a copy operation, that is, the interface is not meant to be used to create new constraints with `Utilities.allocate_constraint`

followed by `Utilities.load_constraint`

after a solve. This means that the order in which the different functions of the API are called is fixed by `Utilities.allocate_load`

and models implementing the API can rely on the fact that functions will be called in this order. That is, it can be assumed that the different functions will the called in the following order:

`Utilities.allocate_variables`

`Utilities.allocate`

and`Utilities.allocate_constraint`

`Utilities.load_variables`

`Utilities.load`

and`Utilities.load_constraint`

`MathOptInterface.Utilities.allocate_load`

— Function.`allocate_load(dest::MOI.ModelLike, src::MOI.ModelLike)`

Implements `MOI.copy_to(dest, src)`

using the Allocate-Load API. The function `supports_allocate_load`

can be used to check whether `dest`

supports the Allocate-Load API.

`supports_allocate_load(model::MOI.ModelLike, copy_names::Bool)::Bool`

Return a `Bool`

indicating whether `model`

supports `allocate_load(model, src, copy_names=copy_names)`

if all the attributes set to `src`

and constraints added to `src`

are supported by `model`

.

`MathOptInterface.Utilities.allocate_variables`

— Function.`allocate_variables(model::MOI.ModelLike, nvars::Integer)`

Creates `nvars`

variables and returns a vector of `nvars`

variable indices.

`MathOptInterface.Utilities.allocate`

— Function.```
allocate(model::ModelLike, attr::ModelLikeAttribute, value)
allocate(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex, value)
allocate(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex, value)
```

Informs `model`

that `load`

will be called with the same arguments after `load_variables`

is called.

`MathOptInterface.Utilities.allocate_constraint`

— Function.`allocate_constraint(model::MOI.ModelLike, f::MOI.AbstractFunction, s::MOI.AbstractSet)`

Returns the index for the constraint to be used in `load_constraint`

that will be called after `load_variables`

is called.

`MathOptInterface.Utilities.load_variables`

— Function.`load_variables(model::MOI.ModelLike, nvars::Integer)`

Prepares `model`

for `load`

and `load_constraint`

.

`MathOptInterface.Utilities.load`

— Function.```
load(model::ModelLike, attr::ModelLikeAttribute, value)
load(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex, value)
load(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex, value)
```

This has the same effect that `set`

with the same arguments except that `allocate`

should be called first before `load_variables`

.

`MathOptInterface.Utilities.load_constraint`

— Function.`load_constraint(model::MOI.ModelLike, ci::MOI.ConstraintIndex, f::MOI.AbstractFunction, s::MOI.AbstractSet)`

Sets the constraint function and set for the constraint of index `ci`

.

### Caching optimizer

Some solvers do not support incremental definition of optimization models. Nevertheless, you are still able to build incrementally an optimization model with such solvers. MathOptInterface provides a utility, `Utilities.CachingOptimizer`

, that will store in a `ModelLike`

the optimization model during its incremental definition. Once the model is completely defined, the `CachingOptimizer`

specifies all problem information to the underlying solver, all at once.

The function `Utilities.state`

allows to query the state of the optimizer cached inside a `CachingOptimizer`

. The state could be:

`NO_OPTIMIZER`

, if no optimizer is attached;`EMPTY_OPTIMIZER`

, if the attached optimizer is empty;`ATTACHED_OPTIMIZER`

, if the attached optimizer is synchronized with the cached model defined in`CachingOptimizer`

.

The following methods modify the state of the attached optimizer:

`Utilities.attach_optimizer`

attachs a new`optimizer`

to a`cached_optimizer`

with state`EMPTY_OPTIMIZER`

. The state of`cached_optimizer`

is set to`ATTACHED_OPTIMIZER`

after the call.`Utilities.drop_optimizer`

drops the underlying`optimizer`

from`cached_optimizer`

, without emptying it. The state of`cached_optimizer`

is set to`NO_OPTIMIZER`

after the call.`Utilities.reset_optimizer`

empties`optimizer`

inside`cached_optimizer`

, without droping it. The state of`cached_optimizer`

is set to`EMPTY_OPTIMIZER`

after the call.

The way to operate a `CachingOptimizer`

depends whether the mode is set to `AUTOMATIC`

or to `MANUAL`

.

- In
`MANUAL`

mode, the state of the`CachingOptimizer`

changes only if the methods`Utilities.attach_optimizer`

,`Utilities.reset_optimizer`

or`Utilities.drop_optimizer`

are being called. Any unattended operation results in an error. - In
`AUTOMATIC`

mode, the state of the`CachingOptimizer`

changes when necessary. Any modification not supported by the solver (e.g. dropping a constraint) results in a drop to the state`EMPTY_OPTIMIZER`

.

When calling `Utilities.attach_optimizer`

, the `CachingOptimizer`

copies the cached model to the optimizer with `copy_to`

. We refer to Implementing copy for more details.

`CachingOptimizer`

`CachingOptimizer`

is an intermediate layer that stores a cache of the model and links it with an optimizer. It supports incremental model construction and modification even when the optimizer doesn't.

A `CachingOptimizer`

may be in one of three possible states (`CachingOptimizerState`

):

`NO_OPTIMIZER`

: The CachingOptimizer does not have any optimizer.`EMPTY_OPTIMIZER`

: The CachingOptimizer has an empty optimizer. The optimizer is not synchronized with the cached model.`ATTACHED_OPTIMIZER`

: The CachingOptimizer has an optimizer, and it is synchronized with the cached model.

A `CachingOptimizer`

has two modes of operation (`CachingOptimizerMode`

):

`MANUAL`

: The only methods that change the state of the`CachingOptimizer`

are`Utilities.reset_optimizer`

,`Utilities.drop_optimizer`

, and`Utilities.attach_optimizer`

. Attempting to perform an operation in the incorrect state results in an error.`AUTOMATIC`

: The`CachingOptimizer`

changes its state when necessary. For example,`optimize!`

will automatically call`attach_optimizer`

(an optimizer must have been previously set). Attempting to add a constraint or perform a modification not supported by the optimizer results in a drop to`EMPTY_OPTIMIZER`

mode.

`MathOptInterface.Utilities.attach_optimizer`

— Function.`attach_optimizer(model::CachingOptimizer)`

Attaches the optimizer to `model`

, copying all model data into it. Can be called only from the `EMPTY_OPTIMIZER`

state. If the copy succeeds, the `CachingOptimizer`

will be in state `ATTACHED_OPTIMIZER`

after the call, otherwise an error is thrown; see `MathOptInterface.copy_to`

for more details on which errors can be thrown.

`MathOptInterface.Utilities.reset_optimizer`

— Function.`reset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer)`

Sets or resets `m`

to have the given empty optimizer. Can be called from any state. The `CachingOptimizer`

will be in state `EMPTY_OPTIMIZER`

after the call.

`reset_optimizer(m::CachingOptimizer)`

Detaches and empties the current optimizer. Can be called from `ATTACHED_OPTIMIZER`

or `EMPTY_OPTIMIZER`

state. The `CachingOptimizer`

will be in state `EMPTY_OPTIMIZER`

after the call.

`MathOptInterface.Utilities.drop_optimizer`

— Function.`drop_optimizer(m::CachingOptimizer)`

Drops the optimizer, if one is present. Can be called from any state. The `CachingOptimizer`

will be in state `NO_OPTIMIZER`

after the call.

`MathOptInterface.Utilities.state`

— Function.`state(m::CachingOptimizer)::CachingOptimizerState`

Returns the state of the CachingOptimizer `m`

. See `Utilities.CachingOptimizer`

.

`MathOptInterface.Utilities.mode`

— Function.`mode(m::CachingOptimizer)::CachingOptimizerMode`

Returns the operating mode of the CachingOptimizer `m`

. See `Utilities.CachingOptimizer`

.

## Function utilities

The following utilities are available for functions:

`MathOptInterface.Utilities.eval_variables`

— Function.`eval_variables(varval::Function, f::AbstractFunction)`

Returns the value of function `f`

if each variable index `vi`

is evaluated as `varval(vi)`

. Note that `varval`

should return a number, see `substitute_variables`

for a similar function where `varval`

returns a function.

`MathOptInterface.Utilities.map_indices`

— Function.`map_indices(index_map::Function, x)`

Substitute any `MOI.VariableIndex`

(resp. `MOI.ConstraintIndex`

) in `x`

by the `MOI.VariableIndex`

(resp. `MOI.ConstraintIndex`

) of the same type given by `index_map(x)`

.

This function is used by implementations of `MOI.copy_to`

on constraint functions, attribute values and submittable values hence it needs to be implemented for custom types that are meant to be used as attribute or submittable value.

`MathOptInterface.Utilities.substitute_variables`

— Function.`substitute_variables(variable_map::Function, x)`

Substitute any `MOI.VariableIndex`

in `x`

by `variable_map(x)`

. The `variable_map`

function returns either `MOI.SingleVariable`

or `MOI.ScalarAffineFunction`

, see `eval_variables`

for a similar function where `variable_map`

returns a number.

This function is used by bridge optimizers on constraint functions, attribute values and submittable values when at least one variable bridge is used hence it needs to be implemented for custom types that are meant to be used as attribute or submittable value.

`MathOptInterface.Utilities.remove_variable`

— Function.`remove_variable(f::AbstractFunction, vi::VariableIndex)`

Return a new function `f`

with the variable vi removed.

`MathOptInterface.Utilities.all_coefficients`

— Function.`all_coefficients(p::Function, f::MOI.AbstractFunction)`

Determine whether predicate `p`

returns `true`

for all coefficients of `f`

, returning `false`

as soon as the first coefficient of `f`

for which `p`

returns `false`

is encountered (short-circuiting). Similar to `all`

.

`MathOptInterface.Utilities.unsafe_add`

— Function.`unsafe_add(t1::MOI.ScalarAffineTerm, t2::MOI.ScalarAffineTerm)`

Sums the coefficients of `t1`

and `t2`

and returns an output `MOI.ScalarAffineTerm`

. It is unsafe because it uses the `variable_index`

of `t1`

as the `variable_index`

of the output without checking that it is equal to that of `t2`

.

`unsafe_add(t1::MOI.ScalarQuadraticTerm, t2::MOI.ScalarQuadraticTerm)`

Sums the coefficients of `t1`

and `t2`

and returns an output `MOI.ScalarQuadraticTerm`

. It is unsafe because it uses the `variable_index`

's of `t1`

as the `variable_index`

's of the output without checking that they are the same (up to permutation) to those of `t2`

.

`unsafe_add(t1::MOI.VectorAffineTerm, t2::MOI.VectorAffineTerm)`

Sums the coefficients of `t1`

and `t2`

and returns an output `MOI.VectorAffineTerm`

. It is unsafe because it uses the `output_index`

and `variable_index`

of `t1`

as the `output_index`

and `variable_index`

of the output term without checking that they are equal to those of `t2`

.

`MathOptInterface.Utilities.isapprox_zero`

— Function.`isapprox_zero(f::MOI.AbstractFunction, tol)`

Return a `Bool`

indicating whether the function `f`

is approximately zero using `tol`

as a tolerance.

**Important note**

This function assumes that `f`

does not contain any duplicate terms, you might want to first call `canonical`

if that is not guaranteed. For instance, given

`f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, -1], [x, x]), 0)`.`

then `isapprox_zero(f)`

is `false`

but `isapprox_zero(MOIU.canonical(f))`

is `true`

.

`MathOptInterface.Utilities.modify_function`

— Function.`modify_function(f::AbstractFunction, change::AbstractFunctionModification)`

Return a new function `f`

modified according to `change`

.

The following functions can be used to canonicalize a function:

`MathOptInterface.Utilities.is_canonical`

— Function.```
is_canonical(f::Union{ScalarAffineFunction, ScalarQuadraticFunction
VectorAffineFunction, VectorQuadraticTerm})
```

Returns a Bool indicating whether the function is in canonical form. See `canonical`

.

`MathOptInterface.Utilities.canonical`

— Function.```
canonical(f::Union{ScalarAffineFunction, VectorAffineFunction,
ScalarQuadraticFunction, VectorQuadraticFunction})
```

Returns the function in a canonical form, i.e.

- A term appear only once.
- The coefficients are nonzero.
- The terms appear in increasing order of variable where there the order of the variables is the order of their value.
- For a
`AbstractVectorFunction`

, the terms are sorted in ascending order of output index.

**Examples**

If `x`

(resp. `y`

, `z`

) is `VariableIndex(1)`

(resp. 2, 3). The canonical representation of `ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5)`

is `ScalarAffineFunction([x, y], [-1, 2], 5)`

.

`MathOptInterface.Utilities.canonicalize!`

— Function.`canonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})`

Convert a function to canonical form in-place, without allocating a copy to hold the result. See `canonical`

.

`canonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})`

Convert a function to canonical form in-place, without allocating a copy to hold the result. See `canonical`

.

The following functions can be used to manipulate functions with basic algebra:

`MathOptInterface.Utilities.scalar_type`

— Function.`scalar_type(F::Type{<:MOI.AbstractVectorFunction})`

Type of functions obtained by indexing objects obtained by calling `eachscalar`

on functions of type `F`

.

`MathOptInterface.Utilities.promote_operation`

— Function.```
promote_operation(op::Function, ::Type{T},
ArgsTypes::Type{<:Union{T, MOI.AbstractFunction}}...) where T
```

Returns the type of the `MOI.AbstractFunction`

returned to the call `operate(op, T, args...)`

where the types of the arguments `args`

are `ArgsTypes`

.

`MathOptInterface.Utilities.operate`

— Function.```
operate(op::Function, ::Type{T},
args::Union{T, MOI.AbstractFunction}...)::MOI.AbstractFunction where T
```

Returns an `MOI.AbstractFunction`

representing the function resulting from the operation `op(args...)`

on functions of coefficient type `T`

. No argument can be modified.

`MathOptInterface.Utilities.operate!`

— Function.```
operate!(op::Function, ::Type{T},
args::Union{T, MOI.AbstractFunction}...)::MOI.AbstractFunction where T
```

Returns an `MOI.AbstractFunction`

representing the function resulting from the operation `op(args...)`

on functions of coefficient type `T`

. The first argument can be modified. The return type is the same than the method `operate(op, T, args...)`

without `!`

.

`MathOptInterface.Utilities.operate_output_index!`

— Function.```
operate_output_index!(
op::Function, ::Type{T}, output_index::Integer,
func::MOI.AbstractVectorFunction
args::Union{T, MOI.AbstractScalarFunction}...)::MOI.AbstractFunction where T
```

Returns an `MOI.AbstractVectorFunction`

where the function at `output_index`

is the result of the operation `op`

applied to the function at `output_index`

of `func`

and `args`

. The functions at output index different to `output_index`

are the same as the functions at the same output index in `func`

. The first argument can be modified.

`MathOptInterface.Utilities.vectorize`

— Function.`vectorize(funcs::AbstractVector{MOI.SingleVariable})`

Returns the vector of scalar affine functions in the form of a `MOI.VectorAffineFunction{T}`

.

`vectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where T`

Returns the vector of scalar affine functions in the form of a `MOI.VectorAffineFunction{T}`

.

`vectorize(funcs::AbstractVector{MOI.ScalarQuadraticFunction{T}}) where T`

Returns the vector of scalar quadratic functions in the form of a `MOI.VectorQuadraticFunction{T}`

.

## Constraint utilities

The following utilities are available for moving the function constant to the set for scalar constraints:

`MathOptInterface.Utilities.shift_constant`

— Function.```
shift_constant(set::MOI.AbstractScalarSet,
offset)
```

Returns a new scalar set `new_set`

such that `func`

-in-`set`

is equivalent to `func + offset`

-in-`new_set`

.

**Examples**

The call `shift_constant(MOI.Interval(-2, 3), 1)`

is equal to `MOI.Interval(-1, 4)`

.

```
normalize_and_add_constraint(model::MOI.ModelLike,
func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false)
```

Adds the scalar constraint obtained by moving the constant term in `func`

to the set in `model`

. If `allow_modify_function`

is `true`

then the function `func`

can be modified.

`MathOptInterface.Utilities.normalize_constant`

— Function.```
normalize_constant(func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false)
```

Return the `func`

-in-`set`

constraint in normalized form. That is, if `func`

is `MOI.ScalarQuadraticFunction`

or `MOI.ScalarAffineFunction`

, the constant is moved to the set. If `allow_modify_function`

is `true`

then the function `func`

can be modified.

## Benchmarks

Functions to help benchmark the performance of solver wrappers. See Benchmarking for more details.

`MathOptInterface.Benchmarks.suite`

— Function.```
suite(
new_model::Function;
exclude::Vector{Regex} = Regex[]
)
```

Create a suite of benchmarks. `new_model`

should be a function that takes no arguments, and returns a new instance of the optimizer you wish to benchmark.

Use `exclude`

to exclude a subset of benchmarks.

**Examples**

```
suite() do
GLPK.Optimizer()
end
suite(exclude = [r"delete"]) do
Gurobi.Optimizer(OutputFlag=0)
end
```

`MathOptInterface.Benchmarks.create_baseline`

— Function.`create_baseline(suite, name::String; directory::String = ""; kwargs...)`

Run all benchmarks in `suite`

and save to files called `name`

in `directory`

.

Extra `kwargs`

are based to `BenchmarkTools.run`

.

**Examples**

```
my_suite = suite(() -> GLPK.Optimizer())
create_baseline(my_suite, "glpk_master"; directory = "/tmp", verbose = true)
```

```
compare_against_baseline(
suite, name::String; directory::String = "",
report_filename::String = "report.txt"
)
```

Run all benchmarks in `suite`

and compare against files called `name`

in `directory`

that were created by a call to `create_baseline`

.

A report summarizing the comparison is written to `report_filename`

in `directory`

.

Extra `kwargs`

are based to `BenchmarkTools.run`

.

**Examples**

```
my_suite = suite(() -> GLPK.Optimizer())
compare_against_baseline(
my_suite, "glpk_master"; directory = "/tmp", verbose = true
)
```