Detailed GAMS Release Notes 22.6

$ife statement with expression evaluation

The $if statement has been enhanced to allow constant expression evaluation. To match the flavor of the basic $if statement, we have introduced two forms:

$ife  expr1 == expr2   true if (expr1-expr2)/(1+abs(expr2)) < 1e-12
$ife  expr             true if expr1 <> 0

The expressions follow the standard GAMS syntax and are explained in more detail below. The .==. form is convenient when expecting rounding errors. For example, we can write

$ife log2(16)^2 == 16  (true statement)

which is more convenient than having to write

$ife NOT round(log2(16)^2-16,10)   (true statement)
$ife round(log2(16)^2,10)=16       (true statement)

$ifthen/elseif/else/endif statement

A new variant on the $if statement has been introduced. It follows the usual structures and allows appropriate nesting. The syntax for the condition are the same as for the $if statement. The $ifthen and $elseif have the same modifiers as the $if statement, namely I for case insensitive compare and E for constant expression evaluation. In the example below we will execute all blocks of such a statement.

$maxgoto 10 $set x a
$label two
$ifthen %x% == a $set x 'c' $log $ifthen   with x=%x%
$elseif %x% == b $set x 'k' $log $elseif 1 with x=%x%
$elseif %x% == c $set x 'b' $log $elseif 2 with x=%x%
$else            $set x 'e' $log $else     with x=%x%
$endif $if NOT %x% == e $goto two

$eval x 1
$label three
display 'x=%x%';
$ifthen %x% == 1 $eval x %x%+1
$elseif %x% == 2 $eval x %x%+1
$elseif %x% == 3 $eval x %x%+1
$elseif %x% == 4 $eval x %x%+1
$else            $set  x done
$endif $if NOT %x% == done $goto three

This is a bit contrived but illustrates some of more subtle features. Anytime we use a looping construct via a $goto statement we have to protect ourselves against the potential of an infinite loop. The number of times we jump back to a label is counted and when a limit is reached, GAMS will issue an error. It is important to note that the %string% references are substituted only once.

Lengthy and nested ithen/else structures can become difficult to debug. Tagging of the begin, the $ifthen and the end, the $endif can be helpful. For example, the next line will fail because the tags do not match:

$ifthen.one x == x
$endif.one

As with the $if statement, the statement on the line with the $ifthen style statements is optional. The following two statements give the same results:

$iftheni %type% == low $include abc  
$elseifi %type% == med $include efg
$else                  $include xyz
$endif

$iftheni %type% == low 
$include abc  
$elseifi %type% == med 
$include efg
$else                  
$include xyz
$endif

The statements following directly a $ifthen, $elseif, or $else on the same line can be a sequence of other dollar control statements or contain proper GAMS syntax. The statements following directly a $endif can only contain another dollar control statements.

$ifthen.two   c==c  display 'true for tag two';
$ifthen.three a==a  $log true for tag three
display '   then clause for tag three';
$ifthen.four x==x display 'true for tag four'; 
$log true for tag four
$else
display '      else clause for tag four';
$endif.four          $log endif four
$endif.three         $log endif three
$endif.two           $log endif two

This will produce a GAMS program like

1  display 'true for tag two';
3  display '   then clause for tag three';
4  display 'true for tag four';

with the following log output

--- Starting compilation
true for tag three
true for tag four
endif four
endif three
endif two

$eval $evallocal $evalglobal

Those three new dollar control options are similar to $set, $setlocal and $setglobal. Those statements are used to assign values to ‘environment variables’ which are named string to be substituted by the %var% reference. The $eval options interpret the argument as a constant expression (see for more details below) and encode the result as a string. For example:

$if NOT set d $eval d 5
$eval h '24*%d%' $eval he '0' $eval dd '0'
Sets d days  / day1*day%d%/
     h hours / hour1*hour%h% /
     dh(d,h) /
$label more $eval dd '%dd%+1' $eval hs '%he%+1' $eval he %he%+24
        day%dd%.hour%hs%*hour%he%
$ife %dd%<%d% $goto more
             /;

will produce the expanded input source code below:

 
   3  Sets d days  / day1*day5/
   4       h hours / hour1*hour120 /
   5       dh(d,h) /
   7          day1.hour1*hour24
  10          day2.hour25*hour48
  13          day3.hour49*hour72
  16          day4.hour73*hour96
  19          day5.hour97*hour120
  21               /;

