# Extensions

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

## Define a new set

`JuMP.AbstractVectorSet`

— Type`AbstractVectorSet`

An abstract type for defining new sets in JuMP.

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

to convert the type into an MOI set.

See also: `moi_set`

.

`JuMP.AbstractScalarSet`

— Type`AbstractScalarSet`

An abstract type for defining new scalar sets in JuMP.

Implement `moi_set(::AbstractScalarSet)`

to convert the type into an MOI set.

See also: `moi_set`

.

## Extend `@variable`

`JuMP.ScalarVariable`

— Type`ScalarVariable{S,T,U,V} <: AbstractVariable`

A struct used when adding variables.

See also: `add_variable`

.

`JuMP.VariableInfo`

— Type`VariableInfo{S,T,U,V}`

A struct by JuMP internally when creating variables. This may also be used by JuMP extensions to create new types of variables.

See also: `ScalarVariable`

.

`JuMP.add_variable`

— Function`add_variable(m::Model, v::AbstractVariable, name::String="")`

Add a variable `v`

to `Model m`

and sets its name.

`JuMP.build_variable`

— Function```
build_variable(
_error::Function,
info::VariableInfo,
args...;
kwargs...,
)
```

Return a new `AbstractVariable`

object.

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

**Arguments**

`_error`

: a function to call instead of`error`

.`_error`

annotates the error message with additional information for the user.`info`

: an instance of`VariableInfo`

. This has a variety of fields relating to the variable such as`info.lower_bound`

and`info.binary`

.`args`

: optional additional positional arguments for extending the`@variable`

macro.`kwargs`

: optional keyword arguments for extending the`@variable`

macro.

See also: `@variable`

Extensions should define a method with ONE positional argument to dispatch the call to a different method. Creating an extension that relies on multiple positional arguments leads to `MethodError`

s if the user passes the arguments in the wrong order.

**Example**

`@variable(model, x, Foo)`

will call

`build_variable(_error::Function, info::VariableInfo, ::Type{Foo})`

Passing special-case positional arguments such as `Bin`

, `Int`

, and `PSD`

is okay, along with keyword arguments:

```
@variable(model, x, Int, Foo(), mykwarg = true)
# or
@variable(model, x, Foo(), Int, mykwarg = true)
```

will call

`build_variable(_error::Function, info::VariableInfo, ::Foo; mykwarg)`

and `info.integer`

will be true.

Note that the order of the positional arguments does not matter.

`build_variable(_error::Function, variables, ::SymmetricMatrixSpace)`

Return a `VariablesConstrainedOnCreation`

of shape `SymmetricMatrixShape`

creating variables in `MOI.Reals`

, i.e. "free" variables unless they are constrained after their creation.

This function is used by the `@variable`

macro as follows:

```
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2], Symmetric)
2×2 LinearAlgebra.Symmetric{VariableRef, Matrix{VariableRef}}:
Q[1,1] Q[1,2]
Q[1,2] Q[2,2]
```

`build_variable(_error::Function, variables, ::SkewSymmetricMatrixSpace)`

Return a `VariablesConstrainedOnCreation`

of shape `SkewSymmetricMatrixShape`

creating variables in `MOI.Reals`

, i.e. "free" variables unless they are constrained after their creation.

This function is used by the `@variable`

macro as follows:

```
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2] in SkewSymmetricMatrixSpace())
2×2 Matrix{AffExpr}:
0 Q[1,2]
-Q[1,2] 0
```

`build_variable(_error::Function, variables, ::HermitianMatrixSpace)`

Return a `VariablesConstrainedOnCreation`

of shape `HermitianMatrixShape`

creating variables in `MOI.Reals`

, i.e. "free" variables unless they are constrained after their creation.

This function is used by the `@variable`

macro as follows:

```
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2] in HermitianMatrixSpace())
2×2 LinearAlgebra.Hermitian{GenericAffExpr{ComplexF64, VariableRef}, Matrix{GenericAffExpr{ComplexF64, VariableRef}}}:
real(Q[1,1]) real(Q[1,2]) + (0.0 + 1.0im) imag(Q[1,2])
real(Q[1,2]) + (0.0 - 1.0im) imag(Q[1,2]) real(Q[2,2])
```

