# Constraints

This page explains how to write various types of constraints in JuMP. Before reading further, please make sure you are familiar with JuMP models, and JuMP Variables. For nonlinear constraints, see Nonlinear Modeling instead.

JuMP is based on the MathOptInterface (MOI) API. Because of this, JuMP thinks of a constraint as the restriction that the output of a *function* belongs to a *set*. For example, instead of representing a constraint $a^\top x \le b$ as a *less-than-or-equal-to* constraint, JuMP models this as the *scalar affine* function $a^\top x$ belonging to the *less-than* set $(-\infty, b]$. Thus, instead of a *less-than-or-equal-to* constraint, we consider this constraint to be a *scalar affine -in- less than* constraint. More generally, we use the shorthand *function-in-set* to refer to constraints composed of different types of functions and sets. In the rest of this page, we will introduce the different types of functions and sets that JuMP knows about as needed. You can read more details about this *function-in-set* concept in the MOI documentation.

The examples use `MOI`

as an alias for the `MathOptInterface`

module. This alias is defined by `using JuMP`

. You may also define it in your code by

```
import MathOptInterface
const MOI = MathOptInterface
```

## The `@constraint`

macro

Constraints are added to a JuMP model using the `@constraint`

macro. Here is an example of how to add the constraint $2x \le 1$ to a JuMP model:

```
julia> @constraint(model, con, 2x <= 1)
con : 2 x <= 1.0
```

Wasn't that easy! Let's unpack what happened, because just like `@variable`

there are a few subtle things going on.

- The mathematical constraint $2x \le 1$ was added to the model.
- A Julia variable called
`con`

was created that is a reference to the constraint. - This Julia variable was stored in
`model`

and can be accessed by`model[:con]`

. - JuMP set the name attribute (the one that is shown when printing) of the constraint to
`"con"`

.

Just like the Julia variables created in `@variable`

, `con`

can be bound to a different value. For example:

```
julia> con
con : 2 x <= 1.0
julia> con = 1
1
julia> con
1
```

However, the reference can be retrieved by querying the model using the symbolic name:

```
julia> con = model[:con]
con : 2 x <= 1.0
julia> con
con : 2 x <= 1.0
```

Because the named variables and constraints are stored in the same namespace, creating a constraint with the same name as a variable or an existing constraint will result in an error. To overcome this limitation, it is possible to create anonymous constraints, just like it is possible to create Anonymous JuMP variables. This is done by dropping the second argument to `@constraint`

:

```
julia> con = @constraint(model, 2x <= 1)
2 x <= 1.0
```

It is also possible use different comparison operators (e.g., `>=`

and `==`

) to create the following types of constraints:

```
julia> @constraint(model, 2x >= 1)
2 x >= 1.0
julia> @constraint(model, 2x == 1)
2 x = 1.0
julia> @constraint(model, 1 <= 2x <= 3)
2 x ∈ [1.0, 3.0]
```

Note that JuMP normalizes the constraints by moving all of the terms containing variables to the left-hand side, and all of the constant terms to the right-hand side. Thus, we get:

```
julia> @constraint(model, 2x + 1 <= 4x + 4)
-2 x <= 3.0
```

## Duality

JuMP adopts the notion of conic duality from MOI. For linear programs, a feasible dual on a `>=`

constraint is nonnegative and a feasible dual on a `<=`

constraint is nonpositive. If the constraint is an equality constraint, it depends on which direction is binding.

JuMP's definition of duality is independent of the objective sense. That is, the sign of feasible duals associated with a constraint depends on the direction of the constraint and not whether the problem is maximization or minimization. **This is a different convention from linear programming duality in some common textbooks.**

The dual value associated with a constraint in the most recent solution can be accessed using the `dual`

function. You can use the `has_duals`

function to check whether the model has a dual solution available to query. For example:

```
julia> model = Model();
julia> @variable(model, x)
x
julia> @constraint(model, con, x <= 1)
con : x <= 1.0
julia> has_duals(model)
false
```

```
julia> @objective(model, Min, -2x)
-2 x
julia> optimize!(model)
julia> has_duals(model)
true
julia> dual(con)
-2.0
julia> @objective(model, Max, 2x)
2 x
julia> optimize!(model)
julia> dual(con)
-2.0
```

To help users who may be less familiar with conic duality, JuMP provides the `shadow_price`

function which returns a value that can be interpreted as the improvement in the objective in response to an infinitesimal relaxation (on the scale of one unit) in the right-hand side of the constraint. `shadow_price`

can be used only on linear constraints with a `<=`

, `>=`

, or `==`

comparison operator.

In the example above, `dual(con)`

returned `-2.0`

regardless of the optimization sense. However, in the second case when the optimization sense is `Max`

, `shadow_price`

returns:

```
julia> shadow_price(con)
2.0
```

