I often see models with set elements 1,2,…. Here is an example:
Of course if we have real data often we can use real names. But in some cases we need to use numbers as IDs. This is also typically the case when we don’t have real data and have to invent things. BTW, inventing data for a model is actually a very useful exercise: it will force you to think about the model in a more structured way.
If I have to invent labels I tend not to use 1,2,3,… but rather prefix the number by a string indicating what it is, e.g.:
set i /i1*i10/ j /j1*j10/ w 'warehouse' /wh1*wh12/ ; |
The reason to use these longer labels is that the output of the model becomes easier to interpret. Below is an example:
Bare numbers | | Prefixed numbers |
set p 'product' /1*10/ f 'factory' /1*4/ w 'warehouse' /1*3/ t 'time period' /1*5/ ;
positive variables x(p,f,w,t) 'product flow from factory to warehouse'; | Declarations |
| set p 'product' /pr1*pr10/ f 'factory' /fact1*fact4/ w 'warehouse' /wh1*wh3/ t 'time period' /t1*t5/ ;
positive variables x(p,f,w,t) 'product flow from factory to warehouse'; |
---- VAR x product flow from factory to warehouse LOWER LEVEL UPPER MARGINAL 1 .1.1.1 . 20.0000 +INF . 1 .1.1.2 . 85.0000 +INF . 1 .1.1.3 . 60.0000 +INF . 1 .1.1.4 . 35.0000 +INF . 1 .1.1.5 . 30.0000 +INF . 1 .1.2.1 . 25.0000 +INF . 1 .1.2.2 . 35.0000 +INF . 1 .1.2.3 . 90.0000 +INF . 1 .1.2.4 . 10.0000 +INF . 1 .1.2.5 . 55.0000 +INF . 1 .1.3.1 . 100.0000 +INF . ... | First part of the solution listing. Without recalling the declaration of variable x this is difficult to understand. |
Using the prefixes we do not have to remember the ordering of the indices for this variable | ---- VAR x product flow from factory to warehouse LOWER LEVEL UPPER MARGINAL pr1 .fact1.wh1.t1 . 20.0000 +INF . pr1 .fact1.wh1.t2 . 85.0000 +INF . pr1 .fact1.wh1.t3 . 60.0000 +INF . pr1 .fact1.wh1.t4 . 35.0000 +INF . pr1 .fact1.wh1.t5 . 30.0000 +INF . pr1 .fact1.wh2.t1 . 25.0000 +INF . pr1 .fact1.wh2.t2 . 35.0000 +INF . pr1 .fact1.wh2.t3 . 90.0000 +INF . pr1 .fact1.wh2.t4 . 10.0000 +INF . pr1 .fact1.wh2.t5 . 55.0000 +INF . pr1 .fact1.wh3.t1 . 100.0000 +INF . ... |
---- 26 VARIABLE x.L product flow from factory to warehouse INDEX 1 = 1 1 2 3 4 5 1.1 20.000 85.000 60.000 35.000 30.000 1.2 25.000 35.000 90.000 10.000 55.000 1.3 100.000 60.000 100.000 80.000 15.000 2.1 65.000 20.000 30.000 70.000 45.000 2.2 40.000 40.000 15.000 20.000 60.000 2.3 85.000 25.000 70.000 80.000 35.000 3.1 15.000 55.000 20.000 90.000 30.000 3.2 30.000 60.000 75.000 65.000 50.000 3.3 45.000 15.000 35.000 5.000 35.000 4.1 20.000 65.000 60.000 80.000 30.000 4.2 70.000 80.000 65.000 30.000 10.000 4.3 15.000 65.000 55.000 5.000 80.000 INDEX 1 = 2 1 2 3 4 5 1.1 10.000 20.000 55.000 80.000 20.000 1.2 5.000 60.000 65.000 40.000 40.000 1.3 25.000 25.000 15.000 95.000 40.000 2.1 80.000 35.000 15.000 75.000 10.000 ... | Same with a default display output. Again only partially reproduced here. |
| ---- 24 VARIABLE x.L product flow from factory to warehouse INDEX 1 = pr1 t1 t2 t3 t4 t5 fact1.wh1 20.000 85.000 60.000 35.000 30.000 fact1.wh2 25.000 35.000 90.000 10.000 55.000 fact1.wh3 100.000 60.000 100.000 80.000 15.000 fact2.wh1 65.000 20.000 30.000 70.000 45.000 fact2.wh2 40.000 40.000 15.000 20.000 60.000 fact2.wh3 85.000 25.000 70.000 80.000 35.000 fact3.wh1 15.000 55.000 20.000 90.000 30.000 fact3.wh2 30.000 60.000 75.000 65.000 50.000 fact3.wh3 45.000 15.000 35.000 5.000 35.000 fact4.wh1 20.000 65.000 60.000 80.000 30.000 fact4.wh2 70.000 80.000 65.000 30.000 10.000 fact4.wh3 15.000 65.000 55.000 5.000 80.000 INDEX 1 = pr2 t1 t2 t3 t4 t5 fact1.wh1 10.000 20.000 55.000 80.000 20.000 fact1.wh2 5.000 60.000 65.000 40.000 40.000 fact1.wh3 25.000 25.000 15.000 95.000 40.000 fact2.wh1 80.000 35.000 15.000 75.000 10.000 ... |
| With the GDX viewer things can become even more mysterious and difficult to decipher as we can flip dimensions around. You get a little bit of help with this: The 5th dimension is LO,L(evel),M,UP. We see we flipped dimensions 4 and 3 (t and w). |
Here we see immediately what is going on. | |
Notes
- It makes sense to use this approach even with real (not invented) numeric IDs. Once the data arrives in GAMS it is often not so easy to “repair” set element labels. If the data is sitting in a database it can be helpful to prefix numeric IDs in the SQL query:
SELECT 'pr' || productid FROM table |
For a spreadsheet, often the easiest way is to insert a column or create a copy of the table with the new prefixed names. - The construct i.val does not work with numbers that are prefixed. I usually work around this to create a parameter val(i) that contains the value of element i. If needed I create a superset of i that has an easy way to populate val(s). E.g.
set s /i3*i10/ i(s) /i3*i5,i8*i10/ ; parameter val(s); val(s) = ord(s)+2; * now we can use val(i) |
- It is not always possible to distinguish dimensions by their element names. E.g.
set i 'nodes' /node1*node10/; alias (i,j); positive variable flow(i,j); |
Here, by nature, the two indices i and j have the same names because they have the same domain.
No comments:
Post a Comment