GAMS [ Home | Downloads | Documentation | Solvers | APIs | Tools | Model Libraries | Resources | Sales | Support | Contact Us | Search ]

asyncloop.gms : Transportation Problem with async loop body execution

Description

This problem finds a least cost shipping schedule that meets
requirements at markets and supplies at factories.

The model demonstrates how to run multiple scenarios with a rich loop body
in a parallel fashion using the GAMS asynchronous execution facility.

This model can be parameterized. With the double-dash option --driver=no
GAMS just executed the scenarios in sequence. Without the double-dash
option --driver or --driver=yes the model calls itself recursively first
executing the code before the loop, then executing the loop body in parallel
and then executing the code after the loop. The merging of the results from
the jobs that executed the loop body is done via restart and GDX.

Reference

  • Dantzig, G B, Chapter 3.3. In Linear Programming and Extensions. Princeton University Press, Princeton, New Jersey, 1963.

Small Model of Type : LP


Category : GAMS Model library


Main file : asyncloop.gms

$title Transportation Problem with async loop body execution (ASYNCLOOP,SEQ=411)
$Ontext

This problem finds a least cost shipping schedule that meets
requirements at markets and supplies at factories.

The model demonstrates how to run multiple scenarios with a rich loop body
in a parallel fashion using the GAMS asynchronous execution facility.

This model can be parameterized. With the double-dash option --driver=no
GAMS just executed the scenarios in sequence. Without the double-dash
option --driver or --driver=yes the model calls itself recursively first
executing the code before the loop, then executing the loop body in parallel
and then executing the code after the loop. The merging of the results from
the jobs that executed the loop body is done via restart and GDX.


Dantzig, G B, Chapter 3.3. In Linear Programming and Extensions.
Princeton University Press, Princeton, New Jersey, 1963.

$Offtext

$if not set driver  $set driver yes
$if set before_loop $goto before_loop
$if set run_loop    $goto run_loop
$if set after_loop  $goto after_loop
$ifi %driver%==yes  $goto driver

* Normal sequential run
$set cond

$label before_loop
  Sets
       i   canning plants   / seattle, san-diego /
       j   markets          / new-york, chicago, topeka / ;

  Parameters

       a(i)  capacity of plant i in cases
         /    seattle     350
              san-diego   600  /

       b(j)  demand at market j in cases
         /    new-york    325
              chicago     300
              topeka      275  / ;

  Table d(i,j)  distance in thousands of miles
                    new-york       chicago      topeka
      seattle          2.5           1.7          1.8
      san-diego        2.5           1.8          1.4  ;

  Scalar f  freight in dollars per case per thousand miles  /90/ ;

  Parameter c(i,j)  transport cost in thousands of dollars per case ;

            c(i,j) = f * d(i,j) / 1000 ;

  Variables
       x(i,j)   shipment quantities in cases
       slack(j) slack for unfilled demand
       z        total transportation costs in thousands of dollars ;

  Positive Variable x, slack ;

  Equations
       cost        define objective function
       supply(i)   observe supply limit at plant i
       demand(j)   satisfy demand at market j ;
  Scalar pen / 1000 /;

  cost ..        z  =e=  sum((i,j), c(i,j)*x(i,j)) + pen*sum(j, slack(j))  ;

  supply(i) ..   sum(j, x(i,j))  =l=  a(i) ;

  demand(j) ..   sum(i, x(i,j))  =g=  b(j) + slack(j) ;

  Model transport /all/ ;

  set s scenarios / scen1*scen10 /;
  parameter bsave(j), bmult(s), obj(s);
  bsave(j) = b(j);
  bmult(s) = uniform(0.9,1.1);

$if set before_loop $exit

$label run_loop
$if set run_loop $set cond $sameas(s,'%myscen%')

  loop(s%cond%,
    Solve transport using lp minimizing z ;
    obj(s) = z.l;
  );
$if set run_loop $exit

$label after_loop
$ifthen set after_loop
  file fx;
  loop(s$(ord(s)<>1),
    put_utility fx 'gdxin' / s.tl:0 '.gdx';
    execute_loadpoint obj;
  );
$endif
  Display obj;
$exit

$label driver
* Implement the logic to run the loop body asynchronously

* First run code before the loop
$call gams "%gams.input%" --before_loop=1 lo=%gams.lo% o=before_loop.lst lf=before_loop.log s=before_loop gdx=before_loop
$if errorlevel 1 $abort problems with before_loop

* Next run loop body code asynchronously
set s loop scenarios;
$gdxin before_loop
$load s
$gdxin

$eolcom //
set  submit(s)   list of jobs to submit
     done(s)     list of completed jobs
parameter
     h(s)        store the instance handle
     maxS        maximum number of active jobs /4/
     tStart      time stamp;

tStart = jnow;
done(s) = no; h(s) = 0;
file fx;

repeat
   submit(s) = no;
   loop(s$(not (done(s) or h(s))),
   submit(s) = yes$(card(submit)+card(h) < maxS));
   loop(submit(s),
      put_utility fx 'log' / 'submit myscen=' s.tl:0;
      put_utility$(ord(s)=1) fx 'exec.async' / 'gams "%gams.input%" --run_loop=1 lo=2 r=before_loop --myscen=' s.tl:0 ' lf=' s.tl:0 '.log o=' s.tl:0 '.lst gdx=' s.tl:0 '.gdx s=run_loop';
      put_utility$(ord(s)>1) fx 'exec.async' / 'gams "%gams.input%" --run_loop=1 lo=2 r=before_loop --myscen=' s.tl:0 ' lf=' s.tl:0 '.log o=' s.tl:0 '.lst gdx=' s.tl:0 '.gdx';
      h(s) = JobHandle;
   );
   loop(s$(JobStatus(h(s)) = 2),
      put_utility fx 'log' / 'collect myscen=' s.tl:0;
      abort$errorlevel 'problem with one of the loop jobs';
      done(s) = yes; h(s) = 0;
   );
   display$sleep(card(h)*0.05) 'sleep some time';
until card(done)=card(s) or timeelapsed > 100;  // wait until all jobs are done
tStart = (jnow - tStart)*3600*24;
display 'Time to run all loops:', tStart;

* Run post loop code that merges the results from the loop jobs
execute 'gams "%gams.input%" --after_loop=1 r=run_loop o=after_loop.lst lf=after_loop.log lo=%gams.lo%';
abort$errorlevel 'problems with after_loop';