Table of Contents
Introduction
This chapter covers the declaration and manipulation of GAMS variables
. Many of the concepts covered in the previous chapters are directly applicable here.
A variable
is the GAMS name for what are called endogenous variables by economists, columns or activities by linear programming experts, and decision variables by industrial Operations Research practitioners. They are the entities whose values are generally unknown until after a model has been solved. A crucial difference between GAMS variables and columns in traditional mathematical programming terminology is that one GAMS variable is likely to be associated with many columns in the traditional formulation.
Variable Declarations
A GAMS variable, like all other identifiers, must be declared before it may be referenced.
The Syntax
The declaration of a variable
is similar to a set
or parameter
declaration, in that domain lists and explanatory text are allowed and recommended, and several variables may be declared in one statement. The syntax is given below.
[var_type] variable[s] var_name [(index_list)] [text] [/var_data/] {, var_name [(index_list)] [text] [/var_data/]}
The keyword var_type
denotes the optional variable type that is explained in detail in the next subsection. Variable[s]
is the keyword that indicates that this is a variable statement. Var_name
is the internal name of the variable in GAMS, it is an identifier. In the optional index_list
the set or sets may be specified over which an indexed variable is declared. The optional explanatory text may be used to describe the variable for future reference and to ease readability. Specifying variable data is another optional element in the variable statement. Variable data allows to initialize variable attributes at compile time. For an example and details on variable attributes, see section Variable Attributes.
A typical variable statement adapted from the model [RAMSEY] is shown below for illustration:
Variables
k(t) capital stock (trillion rupees)
c(t) consumption (trillion rupees per year)
i(t) investment (trillion rupees per year)
utility utility measure;
The declaration of k
above implies, as usual, that references to k
are restricted to the domain of the set t
. A model that includes k
will probably have several corresponding variables in the associated mathematical programming problem: most likely one for each member of t
. In this way, very large models can be constructed using a small number of variables. (It is quite unusual for a model to have as many as 50 distinct variables.) It is still unclear from the declaration whether utility
is not domain checked or whether it is a scalar variable, i.e., one without associated sets. Later references will be used to settle the issue. For more details on domain checking, see section Domain Checking.
As the syntax indicates, the explanatory text is optional. However, it is important that variable declarations include explanatory text and that this be as descriptive as possible, since the text is used to annotate the solution output. Note the use of 'per
' instead of '/
' in the text above: slashes are illegal in all unquoted text.
- Note
- Variable names, the contained set element names plus the explanatory text must obey the general rules for language items.
- Variables can be defined over from 0 up to 20 sets
- The sets over which variables are declared indicate that these variables are potentially defined for every element of the defining sets. However the actual definition of variables does not occur until variables appear in an equation definition where the equation needs to be part of a model that in turn occurs in a solve statement.
Variable Types
There are nine basic types of variables that may be used in variable statements. These are shown in table Table 1.
Keyword | Description | Default Lower Bound | Default Upper Bound |
---|---|---|---|
free (default) | No bounds on variable. Both bounds may be changed from the default values by the user. | -inf | +inf |
positive or nonnegative | No negative values are allowed for variable. The user may change both bounds from the default value. | 0 | +inf |
negative | No positive values are allowed for variables. The user may change both bounds from the default value. | -inf | 0 |
binary | Discrete variable that can only take values of 0 or 1. For details see section Types of Discrete Variables. In relaxed Model types the integrality requirement is relaxed. | 0 | 1 |
integer | Discrete variable that can only take integer values between the bounds. The user may change both bounds from the default value. The default upper bound inside GAMS is +inf but when the variable is passed on to the solver, the option or command line parameter IntVarUp decides what upper bound (by default +inf ) is passed on to the solver in case GAMS has upper bound +inf. In relaxed Model types the integrality requirement is relaxed. | 0 | +inf |
sos1 | A set of variables, such that at most one variable within a group may have a non-zero value. For details see section Types of Discrete Variables. | 0 | +inf |
sos2 | A set of variables, such that at most two variables within a group may have non-zero values and the two non-zero values are adjacent. For details see section Types of Discrete Variables. | 0 | +inf |
semicont | Semi-continuous, must be zero or above a given minimum level. For details see section Types of Discrete Variables. | 1 | +inf |
semiint | Semi-integer, must be zero or above a given minimum level and integer. For details see section Types of Discrete Variables. The default upper bound inside GAMS is +inf but when the variable is passed on to the solver, the option or command line parameter IntVarUp decides what upper bound (by default +inf ) is passed on to the solver in case GAMS has upper bound +inf. In relaxed Model types the integrality requirement is relaxed. | 1 | +inf |
Table 1: Variable types and default bounds
The default type is free
, which means that if the type of the variable is not specified, it will not be bounded at all. The most frequently used types are free
and positive
. The type positive variables
is used for variables for which negative values are meaningless, such as capacities, quantities or prices. Note that bounds may be changed using variable attributes and assignment statements, see section Variable Attributes.
- Note
- Every optimization model must contain at least one unrestricted named variable (i.e. one declared with the keywords
Variable
orFree Variable
). This variable is the objective variable. Even an objective variable can have lower and upper bounds assigned via the.lo
and.up
variable attribute. - If a model is unbounded, a frequent cause for the unboundedness is that the modeler forgot to make a variable positive.
- Every optimization model must contain at least one unrestricted named variable (i.e. one declared with the keywords
Styles for Variable Declaration
Two styles are commonly used to declare variable types. The first is to list all variables with domain specifications and explanatory text as a group, and later to group them separately as to type. The example shown below is adapted from [MEXSS]. The default type is free
, so phi
and phipsi
will be free
variables in the example below. Note the use of variable names derived from the original mathematical representation.
Variables
u(c,i) "purchase of domestic materials (mill units per yr)"
v(c,j) "imports (mill tpy)"
e(c,i) "exports (mill tpy)"
phi "total cost (mill us$)"
phipsi "raw material cost (mill us$)";
Positive Variables u, v, e;
The commas in the list of positive variables are required separators.
- Attention
- It is possible to declare an identifier more than once. However, the second and any subsequent declarations should only add new information that does not contradict what has already been entered.
The second popular way of declaring variables is to list them in groups by type. We rewrite the example above using this second method:
Free Variables
phi "total cost (mill us$)"
phipsi "raw material cost (mill us$)"
Positive Variables
u(c,i) "purchase of domestic materials (mill units per yr)"
v(c,j) "imports (mill typ)"
e(c,i) "exports (mill typ)";
The choice between the two approaches is best based on clarity.
Variable Attributes
While a GAMS parameter has one number associated with each unique label combination, a variable has several. They represent:
Variable Attribute | Symbol | Description |
---|---|---|
Lower bound | .lo | Lower bound for the variable. Set by the user either explicitly or through default values associated with the variable type. |
Upper bound | .up | Upper bound for the variable. Set by the user either explicitly or through default values associated with the variable type. |
Fixed value | .fx | A fixed value for the variable. If set it results in the upper and lower bounds of the variable to be set to the value of the .fx attribute. |
Activity level | .l | Activity level for the variable, also the current value or starting point. This attribute is reset to a new value when a model containing the variable is solved. The activity level is used to construct a basis for the model. |
Marginal | .m | The marginal value (or reduced cost) for the variable. This attribute is reset to a new value when a model containing the variable is solved. The activity level is used to construct a basis for the model. |
Scale factor | .scale | Numerical scaling factor for all coefficients associated with the variable if the model attribute scaleopt is set to 1. For more on scaling, see section Model Scaling - The Scale Option. Only applicable for continuous variables. |
Branching priority | .prior | Branching priority value used in mixed integer programming models if the model attribute prioropt is set to 1. For details see section Setting Priorities for Branching. It can also be used to relax discrete restrictions by setting .prior = +inf regardless of the prioropt setting. Only applicable for discrete variables. |
Stage | .stage | This attribute allows to assign variables to stages in a stochastic program or other block structured model. Thus, among other places, it is used for 2-stage stochastic programs solved with DECIS or the Benders partition in Cplex. |
Table 2: Variable Attributes
Users distinguish between these values when necessary by appending the suffix to the variable name. Examples are given below.
It is possible to specify initial values for these variable attributes at compile time. This can be done within the variable declaration statement as illustrated in the following example or during execution time as explained in section Assigning Values to Variable Attributes.
Variable x1(j) my first / j1.up 10 , j1.lo 5, j1.l 7, j1.m 0, j1.scale 20 /;
The upper bound of the variable x1("j1")
is set to 10, the lower bound is set to 5, the starting value for the activity level is set to 7 and the starting value for the marginal is set to 0. The variable is also scaled by the factor 20, which means it is multiplied by 20.
Note that it is also possible to use a table structure to assign values to variable attributes. The following example is adapted from model [TRNSPORT].
Variable Table x(i,j) initial values
l m
seattle. new-york 50
seattle. chicago 300
san-diego.new-york 275
san-diego.chicago 0.009;
- Note
.fx
and attributes.lo
and.up
on the same variable cannot be in a data statement..fx
sets both.lo
and.up
and hence we would have a double definition of the same attribute. Since attribute.scale
is applicable for continuous variables and attribute.prior
for discrete variables, they share the same internal space in a GAMS variable. Some solvers can make use of priorities even for continuous variables (e.g. BARON). Such priorities need to be supplied via a solver option file.- The attribute
.stage
uses the same internal space as.scale
and.prior
. So a model cannot specify scale factor and branching priorities together with stages. - Fixing a semi-continuous or semi-integer variable to a non-zero value like
x.fx = 4
does not result in a truly fixed variable. The domain of the variable remains{0,4}
. To really fix a semi-continuous or semi-integer variable, the discrete restriction could be relaxed by setting the branching priority to infinity (x.prior=inf
). - For variables in discrete models (such as MIP, MINLP), the
.m
attribute provides the marginals obtained by fixing all the discrete variables and solving the resulting continuous problem (such as LP, NLP). Many solvers allow to enable/disable solving such a fixed problem. When disabled, no marginals will be provided for discrete models.
In addition to the variable attributes introduced above, there are a number of variable attributes that cannot be assigned or exported via execute_unload* but may be used in computations. They are given in Table 3.
Table 3: Additional Variable Attributes that Cannot Be Assigned but May Be Used in Computations.
Bounds on Variables
All default bounds set at declaration time may be changed using assignment statements.
- Attention
- For discrete variable types, the consequences of the type declaration cannot be completely undone (e.g. the
scale
attribute is not available) but their value domain can be changed to continuous by setting attributeprior
to infinity.
Bounds on variables are the responsibility of the user. After variables have been declared, default bounds have already been assigned: for many purposes, especially in linear models, the default bounds are sufficient. In nonlinear models, however, bounds play a far more important role. It may be necessary to provide bounds to prevent undefined operations, such as division by zero. In nonlinear programming it is often necessary to define a 'reasonable' solution space that will assist in efficiently finding a solution.
- Attention
- The lower bound cannot be greater than the upper bound: if you happen to impose such a condition, GAMS will generate an execution error, namely
"**** Matrix error - lower bound > upper bound"
when executing a solve statement.
Note that the upper bound on integer and semi-integer variables needs special consideration. The default upper bound is +inf
and the option or command line parameter IntVarUp controls what upper bound is sent to the solver. With the current default value (0) of IntVarUp, an upper bound of +inf
is sent to the solver. Setting IntVarUp to one will pass 100 as the default upper bound to the solver. The other available values for IntVarUp work like zero, but enable special reports/execution errors in case the solution reports a level value greater than 100 for any integer variable with a default bound of +inf
.
Fixing Variables
GAMS allows the user to fix variables through the .fx
variable suffix. This is almost equivalent to setting the lower bound and upper bound equal to the fixed value. The attribute .fx also resets the activity level
.l to the fixed value. When setting
.lo and
.up the activity level remains unchanged. A
solve
statement will project the activity level within the active bounds. Fixed variables can subsequently be freed by changing the lower and upper bounds.
Activity Levels of Variables
GAMS allows the user to set the activity levels of variables through the .l
variable suffix. These activity levels of the variables prior to the solve statement serve as initial value for the solver. This is particularly important for nonlinear programming problems. For discrete models in many cases the solver needs an additional indicator to interpret the activity levels as a feasible integer solution via a solver option (e.g. Cplex' mipstart).
- Attention
- GAMS only stores variables with non-default values (similar to storing only non-zero values of parameters). Non-default variables can be accidentally created by using harmlessly looking assignments like
Even if the equations only reference such variables over a small subset ofx.up(i,j,k,l) = 0;
(i,j,k,l)
this statement createscard(i)*card(j)*card(k)*card(l)
variable records in the GAMS database. Such fixings ofx(i,j,k,l)
to 0 can be avoided by using dynamic sets or dollar conditions in the equation algebra to only reference tuples of(i,j,k,l)
for whichx(i,j,k,l)
can possible have a non-zero value. - In order to filter only necessary tuples for an equation the filtering conditions needs to be provided only once when defining the equation (
equ(i,j,k)
). This is different for variables because they appear in many equations and the filtering condition needs to be potentially repeated many time. Therefore it is good practice and reduces GAMS model generation time if the filtering of the variables is governed by a dynamic set:
versussum((i,j)$(ord(i)>ord(j) and cap(i,j)>0), x(i,j))
set net(i,j); net(i,j) = ord(i)>ord(j) and cap(i,j)>0; sum(net(i,j), x(i,j))
- GAMS only stores variables with non-default values (similar to storing only non-zero values of parameters). Non-default variables can be accidentally created by using harmlessly looking assignments like
Variables in Display and Assignment Statements
GAMS allows the modeler to use the values associated with the various attributes of each variable in assignment and display
statements. The next two subsections explain the use of variables on the left and right-hand sides of assignment statements respectively. Then we will explain the use of variables in display
statements.
Assigning Values to Variable Attributes
Assignment statements operate on one variable attribute at a time, and require the suffix to specify which attribute is being used. Any index list comes after the suffix.
The following code snippets are from models [MEXSS] and [RAMSEY]. The first example illustrates the use of assignment statements to set upper and lower bounds on variables.
x.up(c,i,j) = 1000 ; phi.lo = inf ;
A very common use is to bound one particular entry individually:
p.up('pellets', 'ahmsa', 'mexico-df') = 200 ;
Or to put small lower bounds on a variable identifier used as a divisor in a nonlinear program:
c.lo(t) = 0.01 ;
Or to provide initial values for a nonlinear problem:
c.l(t) = 4*cinit(t) ;
Remember that the order is important in assignments, and notice that the two pairs of statements below produce very different results. In the first case, the lower bound for c('1985')
will be 0.01, but in the second, the lower bound is 1.
c.fx('1985') = 1; c.lo(t) = 0.01 ;
c.lo(t) = 0.01 ; c.fx ('1985') = 1 ;
Everything works as described in the previous chapter, including the various mechanisms described there of indexed operations, dollar operations, subset assignments and so on. An example from model LOCATION follows.
ship_sm.lo(sl,m)$(ord(sl) = 1 and ord(m) = 1) = 1;
The lower bound of the variable ship_sm(sl,m)
is set to 1 and this assignment is only valid for ship_sm('s1','d1')
, the realization of the variable where both indices are the first members of their respective sets.
Variable Attributes in Assignments
Using variable attributes on the right-hand side of assignment statements is important for a variety of reasons. Two common uses are for generating reports and for generating initial values for some variables based on the values of other variables. For more on variable attributes in report writing, see section Displaying Variable Attributes below and especially chapter The Put Writing Facility.
The following examples adapted from model [CHENERY] illustrate the use of variable attributes on the right-hand side of assignment statements:
* initial values for variables
y.l(i) = 250 ; x.l(i) = 200 ;
e.l(t) = 0 ; m.l(t) = 0 ;
g.l(t) = mew(t) + xsi(t)*m.l(t) ;
h.l(t) = gam(t) - alp(t)*e.l(t) ;
[...]
* generating report after solve
Scalar
cva "total value added at current prices"
rva "real value added"
cli "cost of living index" ;
cva = sum (i, v.l(i)*x.l(i)) ;
cli = sum(i, p.l(i)*ynot(i))/sum(i, ynot(i)) ;
rva = cva/cli ;
Display cli, cva, rva ;
As with parameters, a variable must have some non-default data values associated with it before it can be used in a display
statement or on the right-hand side of an assignment statement. After a solve
statement has been processed or if non-default values have been set with an assignment statement, this condition is satisfied. Solve
statements are introduced and discussed in chapter Model and Solve Statements.
- Attention
- The
.fx
suffix is mostly just a shorthand for.lo
and.up
and can therefore only be used only on the left-hand side of an assignment statement.
- Note
- In general, the variable level needs to be specified via the attribute
.l
for assignment statements. However, the dollar control option $on/offDotL allows the implicit use of the attribute.l
in assignment statements, thus it facilitates using the same algebra in model definitions and assignment statements. This is especially useful in the context of macros.
Displaying Variable Attributes
The display
statement is introduced and discussed in detail in chapter The Display Statement. Here we demonstrate how variable attributes are used in display
statements.
Since several values are associated with each variable, the user must specify which attribute should be displayed when using variables in display
statements. As before, appending the appropriate suffix to the variable name does this and no domain specification may appear. As an example, we show how to display
the level of phi
and the level and the marginal values of v
from [MEXSS]:
display phi.l, v.l, v.m;
The output looks similar, except that (of course) the listing shows which of the values is being displayed. Because zeroes, and especially all zero rows or columns, are suppressed, the patterns seen in the level and marginal displays will be quite different, since non-zero marginal values are often associated with activity levels of zero.
Mexico Steel - Small Static (MEXSS,SEQ=15) E x e c u t i o n ---- 203 VARIABLE PHI.L = 538.811 total cost (mill us$) ---- 203 VARIABLE V.L imports (mill tpy) ( ALL 0.000 ) ---- 203 VARIABLE V.M imports (mill tpy) mexico-df monterrey guadalaja steel 7.018 18.822 6.606
We should mention here a clarification of our previous discussion of displays. It is actually the default values that are suppressed on display output. For parameters and variable levels and marginals, the default is zero, and so zero entries are not shown. For bounds, however, the defaults can be non-zero. The default value for the upper bound of a positive variable is +INF
, and if we would also display v.up
above, for example, we would see:
---- 203 VARIABLE V.UP imports (mill tpy) ( ALL +INF )
If any of the bounds have been changed from the default value, then only the entries for the changed elements will be shown. This may sound confusing, but since few users display bounds it has not proved troublesome in practice.
- Note
- The attribute
.range
may be used indisplay
statements. It provides a convenient way to check whether a variable is fixed as it lists the 0 values explicate because the default for range (which won't be displayed) is +inf.
Summary
Remember that wherever a parameter may appear in a display or an assignment statement, a variable may also appear - provided that it is qualified with one of the suffixes. The only places where a variable name may appear without a suffix is in a variable declaration, as has been shown in this chapter, in an equation definition, which is discussed in chapter Equations, or in a $on/offDotL block.