Friday, August 7, 2009

GAMS: speed of loops

In GAMS models I often see loops where they are not really needed. E.g.

loop(i,
   loop(j,
      loop(k,
         q(i,j,k) = 1;
)));

can be written as:

q(i,j,k) = 1;

Consider the larger fragment:

set i /i1*i200/;
alias(i,j,k);

parameter p(i,j,k);
p(i,j,k) = 1;

parameter q(i,j,k);
loop(i,
   loop(j,
      loop(k,
         q(i,j,k) = 1;
)));

parameter q2(i,j,k);
loop((i,j,k),
   q2(i,j,k) = 1;
);

The timing for the direct assignment to p(i,j,k) is 0.78 seconds. The time to populate q(i,j,k) is 18 seconds. The slightly different loop to fill q2 takes the same time: also 18 seconds. The difference is merely syntax. So if possible try not to use loops: not only is the code more compact, but it also performs better.

A more dramatic example is here (with card(i)=card(j)=card(k)=50):

p(i,j,k) = max(0,p(i,j,k)); 0.031 secs
loop((i,j,k),
  
if(p(i,j,k)<0, p(i,j,k)=0);
);
36.4 secs