Monday, May 12, 2008

$ifthen does not nest (GAMS release 22.7 bug)

My first blog starts with a down note. I was working last night on this very large GAMS model with many model settings implemented as $set/$setglobal macros. In this context I want to nest some $ifthen constructs:

$set stochastic 0
$set erslivestockmodel 1

$ifthen %stochastic%==1
$ ifthen %erslivestockmodel%==1
b(i,"Exports",k) = tempbx(k);
b(i,"Season Average Price",k) = tempbp(k);
b(i,"Feed Use",k) = tempbdf(k);
b(i,"Food",k) = tempbdi(k);
cfixed(i,"Exports",k) = 0;
cfixed(i,"Season Average Price",k) = 0;
cfixed(i,"Feed Use",k) = 0;
cfixed(i,"Food",k) = 0;
$ else
$ include grains.inc
$ endif
$endif


This does not work as nesting is not allowed. You don't get an error message either indicating nesting is not allowed. In some cases you may get a possibly misleading error message, in the worst case it just behaves incorrectly. The documentation in the McCarl User Guide does not mention this limitation. Looks like $ifthen will be less useful in practice than I had hoped.

The workaround is to use a run-time if statement:

$set stochastic 0
$set erslivestockmodel 1

scalars
stochastic /%stochastic%/
erslivestockmodel /%erslivestockmodel%/
;
if(stochastic=1,
if(erslivestockmodel=1,
b(i,"Exports",k) = tempbx(k);
b(i,"Season Average Price",k) = tempbp(k);
b(i,"Feed Use",k) = tempbdf(k);
b(i,"Food",k) = tempbdi(k);
cfixed(i,"Exports",k) = 0;
cfixed(i,"Season Average Price",k) = 0;
cfixed(i,"Feed Use",k) = 0;
cfixed(i,"Food",k) = 0;
else
$ include grains.inc
);
);


This has additional advantages: all branches are syntax-checked even if they are not executed, and we check the type of the parameters using the scalar initializations. Of course we lose some of the compile time features using this approach.

Another workaround would be to place the inner $ifthen in an include file:

$set stochastic 0
$set erslivestockmodel 1

$ifthen %stochastic%==1
$include gamsbugworkaround.inc
$endif
Conclusion: GAMS users be aware when using nested $ifthen constructs. They are not implemented (correctly) and no error message is produced to warn you about this.