Variables
What is a JuMP variable?
The term variable in mathematical optimization has many meanings. Here, we distinguish between the following three types of variables:
- optimization variables, which are the mathematical $x$ in the problem $\max\{f_0(x) | f_i(x) \in S_i\}$.
- Julia variables, which are bindings between a name and a value, for example
x = 1
. (See here for the Julia docs.) - JuMP variables, which are instances of the
VariableRef
struct defined by JuMP that contains a reference to an optimization variable in a model. (Extra for experts: theVariableRef
struct is a thin wrapper around aMOI.VariableIndex
, and also contains a reference to the JuMP model.)
To illustrate these three types of variables, consider the following JuMP code (the full syntax is explained below):
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[1:2])
2-element Array{VariableRef,1}:
x[1]
x[2]
This code does three things:
- It adds two optimization variables to
model
. - It creates two JuMP variables that act as references to those optimization variables.
- It binds those JuMP variables as a vector with two elements to the Julia variable
x
.
To reduce confusion, we will attempt, where possible, to always refer to variables with their corresponding prefix.
JuMP variables can have attributes, such as names or an initial primal start value. We illustrate the name attribute in the following example:
julia> @variable(model, y, base_name="decision variable")
decision variable
This code does four things:
- It adds one optimization variable to
model
. - It creates one JuMP variable that acts as a reference to that optimization variable.
- It binds the JuMP variable to the Julia variable
y
. - It tells JuMP that the name attribute of this JuMP variable is "decision variable". JuMP uses the value of
base_name
when it has to print the variable as a string.
For example, when we print y
at the REPL we get:
julia> y
decision variable
Because y
is a Julia variable, we can bind it to a different value. For example, if we write:
julia> y = 1
1
y
is no longer a binding to a JuMP variable. This does not mean that the JuMP variable has been destroyed. It still exists and is still a reference to the same optimization variable. The binding can be reset by querying the model for the symbol as it was written in the @variable
macro. For example:
julia> model[:y]
decision variable
This act of looking up the JuMP variable by using the symbol is most useful when composing JuMP models across multiple functions, as illustrated by the following example:
function add_component_to_model(model::JuMP.Model)
x = model[:x]
# ... code that uses x
end
function build_model()
model = Model()
@variable(model, x)
add_component_to_model(model)
end
Now that we understand the difference between optimization, JuMP, and Julia variables, we can introduce more of the functionality of the @variable
macro.
Variable bounds
We have already seen the basic usage of the @variable
macro. The next extension is to add lower- and upper-bounds to each optimization variable. This can be done as follows:
julia> @variable(model, x_free)
x_free
julia> @variable(model, x_lower >= 0)
x_lower
julia> @variable(model, x_upper <= 1)
x_upper
julia> @variable(model, 2 <= x_interval <= 3)
x_interval
julia> @variable(model, x_fixed == 4)
x_fixed
In the above examples, x_free
represents an unbounded optimization variable, x_lower
represents an optimization variable with a lower bound and so forth.
When creating a variable with only a lower-bound or an upper-bound, and the value of the bound is not a numeric literal, the name must appear on the left-hand side. Putting the name on the right-hand side will result in an error. For example:
@variable(model, 1 <= x) # works
a = 1
@variable(model, a <= x) # errors
We can query whether an optimization variable has a lower- or upper-bound via the has_lower_bound
and has_upper_bound
functions. For example:
julia> has_lower_bound(x_free)
false
julia> has_upper_bound(x_upper)
true
If a variable has a lower or upper bound, we can query the value of it via the lower_bound
and upper_bound
functions. For example:
julia> lower_bound(x_interval)
2.0
julia> upper_bound(x_interval)
3.0
Querying the value of a bound that does not exist will result in an error.
Instead of using the <=
and >=
syntax, we can also use the lower_bound
and upper_bound
keyword arguments. For example:
julia> @variable(model, x, lower_bound=1, upper_bound=2)
x
julia> lower_bound(x)
1.0
Another option is to use the set_lower_bound
and set_upper_bound
functions. These can also be used to modify an existing variable bound. For example:
julia> @variable(model, x >= 1)
x
julia> lower_bound(x)
1.0
julia> set_lower_bound(x, 2)
julia> lower_bound(x)
2.0
We can delete variable bounds using delete_lower_bound
and delete_upper_bound
:
julia> @variable(model, 1 <= x <= 2)
x
julia> lower_bound(x)
1.0
julia> delete_lower_bound(x)
julia> has_lower_bound(x)
false
julia> upper_bound(x)
2.0
julia> delete_upper_bound(x)
julia> has_upper_bound(x)
false
In addition to upper and lower bounds, JuMP variables can also be fixed to a value using fix
. See also is_fixed
, fix_value
, and unfix
.
julia> @variable(model, x == 1)
x
julia> is_fixed(x)
true
julia> fix_value(x)
1.0
julia> unfix(x)
julia> is_fixed(x)
false
Fixing a variable with existing bounds will throw an error. To delete the bounds prior to fixing, use fix(variable, value; force = true)
.
julia> @variable(model, x >= 1)
x
julia> fix(x, 2)
ERROR: Unable to fix x to 2 because it has existing variable bounds. Consider calling `JuMP.fix(variable, value; force=true)` which will delete existing bounds before fixing the variable.
julia> fix(x, 2; force = true)
julia> fix_value(x)
2.0
Variable names
The name, i.e. the value of the MOI.VariableName
attribute, of a variable can be obtained by JuMP.name(::JuMP.VariableRef)
and set by JuMP.set_name(::JuMP.VariableRef, ::String)
.
JuMP.name
— Method.name(v::VariableRef)::String
Get a variable's name attribute.
JuMP.set_name
— Method.set_name(v::VariableRef, s::AbstractString)
Set a variable's name attribute.
The variable can also be retrieved from its name using JuMP.variable_by_name
.
JuMP.variable_by_name
— Function.variable_by_name(model::AbstractModel,
name::String)::Union{AbstractVariableRef, Nothing}
Returns the reference of the variable with name attribute name
or Nothing
if no variable has this name attribute. Throws an error if several variables have name
as their name attribute.
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> variable_by_name(model, "x")
x
julia> @variable(model, base_name="x")
x
julia> variable_by_name(model, "x")
ERROR: Multiple variables have the name x.
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] get(::JuMP._MOIModel{Float64}, ::Type{MathOptInterface.VariableIndex}, ::String) at /home/blegat/.julia/dev/MathOptInterface/src/Utilities/model.jl:222
[3] get at /home/blegat/.julia/dev/MathOptInterface/src/Utilities/universalfallback.jl:201 [inlined]
[4] get(::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.AbstractOptimizer,MathOptInterface.Utilities.UniversalFallback{JuMP._MOIModel{Float64}}}, ::Type{MathOptInterface.VariableIndex}, ::String) at /home/blegat/.julia/dev/MathOptInterface/src/Utilities/cachingoptimizer.jl:490
[5] variable_by_name(::Model, ::String) at /home/blegat/.julia/dev/JuMP/src/variables.jl:268
[6] top-level scope at none:0
julia> var = @variable(model, base_name="y")
y
julia> variable_by_name(model, "y")
y
julia> set_name(var, "z")
julia> variable_by_name(model, "y")
julia> variable_by_name(model, "z")
z
julia> @variable(model, u[1:2])
2-element Array{VariableRef,1}:
u[1]
u[2]
julia> variable_by_name(model, "u[2]")
u[2]
Variable containers
In the examples above, we have mostly created scalar variables. By scalar, we mean that the Julia variable is bound to exactly one JuMP variable. However, it is often useful to create collections of JuMP variables inside more complicated data structures.
JuMP provides a mechanism for creating three types of these data structures, which we refer to as containers. The three types are Array
s, DenseAxisArray
s, and SparseAxisArray
s. We explain each of these in the following.
Arrays
We have already seen the creation of an array of JuMP variables with the x[1:2]
syntax. This can naturally be extended to create multi-dimensional arrays of JuMP variables. For example:
julia> @variable(model, x[1:2, 1:2])
2×2 Array{VariableRef,2}:
x[1,1] x[1,2]
x[2,1] x[2,2]
Arrays of JuMP variables can be indexed and sliced as follows:
julia> x[1, 2]
x[1,2]
julia> x[2, :]
2-element Array{VariableRef,1}:
x[2,1]
x[2,2]
Variable bounds can depend upon the indices:
julia> @variable(model, x[i=1:2, j=1:2] >= 2i + j)
2×2 Array{VariableRef,2}:
x[1,1] x[1,2]
x[2,1] x[2,2]
julia> lower_bound.(x)
2×2 Array{Float64,2}:
3.0 4.0
5.0 6.0
JuMP will form an Array
of JuMP variables when it can determine at compile time that the indices are one-based integer ranges. Therefore x[1:b]
will create an Array
of JuMP variables, but x[a:b]
will not. If JuMP cannot determine that the indices are one-based integer ranges (e.g., in the case of x[a:b]
), JuMP will create a DenseAxisArray
instead.
DenseAxisArrays
We often want to create arrays where the indices are not one-based integer ranges. For example, we may want to create a variable indexed by the name of a product or a location. The syntax is the same as that above, except with an arbitrary vector as an index as opposed to a one-based range. The biggest difference is that instead of returning an Array
of JuMP variables, JuMP will return a DenseAxisArray
. For example:
julia> @variable(model, x[1:2, [:A,:B]])
2-dimensional DenseAxisArray{VariableRef,2,...} with index sets:
Dimension 1, 1:2
Dimension 2, Symbol[:A, :B]
And data, a 2×2 Array{VariableRef,2}:
x[1,A] x[1,B]
x[2,A] x[2,B]
DenseAxisArrays can be indexed and sliced as follows:
julia> x[1, :A]
x[1,A]
julia> x[2, :]
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
Dimension 1, Symbol[:A, :B]
And data, a 2-element Array{VariableRef,1}:
x[2,A]
x[2,B]
Similarly to the Array
case, bounds can depend upon indices. For example:
julia> @variable(model, x[i=2:3, j=1:2:3] >= 0.5i + j)
2-dimensional DenseAxisArray{VariableRef,2,...} with index sets:
Dimension 1, 2:3
Dimension 2, 1:2:3
And data, a 2×2 Array{VariableRef,2}:
x[2,1] x[2,3]
x[3,1] x[3,3]
julia> lower_bound.(x)
2-dimensional DenseAxisArray{Float64,2,...} with index sets:
Dimension 1, 2:3
Dimension 2, 1:2:3
And data, a 2×2 Array{Float64,2}:
2.0 4.0
2.5 4.5
SparseAxisArrays
The third container type that JuMP natively supports is SparseAxisArray
. These arrays are created when the indices do not form a rectangular set. For example, this applies when indices have a dependence upon previous indices (called triangular indexing). JuMP supports this as follows:
julia> @variable(model, x[i=1:2, j=i:2])
JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}} with 3 entries:
[1, 2] = x[1,2]
[2, 2] = x[2,2]
[1, 1] = x[1,1]
We can also conditionally create variables via a JuMP-specific syntax. This syntax appends a comparison check that depends upon the named indices and is separated from the indices by a semi-colon (;
). For example:
julia> @variable(model, x[i=1:4; mod(i, 2)==0])
JuMP.Containers.SparseAxisArray{VariableRef,1,Tuple{Any}} with 2 entries:
[4] = x[4]
[2] = x[2]
Forcing the container type
When creating a container of JuMP variables, JuMP will attempt to choose the tightest container type that can store the JuMP variables. Thus, it will prefer to create an Array before a DenseAxisArray and a DenseAxisArray before a SparseAxisArray. However, because this happens at compile time, it does not always make the best choice. To illustrate this, consider the following example:
julia> A = 1:2
1:2
julia> @variable(model, x[A])
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
Dimension 1, 1:2
And data, a 2-element Array{VariableRef,1}:
x[1]
x[2]
Since the value (and type) of A
is unknown at parsing time, JuMP is unable to infer that A
is a one-based integer range. Therefore, JuMP creates a DenseAxisArray
, even though it could store these two variables in a standard one-dimensional Array
.
We can share our knowledge that it is possible to store these JuMP variables as an array by setting the container
keyword:
julia> @variable(model, y[A], container=Array)
2-element Array{VariableRef,1}:
y[1]
y[2]
JuMP now creates a vector of JuMP variables instead of a DenseAxisArray. Note that choosing an invalid container type will throw an error.
Integrality shortcuts
Adding integrality constraints to a model such as @constraint(model, x in MOI.ZeroOne())
and @constraint(model, x in MOI.Integer())
is a common operation. Therefore, JuMP supports two shortcuts for adding such constraints.
Binary (ZeroOne) constraints
Binary optimization variables are constrained to the set $x \in \{0, 1\}$. (The MOI.ZeroOne
set in MathOptInterface.) Binary optimization variables can be created in JuMP by passing Bin
as an optional positional argument:
julia> @variable(model, x, Bin)
x
We can check if an optimization variable is binary by calling is_binary
on the JuMP variable, and binary constraints can be removed with unset_binary
.
julia> is_binary(x)
true
julia> unset_binary(x)
julia> is_binary(x)
false
Binary optimization variables can also be created by setting the binary
keyword to true
.
julia> @variable(model, x, binary=true)
x
Integer constraints
Integer optimization variables are constrained to the set $x \in \mathbb{Z}$. (The MOI.Integer
set in MathOptInterface.) Integer optimization variables can be created in JuMP by passing Int
as an optional positional argument:
julia> @variable(model, x, Int)
x
Integer optimization variables can also be created by setting the integer
keyword to true
.
julia> @variable(model, x, integer=true)
x
We can check if an optimization variable is integer by calling is_integer
on the JuMP variable, and integer constraints can be removed with unset_integer
.
julia> is_integer(x)
true
julia> unset_integer(x)
julia> is_integer(x)
false
Semidefinite variables
JuMP also supports modeling with semidefinite variables. A square symmetric matrix $X$ is positive semidefinite if all eigenvalues are nonnegative. We can declare a matrix of JuMP variables to be positive semidefinite as follows:
julia> @variable(model, x[1:2, 1:2], PSD)
2×2 LinearAlgebra.Symmetric{VariableRef,Array{VariableRef,2}}:
x[1,1] x[1,2]
x[1,2] x[2,2]
Note that x
must be a square 2-dimensional Array
of JuMP variables; it cannot be a DenseAxisArray or a SparseAxisArray. (See Variable containers, above, for more on this.)
You can also impose a weaker constraint that the square matrix is only symmetric (instead of positive semidefinite) as follows:
julia> @variable(model, x[1:2, 1:2], Symmetric)
2×2 LinearAlgebra.Symmetric{VariableRef,Array{VariableRef,2}}:
x[1,1] x[1,2]
x[1,2] x[2,2]
Anonymous JuMP variables
In all of the above examples, we have created named JuMP variables. However, it is also possible to create so called anonymous JuMP variables. To create an anonymous JuMP variable, we drop the name of the variable from the macro call. This means dropping the second positional argument if the JuMP variable is a scalar, or dropping the name before the square bracket ([
) if a container is being created. For example:
julia> x = @variable(model)
noname
This shows how (model, x)
is really short for:
julia> x = model[:x] = @variable(model, base_name="x")
x
An Array
of anonymous JuMP variables can be created as follows:
julia> y = @variable(model, [i=1:2])
2-element Array{VariableRef,1}:
noname
noname
If necessary, you can store x
in model
as follows:
julia> model[:x] = x
The <=
and >=
short-hand cannot be used to set bounds on anonymous JuMP variables. Instead, you should use the lower_bound
and upper_bound
keywords.
Passing the Bin
and Int
variable types are also invalid. Instead, you should use the binary
and integer
keywords.
Thus, the anonymous variant of @variable(model, x[i=1:2] >= i, Int)
is:
julia> x = @variable(model, [i=1:2], base_name="x", lower_bound=i, integer=true)
2-element Array{VariableRef,1}:
x[1]
x[2]
Creating two named JuMP variables with the same name results in an error at runtime. Use anonymous variables as an alternative.
User-defined containers
In the section Variable containers, we explained how JuMP supports the efficient creation of collections of JuMP variables in three types of containers. However, users are also free to create collections of JuMP variables in their own datastructures. For example, the following code creates a dictionary with symmetric matrices as the values:
julia> variables = Dict{Symbol, Array{VariableRef,2}}()
Dict{Symbol,Array{VariableRef,2}} with 0 entries
julia> for key in [:A, :B]
global variables[key] = @variable(model, [1:2, 1:2])
end
julia> variables
Dict{Symbol,Array{VariableRef,2}} with 2 entries:
:A => VariableRef[noname noname; noname noname]
:B => VariableRef[noname noname; noname noname]
Deleting variables
JuMP supports the deletion of optimization variables. To delete variables, we can use the delete
method. We can also check whether x
is a valid JuMP variable in model
using the is_valid
method:
julia> @variable(model, x)
x
julia> is_valid(model, x)
true
julia> delete(model, x)
julia> is_valid(model, x)
false
Listing all variables
Use JuMP.all_variables
to obtain a list of all variables present in the model. This is useful for performing operations like:
- relaxing all integrality constraints in the model
- setting the starting values for variables to the result of the last solve
Reference
JuMP.@variable
— Macro.@variable(model, kw_args...)
Add an anonymous variable to the model model
described by the keyword arguments kw_args
and returns the variable.
@variable(model, expr, args..., kw_args...)
Add a variable to the model model
described by the expression expr
, the positional arguments args
and the keyword arguments kw_args
. The expression expr
can either be (note that in the following the symbol <=
can be used instead of ≤
and the symbol >=
can be used instead of ≥
)
- of the form
varexpr
creating variables described byvarexpr
; - of the form
varexpr ≤ ub
(resp.varexpr ≥ lb
) creating variables described byvarexpr
with upper bounds given byub
(resp. lower bounds given bylb
); - of the form
varexpr == value
creating variables described byvarexpr
with fixed values given byvalue
; or - of the form
lb ≤ varexpr ≤ ub
orub ≥ varexpr ≥ lb
creating variables described byvarexpr
with lower bounds given bylb
and upper bounds given byub
.
The expression varexpr
can either be
- of the form
varname
creating a scalar real variable of namevarname
; - of the form
varname[...]
or[...]
creating a container of variables (see Containers in macros).
The recognized positional arguments in args
are the following:
Bin
: Sets the variable to be binary, i.e. either 0 or 1.Int
: Sets the variable to be integer, i.e. one of ..., -2, -1, 0, 1, 2, ...Symmetric
: Only available when creating a square matrix of variables, i.e. whenvarexpr
is of the formvarname[1:n,1:n]
orvarname[i=1:n,j=1:n]
. It creates a symmetric matrix of variable, that is, it only creates a new variable forvarname[i,j]
withi ≤ j
and setsvarname[j,i]
to the same variable asvarname[i,j]
.PSD
: The square matrix of variable is bothSymmetric
and constrained to be positive semidefinite.
The recognized keyword arguments in kw_args
are the following:
base_name
: Sets the name prefix used to generate variable names. It corresponds to the variable name for scalar variable, otherwise, the variable names are set tobase_name[...]
for each index...
of the axesaxes
.lower_bound
: Sets the value of the variable lower bound.upper_bound
: Sets the value of the variable upper bound.start
: Sets the variable starting value used as initial guess in optimization.binary
: Sets whether the variable is binary or not.integer
: Sets whether the variable is integer or not.variable_type
: See the "Note for extending the variable macro" section below.container
: Specify the container type, see Containers in macros.
Examples
The following are equivalent ways of creating a variable x
of name x
with lower bound 0:
# Specify everything in `expr`
@variable(model, x >= 0)
# Specify the lower bound using a keyword argument
@variable(model, x, lower_bound=0)
# Specify everything in `kw_args`
x = @variable(model, base_name="x", lower_bound=0)
The following are equivalent ways of creating a DenseAxisArray
of index set [:a, :b]
and with respective upper bounds 2 and 3 and names x[a]
and x[b]
.
ub = Dict(:a => 2, :b => 3)
# Specify everything in `expr`
@variable(model, x[i=keys(ub)] <= ub[i])
# Specify the upper bound using a keyword argument
@variable(model, x[i=keys(ub)], upper_bound=ub[i])
Note for extending the variable macro
The single scalar variable or each scalar variable of the container are created using add_variable(model, build_variable(_error, info, extra_args...; extra_kw_args...))
where
model
is the model passed to the@variable
macro;_error
is an error function with a singleString
argument showing the@variable
call in addition to the error message given as argument;info
is theVariableInfo
struct containing the information gathered inexpr
, the recognized keyword arguments (exceptbase_name
andvariable_type
) and the recognized positional arguments (exceptSymmetric
andPSD
);extra_args
are the unrecognized positional arguments ofargs
plus the value of thevariable_type
keyword argument if present. Thevariable_type
keyword argument allows the user to pass a position argument tobuild_variable
without the need to give a positional argument to@variable
. In particular, this allows the user to give a positional argument to thebuild_variable
call when using the anonymous single variable syntax@variable(model, kw_args...)
; andextra_kw_args
are the unrecognized keyword argument ofkw_args
.
Examples
The following creates a variable x
of name x
with lower_bound
0 as with the first example above but does it without using the @variable
macro
info = VariableInfo(true, 0, false, NaN, false, NaN, false, NaN, false, false)
JuMP.add_variable(model, JuMP.build_variable(error, info), "x")
The following creates a DenseAxisArray
of index set [:a, :b]
and with respective upper bounds 2 and 3 and names x[a]
and x[b]
as with the second example above but does it without using the @variable
macro
# Without the `@variable` macro
data = Vector{JuMP.variable_type(model)}(undef, length(keys(ub)))
x = JuMP.Containers.DenseAxisArray(data, keys(ub))
for i in keys(ub)
info = VariableInfo(false, NaN, true, ub[i], false, NaN, false, NaN, false, false)
x[i] = JuMP.add_variable(model, JuMP.build_variable(error, info), "x[$i]")
end
The following are equivalent ways of creating a Matrix
of size N x N
with variables custom variables created with a JuMP extension using the Poly(X)
positional argument to specify its variables:
# Using the `@variable` macro
@variable(model, x[1:N,1:N], Symmetric, Poly(X))
# Without the `@variable` macro
x = Matrix{JuMP.variable_type(model, Poly(X))}(N, N)
info = VariableInfo(false, NaN, false, NaN, false, NaN, false, NaN, false, false)
for i in 1:N, j in i:N
x[i,j] = x[j,i] = JuMP.add_variable(model, build_variable(error, info, Poly(X)), "x[$i,$j]")
end
JuMP.owner_model
— Function.owner_model(s::AbstractJuMPScalar)
Return the model owning the scalar s
.
JuMP.VariableRef
— Type.VariableRef <: AbstractVariableRef
Holds a reference to the model and the corresponding MOI.VariableIndex.
JuMP.all_variables
— Function.all_variables(model::Model)::Vector{VariableRef}
Returns a list of all variables currently in the model. The variables are ordered by creation time.
Example
model = Model()
@variable(model, x)
@variable(model, y)
all_variables(model)
# output
2-element Array{VariableRef,1}:
x
y
JuMP.has_lower_bound
— Function.has_lower_bound(v::VariableRef)
Return true
if v
has a lower bound. If true
, the lower bound can be queried with lower_bound
. See also LowerBoundRef
.
JuMP.lower_bound
— Function.lower_bound(v::VariableRef)
Return the lower bound of a variable. Error if one does not exist. See also has_lower_bound
.
JuMP.set_lower_bound
— Function.set_lower_bound(v::VariableRef, lower::Number)
Set the lower bound of a variable. If one does not exist, create a new lower bound constraint. See also delete_lower_bound
.
JuMP.delete_lower_bound
— Function.delete_lower_bound(v::VariableRef)
Delete the lower bound constraint of a variable.
JuMP.has_upper_bound
— Function.has_upper_bound(v::VariableRef)
Return true
if v
has a upper bound. If true
, the upper bound can be queried with upper_bound
. See also UpperBoundRef
.
JuMP.upper_bound
— Function.upper_bound(v::VariableRef)
Return the upper bound of a variable. Error if one does not exist. See also has_upper_bound
.
JuMP.set_upper_bound
— Function.set_upper_bound(v::VariableRef,upper::Number)
Set the upper bound of a variable. If one does not exist, create an upper bound constraint. See also delete_upper_bound
.
JuMP.delete_upper_bound
— Function.delete_upper_bound(v::VariableRef)
Delete the upper bound constraint of a variable.
JuMP.is_fixed
— Function.JuMP.fix_value
— Function.fix_value(v::VariableRef)
Return the value to which a variable is fixed. Error if one does not exist. See also is_fixed
.
JuMP.fix
— Function.fix(v::VariableRef, value::Number; force::Bool = false)
Fix a variable to a value. Update the fixing constraint if one exists, otherwise create a new one. See also unfix
.
If the variable already has variable bounds and force=false
, calling fix
will throw an error. If force=true
, existing variable bounds will be deleted, and the fixing constraint will be added. Note a variable will have no bounds after a call to unfix
.
JuMP.unfix
— Function.unfix(v::VariableRef)
Delete the fixing constraint of a variable.
JuMP.is_integer
— Function.is_integer(v::VariableRef)
Return true
if v
is constrained to be integer. See also IntegerRef
.
JuMP.set_integer
— Function.set_integer(variable_ref::VariableRef)
Add an integrality constraint on the variable variable_ref
. See also unset_integer
.
JuMP.unset_integer
— Function.unset_integer(variable_ref::VariableRef)
Remove the integrality constraint on the variable variable_ref
.
JuMP.IntegerRef
— Function.IntegerRef(v::VariableRef)
Return a constraint reference to the constraint constrainting v
to be integer. Errors if one does not exist.
JuMP.is_binary
— Function.is_binary(v::VariableRef)
Return true
if v
is constrained to be binary. See also BinaryRef
.
JuMP.set_binary
— Function.set_binary(v::VariableRef)
Add a constraint on the variable v
that it must take values in the set $\{0,1\}$. See also unset_binary
.
JuMP.unset_binary
— Function.unset_binary(variable_ref::VariableRef)
Remove the binary constraint on the variable variable_ref
.
JuMP.BinaryRef
— Function.BinaryRef(v::VariableRef)
Return a constraint reference to the constraint constrainting v
to be binary. Errors if one does not exist.
JuMP.index
— Method.index(v::VariableRef)::MOI.VariableIndex
Return the index of the variable that corresponds to v
in the MOI backend.
JuMP.optimizer_index
— Method.optimizer_index(v::VariableRef)::MOI.VariableIndex
Return the index of the variable that corresponds to v
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.