This documentation tracks the development branch of JuMP. For the documentation of the latest JuMP release, see here.
Variables, also known as columns or decision variables, are the results of the optimization.
The primary way to create variables is with the
The first argument will always be a
Model. In the examples below we assume
m is already defined. The second argument is an expression that declares
the variable name and optionally allows specification of lower and upper bounds.
Adding variables “column-wise”, e.g., as in column generation, is supported as well;
see the syntax discussed in the Problem Modification section.
@variable(m, x ) # No bounds @variable(m, x >= lb ) # Lower bound only (note: 'lb <= x' is not valid) @variable(m, x <= ub ) # Upper bound only @variable(m, lb <= x <= ub ) # Lower and upper bounds @variable(m, x == fixedval ) # Fixed to a value (lb == ub)
All these variations create a new local variable, in this case
The names of your variables must be valid Julia variable names.
Integer and binary restrictions can optionally be specified with a third argument,
For advanced users,
SemiInt may be used to create
To create arrays of variables we append brackets to the variable name.
@variable(m, x[1:M,1:N] >= 0 )
will create an
N array of variables. Both ranges and arbitrary
iterable sets are supported as index sets. Currently we only support ranges
of the form
a is an explicit integer, not a variable. Using
ranges will generally be faster than using arbitrary symbols. You can mix both
ranges and lists of symbols, as in the following example:
s = ["Green","Blue"] @variable(m, x[-10:10,s] , Int) x[-4,"Green"]
Bounds can depend on variable indices:
@variable(m, x[i=1:10] >= i )
And indices can have dependencies on preceding indices (e.g. “triangular indexing”):
@variable(m, x[i=1:10,j=i:10] >= 0)
Note the dependency must be on preceding indices, going from left to right. That is,
@variable(m, x[i=j:10,i=1:10] >= 0) is not valid JuMP code.
Conditions can be placed on the index values for which variables are created; the condition follows the statement of the index sets and is separated with a semicolon:
@variable(m, x[i=1:10,j=1:10; isodd(i+j)] >= 0)
Note that only one condition can be added, although expressions can be built up by using the usual
|| logical operators.
An initial value of each variable may be provided with the
start keyword to
@variable(m, x[i=1:10], start=(i/2))
Is equivalent to:
@variable(m, x[i=1:10]) for i in 1:10 setvalue(x[i], i/2) end
For more complicated variable bounds, it may be clearer to specify them using the
upperbound keyword arguments to
@variable(m, x[i=1:3], lowerbound=my_complex_function(i)) @variable(m, x[i=1:3], lowerbound=my_complex_function(i), upperbound=another_function(i))
Variable categories may be set in a more programmatic way by providing
the appropriate symbol to the
category keyword argument:
t = [:Bin,:Int] @variable(m, x[i=1:2], category=t[i]) @variable(m, y, category=:SemiCont)
Variable(m::Model,idx::Int) may be used to create a variable object corresponding to an existing variable in the model (the constructor does not add a new variable to the model). The variable indices correspond to those of the internal MathProgBase model. The inverse of this operation is
linearindex(x::Variable), which returns the flattened out (linear) index of a variable as JuMP provides it to a solver. We guarantee that
x itself. These methods are only useful if you intend to interact with solver properties which are not directly exposed through JuMP.
@variable is equivalent to a simple assignment
x = ... in Julia and therefore redefines variables. The following code will generate a warning and may lead to unexpected results:
@variable(m, x[1:10,1:10]) @variable(m, x[1:5])
After the second line, the Julia variable
x refers to a set of variables indexed
by the range
The reference to the first set of variables has been lost, although they will remain
in the model. See also the section on anonymous variables.
We also provide a syntax for constructing “anonymous” variables.
@variable, you may omit the name of the variable
and instead assign the return value as you would like:
x = @variable(m) # Equivalent to @variable(m, x) x = @variable(m, [i=1:3], lowerbound = i, upperbound = 2i) # Equivalent to @variable(m, i <= x[i=1:3] <= 2i)
upperbound keywords must be used instead of comparison operators for specifying variable bounds within the anonymous syntax. For creating noncontinuous anonymous variables, the
category keyword must be used to avoid ambiguity, e.g.:
x = @variable(m, Bin) # error x = @variable(m, category = :Bin) # ok
Besides these syntax restrictions in the
@variable macro, the only differences between anonymous and named variables are:
- For the purposes of printing a model, JuMP will not have a name for anonymous variables and will instead use
__anon__. You may set the name of a variable for printing by using
basenamekeyword argument described below.
- Anonymous variables cannot be retrieved by using
If you would like to change the name used when printing a variable or group of variables, you may use the
basename keyword argument:
i = 3 @variable(m, x[1:3], basename="myvariable-$i") # OR: x = @variable(m, [1:3], basename="myvariable-$i")
x will display
Semidefinite and symmetric variables¶
JuMP supports modeling with semidefinite variables. A square symmetric matrix \(X\) is positive semidefinite if all eigenvalues are nonnegative; this is typically denoted by \(X \succeq 0\). You can declare a matrix of variables to be positive semidefinite as follows:
@variable(m, X[1:3,1:3], SDP)
Note in particular the indexing: 1) exactly two index sets must be specified, 2) they must both be unit ranges starting at 1, 3) no bounds can be provided alongside the
SDP tag. If you wish to impose more complex semidefinite constraints on the variables, e.g. \(X - I \succeq 0\), you may instead use the
Symmetric tag, along with a semidefinite constraint:
@variable(m, X[1:n,1:n], Symmetric) @SDconstraint(m, X >= eye(n))
Bounds can be provided as normal when using the
Symmetric tag, with the stipulation that the bounds are symmetric themselves.
JuMP provides a convenient syntax for defining multiple variables in a single block:
@variables m begin x y >= 0 Z[1:10], Bin X[1:3,1:3], SDP q[i=1:2], (lowerbound = i, start = 2i, upperbound = 3i) t[j=1:3], (Int, start = j) end # Equivalent to: @variable(m, x) @variable(m, y >= 0) @variable(m, Z[1:10], Bin) @variable(m, X[1:3,1:3], SDP) @variable(m, q[i=1:2], lowerbound = i, start = 2i, upperbound = 3i) @variable(m, t[j=1:3], Int, start = j)
The syntax follows that of
@variable with each declaration separated
by a new line. Note that unlike in
@variable, keyword arguments must be specified within
getlowerbound(x::Variable)- Set/get the lower bound of a variable.
getupperbound(x::Variable)- Set/get the upper bound of a variable.
setcategory(x::Variable, v_type::Symbol)- Set the variable category for
xafter construction. Possible categories are listed above.
getcategory(x::Variable)- Get the variable category for
sum(x)- Operates on arrays of variables, efficiently produces an affine expression. Available in macros.
dot(x, coeffs)- Performs a generalized “dot product” for arrays of variables and coefficients up to three dimensions, or equivalently the sum of the elements of the Hadamard product. Available in macros, and also as
getvalue(x)- Get the value of this variable in the solution. If
xis a single variable, this will simply return a number. If
xis indexable then it will return an indexable dictionary of values. When the model is unbounded,
getvaluewill instead return the corresponding components of an unbounded ray, if available from the solver.
setvalue(x,v)- Provide an initial value
vfor this variable that can be used by supporting MILP solvers. If
NaN, the solver may attempt to fill in this value to construct a feasible solution.
setvaluecannot be used with fixed variables; instead their value may be set with
getdual(x)- Get the reduced cost of this variable in the solution. Similar behavior to
getvaluefor indexable variables.
getvalue function always returns a floating-point value, even when a variable is constrained to take integer values, as most solvers only guarantee integrality up to a particular numerical tolerance. The built-in
round function should be used to obtain integer values, e.g., by calling
Variables (in the sense of columns) can have internal names (different from the Julia variable name) that can be used for writing models to file. This feature is disabled for performance reasons, but will be added if there is demand or a special use case.
getname(x::Variable)- Set/get the variable’s internal name.
Fixed variables, created with the
x == fixedval syntax, have slightly special
semantics. First, it is important to note that fixed variables are considered
optimization variables, not constants, for the purpose of determining the problem
class. For example, in:
@variable(m, x == 5) @variable(m, y) @constraint(m, x*y <= 10)
the constraint added is a nonconvex quadratic constraint. For efficiency reasons,
JuMP will not substitute the constant
x and then
provide the resulting linear constraint to the solver.
Two possible uses for fixed variables are:
- For computing sensitivities. When available from the solver,
the sensitivity of the objective with respect to the fixed value may be queried with
- For solving a sequence of problems with varying parameters.
One may call
JuMP.fix(x, val)to change the value of a fixed variable or to fix a previously unfixed variable. For LPs in particular, most solvers are able to efficiently hot-start when solving the resulting modified problem.