spbenders4.gms : Stochastic Benders - Parallel MPI

Description

```This example demonstrates a stochastic Benders implementation for the
simple transport example.

This is the fourth example of a sequence of stochastic Benders
implementations using various methods to solve the master and
subproblem.

This fourth example implements the stochastic Benders algorithm using
parallel implementation using MPI. In this example the model is started
from the command line as follows:

mpiexec -n 4 gams spbenders4 fileStemApFromEnv=PMI_RANK lo=2

On different platforms this command might look a little different. On HPC
system, that often run Linux and use a specialized MPI, it might be more
efficient (or even required) to use a Python version different from the one
GAMS ships with. As documented in https://www.gams.com/latest/docs/API_PY_TUTORIAL.html#PY_GETTING_STARTED
GAMS Python API packages must also be installed for this Python or an
environment variable (e.g. PYTHONPATH) needs to point to the GAMS Python packages.
Also the PMI_RANK variable might be called differently. In any case GAMS needs
to be instructed to use an external Python installation by setting pySetup=0:

mpirun -n 4 gams spbenders4 fileStemApFromEnv=OMPI_COMM_WORLD_RANK pySetup=0 lo=2

This command spawns card(s)+1 (=4 for the small example) copies of the
spbenders4 model and the environment variable PMI_RANK decided which part
the particular instance plays. The GAMS job with PMI_RANK=0 implements the
master and the GAMS jobs PMI_RANK=1 to PMI_RANK=s implement the subproblems.
The communication of the master variables received and the cut information
happens via the Python package mpi4py and the GAMS embedded code facility.

Keywords: linear programming, stochastic Benders algorithm, transportation
problem, GAMS embedded code facility, Python, parallel computing,
message passing interface
```

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 : spbenders4.gms

``````\$title Stochastic Benders - Parallel MPI (SPBENDERS4,SEQ=421)

\$onText
This example demonstrates a stochastic Benders implementation for the
simple transport example.

This is the fourth example of a sequence of stochastic Benders
implementations using various methods to solve the master and
subproblem.

This fourth example implements the stochastic Benders algorithm using
parallel implementation using MPI. In this example the model is started
from the command line as follows:

mpiexec -n 4 gams spbenders4 fileStemApFromEnv=PMI_RANK lo=2

On different platforms this command might look a little different. On HPC
system, that often run Linux and use a specialized MPI, it might be more
efficient (or even required) to use a Python version different from the one
GAMS ships with. As documented in https://www.gams.com/latest/docs/API_PY_TUTORIAL.html#PY_GETTING_STARTED
GAMS Python API packages must also be installed for this Python or an
environment variable (e.g. PYTHONPATH) needs to point to the GAMS Python packages.
Also the PMI_RANK variable might be called differently. In any case GAMS needs
to be instructed to use an external Python installation by setting pySetup=0:

mpirun -n 4 gams spbenders4 fileStemApFromEnv=OMPI_COMM_WORLD_RANK pySetup=0 lo=2

This command spawns card(s)+1 (=4 for the small example) copies of the
spbenders4 model and the environment variable PMI_RANK decided which part
the particular instance plays. The GAMS job with PMI_RANK=0 implements the
master and the GAMS jobs PMI_RANK=1 to PMI_RANK=s implement the subproblems.
The communication of the master variables received and the cut information
happens via the Python package mpi4py and the GAMS embedded code facility.

Keywords: linear programming, stochastic Benders algorithm, transportation
problem, GAMS embedded code facility, Python, parallel computing,
message passing interface
\$offText

\$set MPI_RANK notSet
\$if setenv PMI_RANK             \$set MPI_RANK %sysEnv.PMI_RANK%
\$if setenv OMPI_COMM_WORLD_RANK \$set MPI_RANK %sysEnv.OMPI_COMM_WORLD_RANK%
\$if %MPI_RANK%==notSet \$abort.noError This model needs to be started with mpiexec/mpirun. See preamble of the model source for details.

