# Variables

## Functions

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

.

**Example**

```
julia> import MathOptInterface as MOI
julia> model = MOI.Utilities.Model{Float64}();
julia> x = MOI.add_variable(model)
MOI.VariableIndex(1)
```

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

An `AddVariableNotAllowed`

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

.

**Example**

```
julia> import MathOptInterface as MOI
julia> model = MOI.Utilities.Model{Float64}();
julia> MOI.add_variables(model, 2)
2-element Vector{MathOptInterface.VariableIndex}:
MOI.VariableIndex(1)
MOI.VariableIndex(2)
```

`MathOptInterface.add_constrained_variable`

— Function```
add_constrained_variable(
model::ModelLike,
set::AbstractScalarSet
)::Tuple{MOI.VariableIndex,
MOI.ConstraintIndex{MOI.VariableIndex, 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`

.

```
add_constrained_variable(
model::ModelLike,
set::Tuple{<:GreaterThan,<:LessThan},
)
```

A special-case method to add a scalar variable with a lower and upper bound.

This method should be implemented by optimizers which have native support for adding a variable with bounds and which cannot performantly modify the variable bounds after creation.

**Example**

```
julia> import MathOptInterface as MOI
julia> model = MOI.Utilities.Model{Float64}();
julia> set = (MOI.GreaterThan(1.0), MOI.LessThan(2.0));
julia> x, (c_l, c_u) = MOI.add_constrained_variable(model, set);
julia> c_l
MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)
julia> c_u
MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64}}(1)
julia> print(model)
Feasibility
Subject to:
VariableIndex-in-GreaterThan{Float64}
v[1] >= 1.0
VariableIndex-in-LessThan{Float64}
v[1] <= 2.0
```

`MathOptInterface.add_constrained_variables`

— Function```
add_constrained_variables(
model::ModelLike,
sets::AbstractVector{<:AbstractScalarSet}
)::Tuple{
Vector{MOI.VariableIndex},
Vector{MOI.ConstraintIndex{MOI.VariableIndex,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`

.

`MathOptInterface.supports_add_constrained_variable`

— Function```
supports_add_constrained_variable(
model::ModelLike,
S::Type{<:AbstractScalarSet}
)::Bool
```

Return a `Bool`

indicating whether `model`

supports constraining a variable to belong to a set of type `S`

either on creation of the variable with `add_constrained_variable`

or after the variable is created with `add_constraint`

.

By default, this function falls back to `supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VariableIndex, S)`

which is the correct definition for most models.

**Example**

Suppose that a solver supports only two kind of variables: binary variables and continuous variables with a lower bound. If the solver decides not to support `VariableIndex`

-in-`Binary`

and `VariableIndex`

-in-`GreaterThan`

constraints, it only has to implement `add_constrained_variable`

for these two sets which prevents the user to add both a binary constraint and a lower bound on the same variable. Moreover, if the user adds a `VariableIndex`

-in-`GreaterThan`

constraint, implementing this interface (that is, `supports_add_constrained_variables`

) enables the constraint to be transparently bridged into a supported constraint.

`MathOptInterface.supports_add_constrained_variables`

— Function```
supports_add_constrained_variables(
model::ModelLike,
S::Type{<:AbstractVectorSet}
)::Bool
```

Return a `Bool`

indicating whether `model`

supports constraining a vector of variables to belong to a set of type `S`

either on creation of the vector of variables with `add_constrained_variables`

or after the variable is created with `add_constraint`

.

By default, if `S`

is `Reals`

then this function returns `true`

and otherwise, it falls back to `supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VectorOfVariables, S)`

which is the correct definition for most models.

**Example**

In the standard conic form (see Duality), the variables are grouped into several cones and the constraints are affine equality constraints. If `Reals`

is not one of the cones supported by the solvers then it needs to implement `supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false`

as free variables are not supported. The solvers should then implement `supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedCones}) = true`

where `SupportedCones`

is the union of all cone types that are supported; it does not have to implement the method `supports_constraint(::Type{VectorOfVariables}, Type{<:SupportedCones})`

as it should return `false`

and it's the default. This prevents the user to constrain the same variable in two different cones. When a `VectorOfVariables`

-in-`S`

is added, the variables of the vector have already been created so they already belong to given cones. If bridges are enabled, the constraint will therefore be bridged by adding slack variables in `S`

and equality constraints ensuring that the slack variables are equal to the corresponding variables of the given constraint function.

Note that there may also be sets for which `!supports_add_constrained_variables(model, S)`

and `supports_constraint(model, MOI.VectorOfVariables, S)`

. For instance, suppose a solver supports positive semidefinite variable constraints and two types of variables: binary variables and nonnegative variables. Then the solver should support adding `VectorOfVariables`

-in-`PositiveSemidefiniteConeTriangle`

constraints, but it should not support creating variables constrained to belong to the `PositiveSemidefiniteConeTriangle`

because the variables in `PositiveSemidefiniteConeTriangle`

should first be created as either binary or non-negative.

`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.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, that is, it is substituted for zero. - For each
`func`

-in-`set`

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

and`func == index`

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

and`index in func.variables`

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

is one, the constraint is deleted; - if
`length(func.variables) > 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`

, that is, it is substituted for zero.

- If

`MathOptInterface.delete`

— Method`delete(model::ModelLike, indices::Vector{R<:Index}) where {R}`

Delete the referenced objects in the vector `indices`

from the model. It may be assumed that `R`

is a concrete type. The default fallback sequentially deletes the individual items in `indices`

, although specialized implementations may be more efficient.

## Attributes

`MathOptInterface.AbstractVariableAttribute`

— Type`AbstractVariableAttribute`

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

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

`MathOptInterface.VariablePrimalStart`

— Type`VariablePrimalStart()`

A variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve. May be a number or `nothing`

(unset).

`MathOptInterface.VariablePrimal`

— Type`VariablePrimal(result_index::Int = 1)`

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

. If `result_index`

is omitted, it is 1 by default.

If the solver does not have a primal value for the variable because the `result_index`

is beyond the available solutions (whose number is indicated by the `ResultCount`

attribute), getting this attribute must throw a `ResultIndexBoundsError`

. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check `PrimalStatus`

before accessing the `VariablePrimal`

attribute.

See `ResultCount`

for information on how the results are ordered.

`MathOptInterface.VariableBasisStatus`

— Type`VariableBasisStatus(result_index::Int = 1)`

A variable attribute for the `BasisStatusCode`

of a variable in result `result_index`

, with respect to an available optimal solution basis.

If the solver does not have a basis status for the variable because the `result_index`

is beyond the available solutions (whose number is indicated by the `ResultCount`

attribute), getting this attribute must throw a `ResultIndexBoundsError`

. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check `PrimalStatus`

before accessing the `VariableBasisStatus`

attribute.

See `ResultCount`

for information on how the results are ordered.