`build_variable(_error::Function, variables, ::PSDCone)`

Return a `VariablesConstrainedOnCreation`

of shape `SymmetricMatrixShape`

constraining the variables to be positive semidefinite.

This function is used by the `@variable`

macro as follows:

```
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2], PSD)
2×2 LinearAlgebra.Symmetric{VariableRef, Matrix{VariableRef}}:
Q[1,1] Q[1,2]
Q[1,2] Q[2,2]
```

## Extend `@constraint`

`JuMP.build_constraint`

— Function```
build_constraint(
_error::Function,
Q::LinearAlgebra.Symmetric{V, M},
::PSDCone,
) where {V<:AbstractJuMPScalar,M<:AbstractMatrix{V}}
```

Return a `VectorConstraint`

of shape `SymmetricMatrixShape`

constraining the matrix `Q`

to be positive semidefinite.

This function is used by the `@constraint`

macros as follows:

```
julia> import LinearAlgebra
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2]);
julia> @constraint(model, LinearAlgebra.Symmetric(Q) in PSDCone())
[Q[1,1] Q[1,2];
Q[1,2] Q[2,2]] ∈ PSDCone()
```

The form above is usually used when the entries of `Q`

are affine or quadratic expressions, but it can also be used when the entries are variables to get the reference of the semidefinite constraint, e.g.,

```
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2], Symmetric)
2×2 LinearAlgebra.Symmetric{VariableRef, Matrix{VariableRef}}:
Q[1,1] Q[1,2]
Q[1,2] Q[2,2]
julia> @constraint(model, Q in PSDCone())
[Q[1,1] Q[1,2];
Q[1,2] Q[2,2]] ∈ PSDCone()
```

```
build_constraint(
_error::Function,
Q::AbstractMatrix{<:AbstractJuMPScalar},
::PSDCone,
)
```

Return a `VectorConstraint`

of shape `SquareMatrixShape`

constraining the matrix `Q`

to be symmetric and positive semidefinite.

This function is used by the `@constraint`

macro as follows:

```
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2]);
julia> @constraint(model, Q in PSDCone())
[Q[1,1] Q[1,2];
Q[2,1] Q[2,2]] ∈ PSDCone()
```

```
build_constraint(
_error::Function,
Q::LinearAlgebra.Hermitian{V,M},
::HermitianPSDCone,
) where {V<:AbstractJuMPScalar,M<:AbstractMatrix{V}}
```

Return a `VectorConstraint`

of shape `HermitianMatrixShape`

constraining the matrix `Q`

to be Hermitian positive semidefinite.

This function is used by the `@constraint`

macros as follows:

```
julia> import LinearAlgebra
julia> model = Model();
julia> @variable(model, Q[1:2, 1:2]);
julia> @constraint(model, LinearAlgebra.Hermitian(Q) in HermitianPSDCone())
[Q[1,1] Q[1,2];
Q[1,2] Q[2,2]] ∈ HermitianPSDCone()
```

```
build_constraint(
_error::Function,
f::AbstractVector{<:AbstractJuMPScalar},
::Nonnegatives,
extra::Union{MOI.AbstractVectorSet,AbstractVectorSet},
)
```

A helper method that re-writes

`@constraint(model, X >= Y, extra)`

into

`@constraint(model, X - Y in extra)`

```
build_constraint(
_error::Function,
f::AbstractVector{<:AbstractJuMPScalar},
::Nonpositives,
extra::Union{MOI.AbstractVectorSet,AbstractVectorSet},
)
```

A helper method that re-writes

`@constraint(model, Y <= X, extra)`

into

`@constraint(model, X - Y in extra)`

`JuMP.add_constraint`

— Function`add_constraint(model::Model, con::AbstractConstraint, name::String="")`

Add a constraint `con`

to `Model model`

and sets its name.

`JuMP.AbstractShape`

— Type`AbstractShape`

Abstract vectorizable shape. Given a flat vector form of an object of shape `shape`

