Resources

SAS code in NETFLOW procedure chapter (netflow)

/****************************************************************/
/*          S A S   S A M P L E   L I B R A R Y                 */
/*                                                              */
/*    NAME: netflow                                             */
/*   TITLE: SAS code in NETFLOW procedure chapter (netflow)     */
/* PRODUCT: OR                                                  */
/*  SYSTEM: ALL                                                 */
/*    KEYS: NETFLOW                                             */
/*   PROCS: NETFLOW                                             */
/*    DATA:                                                     */
/*                                                              */
/* SUPPORT:                             UPDATE:                 */
/*     REF:                                                     */
/*    MISC:                                                     */
/*                                                              */
/****************************************************************/

/****************************************************************
 *                                                              *
 * Introductory Example                                         *
 *                                                              *
 ****************************************************************/

title  'Oil Industry Example';
title3 'Setting Up Nodedata = Noded For Proc Netflow';
data noded;
  input   _node_&$15. _sd_;
  datalines;
middle east       100
u.s.a.             80
servstn1 gas      -95
servstn1 diesel   -30
servstn2 gas      -40
servstn2 diesel   -15
;


title3 'Setting Up Arcdata = Arcd1 For Proc Netflow';
data arcd1;
  input _from_&$11. _to_&$15. _cost_ _capac_ _lo_ _name_ $;
  datalines;
middle east    refinery 1        63     95   20    m_e_ref1
middle east    refinery 2        81     80   10    m_e_ref2
u.s.a.         refinery 1        55      .    .    .
u.s.a.         refinery 2        49      .    .    .
refinery 1     r1               200    175   50    thruput1
refinery 2     r2               220    100   35    thruput2
r1             ref1 gas           .    140    .    r1_gas
r1             ref1 diesel        .     75    .    .
r2             ref2 gas           .    100    .    r2_gas
r2             ref2 diesel        .     75    .    .
ref1 gas       servstn1 gas      15     70    .    .
ref1 gas       servstn2 gas      22     60    .    .
ref1 diesel    servstn1 diesel   18      .    .    .
ref1 diesel    servstn2 diesel   17      .    .    .
ref2 gas       servstn1 gas      17     35    5    .
ref2 gas       servstn2 gas      31      .    .    .
ref2 diesel    servstn1 diesel   36      .    .    .
ref2 diesel    servstn2 diesel   23      .    .    .
;


title3 'Setting Up Condata = Cond1 For Proc Netflow';
data cond1;
  input m_e_ref1 m_e_ref2 thruput1 r1_gas thruput2 r2_gas
        _type_ $ _rhs_;
  datalines;
-2  .  1 .  . . >= -15
. -2  . .  1 . GE -15
.  . -3 4  . . EQ   0
.  .  . . -3 4  =   0
;


proc netflow
  nodedata=noded        /* the supply and demand data */
  arcdata=arcd1         /* the arc descriptions       */
  condata=cond1         /* the side constraints       */
  conout=solution;      /* the solution data set      */
  run;

proc print data=solution;
  var _from_ _to_ _cost_ _capac_ _lo_ _name_
      _supply_ _demand_ _flow_ _fcost_ _rcost_;
  sum _fcost_;
  title3 'Constrained Optimum';
  run;

/****************************************************************
 *                                                              *
 * Syntax: NAMECTRL= Option                                     *
 *                                                              *
 ****************************************************************/

data arcdata;
   input _from_ $ _to_ $ _name $ ;
   datalines;
from to1 .
from to2 arc2
TAIL TO3 .
;
data densecon;
   input from_to1 from_to2 arc2 tail_to3;
   datalines;
2 3 3 5
;
proc netflow
   arcdata=arcdata condata=densecon;
   run;

/****************************************************************
 *                                                              *
 * Details: Input Data Sets: Condata                            *
 *                                                              *
 ****************************************************************/

/*  Dense formulations  */
data cond1;
   input m_e_ref1 m_e_ref2 thruput1 r1_gas thruput2 r2_gas
      _type_ $ _rhs_;
   datalines;
-2  .  1 .  . . >= -15
 . -2  . .  1 . GE -15
 .  . -3 4  . . EQ   0
 .  .  . . -3 4  =   0
;

data cond1b;
   input m_e_ref1 m_e_ref2 thruput1 r1_gas thruput2 r2_gas
         _type_ $ _rhs_;
   datalines;
63 81 200   . 220   . cost   .
95 80 175 140 100 100 capac  .
20 10  50   .  35   . lo     .
-2  .   1   .   .   . >=   -15
 . -2   .   .   1   . GE   -15
 .  .  -3   4   .   . EQ     0
 .  .   .   .  -3   4  =     0
;

data cond1c;
   input _row_ $
         m_e_ref1 m_e_ref2 thruput1 r1_gas thruput2 r2_gas
         _type_ $ _rhs_;
   datalines;
costrow 63  .   .   .   .   . .      .
costrow  . 81 200   .   .   . cost   .
.        .  .   .   . 220   . cost   .
caprow   .  .   .   .   .   . capac  .
caprow  95  . 175   . 100 100 .      .
caprow   . 80 175 140   .   . .      .
lorow   20 10  50   .  35   . lo     .
con1    -2  .   1   .   .   . .      .
con1     .  .   .   .   .   . >=   -15
con2     . -2   .   .   1   . GE   -15
con3     .  .  -3   4   .   . EQ     0
con4     .  .   .   .  -3   4  =     0
;

/*  Sparse formulations  */
title 'Setting Up Condata = Cond2 for PROC NETFLOW';
data cond2;
   input _column_ $ _row1 $ _coef1 _row2 $ _coef2 ;
   datalines;
m_e_ref1  con1  -2     .   .
m_e_ref2  con2  -2     .   .
thruput1  con1   1  con3  -3
r1_gas       .   .  con3   4
thruput2  con2   1  con4  -3
r2_gas       .   .  con4   4
_type_    con1   1  con2   1
_type_    con3   0  con4   0
_rhs_     con1 -15  con2 -15
;

title 'Setting Up Condata = Cond3 for PROC NETFLOW';
data cond3;
   input _column_ $ _row1 $ _coef1 _row2 $ _coef2 _type_ $ ;
   datalines;
m_e_ref1  con1  -2     .   . >=
m_e_ref2  con2  -2     .   . .
thruput1  con1   1  con3  -3 .
r1_gas       .   .  con3   4 .
thruput2  con2   1  con4  -3 .
r2_gas       .   .  con4   4 .
.         con3   .  con4   . eq
.         con1 -15  con2 -15 ge
;

title3 'Setting Up Arcdata = Arcd2 for PROC NETFLOW';
data arcd2;
   input  _from_&$11. _to_&$15. ;
   datalines;
middle east  refinery 1
middle east  refinery 2
u.s.a.       refinery 1
u.s.a.       refinery 2
refinery 1   r1
refinery 2   r2
r1           ref1 gas
r1           ref1 diesel
r2           ref2 gas
r2           ref2 diesel
ref1 gas     servstn1 gas
ref1 gas     servstn2 gas
ref1 diesel  servstn1 diesel
ref1 diesel  servstn2 diesel
ref2 gas     servstn1 gas
ref2 gas     servstn2 gas
ref2 diesel  servstn1 diesel
ref2 diesel  servstn2 diesel
;
title 'Setting Up Condata = Cond4 for PROC NETFLOW';
data cond4;
   input _column_&$27. _row1 $ _coef1 _row2 $ _coef2 _type_ $ ;
   datalines;
