The OPTLP Procedure

Example 12.1 Oil Refinery Problem

(View the complete code for this example.)

Consider an oil refinery scenario. A step in refining crude oil into finished oil products involves a distillation process that splits crude into various streams. Suppose there are three types of crude available: Arabian light (a_l), Arabian heavy (a_h), and Brega (br). These crudes are distilled into light naphtha (na_l), intermediate naphtha (na_i), and heating oil (h_o). These in turn are blended into two types of jet fuel. Jet fuel j_1 is made up of 30% intermediate naphtha and 70% heating oil, and jet fuel j_2 is made up of 20% light naphtha and 80% heating oil. What amounts of the three crudes maximize the profit from producing jet fuel (j_1, j_2)? This problem can be formulated as the following linear program:

subject to

StartLayout 1st Row 1st Column left-parenthesis normal n normal a normal p normal h normal a normal bar normal l right-parenthesis 2nd Column 0.035 normal a normal bar normal l 3rd Column plus 4th Column 0.03 normal a normal bar normal h 5th Column plus 6th Column 0.045 normal b normal r 7th Column equals 8th Column normal n normal a normal bar normal l 2nd Row 1st Column left-parenthesis normal n normal a normal p normal h normal a normal bar normal i right-parenthesis 2nd Column 0.1 normal a normal bar normal l 3rd Column plus 4th Column 0.075 normal a normal bar normal h 5th Column plus 6th Column 0.135 normal b normal r 7th Column equals 8th Column normal n normal a normal bar normal i 3rd Row 1st Column left-parenthesis normal h normal t normal g normal bar normal o normal i normal l right-parenthesis 2nd Column 0.39 normal a normal bar normal l 3rd Column plus 4th Column 0.3 normal a normal bar normal h 5th Column plus 6th Column 0.43 normal b normal r 7th Column equals 8th Column normal h normal bar normal o 4th Row 1st Column left-parenthesis normal b normal l normal e normal n normal d Baseline 1 right-parenthesis 2nd Column Blank 3rd Column Blank 4th Column 0.3 normal j normal bar 1 5th Column Blank 6th Column Blank 7th Column less-than-or-equal-to 8th Column normal n normal a normal bar normal i 5th Row 1st Column left-parenthesis normal b normal l normal e normal n normal d Baseline 2 right-parenthesis 2nd Column Blank 3rd Column Blank 4th Column Blank 5th Column Blank 6th Column 0.2 normal j normal bar 2 7th Column less-than-or-equal-to 8th Column normal n normal a normal bar normal l 6th Row 1st Column left-parenthesis normal b normal l normal e normal n normal d Baseline 3 right-parenthesis 2nd Column Blank 3rd Column Blank 4th Column 0.7 normal j normal bar 1 5th Column plus 6th Column 0.8 normal j normal bar 2 7th Column less-than-or-equal-to 8th Column normal h normal bar normal o 7th Row 1st Column Blank 2nd Column normal a normal bar normal l 3rd Column Blank 4th Column Blank 5th Column Blank 6th Column Blank 7th Column less-than-or-equal-to 8th Column 110 8th Row 1st Column Blank 2nd Column Blank 3rd Column Blank 4th Column normal a normal bar normal h 5th Column Blank 6th Column Blank 7th Column less-than-or-equal-to 8th Column 165 9th Row 1st Column Blank 2nd Column Blank 3rd Column Blank 4th Column Blank 5th Column Blank 6th Column normal b normal r 7th Column less-than-or-equal-to 8th Column 80 EndLayout

and

The constraints "blend1" and "blend2" ensure that j_1 and j_2 are made with the specified amounts of na_i and na_l, respectively. The constraint "blend3" is actually the reduced form of the following constraints:

where h_o1 and h_o2 are dummy variables.

You can use the following SAS code to create the input data set ex1:

data ex1;
   input field1 $ field2 $ field3 $ field4 field5 $ field6;
   datalines;
NAME        .          EX1      .     .         .
ROWS        .          .        .     .         .
 N          profit     .        .     .         .
 E          napha_l    .        .     .         .
 E          napha_i    .        .     .         .
 E          htg_oil    .        .     .         .
 L          blend1     .        .     .         .
 L          blend2     .        .     .         .
 L          blend3     .        .     .         .
COLUMNS     .          .        .     .         .
.           a_l        profit   -175  napha_l   .035
.           a_l        napha_i  .100  htg_oil   .390
.           a_h        profit   -165  napha_l   .030
.           a_h        napha_i  .075  htg_oil   .300
.           br         profit   -205  napha_l   .045
.           br         napha_i  .135  htg_oil   .430
.           na_l       napha_l  -1    blend2    -1
.           na_i       napha_i  -1    blend1    -1
.           h_o        htg_oil  -1    blend3    -1
.           j_1        profit   350   blend1    .3
.           j_1        blend3   .7    .         .
.           j_2        profit   350   blend2    .2
.           j_2        blend3   .8    .         .
BOUNDS      .          .        .     .         .
UP          .          a_l      110   .         .
UP          .          a_h      165   .         .
UP          .          br       80    .         .
ENDATA      .          .        .     .         .
;

You can use the following call to PROC OPTLP to solve the LP problem:

proc optlp data=ex1
   objsense  = max
   algorithm = primal
   primalout = ex1pout
   dualout   = ex1dout
   logfreq   = 1;