To query the dual variables associated with a variable bound, first obtain a constraint reference using one of `UpperBoundRef`

, `LowerBoundRef`

, or `FixRef`

, and then call `dual`

on the returned constraint reference. Note that in linear programming, the duals on variable bounds are also called the reduced costs (although the sign might differ from the one you expect).

## Constraint names

The name, i.e. the value of the `MOI.ConstraintName`

attribute, of a constraint can be obtained by `name(::JuMP.ConstraintRef)`

and set by `set_name(::JuMP.ConstraintRef, ::String)`

.

`JuMP.name`

— Method.`name(v::ConstraintRef)`

Get a constraint's name attribute.

`JuMP.set_name`

— Method.`set_name(v::ConstraintRef, s::AbstractString)`

Set a constraint's name attribute.

The constraint can also be retrieved from its name using `constraint_by_name`

.

`JuMP.constraint_by_name`

— Function.```
constraint_by_name(model::AbstractModel,
name::String)::Union{ConstraintRef, Nothing}
```

Returns the reference of the constraint with name attribute `name`

or `Nothing`

if no constraint has this name attribute. Throws an error if several constraints have `name`

as their name attribute.

```
constraint_by_name(model::AbstractModel,
name::String,
F::Type{<:Union{AbstractJuMPScalar,
Vector{<:AbstractJuMPScalar},
MOI.AbstactFunction}},
S::Type{<:MOI.AbstractSet})::Union{ConstraintRef, Nothing}
```

Similar to the method above, except that it throws an error if the constraint is not an `F`

-in-`S`

contraint where `F`

is either the JuMP or MOI type of the function, and `S`

is the MOI type of the set. This method is recommended if you know the type of the function and set since its returned type can be inferred while for the method above (i.e. without `F`

and `S`

), the exact return type of the constraint index cannot be inferred.

```
julia> using JuMP
julia> model = Model()
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: NO_OPTIMIZER
Solver name: No optimizer attached.
julia> @variable(model, x)
x
julia> @constraint(model, con, x^2 == 1)
con : x² = 1.0
julia> constraint_by_name(model, "kon")
julia> constraint_by_name(model, "con")
con : x² = 1.0
julia> constraint_by_name(model, "con", AffExpr, MOI.EqualTo{Float64})
julia> constraint_by_name(model, "con", QuadExpr, MOI.EqualTo{Float64})
con : x² = 1.0
```

## Constraint containers

So far, we've added constraints one-by-one. However, just like Variable containers, JuMP provides a mechanism for building groups of constraints compactly. References to these groups of constraints are returned in *containers*. Three types of constraint containers are supported: `Array`

s, `DenseAxisArray`

s, and `SparseAxisArray`

s. We explain each of these in the following.

### Arrays

One way of adding a group of constraints compactly is the following:

```
julia> @constraint(model, con[i = 1:3], i * x <= i + 1)
3-element Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,1}:
con[1] : x <= 2.0
con[2] : 2 x <= 3.0
con[3] : 3 x <= 4.0
```

JuMP returns references to the three constraints in an `Array`

that is bound to the Julia variable `con`

. This array can be accessed and sliced as you would with any Julia array:

```
julia> con[1]
con[1] : x <= 2.0
julia> con[2:3]
2-element Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,1}:
con[2] : 2 x <= 3.0
con[3] : 3 x <= 4.0
```

Anonymous containers can also be constructed by dropping the name (e.g. `con`

) before the square brackets:

```
julia> @constraint(model, [i = 1:2], i * x <= i + 1)
2-element Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,1}:
x <= 2.0
2 x <= 3.0
```

Just like `@variable`

, JuMP will form an `Array`

of constraints when it can determine at parse time that the indices are one-based integer ranges. Therefore `con[1:b]`

will create an `Array`

, but `con[a:b]`

will not. A special case is `con[Base.OneTo(n)]`

which will produce an `Array`

. If JuMP cannot determine that the indices are one-based integer ranges (e.g., in the case of `con[a:b]`

), JuMP will create a `DenseAxisArray`

instead.

### DenseAxisArrays

The syntax for constructing a `DenseAxisArray`

of constraints is very similar to the syntax for constructing a `DenseAxisArray`

of variables.

```
julia> @constraint(model, con[i = 1:2, j = 2:3], i * x <= j + 1)
2-dimensional DenseAxisArray{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,2,...} with index sets:
Dimension 1, 1:2
Dimension 2, 2:3
And data, a 2×2 Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,2}:
con[1,2] : x <= 3.0 con[1,3] : x <= 4.0
con[2,2] : 2 x <= 3.0 con[2,3] : 2 x <= 4.0
```

### SparseAxisArrays

The syntax for constructing a `SparseAxisArray`

of constraints is very similar to the syntax for constructing a `SparseAxisArray`