.                               con1 -15   con2 -15    ge
.                            costrow   .      .   .  cost
.                                  .   . caprow   . capac
middle east_refinery 1          con1  -2      .   .     .
middle east_refinery 2          con2  -2      .   .     .
refinery 1_r1                   con1   1   con3  -3     .
r1_ref1 gas                        .   .   con3   4     =
refinery 2_r2                   con2   1   con4  -3     .
r2_ref2 gas                        .   .   con4   4    eq
middle east_refinery 1       costrow  63 caprow  95     .
middle east_refinery 2       costrow  81 caprow  80     .
u.s.a._refinery 1            costrow  55      .   .     .
u.s.a._refinery 2            costrow  49      .   .     .
refinery 1_r1                costrow 200 caprow 175     .
refinery 2_r2                costrow 220 caprow 100     .
r1_ref1 gas                        .   . caprow 140     .
r1_ref1 diesel                     .   . caprow  75     .
r2_ref2 gas                        .   . caprow 100     .
r2_ref2 diesel                     .   . caprow  75     .
ref1 gas_servstn1 gas        costrow  15 caprow  70     .
ref1 gas_servstn2 gas        costrow  22 caprow  60     .
ref1 diesel_servstn1 diesel  costrow  18      .   .     .
ref1 diesel_servstn2 diesel  costrow  17      .   .     .
ref2 gas_servstn1 gas        costrow  17 caprow  35     .
ref2 gas_servstn2 gas        costrow  31      .   .     .
ref2 diesel_servstn1 diesel  costrow  36      .   .     .
ref2 diesel_servstn2 diesel  costrow  23      .   .     .
middle east_refinery 1             .  20      .   .    lo
middle east_refinery 2             .  10      .   .    lo
refinery 1_r1                      .  50      .   .    lo
refinery 2_r2                      .  35      .   .    lo
ref2 gas_servstn1 gas              .   5      .   .    lo
;

title 'Setting Up Condata = Cond5 for PROC NETFLOW';
data cond5;
   input _column_&$27. _row1 $ _coef1 _row2 $ _coef2 _type_ $ ;
   datalines;
middle east_refinery 1          con1  -2 costrow  63     .
middle east_refinery 2          con2  -2   lorow  10     .
refinery 1_r1                      .   .    con3  -3     =
r1_ref1 gas                   caprow 140    con3   4     .
refinery 2_r2                   con2   1    con4  -3     .
r2_ref2 gas                        .   .    con4   4    eq
.                               CON1 -15    CON2 -15    GE
ref2 diesel_servstn1 diesel        .  36 costrow   .  cost
.                                  .   .  caprow   . capac
.                              lorow   .       .   .    lo
middle east_refinery 1        caprow  95   lorow  20     .
middle east_refinery 2        caprow  80 costrow  81     .
u.s.a._refinery 1                  .   .       .  55  cost
u.s.a._refinery 2            costrow  49       .   .     .
refinery 1_r1                   con1   1  caprow 175     .
refinery 1_r1                  lorow  50 costrow 200     .
refinery 2_r2                costrow 220  caprow 100     .
refinery 2_r2                      .  35       .   .    lo
r1_ref1 diesel               caprow2  75       .   . capac
r2_ref2 gas                        .   .  caprow 100     .
r2_ref2 diesel               caprow2  75       .   .     .
ref1 gas_servstn1 gas        costrow  15  caprow  70     .
ref1 gas_servstn2 gas        caprow2  60 costrow  22     .
ref1 diesel_servstn1 diesel        .   . costrow  18     .
ref1 diesel_servstn2 diesel  costrow  17       .   .     .
ref2 gas_servstn1 gas        costrow  17   lorow   5     .
ref2 gas_servstn1 gas              .   . caprow2  35     .
ref2 gas_servstn2 gas              .  31       .   .  cost
ref2 diesel_servstn2 diesel        .   . costrow  23     .
;

/****************************************************************
 *                                                              *
 * Missing S and Missing D Demand Parameters                    *
 *                                                              *
 ****************************************************************/

title  'Oil Industry Example';
title3 'Crude Oil can come from anywhere';
data miss_s;
  missing S;
  input   _node_&$15. _sd_;
  datalines;
middle east         S
u.s.a.              S
servstn1 gas      -95
servstn1 diesel   -30
servstn2 gas      -40
servstn2 diesel   -15
;



proc netflow
  nodedata=miss_s       /* the supply (missing S) and */
                        /* demand data                */
  arcdata=arcd1         /* the arc descriptions       */
  condata=cond1         /* the side constraints       */
  conout=solution;      /* the solution data set      */
  run;
print some_arcs('middle east' 'u.s.a.',_all_)/short;

proc print;
  sum _fcost_;
  run;

data miss_s_x;
   missing S;
   input   _node_&$15. _sd_;
   datalines;
middle east         1
u.s.a.              1
servstn1 gas      -95
servstn1 diesel   -30
servstn2 gas      -40
servstn2 diesel   -15
;

proc netflow
   thrunet
   nodedata=miss_s_x     /* No supply (missing S)      */
   arcdata=arcd1         /* the arc descriptions       */
   condata=cond1         /* the side constraints       */
   conout=solution;      /* the solution data set      */
   run;
print some_arcs('middle east' 'u.s.a.',_all_)/short;

proc print;
   sum _fcost_;
   run;

/****************************************************************
 *                                                              *
 * Network Models: Interior Point Algorithm                     *
 *                                                              *
 ****************************************************************/

 /*  Introductory Example: Network Models:
     Interior Point Algorithm  */


proc netflow
   intpoint              /* <<<--- Interior Point used */
   nodedata=noded        /* the supply and demand data */
   arcdata=arcd1         /* the arc descriptions       */
   condata=cond1         /* the side constraints       */
   conout=solution;      /* the solution data set      */
run;


proc print data=solution;
   var _from_ _to_ _cost_ _capac_ _lo_ _name_
      _supply_ _demand_ _flow_ _fcost_ ;
   sum _fcost_;
   title3 'Constrained Optimum';
run;

/*  Introductory Example: Linear Programming Models:
    Interior Point Algorithm  */

data dcon1;
  input _id_ $17.
        a_light a_heavy brega naphthal naphthai
        heatingo jet_1 jet_2
        _type_ $ _rhs_;
  datalines;
profit            -175 -165 -205  0  0  0 300 300 max     .
naphtha_l_conv    .035 .030 .045 -1  0  0   0   0  eq     0
naphtha_i_conv    .100 .075 .135  0 -1  0   0   0  eq     0
heating_o_conv    .390 .300 .430  0  0 -1   0   0  eq     0
recipe_1             0    0    0  0 .3 .7  -1   0  eq     0
recipe_2             0    0    0 .2  0 .8   0  -1  eq     0
available          110  165   80  .  .  .   .   . upperbd .
;


proc netflow
   arcdata=dcon1
   condata=dcon1
   conout=solutn1;
run;
print problem/short;


proc print data=solutn1;
   var _name_ _objfn_ _upperbd _lowerbd _value_ _fcost_;
   sum _fcost_;
   title3 'LP Optimum';
run;

data scon2;
   format _type_ $8. _col_ $8. _row_ $16. ;
   input _type_ $ _col_ $ _row_ $ _coef_;
   datalines;
max      .             profit                    .
eq       .             napha_l_conv              .
eq       .             napha_i_conv              .
eq       .             heating_oil_conv          .
eq       .             recipe_1                  .
eq       .             recipe_2                  .
upperbd  .             available                 .
.        a_light       profit                 -175
.        a_light       napha_l_conv           .035
.        a_light       napha_i_conv           .100
.        a_light       heating_oil_conv       .390
.        a_light       available               110
.        a_heavy       profit                 -165
.        a_heavy       napha_l_conv           .030
.        a_heavy       napha_i_conv           .075
.        a_heavy       heating_oil_conv       .300
.        a_heavy       available               165
.        brega         profit                 -205
.        brega         napha_l_conv           .045
.        brega         napha_i_conv           .135
.        brega         heating_oil_conv       .430
.        brega         available                80
.        naphthal      napha_l_conv             -1
.        naphthal      recipe_2                 .2
.        naphthai      napha_i_conv             -1
.        naphthai      recipe_1                 .3
.        heatingo      heating_oil_conv         -1
.        heatingo      recipe_1                 .7
.        heatingo      recipe_2                 .8
.        jet_1         profit                  300
.        jet_1         recipe_1                 -1
.        jet_2         profit                  300
.        jet_2         recipe_2                 -1
;

proc netflow
   sparsecondata
   condata=scon2
   conout=solutn2;
run;