\$set MPI_SIZE notSet
\$if setenv PMI_SIZE             \$set MPI_SIZE %sysEnv.PMI_SIZE%
\$if setenv OMPI_COMM_WORLD_RANK \$set MPI_SIZE %sysEnv.OMPI_COMM_WORLD_SIZE%
\$if %MPI_SIZE%==notSet \$abort.noError This model needs to be started with mpiexec/mpirun. See preamble of the model source for details.

* On the major platforms (Windows, Linux, Mac), GMSPYTHONHOME gets set automatically
* if pySetup=1 (default). If the %gams.sysdir%GMSPython directory does not exist on
* these platforms pySetup will be reset to 0 and GAMS relies on an external Python
* setup.
\$if not setEnv GMSPYTHONHOME
\$if %gams.pySetup%==1 \$abort.noError Embedded code Python not ready to be used
\$if not setEnv GMSPYTHONHOME \$log --- Using external Python

Set
i 'factories'            / f1*f3 /
j 'distribution centers' / d1*d5 /;

Parameter
capacity(i) 'unit capacity at factories'
/ f1 500, f2 450, f3 650 /
demand(j)   'unit demand at distribution centers'
/ d1 160, d2 120, d3 270, d4 325, d5 700 /
prodcost    'unit production cost'                    / 14 /
price       'sales price'                             / 24 /
wastecost   'cost of removal of overstocked products' /  4 /;

Table transcost(i,j) 'unit transportation cost'
d1    d2    d3    d4    d5
f1   2.49  5.21  3.76  4.85  2.07
f2   1.46  2.54  1.83  1.86  4.76
f3   3.26  3.08  2.60  3.76  4.45;

\$ifThen not set useBig
Set s 'scenarios' / lo, mid, hi /;

Table ScenarioData(s,*) 'possible outcomes for demand plus probabilities'
d1   d2   d3   d4   d5  prob
lo    150  100  250  300  600  0.25
mid   160  120  270  325  700  0.50
hi    170  135  300  350  800  0.25;
\$else
\$  if not set nrScen \$set nrScen 10
Set s 'scenarios' / s1*s%nrScen% /;
Parameter ScenarioData(s,*) 'possible outcomes for demand plus probabilities';
option seed = 1234;
ScenarioData(s,'prob') = 1/card(s);
ScenarioData(s,j)      = demand(j)*uniform(0.6,1.4);
\$endIf

\$eval cardS card(s)+1
\$if not %cardS%==%MPI_SIZE% \$abort MPI size needs to be %cardS%

embeddedCode Python:
try:
from mpi4py import *
except:
comm = MPI.COMM_WORLD

def symbols2List(*symbols):
return list(map(lambda x: list(gams.get(x)), symbols))
pauseEmbeddedCode
abort\$execerror 'Problems setting up mpy4py or some other Python error. Check the log';

Parameter osub(s), cconst(s), ccoeff(s,j);

\$ifThen.MPI 0==%MPI_RANK%
* Benders master problem
\$if not set maxiter \$set maxiter 25
Set
iter             'max Benders iterations' / 1*%maxiter% /
itActive(iter)   'active Benders cuts';

Parameter
cutconst(iter)   'constants in optimality cuts'    / #iter    0 /
cutcoeff(iter,j) 'coefficients in optimality cuts' / #iter.#j 0 /;

Variable
ship(i,j)        'shipments'
product(i)       'production'
zmaster          'objective variable of master problem'
theta            'future profit';

Positive Variable ship;

Equation
masterobj        'master objective function'
production(i)    'calculate production in each factory'
receive(j)       'calculate quantity to be send to markets'
optcut(iter)     'Benders optimality cuts';

masterobj.. zmaster =e= theta - sum((i,j), transcost(i,j)*ship(i,j))
- sum(i, prodcost*product(i));

production(i).. product(i)  =e= sum(j, ship(i,j));

optcut(itActive)..
theta =l= cutconst(itActive) + sum(j, cutcoeff(itActive,j)*received(j));

