# Constraints

More information can be found in the Constraints section of the manual.

## Macros

`JuMP.@constraint`

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

Add a constraint described by the expression `expr`

.

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

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

The recognized keyword arguments in `kw_args`

are the following:

`base_name`

: Sets the name prefix used to generate constraint names. It corresponds to the constraint name for scalar constraints, otherwise, the constraint names are set to`base_name[...]`

for each index`...`

of the axes`axes`

.`container`

: Specify the container type.`set_string_name::Bool = true`

: control whether to set the`MOI.ConstraintName`

attribute. Passing`set_string_name = false`

can improve performance.

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

For extensions that need to create constraints with more information than just `func`

and `set`

, an additional positional argument can be specified to `@constraint`

that will then be passed on `build_constraint`

. Hence, we can enable this syntax by defining extensions of `build_constraint(_error, func, set, my_arg; kw_args...)`

. This produces the user syntax: `@constraint(model, ref[...], expr, my_arg, kw_args...)`

.

`JuMP.@constraints`

— Macro`@constraints(model, args...)`

Adds groups of constraints at once, in the same fashion as the `@constraint`

macro.

The model must be the first argument, and multiple constraints can be added on multiple lines wrapped in a `begin ... end`

block.

The macro returns a tuple containing the constraints that were defined.

**Examples**

```
@constraints(model, begin
x >= 1
y - w <= 2
sum_to_one[i=1:3], z[i] + y == 1
end)
```

`JuMP.ConstraintRef`

— Type`ConstraintRef`

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

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

## Names

`JuMP.name`

— Method`name(con_ref::ConstraintRef)`

Get a constraint's name attribute.

`JuMP.set_name`

— Method`set_name(con_ref::ConstraintRef, s::AbstractString)`

Set a constraint's name attribute.

`JuMP.constraint_by_name`

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

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

## Modification

`JuMP.normalized_coefficient`

— Function`normalized_coefficient(con_ref::ConstraintRef, variable::VariableRef)`

Return the coefficient associated with `variable`

in `constraint`

after JuMP has normalized the constraint into its standard form. See also `set_normalized_coefficient`

.

`JuMP.set_normalized_coefficient`

— Function`set_normalized_coefficient(con_ref::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_normalized_coefficient(con, x, 4)`

will create the constraint `4x <= 2`

.

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

`JuMP.set_normalized_coefficients`

— Function```
set_normalized_coefficients(
con_ref::ConstraintRef,
variable,
new_coefficients::Vector{Tuple{Int64,T}},
)
```

Set the coefficients of `variable`

in the constraint `con_ref`

to `new_coefficients`

, where each element in `new_coefficients`

is a tuple which maps the row to a new coefficient.

Note that prior to this step, during constraint creation, JuMP will aggregate multiple terms containing the same variable.

```
model = Model()
@variable(model, x)
@constraint(model, con, [2x + 3x, 4x] in MOI.Nonnegatives(2))
set_normalized_coefficients(con, x, [(1, 2.0), (2, 5.0)])
con
# output
con : [2 x, 5 x] ∈ MathOptInterface.Nonnegatives(2)
```

`JuMP.normalized_rhs`

— Function`normalized_rhs(con_ref::ConstraintRef)`

Return the right-hand side term of `con_ref`

after JuMP has converted the constraint into its normalized form. See also `set_normalized_rhs`

.

`JuMP.set_normalized_rhs`

— Function`set_normalized_rhs(con_ref::ConstraintRef, value)`

Set the right-hand side term of `constraint`

to `value`

.

Note that prior to this step, JuMP will aggregate all constant terms onto the right-hand side of the constraint. For example, given a constraint `2x + 1 <= 2`

, `set_normalized_rhs(con, 4)`

will create the constraint `2x <= 4`

, not `2x + 1 <= 4`

.

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

`JuMP.add_to_function_constant`

— Function`add_to_function_constant(constraint::ConstraintRef, value)`

Add `value`

to the function constant term.

Note that for scalar constraints, JuMP will aggregate all constant terms onto the right-hand side of the constraint so instead of modifying the function, the set will be translated by `-value`

. For example, given a constraint `2x <= 3`

, `add_to_function_constant(c, 4)`

will modify it to `2x <= -1`

.

**Examples**

For scalar constraints, the set is translated by `-value`

:

```
julia> @constraint(model, con, 0 <= 2x - 1 <= 2)
con : 2 x ∈ [1.0, 3.0]
julia> add_to_function_constant(con, 4)
julia> con
con : 2 x ∈ [-3.0, -1.0]
```