data vars3;
   input _name_ $ profit available;
   datalines;
a_heavy  -165 165
a_light  -175 110
brega    -205  80
heatingo    0   .
jet_1     300   .
jet_2     300   .
naphthai    0   .
naphthal    0   .
;

data dcon3;
   input _id_ $17.
         a_light a_heavy brega naphthal naphthai
         heatingo jet_1 jet_2
         _type_ $ _rhs_;
   datalines;
naphtha_l_conv    .035 .030 .045 -1  0  0   0   0  eq     0
naphtha_i_conv    .100 .075 .135  0 -1  0   0   0  eq     0
heating_o_conv    .390 .300 .430  0  0 -1   0   0  eq     0
recipe_1             0    0    0  0 .3 .7  -1   0  eq     0
recipe_2             0    0    0 .2  0 .8   0  -1  eq     0
;

proc netflow
     maximize          /* ***** necessary ***** */
     arcdata=vars3
     condata=dcon3
     conout=solutn3;
   objfn profit;
   upperbd available;
   run;

data vars4;
   input _name_ $ profit available;
   datalines;
a_heavy  -165 165
a_light  -175 110
brega    -205  80
jet_1     300   .
jet_2     300   .
;

data dcon4;
   input _id_ $17.
         a_light a_heavy brega naphthal naphthai
         heatingo jet_1 jet_2;
   datalines;
naphtha_l_conv    .035 .030 .045 -1  0  0   0   0
naphtha_i_conv    .100 .075 .135  0 -1  0   0   0
heating_o_conv    .390 .300 .430  0  0 -1   0   0
recipe_1             0    0    0  0 .3 .7  -1   0
recipe_2             0    0    0 .2  0 .8   0  -1
;
proc netflow
     maximize defcontype=eq
     arcdata=vars3
     condata=dcon3
     conout=solutn3;
   objfn profit;
   upperbd available;
   run;

data scon5;
   format _type_ $8. _col_ $8. _row_ $16. ;
   input _type_ $ _col_ $ _row_ $ _coef_;
   datalines;
eq       .             napha_l_conv              .
eq       .             napha_i_conv              .
eq       .             heating_oil_conv          .
eq       .             recipe_1                  .
eq       .             recipe_2                  .
.        a_light       napha_l_conv           .035
.        a_light       napha_i_conv           .100
.        a_light       heating_oil_conv       .390
.        a_heavy       napha_l_conv           .030
.        a_heavy       napha_i_conv           .075
.        a_heavy       heating_oil_conv       .300
.        brega         napha_l_conv           .045
.        brega         napha_i_conv           .135
.        brega         heating_oil_conv       .430
.        naphthal      napha_l_conv             -1
.        naphthal      recipe_2                 .2
.        naphthai      napha_i_conv             -1
.        naphthai      recipe_1                 .3
.        heatingo      heating_oil_conv         -1
.        heatingo      recipe_1                 .7
.        heatingo      recipe_2                 .8
.        jet_1         recipe_1                 -1
.        jet_2         recipe_2                 -1
;
proc netflow
     maximize
     sparsecondata
     arcdata=vars3    /* or arcdata=vars4 */
     condata=scon5
     conout=solutn5;
   objfn profit;
   upperbd available;
   run;

data scon6;
   input _col_ $ _row_&$16. _coef_;
   datalines;
a_light  napha_l_conv           .035
a_light  napha_i_conv           .100
a_light  heating_oil_conv       .390
a_heavy  napha_l_conv           .030
a_heavy  napha_i_conv           .075
a_heavy  heating_oil_conv       .300
brega    napha_l_conv           .045
brega    napha_i_conv           .135
brega    heating_oil_conv       .430
naphthal napha_l_conv             -1
naphthal recipe_2                 .2
naphthai napha_i_conv             -1
naphthai recipe_1                 .3
heatingo heating_oil_conv         -1
heatingo recipe_1                 .7
heatingo recipe_2                 .8
jet_1    recipe_1                 -1
jet_2    recipe_2                 -1
;
proc netflow
     maximize
     defcontype=eq
     sparsecondata
     arcdata=vars3     /* or arcdata=vars4 */
     condata=scon6
     conout=solutn6;
   objfn profit;
   upperbd available;
   run;

/****************************************************************
 *                                                              *
 * Generalized Networks:                                        *
 * How to Specify Data for Arc Multipliers                      *
 *                                                              *
 ****************************************************************/

/*  All Arc Multiplier Data in the ARCDATA= Data Set  */

data nodes;
   input _node_ $ _sd_ ;
datalines;
N1  22
N4 -30
N5 -10
;

data arcs;
   input _from_ $ _to_ $  _cost_ _mult_;
datalines;
N1 N2   2   4
N1 N3  10 0.5
N2 N4   0   1
N2 N5   7   3
N3 N2  12   2
N3 N5  10   2
N5 N4  55 0.9
;



title1 'The NETFLOW Procedure';
proc netflow
   bytes    = 100000
   nodedata = nodes
   arcdata  = arcs
   conout   = solution;
run;

data arcs1b;
   input _from_ $ _to_ $  _cost_;
datalines;
N1 N2   2
N1 N3  10
N2 N4   0
N2 N5   7
N3 N2  12
N3 N5  10
N5 N4  55
;

data MUdense;
   input _type_ $ N1_N2 N1_N3 N2_N4 N2_N5 N3_N2 N3_N5 N5_N4;
datalines;
mult 4.0  0.5  1.0  0.3  2.0  2.0  0.9
;


proc netflow
   gennet
   nodedata = nodes
   arcdata  = arcs1b
   condata  = MUdense
   conout   = soln1b;
run;

data MUsparse;
   input _type_ $ _col_ $ _coef_;
datalines;
mult N1_N2 4.0
mult N1_N3 0.5
mult N2_N4 1.0
mult N2_N5 0.3
mult N3_N2 2.0
mult N3_N5 2.0
mult N5_N4 0.9
;


proc netflow
   gennet   sparsecondata
   nodedata = nodes
   arcdata  = arcs1b
   condata  = MUsparse
   conout   = soln1c;
run;

data arcs1c;
   input _from_ $ _to_ $  _cost_ _mult_;
datalines;
N1 N2   2   4
N1 N3  10  .5
N2 N4   0   .
N2 N5   7   .
N3 N2  12   .
N3 N5  10   .
N5 N4  55   .
;

data MUdense1;
   input _type_ $ N2_N4 N2_N5 N3_N2 N3_N5 N5_N4;
datalines;
mult 1.0  0.3  2.0  2.0  0.9
;

/****************************************************************
 *                                                              *
 * Example 1: Shortest Path Problem                             *
 *                                                              *
 ****************************************************************/

  title 'Shortest Path Problem';
  title2 'How to get Hawaiian Pineapples to a London Restaurant';
  data aircost1;
     input   ffrom&$13. tto&$15. _cost_ ;
     datalines;
  Honolulu       Chicago          105
  Honolulu       San Francisco     75
  Honolulu       Los Angeles       68
  Chicago        Boston            45
  Chicago        New York          56
  San Francisco  Boston            71
  San Francisco  New York          48
  San Francisco  Atlanta           63
  Los Angeles    New York          44
  Los Angeles    Atlanta           57
  Boston         Heathrow London   88
  New York       Heathrow London   65
  Atlanta        Heathrow London   76
  ;


proc netflow
   shortpath
   sourcenode=Honolulu
   sinknode='Heathrow London'   /* Quotes for embedded blank */
   ARCDATA=aircost1
   arcout=spath;
   tail    ffrom;
   head    tto;
run;

proc print data=spath;
   sum _fcost_;
run;

/****************************************************************
 *                                                              *
 * Example 2: Minimum Cost Flow Problem                         *
 *                                                              *
 ****************************************************************/

title 'Minimum Cost Flow Problem';
title2 'How to get Hawaiian Pineapples to a London Restaurant';
proc netflow
  defcapacity=350
  sourcenode='Honolulu'
  sinknode='Heathrow London'  /* Quotes for embedded blank */
  demand=500
     arcdata=aircost1
     arcout=arcout1
     nodeout=nodeout1;
        tail    ffrom;
        head    tto;
  set future1;
  run;
  quit;