, the original object can be obtained by `reshape_vector`

.

`JuMP.shape`

— Function`shape(c::AbstractConstraint)::AbstractShape`

Return the shape of the constraint `c`

.

`JuMP.reshape_vector`

— Function`reshape_vector(vectorized_form::Vector, shape::AbstractShape)`

Return an object in its original shape `shape`

given its vectorized form `vectorized_form`

.

**Example**

Given a `SymmetricMatrixShape`

of vectorized form `[1, 2, 3]`

, the following code returns the matrix `Symmetric(Matrix[1 2; 2 3])`

:

```
julia> reshape_vector([1, 2, 3], SymmetricMatrixShape(2))
2×2 LinearAlgebra.Symmetric{Int64,Array{Int64,2}}:
1 2
2 3
```

`JuMP.reshape_set`

— Function`reshape_set(vectorized_set::MOI.AbstractSet, shape::AbstractShape)`

Return a set in its original shape `shape`

given its vectorized form `vectorized_form`

.

**Example**

Given a `SymmetricMatrixShape`

of vectorized form `[1, 2, 3] in MOI.PositiveSemidefinieConeTriangle(2)`

, the following code returns the set of the original constraint `Symmetric(Matrix[1 2; 2 3]) in PSDCone()`

:

```
julia> reshape_set(MOI.PositiveSemidefiniteConeTriangle(2), SymmetricMatrixShape(2))
PSDCone()
```

`JuMP.dual_shape`

— Function`dual_shape(shape::AbstractShape)::AbstractShape`

Returns the shape of the dual space of the space of objects of shape `shape`

. By default, the `dual_shape`

of a shape is itself. See the examples section below for an example for which this is not the case.

**Example**

Consider polynomial constraints for which the dual is moment constraints and moment constraints for which the dual is polynomial constraints. Shapes for polynomials can be defined as follows:

```
struct Polynomial
coefficients::Vector{Float64}
monomials::Vector{Monomial}
end
struct PolynomialShape <: AbstractShape
monomials::Vector{Monomial}
end
JuMP.reshape_vector(x::Vector, shape::PolynomialShape) = Polynomial(x, shape.monomials)
```

and a shape for moments can be defined as follows:

```
struct Moments
coefficients::Vector{Float64}
monomials::Vector{Monomial}
end
struct MomentsShape <: AbstractShape
monomials::Vector{Monomial}
end
JuMP.reshape_vector(x::Vector, shape::MomentsShape) = Moments(x, shape.monomials)
```

Then `dual_shape`

allows the definition of the shape of the dual of polynomial and moment constraints:

```
dual_shape(shape::PolynomialShape) = MomentsShape(shape.monomials)
dual_shape(shape::MomentsShape) = PolynomialShape(shape.monomials)
```

`JuMP.ScalarShape`

— Type`ScalarShape`

Shape of scalar constraints.

`JuMP.VectorShape`

— Type`VectorShape`

Vector for which the vectorized form corresponds exactly to the vector given.

`JuMP.SquareMatrixShape`

— Type`SquareMatrixShape`

Shape object for a square matrix of `side_dimension`

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

`JuMP.SymmetricMatrixShape`

— Type`SymmetricMatrixShape`

Shape object for a symmetric square matrix of `side_dimension`

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

`JuMP.operator_to_set`

— Function`operator_to_set(_error::Function, ::Val{sense_symbol})`

Converts a sense symbol to a set `set`

such that `@constraint(model, func sense_symbol 0)`

is equivalent to `@constraint(model, func in set)`

for any `func::AbstractJuMPScalar`

.

**Example**

Once a custom set is defined you can directly create a JuMP constraint with it:

```
julia> struct CustomSet{T} <: MOI.AbstractScalarSet
value::T
end
julia> Base.copy(x::CustomSet) = CustomSet(x.value)
julia> model = Model();
julia> @variable(model, x)
x
julia> cref = @constraint(model, x in CustomSet(1.0))
x ∈ CustomSet{Float64}(1.0)
```

However, there might be an appropriate sign that could be used in order to provide a more convenient syntax:

```
julia> JuMP.operator_to_set(::Function, ::Val{:⊰}) = CustomSet(0.0)
julia> MOIU.shift_constant(set::CustomSet, value) = CustomSet(set.value + value)
julia> cref = @constraint(model, x ⊰ 1)
x ∈ CustomSet{Float64}(1.0)
```

Note that the whole function is first moved to the right-hand side, then the sign is transformed into a set with zero constant and finally the constant is moved to the set with `MOIU.shift_constant`

.

`JuMP.parse_constraint`

— Function`parse_constraint(_error::Function, expr::Expr)`

The entry-point for all constraint-related parsing.

**Arguments**

- The
`_error`

function is passed everywhere to provide better error messages `expr`

comes from the`@constraint`

macro. There are two possibilities:`@constraint(model, expr)`

`@constraint(model, name[args], expr)`

`expr`

is the main component of the constraint.

**Supported syntax**

JuMP currently supports the following `expr`

objects:

`lhs <= rhs`

`lhs == rhs`

`lhs >= rhs`

`l <= body <= u`

`u >= body >= l`

`lhs ⟂ rhs`

`lhs in rhs`

`lhs ∈ rhs`

`z => {constraint}`

`!z => {constraint}`

as well as all broadcasted variants.

**Extensions**

The infrastructure behind `parse_constraint`

is extendable. See `parse_constraint_head`

and `parse_constraint_call`

for details.

`JuMP.parse_constraint_head`

— Function`parse_constraint_head(_error::Function, ::Val{head}, args...)`

Implement this method to intercept the parsing of an expression with head `head`

.

Extending the constraint macro at parse time is an advanced operation and has the potential to interfere with existing JuMP syntax. Please discuss with the developer chatroom before publishing any code that implements these methods.

**Arguments**

`_error`

: a function that accepts a`String`

and throws the string as an error, along with some descriptive information of the macro from which it was thrown.`head`

: the`.head`

field of the`Expr`

to intercept`args...`

: the`.args`

field of the`Expr`

.

**Returns**

This function must return:

`is_vectorized::Bool`

: whether the expression represents a broadcasted expression like`x .<= 1`

`parse_code::Expr`

: an expression containing any setup or rewriting code that needs to be called before`build_constraint`

`build_code::Expr`

: an expression that calls`build_constraint(`

or`build_constraint.(`

depending on`is_vectorized`

.

**Existing implementations**

JuMP currently implements:

`::Val{:call}`

, which forwards calls to`parse_constraint_call`

`::Val{:comparison}`

, which handles the special case of`l <= body <= u`

.

See also: `parse_constraint_call`

, `build_constraint`

`JuMP.parse_constraint_call`

— Function```
parse_constraint_call(
_error::Function,
is_vectorized::Bool,
::Val{op},
args...,
)
```

Implement this method to intercept the parsing of a `:call`

expression with operator `op`

.

Extending the constraint macro at parse time is an advanced operation and has the potential to interfere with existing JuMP syntax. Please discuss with the developer chatroom before publishing any code that implements these methods.

**Arguments**

`_error`

: a function that accepts a`String`

and throws the string as an error, along with some descriptive information of the macro from which it was thrown.`is_vectorized`

: a boolean to indicate if`op`

should be broadcast or not`op`

: the first element of the`.args`

field of the`Expr`

to intercept`args...`

: the`.args`

field of the`Expr`

.

**Returns**

This function must return:

`parse_code::Expr`

: an expression containing any setup or rewriting code that needs to be called before`build_constraint`

`build_code::Expr`

: an expression that calls`build_constraint(`

or`build_constraint.(`

depending on`is_vectorized`

.

See also: `parse_constraint_head`

, `build_constraint`

```
parse_constraint_call(
_error::Function,
vectorized::Bool,
::Val{op},
lhs,
rhs,
) where {op}
```

Fallback handler for binary operators. These might be infix operators like `@constraint(model, lhs op rhs)`

, or normal operators like `@constraint(model, op(lhs, rhs))`

.

In both cases, we rewrite as `lhs - rhs in operator_to_set(_error, op)`

.

See `operator_to_set`

for details.