of variables.

```
julia> @constraint(model, con[i = 1:2, j = 1:2; i != j], i * x <= j + 1)
JuMP.Containers.SparseAxisArray{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,2,Tuple{Any,Any}} with 2 entries:
[1, 2] = con[1,2] : x <= 3.0
[2, 1] = con[2,1] : 2 x <= 2.0
```

### Forcing the container type

When creating a container of constraints, JuMP will attempt to choose the tightest container type that can store the constraints. However, because this happens at parse time, it does not always make the best choice. Just like in `@variable`

, we can force the type of container using the `container`

keyword. For syntax and the reason behind this, take a look at the variable docs.

## Vectorized constraints

We can also add constraints to JuMP using vectorized linear algebra. For example:

```
julia> @variable(model, x[i=1:2])
2-element Array{VariableRef,1}:
x[1]
x[2]
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> b = [5, 6]
2-element Array{Int64,1}:
5
6
julia> @constraint(model, con, A * x .== b)
2-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.EqualTo{Float64}},ScalarShape},1}:
x[1] + 2 x[2] == 5.0
3 x[1] + 4 x[2] == 6.0
```

Make sure to use Julia's dot syntax in front of the comparison operators (e.g. `.==`

, `.>=`

, and `.<=`

). If you use a comparison without the dot, an error will be thrown.

Instead of adding an array of `ScalarAffineFunction-in-EqualTo`

constraints, we can instead construct a `VectorAffineFunction-in-Nonnegatives`

constraint as follows:

```
julia> @constraint(model, A * x - b in MOI.Nonnegatives(2))
[x[1] + 2 x[2] - 5, 3 x[1] + 4 x[2] - 6] in MathOptInterface.Nonnegatives(2)
```

In addition to the `Nonnegatives`

set, MOI defines a number of other vector-valued sets such as `Nonpositives`

. See the MOI documentation for more information.

Note also that for the first time we have used an explicit *function-in-set* description of the constraint. Read more about this representation for constraints in the MOI documentation.

## Constraints on a single variable

In Variables, we saw how to modify the variable bounds, as well as add binary and integer restrictions to the domain of each variable. This can also be achieved using the `@constraint`

macro. For example, `MOI.ZeroOne()`

restricts the domain to $\{0, 1\}$:

```
julia> @constraint(model, x in MOI.ZeroOne())
x binary
```

and `MOI.Integer()`

restricts to the domain to the integers $\mathbb{Z}$:

```
julia> @constraint(model, x in MOI.Integer())
x integer
```

JuMP also supports modeling semi-continuous variables, whose domain is $\{0\} ∪ [l, u]$, using the `MOI.Semicontinuous`

set:

```
julia> @constraint(model, x in MOI.Semicontinuous(1.5, 3.5))
x in MathOptInterface.Semicontinuous{Float64}(1.5, 3.5)
```

as well as semi-integer variables, whose domain is $\{0\} ∪ \{l, l+1, \dots, u\}$, using the `MOI.Semiinteger`

set:

```
julia> @constraint(model, x in MOI.Semiinteger(1.0, 3.0))
x in MathOptInterface.Semiinteger{Float64}(1.0, 3.0)
```

## Quadratic constraints

In addition to affine functions, JuMP also supports constraints with quadratic terms. (For more general nonlinear functions, see Nonlinear Modeling.) For example:

```
julia> @variable(model, x[i=1:2])
2-element Array{VariableRef,1}:
x[1]
x[2]
julia> @variable(model, t >= 0)
t
julia> @constraint(model, x[1]^2 + x[2]^2 <= t^2)
x[1]² + x[2]² - t² <= 0.0
```

Note that this quadratic constraint (including the lower bound on `t`

) is equivalent to a second order cone constraint where `||x[1]^2 + x[2]^2||\_2 ≤ t`

and `t ≥ 0`

. Instead of writing out the quadratic expansion, we can pass JuMP the constraint in *function*-in-*set* form. To do so, we need to define the function and the set.

The function is a vector of variables:

```
julia> [t, x[1], x[2]]
3-element Array{VariableRef,1}:
t
x[1]
x[2]
```

Note that the variable `t`

comes first, followed by the `x`

arguments. The set is an instance of `SecondOrderCone`

: `SecondOrderCone()`

. Thus, we can add the second order cone constraint as follows:

```
julia> @constraint(model, [t, x[1], x[2]] in SecondOrderCone())
[t, x[1], x[2]] in MathOptInterface.SecondOrderCone(3)
```

JuMP also supports the `RotatedSecondOrderCone`

which requires the addition of a perspective variable `u`

. The rotated second order cone constraints the variables `t`

, `u`

, and `x`

such that: `||x[1]^2 + x[2]^2||\_2 ≤ t × u`