proc print data=arcout1;sum _fcost_;run;


proc print data=nodeout1;
run;

/****************************************************************
 *                                                              *
 * Example 3: Using a Warm Start                                *
 *                                                              *
 ****************************************************************/

title 'Minimum Cost Flow Problem - Warm Start';
title2 'How to get Hawaiian Pineapples to a London Restaurant';
data aircost2;
  set arcout1;
     oldcost=_cost_;
     oldflow=_flow_;
     oldfc=_fcost_;
     if ffrom='Chicago' then _cost_=_cost_-30;


proc netflow
  warm
     arcdata=aircost2
     nodedata=nodeout1
     arcout=arcout2;
        tail    ffrom;
        head    tto;
        run;
        quit;

proc print data=arcout2;
  var ffrom tto _cost_ oldcost _capac_ _lo_
      _flow_ oldflow _fcost_ oldfc;
  sum _fcost_ oldfc;
run;

/****************************************************************
 *                                                              *
 * Example 4: Production, Inventory, Distribution Problem       *
 *                                                              *
 ****************************************************************/

   title 'Minimum Cost Flow problem';
   title2 'Production Planning/Inventory/Distribution';
   data node0;
     input _node_ $ _supdem_ ;
     datalines;
   fact1_1   1000
   fact2_1    850
   fact1_2   1000
   fact2_2   1500
   shop1_1   -900
   shop2_1   -900
   shop1_2   -900
   shop2_2  -1450
   ;


data arc0;
  input _tail_ $ _head_ $ _cost_ _capac_ _lo_ diagonal factory
        key_id $10. mth_made $ _name_&$17. ;
  datalines;
fact1_1  f1_mar_1  127.9  500 50 19 1 production March prod f1 19 mar
fact1_1  f1_apr_1   78.6  600 50 19 1 production April prod f1 19 apl
fact1_1  f1_may_1   95.1  400 50 19 1 production May   .
f1_mar_1 f1_apr_1   15     50  . 19 1 storage    March .
f1_apr_1 f1_may_1   12     50  . 19 1 storage    April .
f1_apr_1 f1_mar_1   28     20  . 19 1 backorder  April back f1 19 apl
f1_may_1 f1_apr_1   28     20  . 19 1 backorder  May   back f1 19 may
f1_mar_1 f2_mar_1   11      .  . 19 . f1_to_2    March .
f1_apr_1 f2_apr_1   11      .  . 19 . f1_to_2    April .
f1_may_1 f2_may_1   16      .  . 19 . f1_to_2    May   .
f1_mar_1 shop1_1  -327.65 250  . 19 1 sales      March .
f1_apr_1 shop1_1  -300    250  . 19 1 sales      April .
f1_may_1 shop1_1  -285    250  . 19 1 sales      May   .
f1_mar_1 shop2_1  -362.74 250  . 19 1 sales      March .
f1_apr_1 shop2_1  -300    250  . 19 1 sales      April .
f1_may_1 shop2_1  -245    250  . 19 1 sales      May   .
fact2_1  f2_mar_1   88.0  450 35 19 2 production March prod f2 19 mar
fact2_1  f2_apr_1   62.4  480 35 19 2 production April prod f2 19 apl
fact2_1  f2_may_1  133.8  250 35 19 2 production May   .
f2_mar_1 f2_apr_1   18     30  . 19 2 storage    March .
f2_apr_1 f2_may_1   20     30  . 19 2 storage    April .
f2_apr_1 f2_mar_1   17     15  . 19 2 backorder  April back f2 19 apl
f2_may_1 f2_apr_1   25     15  . 19 2 backorder  May   back f2 19 may
f2_mar_1 f1_mar_1   10     40  . 19 . f2_to_1    March .
f2_apr_1 f1_apr_1   11     40  . 19 . f2_to_1    April .
f2_may_1 f1_may_1   13     40  . 19 . f2_to_1    May   .
f2_mar_1 shop1_1  -297.4  250  . 19 2 sales      March .
f2_apr_1 shop1_1  -290    250  . 19 2 sales      April .
f2_may_1 shop1_1  -292    250  . 19 2 sales      May   .
f2_mar_1 shop2_1  -272.7  250  . 19 2 sales      March .
f2_apr_1 shop2_1  -312    250  . 19 2 sales      April .
f2_may_1 shop2_1  -299    250  . 19 2 sales      May   .
fact1_2  f1_mar_2  217.9  400 40 25 1 production March prod f1 25 mar
fact1_2  f1_apr_2  174.5  550 50 25 1 production April prod f1 25 apl
fact1_2  f1_may_2  133.3  350 40 25 1 production May   .
f1_mar_2 f1_apr_2   20     40  . 25 1 storage    March .
f1_apr_2 f1_may_2   18     40  . 25 1 storage    April .
f1_apr_2 f1_mar_2   32     30  . 25 1 backorder  April back f1 25 apl
f1_may_2 f1_apr_2   41     15  . 25 1 backorder  May   back f1 25 may
f1_mar_2 f2_mar_2   23      .  . 25 . f1_to_2    March .
f1_apr_2 f2_apr_2   23      .  . 25 . f1_to_2    April .
f1_may_2 f2_may_2   26      .  . 25 . f1_to_2    May   .
f1_mar_2 shop1_2  -559.76   .  . 25 1 sales      March .
f1_apr_2 shop1_2  -524.28   .  . 25 1 sales      April .
f1_may_2 shop1_2  -475.02   .  . 25 1 sales      May   .
f1_mar_2 shop2_2  -623.89   .  . 25 1 sales      March .
f1_apr_2 shop2_2  -549.68   .  . 25 1 sales      April .
f1_may_2 shop2_2  -460.00   .  . 25 1 sales      May   .
fact2_2  f2_mar_2  182.0  650 35 25 2 production March prod f2 25 mar
fact2_2  f2_apr_2  196.7  680 35 25 2 production April prod f2 25 apl
fact2_2  f2_may_2  201.4  550 35 25 2 production May   .
f2_mar_2 f2_apr_2   28     50  . 25 2 storage    March .
f2_apr_2 f2_may_2   38     50  . 25 2 storage    April .
f2_apr_2 f2_mar_2   31     15  . 25 2 backorder  April back f2 25 apl
f2_may_2 f2_apr_2   54     15  . 25 2 backorder  May   back f2 25 may
f2_mar_2 f1_mar_2   20     25  . 25 . f2_to_1    March .
f2_apr_2 f1_apr_2   21     25  . 25 . f2_to_1    April .
f2_may_2 f1_may_2   43     25  . 25 . f2_to_1    May   .
f2_mar_2 shop1_2  -567.83 500  . 25 2 sales      March .
f2_apr_2 shop1_2  -542.19 500  . 25 2 sales      April .
f2_may_2 shop1_2  -461.56 500  . 25 2 sales      May   .
f2_mar_2 shop2_2  -542.83 500  . 25 2 sales      March .
f2_apr_2 shop2_2  -559.19 500  . 25 2 sales      April .
f2_may_2 shop2_2  -489.06 500  . 25 2 sales      May   .
;


proc netflow
      nodedata=node0
      arcdata=arc0;
  set future1
      nodeout=node2
      arcout=arc1;
      run;
      quit;

options ls=80 ps = 50;
proc print data=arc1 heading=h width=min;
var _tail_ _head_ _cost_ _capac_ _lo_ _name_ _supply_ _demand_ _flow_ _fcost_;
sum _fcost_;
run;

options ls=80 ps = 50;
proc print data=arc1 heading=h width=min;
var _rcost_ _anumb_ _tnumb_ _status_ diagonal factory key_id mth_made;
run;

proc print data=node2;
run;

/****************************************************************
 *                                                              *
 * Example 5: Using an Unconstrained Solution Warm Start        *
 *                                                              *
 ****************************************************************/


