In my previous post, I showed an easy way to aggregate a matrix using mappings in GAMS. If you use a small mapping, you probably won’t make any errors, but if the sets in the mappings have many elements, the chance of an error rises. For example, you forget to map one of the elements on either side, or you map one element twice.
Tom Rutherford wrote a nice piece of code to check your mappings. This code raises an error as soon as you make one of the mistakes mentioned above.
Let us first set up a simple mapping (I tend to name my mappings always like “map<capitalized name of the first set>to<capitalized name of the second set>):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
set f Full set /f1*f5/; alias(f,af); * Set up the aggregation set a Aggregated set /a1, a2, a3/; alias(a,aa); * Define the mapping set mapFtoA(f,a) mapping /(f1,f2).a1, f3.a2, (f4,f5).a3/; display mapFtoA; |
If you look in your listing file, you will see the following:
1 2 3 4 5 6 7 8 |
---- 23 SET mapFtoA mapping a1 a2 a3 f1 YES f2 YES f3 YES f4 YES f5 YES |
To check if you made no errors in the mapping, you could check the listing output, and see, if every set element of f is assigned once and only once to one element of the set a, as well as if all elements of the set a are used.
The code by Tom Rutherford does this is in a very elegant way. First, we define two empty sets, error1 and error2. These sets are used respectively to check errors made in the mapping of the first set (f) and the second set (a) of the mapping.
1 2 3 4 5 6 7 8 9 10 |
* Check the mappings: set error1 First index missing or twice error error2 Second index missing or twice error; error1(f) = yes$(sum(a$mapFtoA(f,a), 1) ne 1); abort$card(error1) "mapagg: inconsistent mapping first index! missing sector is", error1; error2(a) = yes$(SUM(f,1$mapFtoA(f, a)) eq 0); abort$card(error2) "mapagg: inconsistent mapping second index! missing sector is", error2; |
If you make an error in the mapping from f to a, error1 catches this for mistakes with the assignment of f to a. The dollar condition sums ones if there are elements in the row of the mapping (e.g., the first row contains a YES for the combination (f1,a1), so it gives a total sum of 1. If you would have forgotten to map “f1” to an element of a, the sum would be zero, and if you would have mapped this element twice, the sum would be two. If this sum is not equal to 1, error1 is assigned an element for the row with the mistake. In the next line, GAMS aborts if the error1 set has elements. In that case, the cardinal of the set is greater than zero.
The second set, error2, checks if you have used all elements from the aggregated set a. If you have forgotten one, this set will contain the element and the cardinal of error2 is bigger than zero, and GAMS exits with an error showing the missing elements.
This could, of course, be done in different ways. One could define a matrix with ones for the mapping and then sum over the rows and columns. However, this would more code. Changing one of the rules of the Zen of Python a little bit:
1 2 |
There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're American. |
Note, that in the original, the nationality mentioned is “Dutch”…