run;
%put &_OROPTLP_;

Note that the OBJSENSE=MAX option is used to indicate that the objective function is to be maximized.

The primal and dual solutions are displayed in Output 12.1.1.

Output 12.1.1: Example 1: Primal and Dual Solution Output

Primal Solution

ObsObjective Function IDRHS IDVariable
Name
Variable
Type
Objective
Coefficient
Lower
Bound
Upper BoundVariable ValueVariable
Status
Reduced Cost
1profit a_lD-1750110110.000U10.2083
2profit a_hD-16501650.000L-22.8125
3profit brD-20508080.000U2.8125
4profit na_lN001.7977E3087.450B0.0000
5profit na_iN001.7977E30821.800B0.0000
6profit h_oN001.7977E30877.300B0.0000
7profit j_1N35001.7977E30872.667B0.0000
8profit j_2N35001.7977E30833.042B0.0000

Dual Solution

ObsObjective Function IDRHS IDConstraint NameConstraint
Type
Constraint
RHS
Constraint
Lower
Bound
Constraint
Upper
Bound
Dual Variable
Value
Constraint
Status
Constraint Activity
1profit napha_lE0..0.000U0.00000
2profit napha_iE0..-145.833U0.00000
3profit htg_oilE0..-437.500U0.00000
4profit blend1L0..145.833L-0.00000
5profit blend2L0..0.000B-0.84167
6profit blend3L0..437.500L-0.00000


The progress of the solution is printed to the log as follows.

Output 12.1.2: Log: Solution Progress

NOTE: The problem EX1 has 8 variables (0 free, 0 fixed).                        
NOTE: The problem has 6 constraints (3 LE, 3 EQ, 0 GE, 0 range).                
NOTE: The problem has 19 constraint coefficients.                               
NOTE: The MPS read time is 0.00 seconds.                                        
WARNING: The objective sense has been changed to maximization.                  
NOTE: The LP presolver value AUTOMATIC is applied.                              
NOTE: The LP presolver time is 0.00 seconds.                                    
NOTE: The LP presolver removed 3 variables and 3 constraints.                   
NOTE: The LP presolver removed 6 constraint coefficients.                       
NOTE: The presolved problem has 5 variables, 3 constraints, and 13 constraint   
      coefficients.                                                             
NOTE: The LP solver is called.                                                  
NOTE: The Primal Simplex algorithm is used.                                     
                           Objective                Entering      Leaving       
      Phase Iteration        Value         Time     Variable      Variable      
       P 2          1    0.000000E+00         0        j_1         blend1 (S)   
       P 2          2    2.022784E-03         0        j_2         blend2 (S)   
       P 2          3    3.902347E-03         0         br         blend3 (S)   
       P 2          4    4.025073E-03         0        a_l            a_l       
       P 2          5    1.202248E+03         0     blend2 (S)         br       
       P 2          6    1.347921E+03         0                                 
       D 2          7    1.347917E+03         0                                 
NOTE: Optimal.                                                                  
NOTE: Objective = 1347.9166667.                                                 
NOTE: The Primal Simplex solve time is 0.00 seconds.                            
NOTE: The data set WORK.EX1POUT has 8 observations and 10 variables.            
NOTE: The data set WORK.EX1DOUT has 6 observations and 10 variables.            


Note that the %put statement immediately after the OPTLP procedure prints value of the macro variable _OROPTLP_ to the log as follows.

Output 12.1.3: Log: Value of the Macro Variable _OROPTLP_

STATUS=OK ALGORITHM=PS SOLUTION_STATUS=OPTIMAL OBJECTIVE=1347.9166667           
PRIMAL_INFEASIBILITY=2.795912E-15 DUAL_INFEASIBILITY=0 BOUND_INFEASIBILITY=0    
ITERATIONS=7 PRESOLVE_TIME=0.00 SOLUTION_TIME=0.00                              


The value briefly summarizes the status of the OPTLP procedure upon termination.

Alternatively, you can use an MPS-format file instead of a data set. Using the MPS-format file is typically faster than using the data set for large instances. You can use the following file ex1.mps:

   NAME                   EX1
   ROWS
    N          profit
    E          napha_l
    E          napha_i
    E          htg_oil
    L          blend1
    L          blend2
    L          blend3
   COLUMNS
               a_l        profit   -175  napha_l   .035
               a_l        napha_i  .100  htg_oil   .390
               a_h        profit   -165  napha_l   .030
               a_h        napha_i  .075  htg_oil   .300
               br         profit   -205  napha_l   .045
               br         napha_i  .135  htg_oil   .430
               na_l       napha_l  -1    blend2    -1
               na_i       napha_i  -1    blend1    -1
               h_o        htg_oil  -1    blend3    -1
               j_1        profit   350   blend1    .3
               j_1        blend3   .7
               j_2        profit   350   blend2    .2
               j_2        blend3   .8
   BOUNDS
    UP         .          a_l      110
    UP         .          a_h      165
    UP         .          br       80
   ENDATA

You can use the following call to PROC OPTLP to solve the LP problem:

proc optlp mpsfile='ex1.mps'
   objsense  = max
   algorithm = primal
   primalout = ex1pout
   dualout   = ex1dout
   printlevel = 0
   logfreq   = 1;
run;
%put &_OROPTLP_;

The output is the same as when you use the data set for input.

Last updated: April 14, 2021