title 'Minimum Cost Flow problem- Unconstrained Warm Start';
title2 'Production Planning/Inventory/Distribution';
data arc2;
  set arc1;
  oldcost=_cost_;
  oldfc=_fcost_;
  oldflow=_flow_;
  if key_id='backorder'
     then _cost_=_cost_*1.2;
     else if _tail_='f2_may_2' then _cost_=_cost_-30;
  if key_id='production' & mth_made='May' then
     if diagonal=19 then _cost_=_cost_-5;
                    else _cost_=_cost_-20;



proc netflow
  warm future1
  nodedata=node2
  arcdata=arc2
  nodeout=node3
  arcout=arc3;
  run;
  quit;

options ls=80 ps = 50;
proc print data=arc3 heading=h width=min;
sum _fcost_;
var _tail_ _head_ _capac_ _lo_ _supply_ _demand_ _name_ _cost_ _flow_ _fcost_;
run;

options ls=80 ps = 50;
proc print data=arc3 heading=h width=min;
sum oldfc;
var oldcost oldflow oldfc diagonal factory key_id mth_made _anumb_ _tnumb_;
run;

proc print data=node3;
  run;

/****************************************************************
 *                                                              *
 * Example 6: Adding Side Constraints, Using a Warm Start       *
 *                                                              *
 ****************************************************************/

title 'Adding Side Constraints and Using a Warm Start';
title2 'Production Planning/Inventory/Distribution';
data con3;
  input _column_ &$14. _row_ &$15. _coef_ ;
  datalines;
prod f1 19 mar  FACT1 MAR GIZMO  3
prod f1 25 mar  FACT1 MAR GIZMO  4
CHIP/BO LIMIT   FACT1 MAR GIZMO  2600
prod f2 19 mar  FACT2 MAR GIZMO  3
prod f2 25 mar  FACT2 MAR GIZMO  4
CHIP/BO LIMIT   FACT2 MAR GIZMO  3750
prod f1 19 apl  FACT1 APL GIZMO  3
prod f1 25 apl  FACT1 APL GIZMO  4
CHIP/BO LIMIT   FACT1 APL GIZMO  2600
prod f2 19 apl  FACT2 APL GIZMO  3
prod f2 25 apl  FACT2 APL GIZMO  4
CHIP/BO LIMIT   FACT2 APL GIZMO  3750
back f1 19 apl  TOTAL BACKORDER  1
back f1 25 apl  TOTAL BACKORDER  1
back f2 19 apl  TOTAL BACKORDER  1
back f2 25 apl  TOTAL BACKORDER  1
back f1 19 may  TOTAL BACKORDER  1
back f1 25 may  TOTAL BACKORDER  1
back f2 19 may  TOTAL BACKORDER  1
back f2 25 may  TOTAL BACKORDER  1
CHIP/BO LIMIT   TOTAL BACKORDER  50
;


proc netflow
  nodedata=node3 arcdata=arc3 warm
  condata=con3 sparsecondata rhsobs='CHIP/BO LIMIT'
  future2 dualout=dual4 conout=con4;
     id diagonal factory key_id mth_made;
     run;
     quit;

proc print data=con4 heading=h width=min;
sum _fcost_;
var _tail_ _head_ _cost_ _capac_ _lo_ _name_ _supply_ _demand_ _flow_ _fcost_;
run;

proc print data=con4 heading=h width=min;
var _rcost_ _anumb_ _tnumb_ _status_ diagonal factory key_id mth_made;
run;

proc print data=dual4;
  run;

/****************************************************************
 *                                                              *
 * Example 7: Using a Constrained Solution Warm Start           *
 *                                                              *
 ****************************************************************/

  title 'Using a Constrained Solution Warm Start';
  title2 'Production Planning/Inventory/Distribution';
  data new_con4;
     set con4;
     oldcost=_cost_;
     oldflow=_flow_;
     oldfc=_fcost_;
     if _tail_='f1_may_2'
        & (_head_='shop1_2' | _head_='shop2_2')
        then _cost_=_cost_-40;
     run;


proc netflow
   warm
   arcdata=new_con4
   dualin=dual4
   condata=con3
   sparsecondata
   rhsobs='CHIP/BO LIMIT'
   dualout=dual5
   conout=con5;
run;
 quit;

proc print data=con5 heading=h width=min;
sum _fcost_;
var _tail_ _head_ _capac_ _lo_ _supply_ _demand_ _name_ _cost_ _flow_ _fcost_;
run;

proc print data=con5 heading=h width=min;
   sum oldfc;
   var oldcost oldflow oldfc diagonal factory key_id mth_made _anumb_ _tnumb_;
run;

proc print data=dual5;
run;

/****************************************************************
 *                                                              *
 * Example 8: Nonarc Variables in the Side Constraints          *
 *                                                              *
 ****************************************************************/

title 'Nonarc Variables in the Side Constraints';
title2 'Production Planning/Inventory/Distribution';
data con6;
  input _column_ &$17. _row_ &$15. _coef_ ;
  datalines;
prod f1 19 mar     FACT1 MAR GIZMO  3
prod f1 25 mar     FACT1 MAR GIZMO  4
f1 unused chips    FACT1 MAR GIZMO  1
_RHS_              FACT1 MAR GIZMO  2615
prod f2 19 mar     FACT2 MAR GIZMO  3
prod f2 25 mar     FACT2 MAR GIZMO  4
f2 unused chips    FACT2 MAR GIZMO  1
_RHS_              FACT2 MAR GIZMO  3750
prod f1 19 apl     FACT1 APL GIZMO  3
prod f1 25 apl     FACT1 APL GIZMO  4
f1 chips from mar  FACT1 APL GIZMO  -1
_RHS_              FACT1 APL GIZMO  2600
prod f2 19 apl     FACT2 APL GIZMO  3
prod f2 25 apl     FACT2 APL GIZMO  4
f2 chips from mar  FACT2 APL GIZMO  -1
_RHS_              FACT2 APL GIZMO  3750
f1 unused chips    CHIP LEFTOVER    1
f2 unused chips    CHIP LEFTOVER    1
f1 chips from mar  CHIP LEFTOVER    -1
f2 chips from mar  CHIP LEFTOVER    -1
_TYPE_             CHIP LEFTOVER    1
back f1 19 apl     TOTAL BACKORDER  1
back f1 25 apl     TOTAL BACKORDER  1
back f2 19 apl     TOTAL BACKORDER  1
back f2 25 apl     TOTAL BACKORDER  1
back f1 19 may     TOTAL BACKORDER  1
back f1 25 may     TOTAL BACKORDER  1
back f2 19 may     TOTAL BACKORDER  1
back f2 25 may     TOTAL BACKORDER  1
_TYPE_             TOTAL BACKORDER  -1
_RHS_              TOTAL BACKORDER  50
;


data arc6;
  set con5;
  drop oldcost oldfc oldflow _flow_ _fcost_ _status_ _rcost_;
data arc6_b;
  length key_id $10;
  input _name_ &$17. _cost_ _capac_ factory key_id $ ;
  datalines;
f1 unused chips    .   . 1 chips
f2 unused chips    .   . 2 chips
f1 chips from mar  1 150 1 chips
f2 chips from mar  1 150 2 chips
;


proc append force nowarn
   base=arc6 data=arc6_b;
run;

proc netflow
   nodedata=node0 arcdata=arc6
   condata=con6 defcontype=eq sparsecondata
   dualout=dual7 conout=con7;
run;

print nonarcs/short;

title 'Nonarc Variables in the Side Constraints';
title2 'Production Planning/Inventory/Distribution';
options ls=80 ps = 50;
proc print data=con7 heading=h width=min;
sum _fcost_;
var _tail_ _head_ _cost_ _capac_ _lo_ _name_ _supply_ _demand_ _flow_ _fcost_;
run;

options ls=80 ps = 50;
proc print data=con7 heading=h width=min;
var _rcost_ _anumb_ _tnumb_ _status_ diagonal factory key_id mth_made;
run;

options ls=80 ps = 50;
title 'Nonarc Variables in the Side Constraints';
title2 'Production Planning/Inventory/Distribution';
proc print data=dual7;
run;

