Saturday, August 9, 2008

Loops are slow in GAMS

When optimizing GAMS code it is always worthwhile to see if you can remove loops. Here is an example of an if,then,else construct:

   1  set i /i1*i200/;
2
3 alias (i,j,k);
4 parameter a(i,j,k),b(i,j,k),c(i,j,k);
5 a(i,j,k) = uniform(0.1,1);
6 b(i,j,k) = uniform(0.1,1);
7 c(i,j,k) = uniform(0.1,1);
8
9 parameter p1(i,j,k),p2(i,j,k),p3(i,j,k);
10
11 * this is fast
12 p1(i,j,k) = ifthen(b(i,j,k)>0.5,a(i,j,k)/b(i,j,k),c(i,j,k));
13
14 * this is slow
15 loop((i,j,k),
16 if(b(i,j,k)>0.5,
17 p2(i,j,k) = a(i,j,k)/b(i,j,k)
18 else
19 p2(i,j,k) = c(i,j,k)
20 );
21 );
22
23 * this is fast but I feel uneasy about assumption that
24 * these conditions are quaranteed mutual exclusive
25 * for floating point numbers
26 p3(i,j,k) = [a(i,j,k)/b(i,j,k)]$(b(i,j,k)>0.5) + c(i,j,k)$(b(i,j,k)<=0.5);



The profiling info clearly indicates the loop is the slowest alternative:

----      1 ExecInit                 0.000     0.000 SECS      3 Mb
---- 5 Assignment a 1.762 1.762 SECS 261 Mb 8000000
---- 6 Assignment b 1.748 3.510 SECS 518 Mb 8000000
---- 7 Assignment c 1.747 5.257 SECS 775 Mb 8000000
---- 12 Assignment p1 3.307 8.564 SECS 1,032 Mb 8000000
---- 15 Loop 22.027 30.591 SECS 1,288 Mb
---- 26 Assignment p3 3.900 34.491 SECS 1,545 Mb 8000000



I prefer the ifthen construct as this has a real 'else'. The assignment to p3 uses two different $ conditions, which makes me feel uneasy.