### Table of Contents

# Introduction

In this chapter we explicitly cover only *parameter* manipulation, including all aspects of data handling. Much of this material is relevant elsewhere (e.g. to sets), but for specifics related to assignment to sets, to conditions, and to assignments within flow control constructs such as the `loop`

statement, see chapters Dynamic Sets, Conditional Expressions, Assignments and Equations and Programming Flow Control Features respectively.

Once initialized, data often requires manipulation in order to bring it into a form most suitable for use in a model or an application. The assignment statement is the way to do this. All the possible components of the assignment statement except conditions are introduced and discussed in this chapter.

# The Assignment Statement

The assignment statement is the fundamental data manipulation statement in GAMS. It may be used to define or alter values associated with sets, parameters, variables or equations.

A simple assignment is written in the style associated with many other computer languages. GAMS uses the traditional symbols for addition `(+)`

, subtraction `(-)`

, multiplication `(*)`

and division `(/)`

. We will use them in the examples that follow, and give more details in section Expressions.

## Scalar Assignments

Consider the following artificial sequence:

```
scalar x / 1.5 /;
x = 1.2;
x = x + 2;
```

The scalar `x`

is initialized to be 1.5. The second statement changes the value to 1.2, and the third changes it to 3.2. The second and third statements are assignments: each replaces the current value of `x`

with a new one.

Note that the same symbol can be used on the left and right of the `=`

sign. The new value is not available until the calculation is complete, and the operation gives the expected result.

- Note
- An assignment cannot start with a reserved word. A semicolon is therefore required as a delimiter before all assignments.

Note that extended range identifiers (e.g. `INF`

) and acronyms may also be used in assignment statements. For specific details, see sections Extended Range Arithmetic and Acronym Usage respectively.

## Indexed Assignments

The GAMS syntax for performing indexed assignments is extremely powerful. This operation offers what may be thought of as simultaneous or parallel assignments and provides a concise way of specifying large amounts of data. Consider the mathematical statement \( DJ_d = 2.75 \cdot DA_d \) for all elements of \(d\). This means that for every member of the set \(d\), a value is assigned to \(DJ\). This can be written in GAMS as follows:

```
dj(d) = 2.75*da(d) ;
```

This assignment is known technically as an *indexed assignment* and set `d`

as the controlling index or controlling set.

- Attention
- The index set(s) on the left hand side of an indexed assignment are referred to synonymously as the controlling indices, controlling sets, or controlling domain of the assignment.

The extension to two or more controlling indices should be obvious. There will be an assignment made for each label combination that can be constructed using the indices inside the parentheses. Consider the following example of an assignment to all 100 data elements of the parameter `a`

.

```
sets row / r-1*r-10 /
col / c-1*c-10 /
sro(row) / r-7*r-10 / ;
parameters r(row) /r-1*r-7 4, r-8*r-10 5/
c(col) /c-1*c-5 3, c-6*c-10 2/;
parameters a(row,col);
a(row,col) = 13.2 + r(row)*c(col) ;
```

The calculation in the last statement is carried out for each of the 100 unique two-label combinations that can be formed from the elements of `row`

and `col`

. An explicit formulation of the first of these assignments follows:

```
a('r-1','c-1') = 13.2 + r('r-1')*c('c-1');
```

Note that for indexed assignments a copy of the symbols on the right hand side is installed before the assignment is carried out. That means it does not work "in-place" or recursively. Consider the following example where we compute the first ten Fibonacci numbers and store them in parameter `f`

using a loop. The example also illustrates how such a recursive calculation does not work with a parallel assignment statement for parameter `g`

.

```
set i / i1*i10 /
parameter
f(i) / i1 1 /
g(i) / i1 1 /;
loop(i$(ord(i)>=2),
f(i) = f(i-2) + f(i-1);
);
g(i)$(ord(i)>=2) = g(i-2) + g(i-1)
display f,g;
```

The display statement results in the following output.

---- 9 PARAMETER f i1 1.000, i2 1.000, i3 2.000, i4 3.000, i5 5.000 i6 8.000, i7 13.000, i8 21.000, i9 34.000, i10 55.000 ---- 9 PARAMETER g i1 1.000, i2 1.000, i3 1.000

## Restricting the Domain in Assignments

Sometimes it is neccessary to make assignments over selected elements of a set instead of over the entire domain. There are several ways to accomplish this: using explicit labels, subsets, conditionals and tuples.

### Restricting the Domain: Explicit Labels

The strongest restriction of the domain is assigning a value to just one element. Labels may be used explicitly in the context of assignments to accomplish this. The following example illustrates:

```
a('r-7','c-4') = -2.36 ;
```

This statement assigns a constant value to just one element of the parameter `a`

. All other elements of `a`

remain unchanged. Labels must be quoted when used in this way.

### Restricting the Domain: Subsets

In general, wherever a set name may occur in an indexed assignment, a subset may be used instead.

Consider the following example:

```
a(sro,'col-10') = 2.44 -33*r(sro) ;
```

Since the set `sro`

was declared as a subset of the set `row`

, we can use `sro`

as a controlling index in the assignment above to make the assignment only for the elements of `sro`

.

### Restricting the Domain: Conditionals

Conditional assignments are discussed in detail in section Conditional Assignments in chapter Conditional Expressions, Assignments and Equations. For details on the types of logical conditions, see section Logical Conditions. Here we present a simple example to illustrate:

```
a(row,col)$[a(row,col) >= 100] = INF ;
```

This assignment has the following effect: all elements of the parameter `a`

whose value was at least 100 are assigned the value INF, while all other elements of `a`

remain unchanged.

### Restricting the Domain: Tuples

Tuples or multi-dimensional sets are introduced in section Many-to-Many Mapping. In this simple example we show how they may be used to restrict the domain. The example builds on the first example in this section. We repeat the whole code here for clarity.

```
sets row / r-1*r-10 /
col / c-1*c-10 /
sro(row) / r-7*r-10 / ;
set tuple(row,col) /r-1.c-1, r-1.c-10, r-10.c-1, r-10.c-10/;
parameters r(row) /r-1*r-7 4, r-8*r-10 5/
c(col) /c-1*c-5 3, c-6*c-10 2/;
parameters a(row,col), b(row,row);
a(row,col) = 13.2 + r(row)*c(col) ;
a(tuple(row,col)) = 7 + r(row)*c(col) ;
a(tuple) = 0.25 * a(tuple) ;
```

Note that we have introduced the new set `tuple`