/****************************************************************
 *                                                              *
 * Example 9: Pure Networks: Using the EXCESS= Option           *
 *                                                              *
 ****************************************************************/

data parcs;
   input _from_ $ _to_ $ _cost_;
datalines;
s1 d1 1
s1 d2 8
s2 d1 4
s2 d2 2
;

data SleD;
   input _node_ $ _sd_;
datalines;
s1   1
s2  10
d1 -10
d2  -5
;


title1 'The NETFLOW Procedure';
proc netflow
   excess   = slacks
   arcdata  = parcs
   nodedata = SleD
   conout   = solex1;
run;

title1 'The NETFLOW Procedure';
proc netflow
   thrunet
   excess   = slacks
   arcdata  = parcs
   nodedata = SleD
   conout   = solex1t;
run;

data node_missingD1;
   input _node_ $ _sd_;
   missing D;
datalines;
s1   1
s2  10
d1   D
d2  -1
;


title1 'The NETFLOW Procedure';
proc netflow
   excess   = slacks
   arcdata  = parcs
   nodedata = node_missingD1
   conout   = solex1b;
run;

title1 'The NETFLOW Procedure';
proc netflow
   thrunet
   excess   = slacks
   arcdata  = parcs
   nodedata = node_missingD1
   conout   = solex1c;
run;

/****************************************************************
 *                                                              *
 * Example 10: Maximum Flow Problem                             *
 *                                                              *
 ****************************************************************/

data arcs;
   input _from_ $ _to_ $ _cost_ _capac_;
datalines;
S a  .  .
S b  .  .
a c  1  7
b c  2  9
a d  3  5
b d  4  8
c e  5 15
d f  6 20
e g  7 11
f g  8  6
e h  9 12
f h 10  4
g T  .  .
h T  .  .
;


title1 'The NETFLOW Procedure';
proc netflow
   intpoint
   maxflow
   excess = arcs
   arcdata = arcs
   source  = S    sink = T
   conout  = gout3;
run;

title1 'The NETFLOW Procedure';
proc netflow
   intpoint
   excess  = slacks
   arcdata = arcs
   source  = S    sink = T
   maxflow
   conout  = gout3b;
run;

/****************************************************************
 *                                                              *
 * Example 11: Generalized Networks: Using the EXCESS= Option   *
 *                                                              *
 ****************************************************************/

data garcs;
   input _from_ $ _to_ $ _cost_ _mult_;
datalines;
s1 d1 1 .
s1 d2 8 .
s2 d1 4 2
s2 d2 2 2
s2 d3 1 2
s3 d2 5 0.5
s3 d3 4 0.5
;

data gnodes;
   input _node_ $ _sd_ ;
datalines;
s1  5
s2  20
s3  10
d1  -5
d2  -10
d3  -20
;


title1 'The NETFLOW Procedure';
proc netflow
   arcdata  = garcs
   nodedata = gnodes
   excess   = supply
   conout   = gnetout;
run;

data garcs1;
   input _from_ $ _to_ $ _cost_ _mult_;
datalines;
s1 d1 1 0.5
s1 d2 8 0.5
s2 d1 4 .
s2 d2 2 .
s2 d3 1 .
s3 d2 5 0.5
s3 d3 4 0.5
;


title1 'The NETFLOW Procedure';
proc netflow
   arcdata  = garcs1
   nodedata = gnodes
   excess = demand
   conout   = gnetout1;
run;

/****************************************************************
 *                                                              *
 * Example 12: Generalized Networks: Maximum Flow Problem       *
 *                                                              *
 ****************************************************************/

data garcsM;
   input _from_ $ _to_ $ _upper_ _mult_;
datalines;
A B 2 .
A C 2 .
C B 1 .
B D 1 .
C D 2 .
C E 1 3
D E 1 2
E F 5 .
D F 2 .
;


title1 'The NETFLOW Procedure';
proc netflow
   arcdata = garcsM
   maxflow
   source  = A  sink = F
   conout  = gmfpout;
run;

/****************************************************************
 *                                                              *
 * Example 13: Machine Loading Problem                          *
 *                                                              *
 ****************************************************************/

data mlarcs;
   input _from_ $ _to_ $ _cost_ _mult_;
datalines;
P1  M1   4   .
P1  M2   3   2
P1  M3   3   2
P1  M4   1   3
P2  M1  .5   2
P2  M2   2   3
P2  M3  .5   2
P2  M4   3   1
P3  M1   2   3
P3  M2   5   .
P3  M3   1   2
P3  M4  .5   4
;

data mlnodes;
   input _node_ $ _sd_;
datalines;
P1   10
P2   5
P3   10
M1  -40
M2  -40
M3  -50
M4  -50
;


title1 'The NETFLOW Procedure';
proc netflow
   excess   = demand
   arcdata  = mlarcs
   nodedata = mlnodes
   conout   = mlsol;
run;

/****************************************************************
 *                                                              *
 * Example 14: Generalized Networks: Distribution Problem       *
 *                                                              *
 ****************************************************************/

data dnodes;
   input _node_ $ _sd_ ;
   missing S D;
datalines;
S1   700
S2     0
S3   200
D1  -200
D2  -300
D3  -200
D4  -150
D5   100
Y      S
Z      D
;

data darcs;
   input _from_ $ _to_ $ _cost_ _capac_ _mult_;
datalines;
S1  D1    3   200  0.95
S1  D2    3   200  0.95
S1  D3    6   200  0.95
S1  D4    7   200  0.95
S2  D1    7   200  0.95
S2  D2    2   200  0.95
S2  D4    5   200  0.95
S3  D2    6   200  0.95
S3  D4    4   200  0.95
S3  D5    7   200  0.95
D4  D3    4   200  0.95
Y   S2   10   300  .
Y   S3   14   100  .
S1  Z   -5    700  .
D2  Z   -20   100  .
D3  Z   -20   100  .
D5  Z   -25   250  .
;


title1 'The NETFLOW Procedure';
proc netflow
   nodedata = dnodes
   arcdata  = darcs
   conout   = dsol;
run;

/****************************************************************
 *                                                              *
 * Example 15: Converting to an MPS-Format SAS Data Set         *
 *                                                              *
 ****************************************************************/

data exdata;
   input x1 x2 x3 _type_ $ _rhs_;
datalines;
2 -3 -4 min      .
. -2 -3 >=      -5
1  1  2 <=       6
1  2  3 >=       7
10 15 20 upperbd  .
;



/* convert to MPS format */

proc netflow condata=exdata mpsout=mpsdata bytes=100000;
run;

/****************************************************************
 *                                                              *
 * Example 16: Migration to OPTMODEL: Generalized Networks      *
 *                                                              *
 ****************************************************************/

title 'Generalized Networks';

data garcs;
   input _from_ $ _to_ $ _cost_ _mult_;
   datalines;
s1 d1 1 .
s1 d2 8 .
s2 d1 4 2
s2 d2 2 2
s2 d3 1 2
s3 d2 5 0.5
s3 d3 4 0.5
;


data gnodes;
   input _node_ $ _sd_ ;
   datalines;
s1 5
s2 20
s3 10
d1 -5
d2 -10
d3 -20
;


proc optmodel;
   set <str> NODES;
   num _sd_ {NODES} init 0;
   read data gnodes into NODES=[_node_] _sd_;

   set <str,str> ARCS;
   num _lo_ {ARCS} init 0;
   num _capac_ {ARCS} init .;
   num _cost_ {ARCS};
   num _mult_ {ARCS} init 1;
   read data garcs nomiss into ARCS=[_from_ _to_] _cost_ _mult_;
   NODES = NODES union (union {<i,j> in ARCS} {i,j});

   var Flow {<i,j> in ARCS} >= _lo_[i,j];
   min obj = sum {<i,j> in ARCS} _cost_[i,j] * Flow[i,j];
   con balance {i in NODES}: sum {<(i),j> in ARCS} Flow[i,j]
      - sum {<j,(i)> in ARCS} _mult_[j,i] * Flow[j,i] = _sd_[i];

   num infinity = min {r in {}} r;
   /* change equality constraint to le constraint for supply nodes */
   for {i in NODES: _sd_[i] > 0} balance[i].lb = -infinity;

   solve;

   num _supply_ {<i,j> in ARCS} = (if _sd_[i] ne 0 then _sd_[i] else .);
   num _demand_ {<i,j> in ARCS} = (if _sd_[j] ne 0 then -_sd_[j] else .);
   num _fcost_ {<i,j> in ARCS} = _cost_[i,j] * Flow[i,j].sol;

   create data gnetout from [_from_ _to_]
      _cost_ _capac_ _lo_ _mult_ _supply_ _demand_ _flow_=Flow _fcost_;