For vector constraints, the constant is added to the function:

```
julia> @constraint(model, con, [x + y, x, y] in SecondOrderCone())
con : [x + y, x, y] ∈ MathOptInterface.SecondOrderCone(3)
julia> add_to_function_constant(con, [1, 2, 2])
julia> con
con : [x + y + 1, x + 2, y + 2] ∈ MathOptInterface.SecondOrderCone(3)
```

## Deletion

`JuMP.delete`

— Function`delete(model::Model, con_ref::ConstraintRef)`

Delete the constraint associated with `constraint_ref`

from the model `model`

.

Note that `delete`

does not unregister the name from the model, so adding a new constraint of the same name will throw an error. Use `unregister`

to unregister the name after deletion as follows:

```
@constraint(model, c, 2x <= 1)
delete(model, c)
unregister(model, :c)
```

See also: `unregister`

`delete(model::Model, con_refs::Vector{<:ConstraintRef})`

Delete the constraints associated with `con_refs`

from the model `model`

. Solvers may implement specialized methods for deleting multiple constraints of the same concrete type, i.e., when `isconcretetype(eltype(con_refs))`

. These may be more efficient than repeatedly calling the single constraint delete method.

See also: `unregister`

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

Delete the variable associated with `variable_ref`

from the model `model`

.

Note that `delete`

does not unregister the name from the model, so adding a new variable of the same name will throw an error. Use `unregister`

to unregister the name after deletion as follows:

```
@variable(model, x)
delete(model, x)
unregister(model, :x)
```

See also: `unregister`

`delete(model::Model, variable_refs::Vector{VariableRef})`

Delete the variables associated with `variable_refs`

from the model `model`

. Solvers may implement methods for deleting multiple variables that are more efficient than repeatedly calling the single variable delete method.

See also: `unregister`

`delete(model::Model, c::NonlinearConstraintRef)`

Delete the nonlinear constraint `c`

from `model`

.

`JuMP.is_valid`

— Function`is_valid(model::Model, con_ref::ConstraintRef{<:AbstractModel})`

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`

.

`is_valid(model::Model, c::NonlinearConstraintRef)`

Return `true`

if `c`

refers to a valid nonlinear constraint in `model`

.

`JuMP.ConstraintNotOwned`

— Type```
struct ConstraintNotOwned{C <: ConstraintRef} <: Exception
constraint_ref::C
end
```

The constraint `constraint_ref`

was used in a model different to `owner_model(constraint_ref)`

.

## Query constraints

`JuMP.list_of_constraint_types`

— Function`list_of_constraint_types(model::Model)::Vector{Tuple{Type,Type}}`

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{Type,Type},1}:
(GenericAffExpr{Float64,VariableRef}, MathOptInterface.LessThan{Float64})
(VariableRef, MathOptInterface.GreaterThan{Float64})
(VariableRef, MathOptInterface.ZeroOne)
```

**Performance considerations**

Iterating over the list of function and set types is a type-unstable operation. Consider using a function barrier. See the Performance tips for extensions section of the documentation for more details.

`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.VariableIndex,MathOptInterface.GreaterThan{Float64}},ScalarShape},1}:
x ≥ 0.0
julia> all_constraints(model, VariableRef, MOI.ZeroOne)
1-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex,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
```

```
all_constraints(
model::Model;
include_variable_in_set_constraints::Bool,
)::Vector{ConstraintRef}
```

Return a list of all constraints in `model`

.

If `include_variable_in_set_constraints == true`

, then `VariableRef`

constraints such as `VariableRef`

-in-`Integer`

are included. To return only the structural constraints (e.g., the rows in the constraint matrix of a linear program), pass `include_variable_in_set_constraints = false`

.

**Examples**

```
julia> model = Model();
julia> @variable(model, x >= 0, Int);
julia> @constraint(model, 2x <= 1);
julia> @NLconstraint(model, x^2 <= 1);
julia> all_constraints(model; include_variable_in_set_constraints = true)
4-element Vector{ConstraintRef}:
2 x ≤ 1.0
x ≥ 0.0
x integer
x ^ 2.0 - 1.0 ≤ 0
julia> all_constraints(model; include_variable_in_set_constraints = false)
2-element Vector{ConstraintRef}:
2 x ≤ 1.0
x ^ 2.0 - 1.0 ≤ 0
```

**Performance considerations**

Note that this function is type-unstable because it returns an abstractly typed vector. If performance is a problem, consider using `list_of_constraint_types`

and a function barrier. See the Performance tips for extensions section of the documentation for more details.

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