. It is two-dimensional and contains just four elements. As before, the parameter `a`

is first assigned values for all its 100 elements. We then change some of these values using the set `tuple`

as domain. The values of the elements of the parameter `a`

that are not elements of the set `tuple`

remain unchanged.

For a more elaborate example involving tuples, see section Filtering Sets in Assignments.

## Issues with Controlling Indices

- Attention
- The number of controlling indices on the left of the
`=`

sign should be at least as large as the number of indices on the right. There should be no index on the right-hand side of the assignment that is not present on the left unless it is operated on by an indexed operator. For more on indexed operators, see section Indexed Operations.

Consider the following statement:

```
a(row,'col-2') = 22 - c(col) ;
```

GAMS will flag this statement as an error since `col`

is an index on the right-hand side of the equation but not on the left.

Note that there would be no error here if `col`

were a `singleton set`

. Since there is only one element in a singleton set, the intent and behavior is well-defined even when `col`

is not under control.

- Attention
- Each set is counted only once to determine the number of controlling indices. If the intent is for a set to appear independently more than once within the controlling domain, the second and subsequent occurrences of the set should be
`aliases`

of the original set, so that the number of controlling indices is equal to the number of indices. For details on aliases, see section The Alias Statement: Multiple Names for a Set.

Consider the following statement as an illustration:

```
b(row,row) = 7.7 - r(row) ;
```

This statement has only one controlling index, namely `row`

. One element (on the diagonal of `b`

) is assigned for each element of `row`

, for a total of 10 assigned values. None of the off-diagonal elements of `b`

will be changed!

If the intent is to assign values to each element of `b`

, this can be done by introducing an alias `rowp`

for `row`

and using this alias in the second index position. There will then be two controlling indices and GAMS will make assignments over all 100 values of the full Cartesian product. The following example illustrates this method:

```
alias(row,rowp) ;
b(row,rowp) = 7.7 - (r(row) + r(rowp))/2 ;
```

# Expressions

An expression is an arbitrarily complicated specification for a calculation, with parentheses nested as needed for clarity and intent. In this section the discussion of parameter assignments will continue by showing in more detail the expressions that may be used on the right of the `=`

sign. We will cover standard arithmetic operations and indexed operations here, and functions and extended range arithmetic in the next two sections.

## Standard Arithmetic Operations

The standard arithmetic symbols and operations and their order of precedence are given in Table 1. Note that 1 denotes the highest order of precedence and 3 denotes the lowest order of precedence. Parentheses can be used to override the default precedence order in the usual way. Operators (including exponentiation) on the same level are evaluated from left to right.

Operation | Symbol | Order of Precedence |
---|---|---|

Exponentiation | `**` | 1 |

Multiplication | `*` | 2 |

Division | `/` | 2 |

Addition | `+` | 3 |

Subtraction | `-` | 3 |

**Table 1:** Standard Arithmetic Operations

Note that the full GAMS operator precedence hierarchy also includes logical operators; it is given in section Mixed Logical Conditions. Note further that the symbols for addition, subtraction and multiplication have a different meaning if they are used in the context of sets. For details see sections Set Operations and Lag and Lead Operators.

- Attention
- The operation
`x**y`

is equivalent to the function rPower(x,y) and is calculated internally as \(e^{y \times \log(x)}\). This operation is not defined if \(x\) has a negative value; an error will result in this case. If the possibility of negative values for \(x\) is to be admitted*and*the exponent is known to be an integer, then the function power(x,n) may be used.

- Note
- As usual, operations within parentheses or brackets are evaluated before other numerical calculations, where the innermost parentheses are resolved first. Any of the pairs
`()`

,`[]`

and`{}`

are allowed.

Consider for example:

```
x = 5 + 4*3**2;
```

For clarity, this could have been written as follows:

```
x = 5 + (4*[3**2]) ;
```

In both cases the result is 41.

- Note
- It is often better to use parentheses than to rely on the order of precedence of operators, since this prevents errors and clarifies intentions.

Note that expressions may be freely continued over many lines: an end of line is permissible at any point where a blank may be used. Blanks may be used for readability around identifiers, parentheses and operation symbols. Blanks are not allowed within identifiers or numbers, and are significant inside the quotes used to delimit labels.

## Indexed Operations

In addition to the simple operations in Table 1, GAMS also provides the following four indexed operations.

Operation | Keyword |
---|---|

Summation | `sum` |

Product | `prod` |

Minimum value | `smin` |

Maximum value | `smax` |

**Table 2:** Indexed Operations

These four operations are performed over one or more controlling indices. The syntax in GAMS for these operations is:

```
indexed_op( (index_list), expression);
```

`Indexed_op`

is one of the four keywords for indexed operations, `index_list`

is the list of the controlling indices and `expession`

is the expression to be evaluated. If there is only one controlling index, the parentheses around it may be removed. Consider the following simple example adapted from [ANDEAN]:

```
sets i plants / cartagena, callao, moron /
m product / nitr-acid, sulf-acid, amm-sulf /;
parameter capacity(i,m) capacity in tons per day
totcap(m) total capacity by process ;
totcap(m) = sum(i, capacity(i,m));
```

The index over which the summation is done, `i`

, is separated from the reserved word `sum`

by a left parenthesis and from the data term `capacity(i,m)`

by a comma. The set `i`

is called the controlling index for this operation. The scope of the control is the pair of parentheses `()`

that start immediately after the sum. Note that using normal mathematical representation the last line could be written as: \(totC_m = \sum_i C_{im}\).

It is also possible to sum simultaneously over the domain of two or more sets as in the first assignment that follows. The second assignment demonstrates the use of a less trivial expression than an identifier within the indexed operation.

```
count = sum((i,j), a(i,j)) ;
emp = sum(t, l(t)*m(t)) ;
```

The equivalent mathematical forms are:

\[ count = \sum_i\sum_j A_{ij} \quad \textrm{and} \quad emp = \sum_t L_t M_t. \]

Note that the following alternative notation may be used for the first assignment above:

```
count = sum(i, sum(j, a(i,j)));
```

In the context of sets the `sum`

operator may be used to compute the number of elements in a set and for projections. For details see section Projection and Aggregation of Sets.

The `smin`

and `smax`

operations are used to find the largest and smallest values over the domain of the index set or sets. The index for the `smin`

and `smax`

operators is specified in the same manner as in the index for the `sum`

operator. In the following example we want to find the largest capacity:

```
lrgunit = smax((i,m),capacity(i,m));
```