and `t, u ≥ 0`

. It can be added as follows:

```
julia> @variable(model, u)
u
julia> @constraint(model, [t, u, x[1], x[2]] in RotatedSecondOrderCone())
[t, u, x[1], x[2]] in MathOptInterface.RotatedSecondOrderCone(4)
```

In addition to the second order cone and rotated second order cone, MOI defines a number of other conic sets such as the exponential and power cones. See the MathOptInterface documentation for more information.

## Constraints on a collection of variables

In addition to constraining the domain of a single variable, JuMP supports placing constraints of a subset of the variables. We already saw an example of this in the Quadratic constraints section when we constrained a vector of variables to belong to the second order cone.

In a special ordered set of type I (often denoted SOS-I), at most one variable can take a non-zero value. We can construct SOS-I constraints using the `MOI.SOS1`

set:

```
julia> @variable(model, x[1:3])
3-element Array{VariableRef,1}:
x[1]
x[2]
x[3]
julia> @constraint(model, x in MOI.SOS1([1.0, 2.0, 3.0]))
[x[1], x[2], x[3]] in MathOptInterface.SOS1{Float64}([1.0, 2.0, 3.0])
```

Note that we have to pass `MOI.SOS1`

a *weight* vector. This vector implies an ordering on the variables. If the decision variables are related and have a physical ordering (e.g., they correspond to the size of a factory to be built, and the SOS-I constraint enforces that only one factory can be built), then the weight vector, although not used directly in the constraint, can help the solver make a better decision in the solution process.

This ordering is more important in a special ordered set of type II (SOS-II), in which at most two values can be non-zero, and if there are two non-zeros, they must be consecutive according to the ordering. For example, in the following constraint, the possible non-zero pairs are (`x[1]`

and `x[3]`

) and (`x[2]`

and `x[3]`

):

```
julia> @constraint(model, x in MOI.SOS2([3.0, 1.0, 2.0]))
[x[1], x[2], x[3]] in MathOptInterface.SOS2{Float64}([3.0, 1.0, 2.0])
```

## Semidefinite constraints

JuMP provides a special syntax for constraining a matrix to be symmetric positive semidefinite (PSD) with the `@SDconstraint`

macro. In the context of this macro, the inequality `A >= B`

between two square matrices `A`

and `B`

is understood as constraining `A - B`

to be symmetric positive semidefinite.

```
julia> @variable(model, x)
x
julia> @SDconstraint(model, [x 2x; 3x 4x] >= ones(2, 2))
[x - 1 2 x - 1;
3 x - 1 4 x - 1] ∈ PSDCone()
```

Solvers supporting such constraints usually expect to be given a matrix that is *symbolically* symmetric, that is, for which the expression in corresponding off-diagonal entries are the same. In our example, the expressions of entries `(1, 2)`

and `(2, 1)`

are respectively `2x - 1`

and `3x - 1`

which are different. To bridge the gap between the constraint modeled and what the solver expects, JuMP creates an equality constraint `3x - 1 == 2x - 1`

and constrains the symmetric matrix `[x - 1, 2 x - 1, 2 x - 1, 4 x - 1]`

to be positive semidefinite.

If the matrix provided is already symbolically symmetric, the equality constrains are equivalent to `0 = 0`

and are not added. In practice, if all coefficients are smaller than `1e-10`

, the constraint is ignored, if all coefficients are smaller than `1e-8`

but some are larger than `1e-10`

, it is ignored but a warning is displayed, otherwise if at least one coefficient is larger than `1e-8`

, the constraint is added.

If the matrix is known to be symmetric, the PSD constraint can be added as follows:

```
julia> using LinearAlgebra
julia> @constraint(model, Symmetric([x 2x; 2x 4x] - ones(2, 2)) in PSDCone())
[x - 1 2 x - 1;
2 x - 1 4 x - 1] ∈ PSDCone()
```

Note that the lower triangular entries are silently ignored even if they are different so use it with caution:

```
julia> cref = @constraint(model, Symmetric([x 2x; 3x 4x]) in PSDCone())
[x 2 x;
2 x 4 x] ∈ PSDCone()
julia> jump_function(constraint_object(cref))
3-element Array{GenericAffExpr{Float64,VariableRef},1}:
x
2 x
4 x
julia> moi_set(constraint_object(cref))
MathOptInterface.PositiveSemidefiniteConeTriangle(2)
```

## Constraint modifications

A common paradigm, especially in linear programming, is to repeatedly solve a model with different coefficients.

### Modifying a constant term

Most often, modifications involve changing the "right-hand side" of a linear constraint. This presents a challenge for JuMP because it leads to ambiguities. For example, what is the right-hand side term of `@constraint(model, 2x + 1 <= x - 3)`

? This applies more generally to any constant term in a function appearing in the objective or a constraint.

