Disaggregating a Set with Python

Questions on using the GAMS APIs (Python, .NET, etc.)
Post Reply
Tatjana
User
User
Posts: 8
Joined: 5 years ago

Disaggregating a Set with Python

Post by Tatjana »

Hi everyone.
I'm trying to create some sets with Python, but I lack any knowledge about Python and am running into some problems (right now, Python says mapping_com_rest would not be defined - but I'm sure there are more errors. I also noticed that some code of mine already worked with "$onembeddedCode Python", but with my dynamic sets, I need to run Python in execution time).
I've tried to simplify my problem and would be very happy if somebody could take a look at it.

Here is what I'd like to do:
I have sectors i (beef, pork, dairy and vegetables) that include certain commodities com. They are mapped via mapping_com_sec.
Some commodities com_disagg are supposed to appear in a disaggregated form. For this I want to create a new set tl, in which the disaggregated sectors com_disagg appear, as well as the "rest" of the sectors.

So in the end, I would like to have a set tl that looks something like
beef1, beef3, beef4, rest_beef, pork2, pork3, rest_pork, dairy1, dairy2, dairy3, rest_dairy

and a mapping tl2com like
beef1.beef1
beef3.beef3
beef4.beef4
rest_beef.(beef2, beef5)
pork2.pork2
pork3.pork3
rest_pork.(pork1, pork4, pork5)
dairy1.dairy1
dairy2.dairy2
dairy3.dairy3
rest_dairy.()


This is my code:

Code: Select all

Set sec   /beef, pork, dairy, vegetables/
    sec_disagg(sec)
    com /beef1*beef5, pork1*pork5, dairy1*dairy3, vegetables1*vegetables3/
    com_disagg(com) /beef1, beef3, beef4, pork2, pork3, dairy1, dairy2, dairy3/
    mapping_com_sec(sec,com) /beef.(beef1*beef5)
           pork.(pork1*pork5)
           dairy.(dairy1*dairy3)
           vegetables.(vegetables1*vegetables3)/
    tl(*)
    tl2com(*,com)

    sec_disagg(sec)
    mapping_com_rest(sec,com);

sec_disagg(sec) = Yes$sum(com_disagg, 1$mapping_com_sec(sec,com_disagg));

mapping_com_rest(sec_disagg,com) = Yes$mapping_com_sec(sec_disagg,com);
mapping_com_rest(sec_disagg,com_disagg) = No;

Display mapping_com_rest, sec_disagg;



embeddedCode Python:

tl = []
for com_disagg in gams.get("com_disagg"):
  tl.append(com_disagg)
for sec_disagg in gams.get("sec_disagg"):
  tl.append("rest_" + sec_disagg)
gams.set("tl",tl)

tl2com = []
for com_disagg in gams.get("com_disagg"):
  tl2com.append((com_disagg,com_disagg))
for sec_disagg in gams.get("sec_disagg"):
  for com in gams.get("com"):
    if mapping_com_rest in gams.get("mapping_com_rest"):
      tl2com.append(("rest_" + sec_disagg,com))
gams.set("tl2com",tl2com)


endEmbeddedCode tl tl2com
Display tl, tl2com;


Many thanks in advance!
User avatar
bussieck
Moderator
Moderator
Posts: 1042
Joined: 7 years ago

Re: Disaggregating a Set with Python

Post by bussieck »

Independent of the Python problem you can't do what you like to do at execution time. GAMS needs to know all labels at compile time. You create labels rest_xyz at execution time but they will never make it into GAMS. So you need to do all this at compile time. Here is a solution by calling a sub-GAMS script at compile time that executes what you want and create the sets with put files. These you include at compile time in your outer program:

Code: Select all

Set sec   /beef, pork, dairy, vegetables/
    sec_disagg(sec)
    com /beef1*beef5, pork1*pork5, dairy1*dairy3, vegetables1*vegetables3/
    com_disagg(com) /beef1, beef3, beef4, pork2, pork3, dairy1, dairy2, dairy3/
    mapping_com_sec(sec,com) /beef.(beef1*beef5)
           pork.(pork1*pork5)
           dairy.(dairy1*dairy3)
           vegetables.(vegetables1*vegetables3)/
    sec_disagg(sec)
    mapping_com_rest(sec,com);

$gdxOut data
$unload
$gdxOut
$onEchoV > create_t.gms
$call gdxdump data.gdx > data.gms
$include data.gms

sec_disagg(sec) = Yes$sum(com_disagg, 1$mapping_com_sec(sec,com_disagg));

mapping_com_rest(sec_disagg,com) = Yes$mapping_com_sec(sec_disagg,com);
mapping_com_rest(sec_disagg,com_disagg) = No;


file tl / tl.txt /; put tl;
loop(sec_disagg, put sec_disagg.tl:0 /);
loop(sec_disagg, put 'rest_' sec_disagg.tl:0 /);

file tl2com / tl2com.txt /; put tl2com;
loop(mapping_com_sec(sec_disagg,com), put 'rest_' sec_disagg.tl:0 '.' com.tl:0 /);
$offEcho
$call.checkErrorLevel gams create_t.gms lo=2 gdx=create_t

$gdxLoad create_t sec_disagg mapping_com_rest

set tl1(*) /
$include tl.txt
/
tl2com(*,com) /
$include tl2com.txt
/;

Display mapping_com_rest, sec_disagg;
display tl1, tl2com;
-Michael
Tatjana
User
User
Posts: 8
Joined: 5 years ago

Re: Disaggregating a Set with Python

Post by Tatjana »

Hi Bussiek,

thank you for taking the time o look into my problem. Your code didn't give the sets that I desired, but I think you have a good point that I need to execute everything at compile time. So I've been sitting over this for quite a while since your answer - I couldn't make the Python code work entirely, but I have strongly changed my code. If I'd be able to import my two-dimensional set mapping_com_sec and create the list sec_disagg in GAMS, I think something like this might work:

Code: Select all

Set sec   /beef, pork, dairy, vegetables/
    com /beef1*beef5, pork1*pork5, dairy1*dairy3, vegetables1*vegetables3/
    com_disagg(com) /beef1, beef3, beef4, pork2, pork3, dairy1, dairy2, dairy3/
    mapping_com_sec(sec,com) /beef.(beef1*beef5)
           pork.(pork1*pork5)
           dairy.(dairy1*dairy3)
           vegetables.(vegetables1*vegetables3)/
    tl
    tl2com(tl<,com)

$onEmbeddedCode Python:

sec = list(gams.get("sec"))
com = list(gams.get("com"))
com_disagg(com) = list(gams.get("com_disagg"))
mapping_com_sec(sec,com) = gams.get('mapping_com_sec')

sec_disagg = []
for sec in gams.get("sec"):
  if sec in mapping_com_sec(sec,com_disagg):
    sec_disagg.append("sec")

tl2com = []
for com_disagg in gams.get("com_disagg"):
  tl2com.append((com_disagg,com_disagg))
for sec_disagg in sec_disagg:
  for com in gams.get("com"):
    if com not in gams.get("com_disagg"):
      if mapping_com_sec:
        tl2com.append(("rest_" + sec_disagg,com))
gams.set("tl2com",tl2com)

$offEmbeddedCode tl2com


Display tl2com;
Post Reply