In GAMS set elements (used for indexing) are strings. This means it is not necessary to use non-descriptive numbers as in:

set i /1*50/;

Actually, even with numbered elements, it is good practice to prefix such elements, as in:

set i /i1*i50/;

This will help when inspecting large, multi-dimensional data-structures.

As an example consider the code fragment:

set

i /1*8/

j /1*4/

k /1*6/

;

parameter p(i,j,k);

p(i,j,k) = uniform(0,1);

I see these type of numbered sets quite often. Here is why this may be a bad idea: especially after pivoting a bit, it is really difficult to see what is going on:

If we prefix the set elements with a name, we achieve much more clarity:

When I receive a model with numbered set elements the first thing I try to do is to prefix the labels.

Of course, in practical models, we often can use meaningful names, but sometimes we just have numbers as IDs. I have also seen cases where the ID is a number or a very long description. In that case, the number can be a better candidate for set element.

### Exporting set elements

In GAMS a parameter is really a sparse (multi-dimensional) matrix. This corresponds quite nicely to a table in a RDBMS (relational database) or to a dataframe in R or Python. A matrix in R or Python is dense, so those data structures do not work as well for large, sparse parameters, although R has nice facilities to use matrices with row and column names.

### Example

Let’s generate some data in GAMS and export to an SQLite database:

set

i 'observations' /i1*i50/

s 'scenarios' /scen1*scen3/

;

parameter results(s,i);

results('scen1',i) = normal(0,1);

results('scen2',i) = normal(-1+4*ord(i)/card(i),0.4);

results('scen3',i) = uniform(4,5);

execute_unload "results.gdx",results;

execute "gdx2sqlite -i results.gdx -o results.db";

We can try to plot this data in R as follows:

library("RSQLite") library("ggplot2") # connect to the sqlite file sqlite = dbDriver("SQLite") db = dbConnect(sqlite, "results.db") # retrieve data df = dbGetQuery(db,"select * from results") head(df) ggplot(data=df,aes(x=i,y=value,color=s)) + geom_line() dbDisconnect(db)

The output of head(df) indicates we read the data correctly:

## head(df)

s i value

1 scen1 i1 -0.3133429

2 scen1 i2 0.3276748

3 scen1 i3 0.4635588

4 scen1 i4 -1.8299478

5 scen1 i5 -0.7316124

6 scen1 i6 -0.9715983

Unfortunately, things don’t work exactly as expected. We see an error message:

geom_path: Each group consists of only one observation. Do you need to adjust

the group aesthetic?

And the plot does not look correct:

The reason is the variable df$i.If we convert this back to integers we are ok. To do this conversion we actually have to do two things:

- Drop the first character ‘i’ from df$i.
- Convert df$i from string to numeric (type casting).

Interestingly we can fix this in several stages:

### Partial GAMS solution

We can not really rename set elements in GAMS. However we can create a new parameter, a mapping set and use a sum statement to map between sets:

set

i 'observations' /i1*i50/

s 'scenarios' /scen1*scen3/

i2 'observations as number' /1*50/

map(i2,i) '1-1 mapping set'

;

map(i2,i)$(ord(i2)=ord(i)) = yes;

parameter results(s,i);

results('scen1',i) = normal(0,1);

results('scen2',i) = normal(-1+4*ord(i)/card(i),0.4);

results('scen3',i) = uniform(4,5);

parameter results2(s,i2);

results2(s,i2) = sum(map(i2,i),results(s,i));

Now we can export the parameter results2 instead of results. Note that index i2 will still be a string when it arrives in R. The type casting to a numeric type has to be done in R or in SQL (see next sections how this can be done).

### Conversion in R

The conversion to a numeric type can be done in R in just one line

df$i <- as.numeric(substring(df$i,2))

### Conversion in SQL

We can also perform the conversion in SQL while reading the data from the SQLite database file:

select s,

cast(substr(i,2) as numeric) as i,

value

from results

cast(substr(i,2) as numeric) as i,

value

from results

### Scripting

This whole thing can be easily scripted in GAMS.

## No comments:

## Post a Comment