`num_constraints(model::Model; count_variable_in_set_constraints::Bool)`

Return the number of constraints in `model`

.

If `count_variable_in_set_constraints == true`

, then `VariableRef`

constraints such as `VariableRef`

-in-`Integer`

are included. To count only the number of structural constraints (e.g., the rows in the constraint matrix of a linear program), pass `count_variable_in_set_constraints = false`

.

**Examples**

```
julia> model = Model();
julia> @variable(model, x >= 0, Int);
julia> @constraint(model, 2x <= 1);
julia> num_constraints(model; count_variable_in_set_constraints = true)
3
julia> num_constraints(model; count_variable_in_set_constraints = false)
1
```

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

`JuMP.constraint_object`

— Function`constraint_object(con_ref::ConstraintRef)`

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

.

## Start values

`JuMP.set_dual_start_value`

— Function`set_dual_start_value(con_ref::ConstraintRef, value)`

Set the dual start value (MOI attribute `ConstraintDualStart`

) of the constraint `con_ref`

to `value`

. To remove a dual start value set it to `nothing`

.

See also `dual_start_value`

.

`JuMP.dual_start_value`

— Function`dual_start_value(con_ref::ConstraintRef)`

Return the dual start value (MOI attribute `ConstraintDualStart`

) of the constraint `con_ref`

.

Note: If no dual start value has been set, `dual_start_value`

will return `nothing`

.

See also `set_dual_start_value`

.

## Special sets

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

.

**Examples**

The following constrains $\|(x-1, x-2)\|^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 = @constraint(model, a >= b, PSDCone())
[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 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.SOS1`

— Type`SOS1`

SOS1 (Special Ordered Sets type 1) object than can be used to constrain a vector `x`

to a set where at most 1 variable can take a non-zero value, all others being at 0. The `weights`

, when specified, 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. This is a shortcut for the `MathOptInterface.SOS1`

set.

`JuMP.SOS2`

— Type`SOS2`

SOS1 (Special Ordered Sets type 2) object than can be used to constrain a vector `x`

to a set where at most 2 variables can take a non-zero value, all others being at 0. In addition, if two are non-zero these must be consecutive in their ordering. 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. This is a shortcut for the `MathOptInterface.SOS2`

set.

`JuMP.SkewSymmetricMatrixSpace`

— Type`SkewSymmetricMatrixSpace()`

Use in the `@variable`

macro to constrain a matrix of variables to be skew-symmetric.

**Examples**

`@variable(model, Q[1:2, 1:2] in SkewSymmetricMatrixSpace())`

`JuMP.SkewSymmetricMatrixShape`

— Type`SkewSymmetricMatrixShape`

Shape object for a skew symmetric square matrix of `side_dimension`

rows and columns. The vectorized form contains the entries of the upper-right triangular part of the matrix (without the diagonal) given column by column (or equivalently, the entries of the lower-left triangular part given row by row). The diagonal is zero.

`JuMP.SymmetricMatrixSpace`

— Type`SymmetricMatrixSpace()`

Use in the `@variable`

macro to constrain a matrix of variables to be symmetric.

**Examples**

```
julia> @variable(model, Q[1:2, 1:2] in SymmetricMatrixSpace())
2×2 LinearAlgebra.Symmetric{VariableRef,Array{VariableRef,2}}:
Q[1,1] Q[1,2]
Q[1,2] Q[2,2]
```

`JuMP.moi_set`

— Function`moi_set(constraint::AbstractConstraint)`

Return the set of the constraint `constraint`

in the function-in-set form as a `MathOptInterface.AbstractSet`

.

`moi_set(s::AbstractVectorSet, dim::Int)`

Returns the MOI set of dimension `dim`

corresponding to the JuMP set `s`

.

## Printing

`JuMP.function_string`

— Function```
function_string(
mode::MIME,
func::Union{JuMP.AbstractJuMPScalar,Vector{<:JuMP.AbstractJuMPScalar}},
)
```

Return a `String`

representing the function `func`

using print mode `mode`

.

`JuMP.constraints_string`

— Function`constraints_string(mode, model::AbstractModel)::Vector{String}`

Return a list of `String`

s describing each constraint of the model.

`JuMP.in_set_string`

— Function`in_set_string(mode::MIME, set)`

Return a `String`

representing the membership to the set `set`

using print mode `mode`

.

`JuMP.show_constraints_summary`

— Function`show_constraints_summary(io::IO, model::AbstractModel)`

Write to `io`

a summary of the number of constraints.