Macros in GAMS

Top  Previous  Next

GAMS includes the ability to defines macros as of version 22.9.  The design of the macro facility was inspired by the GAMS-F preprocessor for function definition developed by Ferris, Rutherford and Starkweather, 1998, 2005.

Macros are widely used in computer science to define and automate structured text replacements. The GAMS macro processors functions similar to the popular C/C++ macro preprocessor. However, it is GAMS syntax driven.

Basic Definition

The definition takes the form

 $macro name  macro body        

 $macro name(arg1,arg3,arg2,..) macro body with tokens arg1,..

The name of the macro has to be unique, similar to other GAMS data types like sets and parameters. A ( following immediately the macro name starts the list of replacement arguments and a ) ends it. These will be expanded by the arguments in parentheses in a call to the macro.

The macro body is not further analyzed after removing leading and trailing spaces.

The items to replace in the macro body follow the standard GAMS identifier conventions. For example: let us define a simple macro that forms 1 over an item

$macro oneoverit(y) 1/y

 

then let us use it calling the macro twice with two different arguments(macros.gms)

 

z = oneoverit(x1)+oneoverit(x2);

will then be expanded using the arguments into:

z = 1/x1 +1/x2;

as GAMS recognizes oneoverit(x1) as a macro and substitutes x1 (the argument in oneoverit(x1)) for y (in the original definition of the macro oneoverit(y))and does the same for x2.

Note the item used in the macro(y) is just a symbol and can duplicate the name of other items in the code.  For example the macro could have been defined

$macro oneoverit(x1) 1/x1

 

even though x1 is a named scalar in the code.

 

Multiple arguments

The actual calling arguments of macros can contain multiple arguments. In such a case the multiple arguments are separated by commas. (macros.gms)

$macro ratio(a,b) a/b 

when called with

z = ratio(x1,x2);

will expand into:

z = x1/x2;

 

Multi-line Macros

 

One can extend macros to multiple lines using a \ (macros.gms)

 $macro equ2(z,d,q)  equation equ2_&z&d; \

                          equ2_&z&d.. z*q =e= 0;

 

Macros within Macros

Macros can be included within macros (macros.gms)

$macro product(a,b) a*b

$macro addup(i,x,z) sum(i,product(x(i),z))

 

when called with

z = addup(j,a1,x1);

will expand into:

z = sum(j,a1(j)*x1);

 

Note multiple pairs of parenthesis and quotes can be used freely to protect the separating comma.

 

More careful expansion

The recognition of macros and expansion of arguments can be more carefully controlled by the use of ampersands (&) in the macro body. Ordinarily the macro will only substitute for full words thus the macro group (macros.gms)

$macro  f(i)  sum(j, x(i,j))

$macro equh(q)  equation equ_q(i); equ_q(i).. q =e= 0;

equh(f(i))

 

which would expand to become

equation equ_q(i); equ_q(i).. sum(j, x(i,j)) =e= 0;

Note this contains q in a number of other places.  If one wished to replace some of them as well one could use (macros.gms)

$macro  f2(r,i)  sum(j, r(i,j))

$macro equ2(z,d,q)  equation equ2_&z&d; equ2_&z&d.. z*q =e= 0;

equ2(1,(i),f2(x,i))

equ2(2,(k),f2(r,k))

which would expand to become

 

equation equ2_1(i); equ2_1(i).. 1*sum(j, x(i,j)) =e= 0;

equation equ2_2(k); equ2_2(k).. 2*sum(j, r(k,j)) =e= 0;

where the &z and $d are replaced.

One can also include expressions with spaces, commas and unbalanced parentheses using && which includes an expression removing the outer set of quotes. (macros.gms)

$macro d(q) display &&q;

$macro ss(q) &&q)

d('"hereit is" , i,k')

d('"(zz"')

z=ss('sum(j,a1(j)');

z=ss('prod(j,a1(j)');

where note the d expressions contain quotes, spaces and commas and the ss expression has unbalanced parentheses within the quoted parts.

In turn these expand to become

display "hereit is" , i,k;

display "(zz";

z=sum(j,a1(j));

z=prod(j,a1(j));

 

Infinite nested macros

Nested macro use can result in an expansion of infinite length. For example:

$macro a  b,a

display a; 

will expand into:

display b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,……

GAMS will eventually refuse to do more substitutions and issue a compilation error.

Use in report writing

Another feature of macros is the implicit use of the .L suffix in report writing and other data manipulation statements. This allows using the same algebra in model definitions and assignment statements. The following code illustrates this feature (macrotrnsport.gms)

$macro sumit(i,term) sum(i,term)

  cost ..        z  =e=  sumit((i,j), (c(i,j)*x(i,j))) ;

  supply(i) ..   sumit(j, x(i,j))  =l=  a(i) ;

  demand(j) ..   sumit(i, x(i,j))  =g=  b(j) ;

  Model transport /all/ ;

  Solve transport using lp minimizing z ;

$onDotL

parameter tsupply(i) total demand for report

          tdemand(j) total demand for report;

          tsupply(i)=sumit(j, x(i,j));

          tdemand(j)=sumit(i, x(i,j));

which will expand into:

cost ..        z  =e=  sum((i,j),(c(i,j)*x(i,j))) ;

supply(i) ..   sum(j,x(i,j))  =l=  a(i) ;

demand(j) ..   sum(i,x(i,j))  =g=  b(j) ;

Model transport /all/ ;

Solve transport using lp minimizing z ;

parameter tsupply(i) total demand for report

tdemand(j) total demand for report;

tsupply(i)=sum(j,x.L(i,j));

tdemand(j)=sum(i,x.L(i,j));

The $ondotl enables the implicit .L suffix for variables. This feature was introduced to make macros more useful and is not limited to be used in macro bodies. Since this a new feature it has to be enabled. The matching $offdotl will disable this feature.

Other notes

Three more commands are relevant to macros.

 $show will list any GAMS macros defined.

 $onmacro/$offmacro will enable or disable the expansion of macros; the default is $onmacro.

 $on/offexpand will change the processing of macros appearing in the arguments of a macro call. The default operation is not to expand macros in the arguments. The switch $onexpand enables the recognition and expansion of macros in the macro argument list. $offexpand will restore the default behavior.

Macro definitions are preserved in a save/restart file and are available again when performing a continued compilation.