Monday, July 12, 2021

GAMS Singleton Set Issue

There is a nasty problem with the singleton set in GAMS. A singleton set is a set that can contain only zero or one element. Adding more elements implies replacement. I don't use it very often. Here is a reason why.

Consider the small example:

 set i /i1*i20/; parameter p(i); p(i) = uniform(0,10); * find last element >= 5 scalar threshold /5/; singleton set k(i); loop(i,   k(i)\$(p(i)>=threshold) = yes; ); display p,k;

I would expect to see as output for k the last element in p(i) that is larger than 5. However, we see:

```----     12 PARAMETER p

i1  1.717,    i2  8.433,    i3  5.504,    i4  3.011,    i5  2.922,    i6  2.241,    i7  3.498,    i8  8.563
i9  0.671,    i10 5.002,    i11 9.981,    i12 5.787,    i13 9.911,    i14 7.623,    i15 1.307,    i16 6.397
i17 1.595,    i18 2.501,    i19 6.689,    i20 4.354

----     12 SET k

( EMPTY )
```

The problem is that the dollar-controlled assignment to a singleton set is incorrectly implemented. The singleton set is cleared before the assignment without looking at the dollar condition. We can see this by using an alternative formulation of the loop:

 loop(i,   if(p(i)>=threshold,      k(i) = yes;   ) );

Now the output is correct:

```----     19 PARAMETER p

i1  1.717,    i2  8.433,    i3  5.504,    i4  3.011,    i5  2.922,    i6  2.241,    i7  3.498,    i8  8.563
i9  0.671,    i10 5.002,    i11 9.981,    i12 5.787,    i13 9.911,    i14 7.623,    i15 1.307,    i16 6.397
i17 1.595,    i18 2.501,    i19 6.689,    i20 4.354

----     19 SET k

i19
```

Conclusion

Beware when using singleton sets in GAMS: it can deliver unexpected results. A workaround for a dollar-controlled assignment is using an if statement.