To avoid these ambiguities, JuMP includes the ability to *fix* variables to a value using the `fix`

function. Fixing a variable sets its lower and upper bound to the same value. Thus, changes in a constant term can be simulated by adding a dummy variable and fixing it to different values. Here is an example:

```
julia> @variable(model, const_term)
const_term
julia> @constraint(model, con, 2x <= const_term)
con : 2 x - const_term <= 0.0
julia> fix(const_term, 1.0)
```

Even though `const_term`

is fixed, it is still a decision variable. Thus, `const_term * x`

is bilinear. Fixed variables are not replaced with constants when communicating the problem to a solver.

### Modifying a variable coefficient

It is also possible to modify the scalar coefficients (but notably *not yet* the quadratic coefficients) using the `set_coefficient`

function. Here is an example:

```
julia> @constraint(model, con, 2x <= 1)
con : 2 x <= 1.0
julia> set_coefficient(con, x, 3)
julia> con
con : 3 x <= 1.0
```

## Constraint deletion

Constraints can be deleted from a model using `delete`

. Just like variable references, it is possible to check if a constraint reference is valid using `is_valid`

. Here is an example of deleting a constraint:

```
julia> @constraint(model, con, 2x <= 1)
con : 2 x <= 1.0
julia> is_valid(model, con)
true
julia> delete(model, con)
julia> is_valid(model, con)
false
```

## Accessing constraints from a model

You can query the types of constraints currently present in the model by calling `list_of_constraint_types`

. Then, given a function and set type, use `num_constraints`

to access the number of constraints of this type and `all_constraints`

to access a list of their references. Then use `constraint_object`

to get an instance of an `AbstractConstraint`

object, either `ScalarConstraint`

or `VectorConstraint`

, that stores the constraint data.

```
julia> model = Model();
julia> @variable(model, x[i=1:2] >= i, Int);
julia> @constraint(model, x[1] + x[2] <= 1);
julia> list_of_constraint_types(model)
3-element Array{Tuple{DataType,DataType},1}:
(VariableRef, MathOptInterface.Integer)
(VariableRef, MathOptInterface.GreaterThan{Float64})
(GenericAffExpr{Float64,VariableRef}, MathOptInterface.LessThan{Float64})
julia> num_constraints(model, VariableRef, MOI.Integer)
2
julia> all_constraints(model, VariableRef, MOI.Integer)
2-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.Integer},ScalarShape},1}:
x[1] integer
x[2] integer
julia> num_constraints(model, VariableRef, MOI.GreaterThan{Float64})
2
julia> all_constraints(model, VariableRef, MOI.GreaterThan{Float64})
2-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.GreaterThan{Float64}},ScalarShape},1}:
x[1] ≥ 1.0
x[2] ≥ 2.0
julia> num_constraints(model, GenericAffExpr{Float64,VariableRef}, MOI.LessThan{Float64})
1
julia> less_than_constraints = all_constraints(model, GenericAffExpr{Float64,VariableRef}, MOI.LessThan{Float64})
1-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},1}:
x[1] + x[2] ≤ 1.0
julia> con = constraint_object(less_than_constraints[1])
ScalarConstraint{GenericAffExpr{Float64,VariableRef},MathOptInterface.LessThan{Float64}}(x[1] + x[2], MathOptInterface.LessThan{Float64}(1.0))
julia> con.func
x[1] + x[2]
julia> con.set
MathOptInterface.LessThan{Float64}(1.0)
```

## Reference

`JuMP.@constraint`

— Macro.`@constraint(m::Model, expr)`

Add a constraint described by the expression `expr`

.

`@constraint(m::Model, ref[i=..., j=..., ...], expr)`

Add a group of constraints described by the expression `expr`

parametrized by `i`

, `j`

, ...

The expression `expr`

can either be

- of the form
`func in set`

constraining the function`func`

to belong to the set`set`

which is either a`MathOptInterface.AbstractSet`

or one of the JuMP shortcuts`SecondOrderCone`

,`RotatedSecondOrderCone`

and`PSDCone`

, e.g.`@constraint(model, [1, x-1, y-2] in SecondOrderCone())`

constrains the norm of`[x-1, y-2]`

be less than 1; - of the form
`a sign b`

, where`sign`

is one of`==`

,`≥`

,`>=`

,`≤`

and`<=`

building the single constraint enforcing the comparison to hold for the expression`a`

and`b`

, e.g.`@constraint(m, x^2 + y^2 == 1)`

constrains`x`

and`y`

to lie on the unit circle; - of the form
`a ≤ b ≤ c`

or`a ≥ b ≥ c`

(where`≤`

and`<=`

(resp.`≥`

and`>=`

) can be used interchangeably) constraining the paired the expression`b`

to lie between`a`

and`c`

