Matching 2 sets in a loop, in sequence

Problems with modeling
Post Reply
henryhu.89
User
User
Posts: 15
Joined: 3 years ago

Matching 2 sets in a loop, in sequence

Post by henryhu.89 »

Hello,

I have recently come across a challenge when trying to code a model and was hoping someone where had some ideas (apologies in advance if the solution is obvious and I'm just not seeing it, GAMs can be confusing for me sometimes), here's what I want to do:

*step1. generate a household set
set hh /hh1 hh2 hh3/;

*step2. generate a matching set of double-dash parameters
set dd /dd1 dd2 dd3/;

*step3. make dd1,dd2 and dd3 double dash parameters :
$if not set dd1 $set dd1 0
$if not set dd2 $set dd2 0
$if not set dd3 $set dd3 0

*(I need this step to be in a loop, I have tried:
loop(dd,
$if not set dd $set dd 0)
but this doesn't work
)

*Step4. Match HH and DD sets in a loop
*Finally, I want to generate a parameter that matches hh1->dd1, hh2->dd2 and hh3->dd3 (this is another part I'm having trouble figuring out, here's the end result I want, but in a loop):

parameter x(hh);
x("hh1")=%dd1%;
x("hh2")=%dd2%;
x("hh3")=%dd3%;

Finally, these are generic names so I can't just make a third set /1 2 3 4.../ as a suffix. Any help would be appreciated, thanks!

Update: So I managed to get it to work through some janky code, which I hope to improve and learn more GAMs through. The below code works, but is horribly inelegant...

*Step 1. define household set:
set hh /hh1 hh2 hh3 hh4 hh5 hh6/;

*Step2. manually define double dash parameters: (if someone knows how to loop this, it would be fantastic)
$if not set sim_1 $set sim_1 11
$if not set sim_2 $set sim_2 11
$if not set sim_3 $set sim_3 11
$if not set sim_4 $set sim_4 11
$if not set sim_5 $set sim_5 11
$if not set sim_6 $set sim_6 11
$if not set sim_7 $set sim_7 11 (<- this one is redundant, but I am setting up more than I currently need since "set hh" needs to be dynamically updated)

*Step3. Define parameter:
parameter simulation(h,sim);

*Step4. Feed double-dash values into "simulation(h,sim)":
loop(h,
if(ord(h)=1,
simulation(h,"simid")=%sim_1%);
if(ord(h)=2,
simulation(h,"simid")=%sim_2%);
if(ord(h)=3,
simulation(h,"simid")=%sim_3%);
if(ord(h)=4,
simulation(h,"simid")=%sim_4%);
if(ord(h)=5,
simulation(h,"simid")=%sim_5%);
if(ord(h)=6,
simulation(h,"simid")=%sim_6%);
if(ord(h)=7,
simulation(h,"simid")=%sim_7%);

);

I guess the real question now is how to streamline this code, hopefully using loops to generate the double-dash parameters... Thanks in advance for any tips/suggestions.
User avatar
bussieck
Moderator
Moderator
Posts: 1037
Joined: 7 years ago

Re: Matching 2 sets in a loop, in sequence

Post by bussieck »

I am not sure I understand, but looking at your second part of the email it seems that you want to have a parameter over h those values you want to set (partially) from the command line via double dash parameters. GAMS is not designed to get large amounts of data via the command line. Data usually comes from files (or is part of the GAMS program). So it would be best to create a text file simid.txt with

Code: Select all

h1 2
h5 7
..
and then do

Code: Select all

set h /h1*h100/
parameter simid(h) / 
$include simid.txt
/;
* The default value for the h not part of simid.txt can be set like this (if 0 is a legal value in simid.txt, one need to do some more trickery with EPS)
simid(h)$(simid(h)=0) = 11;
* You can either assign the parameter simulation in an assignment statement 
simulation(h,"simid")=simid(h);
* If you need to do something more with the individual household in a loop:
loop(h,
  simulation(h,"simid")=simid(h);
  ...
);  
Perhaps, you can explain why you need to use the command line (and double dash parameters) to pass data to GAMS?

-Michael
henryhu.89
User
User
Posts: 15
Joined: 3 years ago

Re: Matching 2 sets in a loop, in sequence

Post by henryhu.89 »

Hello Michael,

Thanks for the reply!

Currently, we are passing data to a model using 2 excel sheets (using GDXRRW to convert to .gdx and then read into GAMs), one for large amounts of data (from a data set) and one to control model parameters. It's the model parameter excel file I am trying to replace with a more streamlined method of running the model from the command line. I anticipate only around 10-15 double-dash parameters being passed with any given run, so hopefully that's fine.

I believe the code you shared is spot on in terms of what I'm trying to do, though I trying to avoid any external file methods. I think I've managed to figure out how to get the job done, but was wondering if there was a better way to write this code (for learning purposes). Also, if there was an easy way to generate double-dash parameters via $set in a loop, or if the current loop could be improved (is there a way to reference which cycle of the loop we are currently in without using ord()?, for example in the "put" commands, ".tl" seems to return the name of a parameter in the current cycle of the loop). Thanks again!
User avatar
bussieck
Moderator
Moderator
Posts: 1037
Joined: 7 years ago

Re: Matching 2 sets in a loop, in sequence

Post by bussieck »

If it has to by double dash from the command line the following code will do. Loops at compile time are not very pretty. I also need to write a temporary file because GAMS does not do a "double string replacement", so you cannot do and expect to log %X1%:

Code: Select all

$set CNT 1
$log %X%CNT%%
You can get this double replacement by creating a file and have the compiler interpret the file again:

Code: Select all

$set CNT 1
$echo $log %X%CNT%% > logx1.gms
$include logx1.gms
That's what the example basically does in a loop:

Code: Select all

set h /h1*h15/
$eval CARDHP1 card(h)+1
$set CNT 1
$set fn "%gams.scrDir%simid.%gams.scrExt%"
$label LOOPSTART
$  echo $if     set sim__%CNT% h%CNT% %sim__%CNT%% >> "%fn%"
$  echo $if not set sim__%CNT% h%CNT% 11           >> "%fn%"
$  eval CNT %CNT%+1
$  if %CNT%==%CARDHP1% $goTo LOOPDONE
$  goTo LOOPSTART
$label LOOPDONE
parameter simid(h) /
$include "%fn%"
/;
display simid;
For a few years we ship GAMS with an embedded Python system to have a more powerful scripting language available. Read more about it at https://www.gams.com/latest/docs/UG_EmbeddedCode.html. The same code with embedded Python looks as follows:

Code: Select all

set h /h1*h15/
$set fn "%gams.scrDir%simid.%gams.scrExt%"
$onEmbeddedCode Python:
with open(r"%fn%", "w") as tf:
  for cnt in range(len(gams.get('h'))):    
    tf.write(f'$if     set sim__{cnt+1} h{cnt+1} %sim__{cnt+1}%\n')
    tf.write(f'$if not set sim__{cnt+1} h{cnt+1} 11\n')
$offEmbeddedCode
parameter simid(h) /
$include "%fn%"
/;
display simid;
Hope this helps,
-Michael
henryhu.89
User
User
Posts: 15
Joined: 3 years ago

Re: Matching 2 sets in a loop, in sequence

Post by henryhu.89 »

Thanks so much for the tips! I'll definitely look into the embedded python, it seems like a handy tool.
Post Reply