quit;

proc print data=gnetout;
run;

data garcs1;
   input _from_ $ _to_ $ _cost_ _mult_;
   datalines;
s1 d1 1 0.5
s1 d2 8 0.5
s2 d1 4 .
s2 d2 2 .
s2 d3 1 .
s3 d2 5 0.5
s3 d3 4 0.5
;


proc optmodel;
   set <str> NODES;
   num _sd_ {NODES} init 0;
   read data gnodes into NODES=[_node_] _sd_;

   set <str,str> ARCS;
   num _lo_ {ARCS} init 0;
   num _capac_ {ARCS} init .;
   num _cost_ {ARCS};
   num _mult_ {ARCS} init 1;
   read data garcs1 nomiss into ARCS=[_from_ _to_] _cost_ _mult_;
   NODES = NODES union (union {<i,j> in ARCS} {i,j});

   var Flow {<i,j> in ARCS} >= _lo_[i,j];
   for {<i,j> in ARCS: _capac_[i,j] ne .} Flow[i,j].ub = _capac_[i,j];
   min obj = sum {<i,j> in ARCS} _cost_[i,j] * Flow[i,j];
   con balance {i in NODES}: sum {<(i),j> in ARCS} Flow[i,j]
      - sum {<j,(i)> in ARCS} _mult_[j,i] * Flow[j,i] = _sd_[i];

   num infinity = min {r in {}} r;
   /* change equality constraint to ge constraint */
   for {i in NODES: _sd_[i] < 0} balance[i].ub = infinity;

   solve;

   num _supply_ {<i,j> in ARCS} = (if _sd_[i] ne 0 then _sd_[i] else .);
   num _demand_ {<i,j> in ARCS} = (if _sd_[j] ne 0 then -_sd_[j] else .);
   num _fcost_ {<i,j> in ARCS} = _cost_[i,j] * Flow[i,j].sol;

   create data gnetout1 from [_from_ _to_]
      _cost_ _capac_ _lo_ _mult_ _supply_ _demand_ _flow_=Flow _fcost_;
quit;

proc print data=gnetout1;
run;

/****************************************************************
 *                                                              *
 * Example 17: Migration to OPTMODEL: Maximum Flow              *
 *                                                              *
 ****************************************************************/

title 'Maximum Flow Problem';

data arcs;
   input _from_ $ _to_ $ _cost_ _capac_;
   datalines;
S a . .
S b . .
a c 1 7
b c 2 9
a d 3 5
b d 4 8
c e 5 15
d f 6 20
e g 7 11
f g 8 6
e h 9 12
f h 10 4
g T . .
h T . .
;


proc optmodel;
   str source = 'S';
   str sink = 'T';

   set <str> NODES;
   num _supdem_ {i in NODES} = (if i in {source, sink} then . else 0);

   set <str,str> ARCS;
   num _lo_ {ARCS} init 0;
   num _capac_ {ARCS} init .;
   num _cost_ {ARCS} init 0;
   read data arcs nomiss into ARCS=[_from_ _to_] _cost_ _capac_;
   NODES = (union {<i,j> in ARCS} {i,j});

   var Flow {<i,j> in ARCS} >= _lo_[i,j];
   for {<i,j> in ARCS: _capac_[i,j] ne .} Flow[i,j].ub = _capac_[i,j];
   max obj = sum {<i,j> in ARCS: j = sink} Flow[i,j];
   con balance {i in NODES diff {source, sink}}:
      sum {<(i),j> in ARCS} Flow[i,j]
      - sum {<j,(i)> in ARCS} Flow[j,i] = _supdem_[i];

   solve;

   num _supply_ {<i,j> in ARCS} =
      (if _supdem_[i] ne 0 then _supdem_[i] else .);
   num _demand_ {<i,j> in ARCS} =
      (if _supdem_[j] ne 0 then -_supdem_[j] else .);
   num _fcost_ {<i,j> in ARCS} = _cost_[i,j] * Flow[i,j].sol;

   create data gout3 from [_from_ _to_]
      _cost_ _capac_ _lo_ _supply_ _demand_ _flow_=Flow _fcost_;
quit;

proc print data=gout3;
run;

/****************************************************************
 *                                                              *
 * Example 18: Migration to OPTMODEL: Production, Inventory,    *
 *                                    Distribution              *
 *                                                              *
 ****************************************************************/

title 'Minimum Cost Flow Problem';
title2 'Production Planning/Inventory/Distribution';

data node0;
   input _node_ $ _supdem_ ;
   datalines;
fact1_1 1000
fact2_1 850
fact1_2 1000
fact2_2 1500
shop1_1 -900
shop2_1 -900
shop1_2 -900
shop2_2 -1450
;


data arc0;
   input _tail_ $ _head_ $ _cost_ _capac_ _lo_
      diagonal factory key_id $10. mth_made $ _name_&$17.;
   datalines;