; - of the forms
`@constraint(m, a .sign b)`

or`@constraint(m, a .sign b .sign c)`

which broadcast the constraint creation to each element of the vectors.

**Note for extending the constraint macro**

Each constraint will be created using `add_constraint(m, build_constraint(_error, func, set))`

where

`_error`

is an error function showing the constraint call in addition to the error message given as argument,`func`

is the expression that is constrained- and
`set`

is the set in which it is constrained to belong.

For `expr`

of the first type (i.e. `@constraint(m, func in set)`

), `func`

and `set`

are passed unchanged to `build_constraint`

but for the other types, they are determined from the expressions and signs. For instance, `@constraint(m, x^2 + y^2 == 1)`

is transformed into `add_constraint(m, build_constraint(_error, x^2 + y^2, MOI.EqualTo(1.0)))`

.

To extend JuMP to accept new constraints of this form, it is necessary to add the corresponding methods to `build_constraint`

. Note that this will likely mean that either `func`

or `set`

will be some custom type, rather than e.g. a `Symbol`

, since we will likely want to dispatch on the type of the function or set appearing in the constraint.

`JuMP.@SDconstraint`

— Macro.`@SDconstraint(model::Model, expr)`

Add a semidefinite constraint described by the expression `expr`

.

`@SDconstraint(model::Model, ref[i=..., j=..., ...], expr)`

Add a group of semidefinite constraints described by the expression `expr`

parametrized by `i`

, `j`

, ...

The expression `expr`

needs to be of the form `a sign b`

where `sign`

is `⪰`

, `≥`

, `>=`

, `⪯`

, `≤`

or `<=`

and `a`

and `b`

are `square`

matrices. It constrains the matrix `x = a - b`

(or `x = b - a`

if the sign is `⪯`

, `≤`

or `<=`

) to be symmetric and positive semidefinite.

By default, we check numerical symmetry of the matrix `x`

, and if symmetry is violated by some arbitrary amount, we add explicit equality constraints. You can use `Symmetric(x) in PSDCone()`

with the `@constraint`

macro to skip these checks if you know the matrix must be symmetric; see `PSDCone`

for more information.

**Examples**

The following constrains the matrix `[x-1 2x-2; -3 x-4]`

to be symmetric and positive semidefinite, that is, it constrains `2x-2`

to be equal to `-3`

and constrains all eigenvalues of the matrix to be nonnegative.

```
julia> model = Model();
julia> @variable(model, x)
x
julia> a = [x 2x
0 x];
julia> b = [1 2
3 4];
julia> cref = @SDconstraint(model, a ⪰ b)
[x - 1 2 x - 2;
-3 x - 4 ] ∈ PSDCone()
julia> jump_function(constraint_object(cref))
4-element Array{GenericAffExpr{Float64,VariableRef},1}:
x - 1
-3
2 x - 2
x - 4
julia> moi_set(constraint_object(cref))
MathOptInterface.PositiveSemidefiniteConeSquare(2)
```

In the set `PositiveSemidefiniteConeSquare(2)`

in the last output, `Square`

means that the matrix is passed as a square matrix as the corresponding off-diagonal entries need to be constrained to be equal. A similar set `PositiveSemidefiniteConeTriangle`

exists which only uses the upper triangular part of the matrix assuming that it is symmetric, see `PSDCone`

to see how to use it.

`JuMP.SecondOrderCone`

— Type.`SecondOrderCone`

Second order cone object that can be used to constrain the euclidean norm of a vector `x`

to be less than or equal to a nonnegative scalar `t`

. This is a shortcut for the `MathOptInterface.SecondOrderCone`

.

**Examples**

The following constrains $\|(x-1, x-2)\|_2 \le t$ and $t \ge 0$:

```
julia> model = Model();
julia> @variable(model, x)
x
julia> @variable(model, t)
t
julia> @constraint(model, [t, x-1, x-2] in SecondOrderCone())
[t, x - 1, x - 2] ∈ MathOptInterface.SecondOrderCone(3)
```

`JuMP.RotatedSecondOrderCone`

— Type.`RotatedSecondOrderCone`

Rotated second order cone object that can be used to constrain the square of the euclidean norm of a vector `x`

to be less than or equal to $2tu$ where `t`

and `u`

are nonnegative scalars. This is a shortcut for the `MathOptInterface.RotatedSecondOrderCone`

.

**Examples**

The following constrains $\|(x-1, x-2)\|_2 \le 2tx$ and $t, x \ge 0$:

```
julia> model = Model();
julia> @variable(model, x)
x
julia> @variable(model, t)
t
julia> @constraint(model, [t, x, x-1, x-2] in RotatedSecondOrderCone())
[t, x, x - 1, x - 2] ∈ MathOptInterface.RotatedSecondOrderCone(4)
```

