|
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;
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.
|