fact1_1  f1_mar_1 127.9   500 50 19 1 production March prod f1 19 mar
fact1_1  f1_apr_1 78.6    600 50 19 1 production April prod f1 19 apl
fact1_1  f1_may_1 95.1    400 50 19 1 production May   .
f1_mar_1 f1_apr_1 15      50  .  19 1 storage    March .
f1_apr_1 f1_may_1 12      50  .  19 1 storage    April .
f1_apr_1 f1_mar_1 28      20  .  19 1 backorder  April back f1 19 apl
f1_may_1 f1_apr_1 28      20  .  19 1 backorder  May   back f1 19 may
f1_mar_1 f2_mar_1 11      .   .  19 . f1_to_2    March .
f1_apr_1 f2_apr_1 11      .   .  19 . f1_to_2    April .
f1_may_1 f2_may_1 16      .   .  19 . f1_to_2    May   .
f1_mar_1 shop1_1  -327.65 250 .  19 1 sales      March .
f1_apr_1 shop1_1  -300    250 .  19 1 sales      April .
f1_may_1 shop1_1  -285    250 .  19 1 sales      May   .
f1_mar_1 shop2_1  -362.74 250 .  19 1 sales      March .
f1_apr_1 shop2_1  -300    250 .  19 1 sales      April .
f1_may_1 shop2_1  -245    250 .  19 1 sales      May   .
fact2_1  f2_mar_1 88.0    450 35 19 2 production March prod f2 19 mar
fact2_1  f2_apr_1 62.4    480 35 19 2 production April prod f2 19 apl
fact2_1  f2_may_1 133.8   250 35 19 2 production May   .
f2_mar_1 f2_apr_1 18      30  .  19 2 storage    March .
f2_apr_1 f2_may_1 20      30  .  19 2 storage    April .
f2_apr_1 f2_mar_1 17      15  .  19 2 backorder  April back f2 19 apl
f2_may_1 f2_apr_1 25      15  .  19 2 backorder  May   back f2 19 may
f2_mar_1 f1_mar_1 10      40  .  19 . f2_to_1    March .
f2_apr_1 f1_apr_1 11      40  .  19 . f2_to_1    April .
f2_may_1 f1_may_1 13      40  .  19 . f2_to_1    May   .
f2_mar_1 shop1_1  -297.4  250 .  19 2 sales      March .
f2_apr_1 shop1_1  -290    250 .  19 2 sales      April .
f2_may_1 shop1_1  -292    250 .  19 2 sales      May   .
f2_mar_1 shop2_1  -272.7  250 .  19 2 sales      March .
f2_apr_1 shop2_1  -312    250 .  19 2 sales      April .
f2_may_1 shop2_1  -299    250 .  19 2 sales      May   .
fact1_2  f1_mar_2 217.9   400 40 25 1 production March prod f1 25 mar
fact1_2  f1_apr_2 174.5   550 50 25 1 production April prod f1 25 apl
fact1_2  f1_may_2 133.3   350 40 25 1 production May   .
f1_mar_2 f1_apr_2 20      40  .  25 1 storage    March .
f1_apr_2 f1_may_2 18      40  .  25 1 storage    April .
f1_apr_2 f1_mar_2 32      30  .  25 1 backorder  April back f1 25 apl
f1_may_2 f1_apr_2 41      15  .  25 1 backorder  May   back f1 25 may
f1_mar_2 f2_mar_2 23      .   .  25 . f1_to_2    March .
f1_apr_2 f2_apr_2 23      .   .  25 . f1_to_2    April .
f1_may_2 f2_may_2 26      .   .  25 . f1_to_2    May   .
f1_mar_2 shop1_2  -559.76 .   .  25 1 sales      March .
f1_apr_2 shop1_2  -524.28 .   .  25 1 sales      April .
f1_may_2 shop1_2  -475.02 .   .  25 1 sales      May   .
f1_mar_2 shop2_2  -623.89 .   .  25 1 sales      March .
f1_apr_2 shop2_2  -549.68 .   .  25 1 sales      April .
f1_may_2 shop2_2  -460.00 .   .  25 1 sales      May   .
fact2_2  f2_mar_2 182.0   650 35 25 2 production March prod f2 25 mar
fact2_2  f2_apr_2 196.7   680 35 25 2 production April prod f2 25 apl
fact2_2  f2_may_2 201.4   550 35 25 2 production May   .
f2_mar_2 f2_apr_2 28      50  .  25 2 storage    March .
f2_apr_2 f2_may_2 38      50  .  25 2 storage    April .
f2_apr_2 f2_mar_2 31      15  .  25 2 backorder  April back f2 25 apl
f2_may_2 f2_apr_2 54      15  .  25 2 backorder  May   back f2 25 may
f2_mar_2 f1_mar_2 20      25  .  25 . f2_to_1    March .
f2_apr_2 f1_apr_2 21      25  .  25 . f2_to_1    April .
f2_may_2 f1_may_2 43      25  .  25 . f2_to_1    May   .
f2_mar_2 shop1_2  -567.83 500 .  25 2 sales      March .
f2_apr_2 shop1_2  -542.19 500 .  25 2 sales      April .
f2_may_2 shop1_2  -461.56 500 .  25 2 sales      May   .
f2_mar_2 shop2_2  -542.83 500 .  25 2 sales      March .
f2_apr_2 shop2_2  -559.19 500 .  25 2 sales      April .
f2_may_2 shop2_2  -489.06 500 .  25 2 sales      May   .
;


proc optmodel;
   set <str> NODES;
   num _supdem_ {NODES} init 0;
   read data node0 into NODES=[_node_] _supdem_;

   set <str,str> ARCS;
   num _lo_ {ARCS} init 0;
   num _capac_ {ARCS} init .;
   num _cost_ {ARCS};
   num diagonal {ARCS};
   num factory {ARCS};
   str key_id {ARCS};
   str mth_made {ARCS};
   str _name_ {ARCS};
   read data arc0 nomiss into ARCS=[_tail_ _head_] _lo_ _capac_ _cost_
      diagonal factory key_id mth_made _name_;
   NODES = NODES union (union {<i,j> in ARCS} {i,j});

   var Flow {<i,j> in ARCS} >= _lo_[i,j];
   for {<i,j> in ARCS: _capac_[i,j] ne .} Flow[i,j].ub = _capac_[i,j];
   min obj = sum {<i,j> in ARCS} _cost_[i,j] * Flow[i,j];
   con balance {i in NODES}:
      sum {<(i),j> in ARCS} Flow[i,j]
      - sum {<j,(i)> in ARCS} Flow[j,i] = _supdem_[i];

   num infinity = min {r in {}} r;
   num excess = sum {i in NODES} _supdem_[i];
   if (excess > 0) then do;
      /* change equality constraint to le constraint for supply nodes */
      for {i in NODES: _supdem_[i] > 0} balance[i].lb = -infinity;
   end;
   else if (excess < 0) then do;
      /* change equality constraint to ge constraint for demand nodes */
      for {i in NODES: _supdem_[i] < 0} balance[i].ub = infinity;
   end;

   solve;

   num _supply_ {<i,j> in ARCS} =
      (if _supdem_[i] ne 0 then _supdem_[i] else .);
   num _demand_ {<i,j> in ARCS} =
      (if _supdem_[j] ne 0 then -_supdem_[j] else .);
   num _fcost_ {<i,j> in ARCS} = _cost_[i,j] * Flow[i,j].sol;

   create data arc1 from [_tail_ _head_]
      _cost_ _capac_ _lo_ _name_ _supply_ _demand_ _flow_=Flow _fcost_
      _rcost_ =
         (if Flow[_tail_,_head_].rc ne 0 then Flow[_tail_,_head_].rc else .)
      _status_ = Flow.status diagonal factory key_id mth_made;
   create data node2 from [_node_]
      _supdem_ = (if _supdem_[_node_] ne 0 then _supdem_[_node_] else .)
      _dual_ = balance.dual;
quit;

options ls=80 ps=54;
proc print data=arc1 heading=h width=min;
   var _tail_ _head_ _cost_ _capac_ _lo_ _name_
   _supply_ _demand_ _flow_ _fcost_;
   sum _fcost_;
run;
proc print data=arc1 heading=h width=min;
   var _rcost_ _status_ diagonal factory key_id mth_made;
run;
proc print data=node2;
run;

/****************************************************************
 *                                                              *
 * Example 19: Migration to OPTMODEL: Shortest Path             *
 *                                                              *
 ****************************************************************/

title 'Shortest Path Problem';
title2 'How to get Hawaiian Pineapples to a London Restaurant';

data aircost1;
   input ffrom&$13. tto&$15. _cost_;
   datalines;
Honolulu       Chicago         105
Honolulu       San Francisco    75
Honolulu       Los Angeles      68
Chicago        Boston           45
Chicago        New York         56
San Francisco  Boston           71
San Francisco  New York         48
San Francisco  Atlanta          63
Los Angeles    New York         44
Los Angeles    Atlanta          57
Boston         Heathrow London  88
New York       Heathrow London  65
Atlanta        Heathrow London  76
;


proc optmodel;
   str sourcenode = 'Honolulu';
   str sinknode = 'Heathrow London';

   set <str> NODES;
   num _supdem_ {i in NODES} = (if i = sourcenode then 1
      else if i = sinknode then -1 else 0);

   set <str,str> ARCS;
   num _lo_ {ARCS} init 0;
   num _capac_ {ARCS} init .;
   num _cost_ {ARCS};
   read data aircost1 into ARCS=[ffrom tto] _cost_;
   NODES = (union {<i,j> in ARCS} {i,j});

   var Flow {<i,j> in ARCS} >= _lo_[i,j];
   min obj = sum {<i,j> in ARCS} _cost_[i,j] * Flow[i,j];
   con balance {i in NODES}: sum {<(i),j> in ARCS} Flow[i,j]
      - sum {<j,(i)> in ARCS} Flow[j,i] = _supdem_[i];
   solve;

   num _supply_ {<i,j> in ARCS} =
      (if _supdem_[i] ne 0 then _supdem_[i] else .);
   num _demand_ {<i,j> in ARCS} =
      (if _supdem_[j] ne 0 then -_supdem_[j] else .);
   num _fcost_ {<i,j> in ARCS} = _cost_[i,j] * Flow[i,j].sol;

   create data spath from [ffrom tto]
      _cost_ _capac_ _lo_ _supply_ _demand_ _flow_=Flow _fcost_
      _rcost_ = (if Flow[ffrom,tto].rc ne 0 then Flow[ffrom,tto].rc else .)
      _status_ = Flow.status;
quit;

proc print data=spath;
   sum _fcost_;
run;