`JuMP.PSDCone`

— Type.`PSDCone`

Positive semidefinite cone object that can be used to constrain a square matrix to be positive semidefinite in the `@constraint`

macro. If the matrix has type `Symmetric`

then the columns vectorization (the vector obtained by concatenating the columns) of its upper triangular part is constrained to belong to the `MOI.PositiveSemidefiniteConeTriangle`

set, otherwise its column vectorization is constrained to belong to the `MOI.PositiveSemidefiniteConeSquare`

set.

**Examples**

Consider the following example:

```
julia> model = Model();
julia> @variable(model, x)
x
julia> a = [ x 2x
2x x];
julia> b = [1 2
2 4];
julia> cref = @SDconstraint(model, a ⪰ b)
[x - 1 2 x - 2;
2 x - 2 x - 4 ] ∈ PSDCone()
julia> jump_function(constraint_object(cref))
4-element Array{GenericAffExpr{Float64,VariableRef},1}:
x - 1
2 x - 2
2 x - 2
x - 4
julia> moi_set(constraint_object(cref))
MathOptInterface.PositiveSemidefiniteConeSquare(2)
```

We see in the output of the last command that the matrix the vectorization of the matrix is constrained to belong to the `PositiveSemidefiniteConeSquare`

.

```
julia> using LinearAlgebra # For Symmetric
julia> cref = @constraint(model, Symmetric(a - b) in PSDCone())
[x - 1 2 x - 2;
2 x - 2 x - 4 ] ∈ PSDCone()
julia> jump_function(constraint_object(cref))
3-element Array{GenericAffExpr{Float64,VariableRef},1}:
x - 1
2 x - 2
x - 4
julia> moi_set(constraint_object(cref))
MathOptInterface.PositiveSemidefiniteConeTriangle(2)
```

As we see in the output of the last command, the vectorization of only the upper triangular part of the matrix is constrained to belong to the `PositiveSemidefiniteConeSquare`

.

`JuMP.shadow_price`

— Function.`shadow_price(constraint::ConstraintRef)`

The change in the objective from an infinitesimal relaxation of the constraint. This value is computed from `dual`

and can be queried only when `has_duals`

is `true`

and the objective sense is `MIN_SENSE`

or `MAX_SENSE`

(not `FEASIBILITY_SENSE`

). For linear constraints, the shadow prices differ at most in sign from the `dual`

value depending on the objective sense.

**Notes**

- The function simply translates signs from
`dual`

and does not validate the conditions needed to guarantee the sensitivity interpretation of the shadow price. The caller is responsible, e.g., for checking whether the solver converged to an optimal primal-dual pair or a proof of infeasibility. - The computation is based on the current objective sense of the model. If this has changed since the last solve, the results will be incorrect.
- Relaxation of equality constraints (and hence the shadow price) is defined based on which sense of the equality constraint is active.

`JuMP.set_coefficient`

— Function.`set_coefficient(constraint::ConstraintRef, variable::VariableRef, value)`

Set the coefficient of `variable`

in the constraint `constraint`

to `value`

.

Note that prior to this step, JuMP will aggregate multiple terms containing the same variable. For example, given a constraint `2x + 3x <= 2`

, `set_coefficient(c, x, 4)`

will create the constraint `4x <= 2`

.

```
model = Model()
@variable(model, x)
@constraint(model, con, 2x + 3x <= 2)
set_coefficient(con, x, 4)
con
# output
con : 4 x <= 2.0
```

`JuMP.is_valid`

— Function.`is_valid(model::Model, constraint_ref::ConstraintRef{Model})`

Return `true`

if `constraint_ref`

refers to a valid constraint in `model`

.

`is_valid(model::Model, variable_ref::VariableRef)`

Return `true`

if `variable`

refers to a valid variable in `model`

.

`JuMP.delete`

— Function.`delete(model::Model, constraint_ref::ConstraintRef)`

Delete the constraint associated with `constraint_ref`

from the model `model`

.

`delete(model::Model, variable_ref::VariableRef)`

Delete the variable associated with `variable_ref`

from the model `model`

.

`JuMP.LowerBoundRef`

— Function.`LowerBoundRef(v::VariableRef)`

Return a constraint reference to the lower bound constraint of `v`

. Errors if one does not exist.

`JuMP.UpperBoundRef`

— Function.`UpperBoundRef(v::VariableRef)`

Return a constraint reference to the upper bound constraint of `v`

. Errors if one does not exist.

`JuMP.FixRef`

— Function.`FixRef(v::VariableRef)`

Return a constraint reference to the constraint fixing the value of `v`

. Errors if one does not exist.

`JuMP.ConstraintRef`

— Type.`ConstraintRef`

Holds a reference to the model and the corresponding MOI.ConstraintIndex.

`JuMP.list_of_constraint_types`

