Map two sets via an intermediate set

Dear Forum,

actually I would think my problem is quite easy to solve but it seems like it don’t use the right keywords for my search.

I want to map two sets via an “intermediate set”. So let’s say I have three sets: a, b and c. And I have two more sets which map a with b and b with c. What I now want is one additional set, which is a mapping of a and c, based on the two existing mappings.

Sets a       / j1*j2 / 
     b       / k1*k3 /
     c       / h1*h3 /
     ab(a,b) / j1.k1, j2.k2, j2.k3 / 
     bc(b,c) / k1.h1, k1.h2, k2.h3 /

Now needed is a set ac, which maps a with c, based on the sets ab and bc. The solution would be this:

Set ac(a,c) / j1.h1, j1.h2, j2.h3 /

Would be super happy if someone could help me out!

Benj

Good question.
If I rephrase your question, it will become clearer: For a given b, you want ac to be true if ab(a, b) is true and bc(b, c) is true.
Write that in the GAMS way and you are done:

Sets a       / j1*j2 / 
     b       / k1*k3 /
     c       / h1*h3 /
     ab(a,b) / j1.k1, j2.k2, j2.k3 / 
     bc(b,c) / k1.h1, k1.h2, k2.h3 /
     ;
     
set ac(a, c);

loop(b,
ac(a, c)$(ab(a, b) and bc(b, c)) = yes;
);
display ac;

You will see ac displayed in the .lst file. All I am doing is looping over b and populating ac as needed.
Hope this helps.

  • Atharv

The solution of my colleague Atharv works correctly and well. For very large data parallel assignment statements are way faster than loops, so in case you have very large data you might want to know how to do this fast with parallel assignment statements. The trick is to first build a three dimensional map abc and then project the b out. I parameterized the code so I can run for large n (even though the mapping between a, b, and c is trivial)

$if not set n $set n 10
Sets a       / j1*j%n% / 
     b       / k1*k%n% /
     c       / h1*h%n% /
     ab(a,b) / #a:#b / 
     bc(b,c) / #b:#c /
     
set abc(a,b,c), ac(a,c);
loop(b, ac(a, c)$(ab(a, b) and bc(b, c)) = yes);
option clear=ac;
abc(a,b,c) = ab(a,b) and bc(b,c);
ac(a,c) = sum(b, abc(a,b,c));

When running this with n=10000 the profiler (profile=1) tells me about the execution speed (first column is the execution time in seconds):

     8.906   0.053GB         9 Loop       
     0.047   0.065GB        12 Assignment ac (100000)
     0.016   0.055GB        11 Assignment abc (100000)

The last assignment to ac can also be replaced by “option ac<abc;” which goes even faster but is not easy to read.

-Michael