Syntax for constant evaluation

The syntax of constant expression use in data statements and $conditions follows the GAMS syntax, but restricted to scalar values and a subset of functions, as summarized below:

When used in data statement, the constant expressions have to be enclosed in a pair of Square brackets [ ] or curly brackets or braces { }. Spaces can be used freely inside those brackets. When used in dollar control options, like $eval or $if statements brackets are not required, however, we may have to enclose the expression within quotes (single or double) if we want to embed spaces or continue with additional $options on the same line. For example, when using $eval followed by another $statement:

$eval x 3 / 5 * pi     
$eval y "3/5*pi"  $eval z  pi  /  2  
$eval a ' exp(1)  / pi  '  $set b anything goes here
$show
.
Level SetVal                 Type       Text
--------------------------------------------
    0 x                      SCOPED     1.88495559215388
    0 y                      SCOPED     1.88495559215388
    0 z                      SCOPED     1.5707963267949
    0 a                      SCOPED     0.865255979432265
    0 b                      SCOPED     anything goes here

As with other dollar control statements, without the quotes, the entire remaining line will be interpreted as one argument.

The $ife and $ifthene/$elseife statements have a related problem which has been inherited by mimicking the Windows bat and cmd scripting conventions. When a constant expression contains spaces it has to be enclosed in quotes, as shown below.

$ife   (2+3)>=(2+2)            display 'OK, no spaces';
$ife  ' (2 + 3) >=  (2 + 2) '  display 'now we need quotes'; 

Finally, here are some data examples:

Scalars x PI half / {pi/2} /, e famous number / [ exp( 1 ) ] /;
Parameter y demo / USA.(high,low) [1/3], USA.medium {1/4} /;

Additional Licensing Information

Information about the licensing process is now available at compile and execution time.

At Compile Time

Two new System environment variables LicenseStatus and LicenseStatusText complement the other license related variables. In addition, two functions have been added to retrieve the licensing level and status. The use of those variables is demonstrated in the updated library model .licememo.. Here is an extract:

$set filename %gams.license%
$if '%filename' == '' $set filename %gams.sysdir%gamslice.txt
if(%system.licensestatus%,
   put '**** Error Message: %system.licensestatustext%'
     / '**** License file : %filename%'
     / '**** System downgraded to demo mode'// );

If called with an incorrect license, the report may contain:

**** Error Message: could not open specified license file
**** License file : garbage
**** System downgraded to demo mode

The variable system.licensestaus returns zero if no error has been encountered by the licensing process. The variable system.licensestatustext contains the respective explanation about a licensing failure. The above example uses compile time string substitutions and are not updated when execution a pre compiled work file.

At Run Time

Two new functions, LicenseLevel and LicenseStatus, provide this information at runtime:

The <name>.TN attribute on put arguments

Some special features for option files or other information files require writing complete expanded references of indexed identifiers like variables or equations. For example, the options for CPLEX indicator variables can now be written more compactly. For example, we no can write:

loop(lt(j,jj),
   put / 'indic ' seq.tn(j,jj) '$' y.tn(j,jj) yes
       / 'indic ' seq.tn(jj,j) '$' y.tn(j,jj) NO   );

This will produce

indic seq('A','B')$y('A','B')         YES
indic seq('B','A')$y('A','B')          NO
indic seq('A','C')$y('A','C')         YES
indic seq('C','A')$y('A','C')          NO
indic seq('B','C')$y('B','C')         YES
indic seq('C','B')$y('B','C')          NO

Besides the more compact GAMS code, it provides complete syntax checking at compile time.

Enhanced functions on controlling sets

New syntax has been added to extract more information about a controlling set. It is similar to the ord(i) operator but uses the dot notation. The new functions are:

The following example illustrates some of those new features:

set i / '-inf',1,12,24,'13.14',inf /; parameter report;
report(i,'value')    = i.val;
report(i,'length')   = i.len;
report(i,'offset')   = i.off;
report(i,'position') = i.pos;
display report;

The display shows

----      6 PARAMETER report  

            value      length      offset    position

-inf         -INF       4.000                   1.000
1           1.000       1.000       1.000       2.000
12         12.000       2.000       2.000       3.000
24         24.000       2.000       3.000       4.000
13.14      13.140       5.000       4.000       5.000
inf          +INF       3.000       5.000       6.000