— Function.`list_of_constraint_types(model::Model)`

Return a list of tuples of the form `(F, S)`

where `F`

is a JuMP function type and `S`

is an MOI set type such that `all_constraints(model, F, S)`

returns a nonempty list.

**Example**

```
julia> model = Model();
julia> @variable(model, x >= 0, Bin);
julia> @constraint(model, 2x <= 1);
julia> list_of_constraint_types(model)
3-element Array{Tuple{DataType,DataType},1}:
(VariableRef, MathOptInterface.ZeroOne)
(VariableRef, MathOptInterface.GreaterThan{Float64})
(GenericAffExpr{Float64,VariableRef}, MathOptInterface.LessThan{Float64})
```

`JuMP.all_constraints`

— Function.`all_constraints(model::Model, function_type, set_type)::Vector{<:ConstraintRef}`

Return a list of all constraints currently in the model where the function has type `function_type`

and the set has type `set_type`

. The constraints are ordered by creation time.

See also `list_of_constraint_types`

and `num_constraints`

.

**Example**

```
julia> model = Model();
julia> @variable(model, x >= 0, Bin);
julia> @constraint(model, 2x <= 1);
julia> all_constraints(model, VariableRef, MOI.GreaterThan{Float64})
1-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.GreaterThan{Float64}},ScalarShape},1}:
x ≥ 0.0
julia> all_constraints(model, VariableRef, MOI.ZeroOne)
1-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.ZeroOne},ScalarShape},1}:
x binary
julia> all_constraints(model, AffExpr, MOI.LessThan{Float64})
1-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},1}:
2 x ≤ 1.0
```

`JuMP.num_constraints`

— Function.`num_constraints(model::Model, function_type, set_type)::Int64`

Return the number of constraints currently in the model where the function has type `function_type`

and the set has type `set_type`

.

See also `list_of_constraint_types`

and `all_constraints`

.

**Example**

```
julia> model = Model();
julia> @variable(model, x >= 0, Bin);
julia> @variable(model, y);
julia> @constraint(model, y in MOI.GreaterThan(1.0));
julia> @constraint(model, y <= 1.0);
julia> @constraint(model, 2x <= 1);
julia> num_constraints(model, VariableRef, MOI.GreaterThan{Float64})
2
julia> num_constraints(model, VariableRef, MOI.ZeroOne)
1
julia> num_constraints(model, AffExpr, MOI.LessThan{Float64})
2
```

`JuMP.constraint_object`

— Function.`constraint_object(ref::ConstraintRef)`

Return the underlying constraint data for the constraint referenced by `ref`

.

`JuMP.AbstractConstraint`

— Type.`abstract type AbstractConstraint`

An abstract base type for all constraint types. `AbstractConstraint`

s store the function and set directly, unlike `ConstraintRef`

s that are merely references to constraints stored in a model. `AbstractConstraint`

s do not need to be attached to a model.

`JuMP.ScalarConstraint`

— Type.`struct ScalarConstraint`

The data for a scalar constraint. The `func`

field containts a JuMP object representing the function and the `set`

field contains the MOI set. See also the documentation on JuMP's representation of constraints for more background.

`JuMP.VectorConstraint`

— Type.`struct VectorConstraint`

The data for a vector constraint. The `func`

field containts a JuMP object representing the function and the `set`

field contains the MOI set. The `shape`

field contains an `AbstractShape`

matching the form in which the constraint was constructed (e.g., by using matrices or flat vectors). See also the documentation on JuMP's representation of constraints.

`JuMP.index`

— Method.`index(cr::ConstraintRef)::MOI.ConstraintIndex`

Return the index of the constraint that corresponds to `cr`

in the MOI backend.

`JuMP.optimizer_index`

— Method.`optimizer_index(cr::ConstraintRef{Model})::MOI.ConstraintIndex`

Return the index of the constraint that corresponds to `cr`

in the optimizer model. It throws `NoOptimizer`

if no optimizer is set and throws an `ErrorException`

if the optimizer is set but is not attached or if the constraint is bridged.

## Constructing constraints without adding them to the model

For advanced use cases.

`JuMP.@build_constraint`

— Macro.`@build_constraint(constraint_expr)`

Constructs a `ScalarConstraint`

or `VectorConstraint`

using the same machinery as `@constraint`

but without adding the constraint to a model.

Constraints using broadcast operators like `x .<= 1`

are also supported and will create arrays of `ScalarConstraint`

or `VectorConstraint`

.

**Examples**

```
model = Model();
@variable(model, x);
@build_constraint(2x >= 1)
# output
ScalarConstraint{GenericAffExpr{Float64,VariableRef},MathOptInterface.GreaterThan{Float64}}(2 x, MathOptInterface.GreaterThan{Float64}(1.0))
```