Set element order

Top  Previous  Next

GAMS operates on a first in first out basis.  The order of output items is always controlled by the first time something is seen. Many users are frustrated with the ordering of set elements in the output.  This can be changed.

It is worthwhile knowing the rules that ordering follows.  GAMS uses something called the unique element list (UEL) to store set elements. This is a single list of all set elements.  The elements enter that list in the order of their appearance and that is the order in which they will appear in the output i.e. first in first out.

This means if I have the sets ONE and TWO with the elements below (dispset.gms)

 

set ONE /A,C,B,Total,8/;

Set TWO /D,A,F,TOTAL/;

Set items1through10 /1*10/;

Parameter  item(two) /D 1,A 3, F 5/;

item("total")=sum(two$(not sameas(two,"total")),item(two));

display item,items1through10;

 

Then the display output will appear as follows.  Note in the display of the parameter item that the output appears with the set element Total in the second position even though it was typed in the last position of the set called TWO and the parameter item is defined over that set.

 

----      6 PARAMETER item

     A     3.000,    Total 9.000,    D     1.000,    F     5.000

----      6 SET       items1through10

8 ,   1 ,   2 ,   3 ,   4 ,   5 ,   6 ,   7 ,   9 ,   10

 

This occurs because Total was seen before D and F in the sets because it was seen first in set ONE, even though it was listed last in set TWO.

Similarly, look what has happened in the display of the set items1through10.  Here 8 appears first then 1-7 and 9-10.  This happens because the set element 8 appeared in the set ONE before 1-7 and 9-10 were seen.

Notes:

There are three ways of fixing such problems.

One could change the name of the "total" item in the set named "two" so it was a name not seen before and 8 in the set "one" to new8 so it will not be seen again.  For example I could utilize the commands (dispset1.gms)

set     ONE     /A,C,B,Total,new8/

Set     TWO     /D,A,F,TOTAL2/

Parameter item(two) /D 1,A 3, F 5/;

Item("total2")=sum(two$(not sameas(two,"total2")),item(two));

 

yielding

 

A     3.000,    D     1.000,    F     5.000 TOTAL2 9.000

and

1 ,    2 ,    3 ,    4 ,    5 ,    6 ,    7 ,    8 ,    9 ,    10

 

where use of total2 which had not been seen before and new8 which will not be seen again, restores the desired ordering.

One could define a set at the top of the program which contains all elements in the order desired using set definitions as follows (dispset3.gms)

    set     UELORDER    /A,B,C,D,F,Total,1*20/

    set     ONE     /A,C,B,Total,8/

    Set     TWO     /D,A,F,TOTAL2/

    Set items1through10 /1*10/;

 

In turn the displays would always have "Total" at the end and the 1-10 in the desired order.

One can employ an ordering set.  Yet another approach can be used adding another dimension to the item of interest and employing an ordering set (dispset4.gms).  In such a case, I add new set as the first index and put in a set that I know the order of.  Then, by judiciously defining the first dimension I control the order.

Consider the following example where I want to better control appearance of the data in the table "items" on output

set         one                 /A,B,C,D,F,Average,ITEMS/;

Set     PQ /Price,Quantity/;

Table Items(one,PQ)

       Price  Quantity

   A     2     9000

   B     6     3000

   C     2.5   4000

   D     2.1   3000

   F     2.4   1.90;

items("Average",PQ)= SUM(one,items(one,pq))

                     /sum(one,1$items(one,pq));

display items;

 

In turn the display output is

 

---- PARAMETER ITEMS

                Price      Quantity

     A          2.000      9000.000

     B          6.000      3000.000

     C          2.500      4000.000

     D          2.100      3000.000

     F          2.400      1.900

     Average    3.000      3800.380

 

 But suppose I wanted average first.  I do this by adding the set numberordr with values r1 through  r100.  Also I define items1 which is a new parameter with dimension one greater than items which has the numberordr set defining it in the first index position.  Then I insure the items I want first have lower values in the numberordr place. (dispset4.gms).  I also experiment with another ordering in the parameter items2.

 

Set  numberordr /r1*r100/

set  one        /A,B,C,D,F,Average/

Set  order2(numberordr,one)

                /r3.(A,D,F),r2.Average,r1.(C,B)/

Set     PQ /Price,Quantity/

Table Items(one,PQ)

      Price     Quantity

A     2         9000

B     6         3000

C     2.5       4000

D     2.1       3000

F     2.4       1.90;

items("Average",PQ)=

SUM(one,items(one,pq))/sum(one,1$items(one,pq));

parameter items1(numberordr,one,pq) ordered first way;

items1("r2",one,pq)$(not sameas(one,"average"))

=items(one,pq);

items1("r1","average",pq)=items("average",pq);

parameter items2(numberordr,one,pq) ordered second way;

items2(numberordr,one,pq)

=sum(order2(numberordr,one),items(one,pq));

display items,items1,items2;

 

In turn the output is

 

 

----PARAMETER ITEMS1 

                 Price    Quantity

r1.Average       3.000    3800.380

r2.A             2.000    9000.000

r2.B             6.000    3000.000

r2.C             2.500    4000.000

r2.D             2.100    3000.000

r2.F             2.400       1.900

 

----     18 PARAMETER ITEMS2

                   Price    Quantity

r1.B             6.000    3000.000

r1.C             2.500    4000.000

r2.Average       3.000    3800.380

r3.A             2.000    9000.000

r3.D             2.100    3000.000

r3.F             2.400       1.900

 

 where note by manipulating the association of items in the numberordr set with the things I wish reordered I can rearrange the output.