- Attention
- The indexed operations
`smin`

and`smax`

may be used in equation definitions only if the corresponding model is of type DNLP. For more on GAMS model types, see GAMS Model Types.

- Note
- In the context of assignment statements, the attributes of variables and equations (e.g.
`x.up(i,j)`

) may be used in indexed operations just as scalars and parameters are used. For more on variable and equations attributes, see sections Variable Attributes and Equation Attributes respectively. - In the context of equation definitions, scalars, parameters and variables may appear freely in indexed operations. For more on equation definitions, see section Defining Equations.

- In the context of assignment statements, the attributes of variables and equations (e.g.

Sometimes it is necessary to restrict the domain of indexed operations. This may be done with the same techniques as in indexed assignments, see section Restricting the Domain in Assignments for details. See also section Conditional Indexed Operations for more details on conditions in the context of indexed operations.

We now turn to two additional capabilities that are available in GAMS to add power and flexibility to expression calculations: functions and extended range arithmetic.

# Functions

Functions play an important role in the GAMS language, especially for nonlinear models. Like other programming languages, GAMS provides a number of built-in or intrinsic functions. GAMS is used in an extremely diverse set of application areas and this creates frequent requests for the addition of new and quite sophisticated or specialized functions. There is a trade-off between satisfying these requests and avoiding a complexity not needed by most users. The GAMS Function Library Facility provides the means for managing this trade-off, see subsection Extrinsic Functions below.

## Intrinsic Functions

GAMS provides many functions, ranging from commonly used standard functions like exponentiation, logarithms, and trigonometric functions to utility functions for controlling and querying the running GAMS job or process. The complete list of available functions is given in the following tables: Mathematical Functions, String Manipulation Functions, Logical Functions, Time and Calendar Functions, and GAMS Utility and Performance Functions. For details specific to using these functions in equations, see the section on Expressions in Equation Definitions.

Some of the tables that follow contain an endogenous classification column "End. Classif." that specifies in which models the function may legally appear. In order of least to most restrictive, the choices are *DNLP*, *NLP*, *any*, *none*. See section Classification of Models for details on model types in GAMS. Note well: functions classified as *any* are only permitted with exogenous (constant) arguments.

Functions are typically used in assignment statements and equations. In these cases, they are only evaluated at execution time. Some functions can also be used at compile time, e.g. to compute the factorial or square root of a scalar. Some of the tables below contain a column "Compile Time" indicating which functions can be used at compile time.

A word on the notation in the tables below: for function arguments, lower case indicates that an endogenous variable is allowed. For details on endogeneous variables, see section Functions in Equation Definitions. Upper case function arguments indicate that a constant is required. Arguments in square brackets may be omitted: the default values used in such cases are specified in the function description provided.

### Mathematical Functions

Mathematical functions may be used as expressions in assignment statements and in equation definitions. We start with some simple examples to illustrate. A list with all mathematical functions available in GAMS is given in Table 3.

**Exp(x)**

```
a = exp(t);
b = exp(t+2);
```

The GAMS function `exp(x)`

returns the exponentional \(e^x\) of its argument. The assignments above set \(a=e^t\) and \(b=e^{t+2}\) respectively.

**Log(x)**

```
z(j) = log(y(j));
```

The GAMS function `log(x)`

returns the natural logarithm of its argument. The assignment above evaluates the logarithm once for each element of the controlling domain `j`

.

**Max(x1,x2,x3,...)**

```
x = max(y+2, t, t*t);
```

The function `max`

returns the maximum of a set of expressions or terms. In the assignment above, `x`

will be assigned the maximum of \(y+2\), \(t\), and \(t \cdot t\).

**Round(x[,DECPL])**

The function `round`

rounds its argument `x`

to the specified number `DECPL`

of places, where positive values of `DECPL`

indicating rounding to the right of the decimal point. If the argument `DECPL`

is not specified, it defaults to zero, and the function rounds its argument to the nearest integer value. For example,

```
x = round(q);
y = round(q,d);
z = round(12.432,2);
h = round(515.5,-1);
```

In the first assignment `q`

is rounded to the nearest integer value, while in the second `q`

is rounded to the number of decimals specified by `d`

. The result of the third assignment is 12.43, while the final assignment results in a value of 520.

**Table 3: ****Mathematical Functions**

Function | Description | End. Classif. | Compile Time |
---|---|---|---|

`abs(x)` | Absolute value of the argument \(x\). | DNLP | yes |

`arccos(x)` | Inverse cosine of the argument \(x\), where \(x\) is a real number between -1 and 1 and the output is in radians, see MathWorld | NLP | no |

`arcsin(x)` | Inverse sine of the argument \(x\), where \(x\) is a real number between -1 and 1 and the output is in radians, see MathWorld | NLP | no |

`arctan(x)` | Inverse tangent of the argument \(x\), where \(x\) is a real number and the output is in radians, see MathWorld | NLP | no |

`arctan2(y,x)` | Four-quadrant arctan function yielding \( \arctan(\frac{y}{x})\) which is the angle the vector \((x,y) \) makes with (1,0) in radians. | NLP | no |

`beta(x,y)` | Beta function: \( B(x,y) = \frac{\gamma(x)\gamma(y)}{\gamma(x+y)}\), see MathWorld | DNLP | no |

`betaReg(x,y,z)` | Regularized beta function, see MathWorld | NLP | no |

`binomial(n,k)` | (Generalized) Binomial coefficient for \( n > -1\), \( -1 < k < n+1 \). | NLP | no |

`ceil(x)` | Ceiling: returns the smallest integer greater than or equal to \(x\). | DNLP | yes |

`centropy(x,y[,Z])` | Cross-entropy: \(x \cdot \ln(\frac{x+Z}{y+Z})\), where \(Z >= 0\). Default \(Z\): `1e-20` . | NLP | no |

`cos(x)` | Cosine of the argument \(x\), where \(x\) must be in radians, see MathWorld | NLP | yes |

`cosh(x)` | Hyperbolic Cosine of \(x\), where \(x\) must be in radians, see MathWorld | NLP | no |

`cvPower(X,y)` | Real power: returns \( \mathbf{X^{y}}\) for \(X\geq0\). | NLP | no |

`div(dividend,divisor)` | Returns \( \mathbf{\frac{dividend}{divisor}}\), undefined for \(divisor=0\). | NLP | no |

`div0(dividend,divisor)` | Returns \( \mathbf{\frac{dividend}{divisor}}\), returns \(10^{299}\) for \(divisor=0\). | NLP | no |

`eDist(x1[,x2,x3,...]) ` | Euclidean or L-2 Norm: \(\sqrt{ x_{1}^{2} + x_{2}^{2} + ... }\). | NLP | no |

`entropy(x)` | Entropy: \(-x\cdot\ln(x)\). | NLP | no |

`errorf(x)` | Integral of the standard normal distribution from negative infinity to \(x\): \(\frac{1}{\sqrt{2\pi}} \int\limits_{-\infty}^x e^{\frac{-t^{2}}{2}}dt\). | NLP | no |

`execSeed` | Reads or resets the seed for the random number generator (RNG). Note that the state of the RNG cannot typically be captured in one seed value; in such cases "reading" the seed involves harvesting a seed from the RNG, resetting the RNG with this seed, and returning the seed. | none | no |

`exp(x)` | Exponential of \(x\): \(e^{x}\), see MathWorld | NLP | yes |

`fact(N)` | Factorial of \(N\), where \(N \geq 0\) is an integer. | any | yes |

`floor(x)` | Floor: greatest integer less than or equal to \(x\). | DNLP | yes |

`frac(x)` | Returns the fractional part of \(x\), s.t. `x = trunc(x) + frac(x)` | DNLP | yes |

`gamma(x)` | Gamma function : \( \gamma(x)= \int\limits_{0}^{\infty} t^{x-1}e^{-t}dt\), see MathWorld | NLP | no |

`gammaReg(x,a)` | Regularized Gamma function, see MathWorld | NLP | no |

`log(x)` | Natural logarithm: logarithm base \(e\), see MathWorld | NLP | yes |

`logBeta(x,y)` | Log Beta function: \(\log(B(x,y))\). | NLP | no |

`logGamma(x)` | Log Gamma function as discussed in MathWorld | NLP | no |

`log10(x)` | Common logarithm: logarithm base 10, see MathWorld | NLP | yes |

`log2(x)` | Binary logarithm: logarithm base 2, see MathWorld | NLP | yes |

`max(x1,x2,x3,...)` | Maximum value of the arguments, where the number of arguments may vary. | DNLP | yes |

`min(x1,x2,x3,...)` | Minimum value of the arguments, where the number of arguments may vary. | DNLP | yes |

`mod(x,y)` | Remainder of \(x\) divided by \(y\). | DNLP | yes |

`ncpCM(x,y,Z)` | Chen-Mangasarian smoothing: \(x-Z\cdot \ln(1+e^{\frac{x-y}{Z}})\). | NLP | no |

`ncpF(x,y[,Z])` | Fisher-Burmeister smoothing: \(\sqrt{(x^{2}+y^{2}+2\cdot Z)}-x-y\), \(Z\geq0\). Default \(Z=0\). | NLP | no |

`ncpVUpow(r,s[,MU])` | NCP Veelken-Ulbrich: smoothed min(r,s) result = \( \left\{ \begin{array}{ll}\frac{(r + s - |t|)}{2} & if \ |t| \geq \mu\\ \frac{(r + s - \frac{\mu}{8} \cdot (- (\frac{t}{\mu})^{4}+6(\frac{t}{\mu})^{2} +3))}{2} & otherwise \end{array} \right.\) where \(t=r-s\). Default \(MU=0\). | NLP | no |

`ncpVUsin(r,s[,MU])` | NCP Veelken-Ulbrich: smoothed min(r,s) result = \( \left\{ \begin{array}{ll} \frac{(r + s - |t|)}{2} & if \ |t| \geq \mu\\\frac{(r + s - (\frac{2\mu}{\pi} \sin(\frac{\pi}{2\mu} +\frac{3\pi}{2})+\mu))}{2} & otherwise \end{array} \right.\) where \(t=r-s\). Default \(MU=0\). | NLP | no |

`normal(MEAN,STDDEV)` | Generate a random number from the normal distribution with mean `MEAN` and standard deviation `STDDEV` , see MathWorld | none | no |

`pi` | Value of \( \mathbf{\pi=3.141593...}\). | any | yes |

`poly(x,A0,A1,A2[,A3,...])` | Returns \(p(x)\), where the polynomial \(p(x) = A_{0}+A_{1}x+A_{2}x^{2}+A_{3}x^{3}+...+A_{20}x^{20}\). By default \(A_{3},...,A_{20}=0\). | NLP | no |

`power(x,Y)` | Returns \( \mathbf{x^Y}\), where \(Y\) must be an integer. | NLP | no |

`randBinomial(N,P)` | Generate a random number from the binomial distribution, where \(N\) is the number of trials and \(P\) the probability of success for each trial, see MathWorld | none | no |

`randLinear(LOW,SLOPE,HIGH)` | Generate a random number between `LOW` and `HIGH` with linear distribution, `SLOPE` must be greater than \(\frac{2}{\mbox{HIGH}-\mbox{LOW}}\) | none | no |

`randTriangle(LOW,MID,HIGH)` | Generate a random number between `LOW` and `HIGH` with triangular distribution, `MID` is the most probable number, see MathWorld | none | no |

`round(x[,DECPL])` | Round \(x\) to `DECPL` decimal places. Default `DECPL=0` | DNLP | yes |

`rPower(x,y)` | Returns \(x^{y}\) for \(x > 0\) and also for \(x = 0\) and restricted values of \(y\). This function is equivalent to the operation '`x**y` ', see Standard Arithmetic Operations. | NLP | no |

`sigmoid(x)` | Sigmoid: \(\frac{1}{1+e^{-x}}\), see MathWorld | NLP | no |

`sign(x)` | Sign of \(x\): returns 1 if \(x > 0\), -1 if \(x < 0\), and 0 if \(x = 0\). | DNLP | yes |

`signPower(x,Y)` | Signed power: for \(Y > 0\), returns \(x^{Y}\) if \(x\geq 0\) and \(-1\cdot |x|^{Y}\) if \(x<0\). | NLP | no |

`sin(x)` | Sine of the argument \(x\), where \(x\) must be in radians, see MathWorld | NLP | yes |

`sinh(x)` | Hyperbolic sine of \(x\), where \(x\) must be in radians, see MathWorld | NLP | no |

`slexp(x[,S])` | Smooth (linear) exponential: result = \( \left\{ \begin{array}{ll} e^{x} & \mbox{if} \ x \leq S \\ e^{x} \cdot (1 + (x - S)) & \mbox{otherwise} \end{array} \right.\ \ \) where \(S<=150\), default \(S=150\). | NLP | no |

`sllog10(x[,S])` | Smooth (linear) logarithm base 10: result = \( \left\{ \begin{array}{ll} \log_{10}(x) & \mbox{if} \ x \geq S \\ \frac{1}{\ln(10)} \cdot (\ln S + \frac{x - S}{S}) & \mbox{otherwise} \end{array} \right.\ \ \) where \(S>=-150\), default \(S=-150\). | NLP | no |

`slrec(x[,S])` | Smooth (linear) reciprocal: result = \( \left\{ \begin{array}{ll} \frac{1}{x} & \mbox{if} \ x \geq S \\ \frac{1}{S} - \frac{x - S}{S^2} & \mbox{otherwise} \end{array} \right.\ \ \) where \(S>=10^{-10}\), default \(S=10^{-10}\). | NLP | no |

`sqexp(x[,S])` | Smooth (quadratic) exponential: result = \( \left\{ \begin{array}{ll} e^{x} & \mbox{if} \ x \leq S \\ e^{x} \cdot (1 + (x - S) + \frac{{(x - S)}^{2}}{2}) & \mbox{otherwise} \end{array} \right.\ \ \) where \(S<=150\), default \(S=150\). | NLP | no |

`sqlog10(x[,S])` | Smooth (quadratic) logarithm base 10: result = \( \left\{ \begin{array}{ll} \log_{10}(x) & \mbox{if} \ x \geq S \\ \frac{1}{\ln(10)} \cdot (\ln S + \frac{x - S}{S} - \frac{(x - S)^2}{2S^2}) & \mbox{otherwise} \end{array} \right.\ \ \) where \(S>=-150\), default \(S=-150\). | NLP | no |

`sqr(x)` | Square of argument \(x\). | NLP | yes |

`sqrec(x[,S])` | Smooth (quadratic) reciprocal: result = \( \left\{ \begin{array}{ll} \frac{1}{x} & \mbox{if} \ x \geq S \\ \frac{1}{S} - \frac{x - S}{S^2} + \frac{(x - S)^2}{S^3} & \mbox{otherwise} \end{array} \right.\ \ \) where \(S>=10^{-10}\), default \(S=10^{-10}\). | NLP | no |

`sqrt(x)` | `Square root` of \(x\), see MathWorld | NLP | yes |

`tan(x)` | Tangent of the argument \(x\), where \(x\) must be in radians, see MathWorld | NLP | yes |

`tanh(x)` | Hyperbolic tangent of \(x\), where \(x\) must be in radians, see MathWorld | NLP | no |

`trunc(x)` | Truncation: returns the integer part of \(x\), truncating towards zero. | DNLP | yes |

`uniform(LOW,HIGH)` | Generates a random number from the uniform distribution between `LOW` and `HIGH` , see MathWorld | none | no |

`uniformInt(LOW,HIGH)` | Generates an integer random number from the discrete uniform distribution whose outcomes are the integers between `LOW` and `HIGH` , inclusive, see MathWorld | none | no |

`vcPower(x,Y)` | Returns \(x^{Y}\) for \(x\geq0\). | NLP | no |

### String Manipulation Functions

GAMS provides some string manipulation capability by extending the `card`

and `ord`

functions to work on strings as well as sets. In Table 4 the extended behavior is described. In this context, the functions take *strings* and *places* as arguments, and the numeric *places* argument must be a constant. This behavior only applies to execution-time usage of these functions.

**Table 4:** **String Manipulation Functions**

Function | Description |
---|---|

`card(STRING)` | Returns the number of characters in the `string` . |

`ord(STRING[,PLACE])` | Returns the ASCII code number of a character in a position in a `string` . The optional `place` entry defaults to 1 if omitted and identifies the character position within the `string` to be examined (1 for the first, 2 for the second, etc.) |

There are four types or sources of strings in this context. A string may be a string literal, i.e. a concatenation of letters and blanks as in `"drink it"`

in the example that follows. It may be the symbol text (aka the explanatory text) associated with any symbol. Or it may be the labels or text associated with the elements of a set. The following table gives an overview:

Notation | Description | Comments |
---|---|---|

`characters` | A concatenation of characters and blanks: all legal GAMS characters are allowed, see section Characters for details. | The characters must be surrounded by double or single quotes. |

`symbol_name.ts` | The string is the explanatory text associated with a symbol name. | If the explanatory text is missing, the value of `card` is 0. |

`set_name.tl` | The string is the label for a set element. | This string type may be used only when `set_name` is part of the controlling domain. |

`set_name.te` | The string is the explanatory text associated with a set element. | This string type may be used only when `set_name` is part of the controlling domain. If the explanatory text is missing, the value of `card` is 0. |

The string types are illustrated in the following example. Note that the directive in the first line activates the end-of-line comment option, see eolCom.

```
$oneolcom
variable z 'any symbol can have explanatory text';
set teas "teas available to order" / black "English Breakfast", green, peppermint /;
scalar p;
p = card("drink it"); !! result: p=8
p = card(z.ts); !! result: p=36
p = card(teas.ts); !! result: p=23
loop{teas,
p = card(teas.tl) !! length of set element label from the set "teas": "teas" is the controlling set
display "length of set element label", p;
p = card(teas.te) !! length of set element explanatory text: "teas" is the controlling set
display "length of set element explanatory text", p;
};
```

Note that the strings `teas.tl`

and `teas.te`

are used in the context of a `loop`

statement (see section The Loop Statement). This is a typical usage pattern.

### Logical Functions

Logical functions may be used as expressions in assignment statements as in the following example.

```
x = ifthen(tt=2, 3, 4+y);
```

Here \(x=3\) if \(tt=2\), otherwise \(x=4+y\).

The logical functions available in GAMS are given in Table 6. Note that logical functions may also be used in conditions and logic equations, see sections Logical Conditions and Logic Equations respectively. Most of the logical functions can also be indicated using the familiar operator notation, e.g. (x and y), (x >= y), etc. In such cases, the operator notation is allowed at compile time. Further, note that the inputs and outputs of these functions are often logical/Boolean values, so GAMS does implicit conversions as necessary. As expected, false becomes 0 and true becomes 1 when converting logical values to numeric, and 0 becomes false and nonzero becomes true when numeric values are converted to logicals. For details on behavior when the inputs are special values, see sections Extended Range Arithmetic and Acronym Usage, but note that `EPS`

, `+INF`

, `-INF`

, and acronyms become true when converted to logicals.

Function | Alternative Notation 1 | Alternative Notation 2 | Description | Return Values | End. Classif. | Compile Time |
---|---|---|---|---|---|---|

`bool_and(x,y)` | `x and y` | Boolean `AND` | Returns true iff both x and y are true | DNLP | alt | |

`bool_eqv(x,y)` | `x eqv y` | `x <=> y` | Boolean equivalence | Returns false iff exactly one argument is false | DNLP | alt |

`bool_imp(x,y)` | ` x imp y` | ` x -> y` | Boolean implication | Returns true iff x is false or y is true | DNLP | alt |

`bool_not(x)` | ` not x` | Boolean `NOT` | Returns true iff x is false | DNLP | alt | |

`bool_or(x,y)` | `x or y` | Boolean `OR` | Returns true iff x is true or y is true | DNLP | alt | |

`bool_xor(x,y)` | `x xor y` | Boolean `XOR` | Returns true iff exactly one argument is false | DNLP | alt | |

`ifThen(cond,iftrue,else)` | Condition | If the logical condition (first argument) is true, the function returns `iftrue` , else it returns `else` . See example above. | DNLP | yes | ||

`rel_eq(x,y)` | `x eq y` | `x = y` | Numeric Relation: Equal | Returns true iff \(x=y\) | DNLP | alt |

`rel_ge(x,y)` | `x ge y` | `x >= y` | Numeric Relation: Greater Equal | Returns true iff \(x\geq y\) | DNLP | alt |

`rel_gt(x,y)` | `x gt y` | `x > y` | Numeric Relation: Greater Than | Returns true iff \(x>y\) | DNLP | alt |

`rel_le(x,y)` | `x le y` | `x <= y` | Numeric Relation: Less Equal | Returns true iff \(x\leq y\) | DNLP | alt |

`rel_lt(x,y)` | `x lt y` | `x < y` | Numeric Relation: Less Than | Returns true iff \(x<y\) | DNLP | alt |

`rel_ne(x,y)` | `x ne y` | `x <> y` | Numeric Relation: Not Equal | Returns true iff \(x\neq y\) | DNLP | alt |

### Time and Calendar Functions

GAMS offers several functions that relate to time and dates. The fundamental measurement of time in GAMS is the serial day number beginning with January 1, 1900. This serial day number is a real number whose integer part contains a unique number for each day and whose fractional part contains information about hours, minutes, and seconds. We can think of the serial day number as being a `date.time`

pair. The day information extracted from serial day numbers is based on the Gregorian calendar.

- Note
- In all functions given in Table 7,
*serial day 1*is*January 1, 1900*.

All of the functions in Table 7 can be used at compile time.

**Table 7:** **Time and Calendar Functions**

Function | Description | End. Classif. |
---|---|---|

`gday(SDAY)` | Returns Gregorian day from a serial day number `date.time` . | any |

`gdow(SDAY)` | Returns Gregorian day of week from a serial day number `date.time` . | any |

`ghour(SDAY)` | Returns Gregorian hour of day from a serial day number `date.time` . | any |

`gleap(SDAY)` | Returns 1 if the year that corresponds to a serial day number `date.time` , is a leap year, else returns 0. | any |

`gmillisec(SDAY)` | Returns Gregorian milli second from a serial day number `date.time` . | any |

`gminute(SDAY)` | Returns Gregorian minute of hour from a serial day number `date.time` . | any |

`gmonth(SDAY)` | Returns Gregorian month from a serial day number `date.time` . | any |

`gsecond(SDAY)` | Returns Gregorian second of minute from a serial day number `date.time` . | any |

`gyear(SDAY)` | Returns Gregorian year from a serial day number `date.time` . | any |

`jdate(YEAR,MONTH,DAY)` | Returns a serial day number. | any |

`jnow` | Returns the current time as a serial day number. | none |

`jstart` | Returns the time of the start of the GAMS job as a serial day number. | none |

`jtime(HOUR,MIN,SEC)` | Returns fraction of a day that corresponds to hour, minute and second. | any |

### GAMS Utility and Performance Functions

GAMS provides several functions that may be used to get (and in some cases set) GAMS system information, for example:

```
scalar o;
o = heapLimit;
heapLimit = 1024;
```

**Table 8:** **GAMS Utility and Performance Functions**

Function | Description | End. Classif. | Compile Time |
---|---|---|---|

`embeddedHandle` | Returns the handle for the last embedded code section executed, see section Syntax in chapter Embedded Code Facility for details. | none | no |

`errorLevel` | Return code of the most recently used command. | none | yes |

`execError` | Get or set the number of execution errors. | none | no |

`gamsRelease` | Returns the release number of the running GAMS system, for example 24.7. | none | yes |

`gamsVersion` | Returns the version number of the running GAMS system, for example 247. | none | yes |

`handleCollect(HANDLE)` | Tests if the solve of the model instance identified by the calling argument `HANDLE` is done: if so, it loads the solution into GAMS. For details, see Table 1 in section Grid Computing. | none | no |

`handleDelete(HANDLE)` | Deletes the model instance identified by `HANDLE` . For details, see Table 1 in section Grid Computing. | none | no |

`handleStatus(HANDLE)` | Tests if the solve of the model instance identified by `HANDLE` is done: if so, it loads the solution into a GDX file. For details, see Table 1 in section Grid Computing. | none | no |

`handleSubmit(HANDLE)` | Resubmits the model instance identified by `HANDLE` for solution. For details, see Table 1 in section Grid Computing. | none | no |

`heapFree` | Get the amount of free memory in the heap in MB, i.e. memory allocated to the process and available for future use by GAMS. | none | no |

`heapLimit` | Get or set the current heap limit (maximum allowable dynamic memory usage) in Mb. | none | no |

`heapSize` | Get the current heap size in Mb. | none | no |

`jobHandle` | Returns the process ID ( of the last job started. `PID` ) | none | yes |

`jobKill(PID)` | Sends a kill signal to the job with process ID `PID` . The return value is 1 if this was successful, 0 otherwise. | none | yes |

`jobStatus(PID)` | Get the status of the job with process ID `PID` . Possible return values are: 0: error (input is not a valid `PID` or access is denied) 1: process is still running 2: process is finished with return code which could be accessed by errorlevel 3: process not running anymore or was never running, no return code available | none | yes |

`jobTerminate(PID)` | Sends an interrupt signal to the job with process ID `PID` . The return value is 1 if this was successful, 0 otherwise. | none | yes |

`licenseLevel` | Get an indicator for the type of license: 0: demo license, limited to small models 1: full unlimited developer license 2: run time license, no new variables or equations can be introduced besides those inherited from a work file 3: application license, only works with a specific work file which is locked to the license file. | any | no |

`licenseStatus` | Returns non-zero if a license error has occurred. | any | no |

`mapVal(x)` | Returns an integer value that indicates what special value (if any) is stored in the input \(x\). Possible results: 0: \(x\) is not a special value 4: \(x\) is `UNDF` (undefined)5: \(x\) is `NA` (not available)6: \(x\) is `INF` ( \(\infty\)) 7: \(x\) is `-INF` ( \(-\infty\)) 8: \(x\) is `EPS` >8: \(x\) is an acronym | any | no |

`maxExecError` | Get or set the maximum number of execution errors. | none | no |

`numCores` | Get the number of logical CPU cores in the system | any | yes |

`readyCollect(HANDLES[,MAXWAIT])` | Waits until a model solution is ready to be collected. For details, see Table 1 in section Grid Computing. | none | no |

`sleep(SEC)` | Pause or sleep execution for `SEC` seconds. | none | yes |

`timeClose` | Returns the accumulated closedown time, i.e. the time GAMS uses to save its state to disk prior to a solve. | none | no |

`timeComp` | Returns the compilation time in seconds. | none | no |

`timeElapsed` | Returns the elapsed time since the start of a GAMS run in seconds. | none | no |

`timeExec` | Returns the execution time in seconds. | none | no |

`timeStart` | Returns the accumulated startup time, i.e. the time GAMS uses to restore its state from disk after a solve. | none | no |

## Extrinsic Functions

Using the GAMS Function Library Facility, functions may be imported from an external library into a GAMS model. Apart from the import syntax, the imported functions may be used in the same way as intrinsic functions. In particular, they may be used in equation definitions. Some function libraries are included with the standard GAMS software distribution, but GAMS users can also create their own libraries using an open programming interface. The GAMS Test Library instances [TRILIB01], [TRILIB02], [TRILIB03], and [CPPLIB00] are simple examples (in the programming languages C, Delphi, Fortran and C++, respectively) that come with every GAMS system.

For details on using and creating extrinsic function libraries, and on the extrinsic function libraries that are provided with GAMS, see the chapter on Extrinsic Functions.

## Function Suffixes

Up to this point, this section has described and discussed functions without mentioning their derivatives. These derivatives are very important, though: most of the nonlinear solvers integrated with GAMS will require first derivatives to solve models, and many will also use or require second derivatives as well. It is sometimes useful (e.g. when testing an extrinsic function) to evaluate the derivatives of GAMS functions instead of the functions themselves. This can be done via function suffixes.

Function suffixes can specify the evaluation of a gradient (i.e. first derivative), a Hessian (i.e. second derivative), a minimum or maximum value of the function over a given range, or the minimum or maximum value of the gradient over a given range. A full list of function suffixes is given in Table 9. For functions whose arguments are constant, the derivatives are zero, so typically `func`

is a mathematical function listed in Table 3 above. Note that function suffixes are *not* defined for functions without arguments (for example, `pi`

), so specifying something like `pi.grad`

results in a compilation error.

Function Suffix | Description |
---|---|

`func.value(x)` | Value of the function `func` at `x` , equals `func(x)` . |

`func.grad(x)` | Value of the gradient of the function `func` at `x` . |

`func.gradn(x)` | Value of the gradient of the function `func` at `x` , computed numerically. |

`func.hess(x)` | Value of the Hessian of the function `func` at `x` . |

`func.hessn(x)` | Value of the Hessian of the function `func` at `x` , computed numerically. |

`func.low(x1:x2)` | Lower bound of the function `func(x)` on the interval `[x1,x2]` . |

`func.high(x1:x2)` | Upper bound of the function `func(x)` on the interval `[x1,x2]` . |

`func.gradL(x1:x2)` | Lower bound of the gradient of the function `func(x)` on the interval `[x1,x2]` . |

`func.gradH(x1:x2)` | Upper bound of the gradient of the function `func(x)` on the interval `[x1,x2]` . |

Consider the following simple example:

```
scalars g, l, h, gl, gh;
g = sin.grad(0);
l = sin.low(pi/3:pi/2);
h = sin.high(pi/3:pi/2);
gl = sin.gradL(pi/3:pi/2);
gh = sin.gradH(pi/3:pi/2);
display g, l, h, gl, gh;
```

For univariate functions like sine or cosine, there is no need to specify a variable index when evaluating derivatives. For multivariate functions, the default is to take partial derivatives w.r.t. the first variable. To specify other variables, the colon syntax in the example below is used.

```
scalars
x / 1 /
ylo / -1 /
yup / 2 /
e0, e1, elo, ehi
e_1, e_2
e_11, e_22, e_21
;
e0 = edist(x,ylo);
e1 = edist(x,yup);
elo = edist.low (x,ylo:x,yup);
ehi = edist.high(x,ylo:x,yup);
e_1 = edist.grad(x,yup);
* e_1 = edist.grad(1:x,yup); same as above
e_2 = edist.grad(2:x,yup);
e_11 = edist.hess(x,yup);
* e_11 = edist.hess(1:1:x,yup); same as above
e_22 = edist.hess(2:2:x,yup);
e_21 = edist.hess(2:1:x,yup);
display x, ylo, yup, e0, e1, elo, ehi, e_1, e_2, e_11, e_22, e_21;
```

For more examples, see model [FUNCS4] in the GAMS Test Library.

- Note
- The function suffixes
`value`

,`grad`

,`gradn`

,`hess`

and`hessn`

are also defined for extrinsic functions. When implementing an extrinsic function, be aware that missing derivatives will be computed numerically: see model [TRILIB01] for an example.

- The function suffixes

To compute derivatives numerically, GAMS uses finite difference approximations. This computation can be controlled with two options: the FDOpt option controls which variant of the finite difference method is used, while the FDDelta option controls the step size.

# Extended Range Arithmetic and Error Handling

GAMS uses an *extended range* arithmetic to handle missing data, the results of undefined operations, infinite values, and zeros that are stored explicitly. The *special values* used in this arithmetic are listed and described in Table 10 below, along with the value of the mapVal function that corresponds to these values. We can think of special values as any value for which mapVal does not return 0.

Special value | Description | `mapVal` |
---|---|---|

`INF` | Plus infinity. Similar to IEEE plus infinity. Behaves in the expected way in computations, so that e.g. min(x,INF) = x unless x is also special. | 6 |

`-INF` | Minus infinity. Similar to IEEE minus infinity. Behaves in the expected way in computations, so that e.g. max(x,INF) = x unless x is also special. | 7 |

`NA` | Not available - used to indicate missing data. It is a sticky value: e.g. max(x,NA) = NA even for x = INF | 5 |

`UNDF` | Undefined - indicates the result of an undefined or illegal operation. Similar to IEEE NaN. A user cannot directly set a value to `UNDF` unless the dollar control option onUNDF is active. For details, see the chapter on Dollar Control Options. | 4 |

`EPS` | A stored zero value. If the dollar control option onEPS is active, zeros in a parameter or table statement are treated as `EPS` . For details on dollar control options, see chapter Dollar Control Options. | 8 |

**Table 10:** Special Values for Extended Range Arithmetic

- Attention
- Avoid creating or using numbers with very large (
`1.0e299`

or above) or very small (`1.0e-299`

or below) magnitudes. Large numbers may be treated by GAMS as undefined (`UNDF`

) or other special values, leading to unpredictable and unusable results. Always use`INF`

(or`-INF`

) explicitly for arbitrarily large (or small) numbers.

GAMS has defined the results of all arithmetic operations and all function evaluations that use these special values. The behavior is designed to both maximize utility and minimize surprise, and is illustrated in the library model [CRAZY]. For example: `1+INF`

evaluates to `INF`

, `1-EPS`

to `1`

, `NA`

* 2 to `NA`

, and `EPS*INF`

to `UNDF`

.

The following table shows a selection of results for exponentiation and division for a variety of input parameters including `NA`

and `INF`

.

`a` | `b` | `a**b` | `power(a,b)` | `a/b` |
---|---|---|---|---|

2 | 2 | 4 | 4 | 1 |

-2 | 2 | `UNDF` | 4 | -1 |

2 | 2.1 | 4.28 | `UNDF` | .952 |

`NA` | 2.5 | `NA` | `NA` | `NA` |

3 | 0 | 1 | 1 | `UNDF` |

`INF` | 2 | `INF` | `INF` | `INF` |

2 | `INF` | `UNDF` | `UNDF` | 0 |

**Table 11:** Extended Range Arithmetic in Exponentiation and Division

Note that most extended range identifiers may be used in assignment statements, as illustrated below.

```
a(row,'col-3') = NA;
a(row,'col-4') = INF;
a(row,'col-5') = -INF;
```

The values most often used in assignments are `NA`

in incomplete tables and `INF`

for variable bounds.

The special value `EPS`

is numerically equal to zero, so when used in the context of numerical comparisons, it behaves as zero. For example, the logical expressions `x > 0`

and `x > EPS`

have the same result. However, EPS is a *stored* zero, so setting a parameter to zero (e.g. `a(row,col)=0`

) results in no values being stored for `a`

, while setting a parameter to EPS (e.g. `a(row,col)=EPS`

) results in the value EPS being stored for every `(row,col)`

tuple. This is sometimes useful, especially if `a`

is used later in loops (see Programming Flow Control Features) or dollar conditions (see Conditional Expressions, Assignments and Equations). For example, consider the statement

```
a(row,col)$[a(row,col)] = INF ;
```

In the case where `a`

was originally assigned to be zero, the dollar-condition is always false so no infinities are assigned. If `a`

was originally assigned the value EPS, the dollar-condition is always true and every tuple in `a`

will be set to infinity.

When an attempted arithmetic operation is illegal or has undefined results because of the value of arguments (division by zero is the normal example), an error is reported and the result is set to undefined (`UNDF`

). The error is marked on the output file with a row of four asterisks '`****`

' making this sequence a good search target in the editor. GAMS will also report the line number of the offending statement and give as much detail as possible about the cause. From there on, the resulting `UNDF`

is treated as a proper data value and does not trigger additional error messages. For more on error messages, see chapter GAMS Output.

- Note
- GAMS will not solve a model if an error has been detected, and it will terminate with an error condition.

It is therefore wise to anticipate and avoid operations like division by zero that will cause errors. This is most easily done with the dollar control, and is discussed in section The Dollar Condition.

# Predefined Symbols

GAMS offers several *predefined* symbols including: sameAs, diag, sortedUels, `solvers`

, `licenseCodes`

, `solverCapabilities`

, `componentEDate`

, `componentMDate`

, and `ComponentLicenseOptions`

. With the exception of `sameAs`

, `diag`

, and `sortedUels`

these predefined symbols are for very special (and mostly internal) purpose, but the way they work is identical.

These symbols can be used in a GAMS program without being declared but work in an idiosyncratic way. For example, the complete program

```
display solvers, sameAs;
```

compiles and executes without error and produces the following result in the listing file:

---- 1 SET Solvers Available Solvers ( EMPTY ) ---- 1 SET SameAs Set Element Comparison Without Checking ( EMPTY )

However, if labels have been declared (in any set) that corresponds to a solver name, then set `solvers`

will contain this label. Consider the following example:

```
Set titles / Lord, Baron, Duke /;
Set greeks / Euclid, Pythagoras, Antigone /;
display solvers, sameAs;
```

Note that `Antigone`

and `Baron`

are the names of solvers in GAMS and therefore is will be displayed as a member of the set `solvers`

. Also note that the set `sameAs`

contains the diagonal elements for both sets:

---- 3 SET Solvers Available Solvers Baron , Antigone ---- 3 SET SameAs Set Element Comparison Without Checking Lord Baron Duke Euclid Pythagoras Antigone Lord YES Baron YES Duke YES Euclid YES Pythagoras YES Antigone YES

User defined symbols can have the same name as a predefined symbol. In this case the user symbol *hides* the predefined symbols as demonstrated in the following example:

```
Set diag / 1*3 /;
$if setType diag $log diag is a set
$if preType diag $log diag is a predefined type
```

The log will only contain the line `diag is a set`

. The test `$if preType diag`

fails.

The list of all predefined symbols can be retrieved by declaring and displaying a set using some system data `set pre /system.predefinedSymbols/; display pre;`

which results in

---- 1 SET pre SameAs , Diag , Solvers LicenseCodes , SolverCapabilities , SortedUels ComponentEDate , ComponentMDate , ComponentLicenseOptions

# Summary

GAMS provides powerful facilities for data manipulation with parallel assignment statements, built-in functions and extended range arithmetic.