product.up(i) = capacity(i);

Model masterproblem / all /;

Scalar
rgap       'relative gap'       /    0 /
lowerBound 'global lower bound' / -inf /
upperBound 'global upper bound' / +inf /
objMaster                       /    0 /
objSub                          /    0 /;

objMaster     = 0;

\$if not set rtol \$set rtol 0.001
loop(iter,
continueEmbeddedCode:
cut = comm.gather(None, root=0)[1:]
gams.set('osub',   [c for c in cut])
gams.set('cconst', [c for c in cut])
gams.set('ccoeff', [rec for s in cut for rec in s])
pauseEmbeddedCode osub, cconst, ccoeff
objSub           = sum(s, osub(s));
cutconst(iter)   = sum(s, cconst(s));
cutcoeff(iter,j) = sum(s, ccoeff(s,j));

if(lowerBound < objMaster + objSub, lowerBound = objMaster + objSub);
rgap = (upperBound - lowerBound)/(1 + abs(upperBound));
break\$(rgap < %rtol%);
itActive(iter) = yes;
solve masterproblem max zmaster using lp;
upperBound = zmaster.l;
objMaster  = zmaster.l - theta.l;
);

* Terminate sub jobs
continueEmbeddedCode:
comm.bcast([,[]], root=0)
endEmbeddedCode
abort\$(rgap >= %rtol%) 'need more iterations', lowerbound, upperbound;
display 'optimal solution', lowerbound, upperbound;

\$else.MPI
* Benders' subproblem
Variable
received(j) 'quantity sent to market (from master)'
sales(j)    'sales (actually sold)'
waste(j)    'overstocked products'
zsub        'objective variable of sub problem';

Positive Variable sales, waste;

Equation
subobj      'subproblem objective function'
selling(j)  'part of received is sold'
market(j)   'upperbound on sales';

subobj..     zsub =e= sum(j, price*sales(j)) - sum(j, wastecost*waste(j));

selling(j).. sales(j) + waste(j) =e= received.l(j);

market(j)..  sales(j) =l= demand(j);

Model subproblem / subobj, selling, market /;

* Infinite loop
Singleton Set ss(s);
ss(s)     = ord(s)=%MPI_RANK%;
demand(j) = scenarioData(ss,j);

Scalar done;

while(1,
continueEmbeddedCode:
rx = comm.bcast(None, root=0)
gams.set('done', rx)
{"ft_lang_label":"__label__en","ft_lang_prob":0.57653403,"math_prob":0.8474431,"size":9777,"snap":"2019-26-2019-30","text_gpt3_token_len":2733,"char_repetition_ratio":0.10068556,"word_repetition_ratio":0.41566265,"special_character_ratio":0.2640892,"punctuation_ratio":0.16100278,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9732481,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2019-06-18T10:51:23Z\",\"WARC-Record-ID\":\"<urn:uuid:cd0d5861-a2a7-46f7-a7d7-fe42a4422087>\",\"Content-Length\":\"38103\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:f0f8f3ad-f342-4258-b362-f8b41807e026>\",\"WARC-Concurrent-To\":\"<urn:uuid:3b2f8c72-e8e5-4d90-bb61-4cced4b0d4ec>\",\"WARC-IP-Address\":\"18.205.149.197\",\"WARC-Target-URI\":\"https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_spbenders4.html\",\"WARC-Payload-Digest\":\"sha1:XVSWNT72HP5A7GQQ2YNNZI34TGNIWNT7\",\"WARC-Block-Digest\":\"sha1:QBC2L4WKXTR375J6SMXQ5E3ESNQDAU3U\",\"WARC-Identified-Payload-Type\":\"application/xhtml+xml\",\"warc_filename\":\"/cc_download/warc_2019/CC-MAIN-2019-26/CC-MAIN-2019-26_segments_1560627998716.67_warc_CC-MAIN-20190618103358-20190618125358-00025.warc.gz\"}"}