Variables

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 or Free 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.

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.

Variable Attribute Symbol Description
Range .range The difference between the lower and upper bounds for a variable. It becomes zero if the lower equals the upper bound, e.g. if the fx attribute is set.
Slack upper bound .slackup Slack from variable upper bound. This is defined as the greater of two values: zero or the difference between the upper bound and the level value of a variable.
Slack lower bound .slacklo Slack from variable lower bound. This is defined as the greater of two values: zero or the difference between the level value and the lower bound of a variable.
Slack .slack Minimum slack from variable bound. This is defined as the minimum of two values: the slack from the variable lower bound and the slack from the variable upper bound.
Infeasibility .infeas Amount by which a variable is infeasible falling below its lower bound or above its upper bound. This is defined as the smallest of three values: zero, the difference between the lower bound and the level value, the difference between the level value and the upper bound of a variable, i.e. max(0, lower-level, level-upper).

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 attribute prior 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
    x.up(i,j,k,l) = 0;
    
    Even if the equations only reference such variables over a small subset of (i,j,k,l) this statement creates card(i)*card(j)*card(k)*card(l) variable records in the GAMS database. Such fixings of x(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 which x(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:
    sum((i,j)$(ord(i)>ord(j) and cap(i,j)>0), x(i,j))
    
    versus
    set net(i,j); net(i,j) = ord(i)>ord(j) and cap(i,j)>0;
    sum(net(i,j), x(i,j))
    

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 in display 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.