gussex1.gms : Simple GUSS example

Description

GUSS is a procedure that facilitates optimization of a collection of related
problems modifying data in those problems. GUSS allows one to solve the
collection of models in a single pass without needing repeated solves or a
LOOP over multiple solves. GUSS is not really a solver but rather organizes and
passes data to and from another LP, NLP, MIP etc solver. This is all done in a
faster fashion than say when using multiple solves through the GAMS Loop command.

In particular GUSS runs the model repeatedly over user specified data for model
parameters that collectively define alternative scenarios to be run. In doing
this it repeatedly updates the base model with the altered scenario data, then
solves the updated model for that scenario and saves user chosen results for
each scenario.

GUSS was developed by Michael R. Bussieck, Michael C. Ferris, and Timo Lohmann.
It is documented in http://www.gams.com/modlib/adddocs/gusspaper.pdf and in the
GUSS section of the solver manual.

Use of GUSS for an existing model requires six steps

1. Definition of scenarios to run
2. Definition of parameters holding scenario specific data for the items
   in the model that to be changed
3. Definition of parameters that will hold scenario specific model results
   for the items that the user wished to save
4. Definition of a set that tells GUSS the scenarios to run, data to change
   and results to save
5. Modification of the solve statement to identify that scenarios will be run
6. Development of code to report the scenario results

These 6 steps are demonstrated used the simple transport model


Small Model of Type : LP


Category : GAMS Model library


Main file : gussex1.gms

$title Simple GUSS Example (GUSSEX1,SEQ=398)

$onText
GUSS is a procedure that facilitates optimization of a collection of related
problems modifying data in those problems. GUSS allows one to solve the
collection of models in a single pass without needing repeated solves or a
LOOP over multiple solves. GUSS is not really a solver but rather organizes and
passes data to and from another LP, NLP, MIP etc solver. This is all done in a
faster fashion than say when using multiple solves through the GAMS Loop command.

In particular GUSS runs the model repeatedly over user specified data for model
parameters that collectively define alternative scenarios to be run. In doing
this it repeatedly updates the base model with the altered scenario data, then
solves the updated model for that scenario and saves user chosen results for
each scenario.

GUSS was developed by Michael R. Bussieck, Michael C. Ferris, and Timo Lohmann.
It is documented in http://www.gams.com/modlib/adddocs/gusspaper.pdf and in the
GUSS section of the solver manual.

Use of GUSS for an existing model requires six steps

1. Definition of scenarios to run
2. Definition of parameters holding scenario specific data for the items
   in the model that to be changed
3. Definition of parameters that will hold scenario specific model results
   for the items that the user wished to save
4. Definition of a set that tells GUSS the scenarios to run, data to change
   and results to save
5. Modification of the solve statement to identify that scenarios will be run
6. Development of code to report the scenario results

These 6 steps are demonstrated used the simple transport model


Bussieck, M R, Ferris, M C, and Lohmann, T, GUSS: Solving Collections of Data
Related Models within GAMS. In Kallrath, J, Ed, Algebraic Modeling Systems: Modeling
and Solving Real World Optimization Problems. Springer, Berlin Heidelberg, 2012, pp. 35-56.

Keywords: linear programming, transportation problem, scheduling, GUSS, scenario analysis
$offText

Set
   i 'canning plants' / seattle,  san-diego /
   j 'markets'        / new-york, chicago, topeka /;

Parameter
   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.4              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;

Variable
   x(i,j) 'shipment quantities in cases'
   z      'total transportation costs in thousands of dollars';

Positive Variable x;

Equation
   cost      'define objective function'
   supply(i) 'observe supply limit at plant i'
   demand(j) 'satisfy demand at market j';

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

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

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

Model transport / all /;

Set ScenariosToRun 'scenarios' / base, run1, run2 /;

Table newsupply(ScenariosToRun,i) 'updater for a'
         seattle  san-diego
   base      350        600
   run1      300        650
   run2      401        549;

Table newdemand(ScenariosToRun,j) 'updater for b'
         new-york  chicago  topeka
   base       325      300     275
   run1       325      300     275
   run2       350      300     250;

Set mattrib / system.GUSSModelAttributes /;

Parameter
   xl(ScenariosToRun,i,j)         'collector for level of x'
   xm(ScenariosToRun,i,j)         'collector for marginal of x'
   demandl(ScenariosToRun,j)      'collector for level of demand'
   demandm(ScenariosToRun,j)      'collector for marginal of demand'
   srep(ScenariosToRun, mattrib)  'model attibutes like modelstat etc'
   o(*)                           'GUSS options' / SkipBaseCase 1 /;

Set dict / ScenariosToRun.scenario.''
           o.             opt     .srep
           a.             param   .newsupply
           b.             param   .newdemand
           x.             level   .xl
           x.             marginal.xm 
           demand.        level   .demandl
           demand.        marginal.demandm /;

solve transport using lp minimizing z scenario dict;

* The solve statement from the line above results can also be expressed
* in traditional GAMS syntax as follows:
$onText
loop(ScenariosToRun,
   a(i) = newsupply(ScenariosToRun,i);
   b(j) = newdemand(ScenariosToRun,j);
   solve transport using lp minimizing z;
   xl(ScenariosToRun,i,j) = x.l(i,j);
   xm(ScenariosToRun,i,j) = x.m(i,j);
   demandl(ScenariosToRun,j) = demand.l(j);
   demandm(ScenariosToRun,j) = demand.m(j);
);
$offText

Set Error(scenariostorun) 'empty solution';
Error(scenariostorun) = sum((i,j), xl(scenariostorun,i,j)) = 0;

abort$card(error) 'Missing solution for some scenarios', error;

* Now rerun GUSS with scaleOpt=1 and compare solution
Parameter
   sxl(ScenariosToRun,i,j)         'collector for level of x'
   sxm(ScenariosToRun,i,j)         'collector for marginal of x'
   sdemandl(ScenariosToRun,j)      'collector for level of demand'
   sdemandm(ScenariosToRun,j)      'collector for marginal of demand';

Set sdict / ScenariosToRun.scenario.''
           o.             opt     .srep
           a.             param   .newsupply
           b.             param   .newdemand
           x.             level   .sxl
           x.             marginal.sxm 
           demand.        level   .sdemandl
           demand.        marginal.sdemandm /;

x.scale(i,j) = 10;
demand.scale(j) = 100;
transport.scaleOpt = 1;

solve transport using lp minimizing z scenario sdict;

abort$(smax((ScenariosToRun,i,j), abs(xl(ScenariosToRun,i,j)-sxl(ScenariosToRun,i,j))) > 1e-3) 'Wrong x.l scaled and unscaled:', xl, sxl;
abort$(smax((ScenariosToRun,i,j), abs(xm(ScenariosToRun,i,j)-sxm(ScenariosToRun,i,j))) > 1e-3) 'Wrong x.m scaled and unscaled:', xm, sxm;
abort$(smax((ScenariosToRun,j), abs(demandl(ScenariosToRun,j)-sdemandl(ScenariosToRun,j))) > 1e-3) 'Wrong demand.l scaled and unscaled:', demandl, sdemandl;
abort$(smax((ScenariosToRun,j), abs(demandm(ScenariosToRun,j)-sdemandm(ScenariosToRun,j))) > 1e-3) 'Wrong demand.m scaled and unscaled:', demandm, sdemandm;