Food Manufacture 2: Limiting the Number of Ingredients and Adding Extra Conditions


PROC OPTMODEL Statements and Output

For completeness, all statements are shown. Statements that are new or changed from Chapter 1 are indicated.

proc optmodel;
   set <str> OILS;
   num hardness {OILS};
   read data hardness_data into OILS=[oil] hardness;

   set PERIODS;
   num cost {OILS, PERIODS};
   read data cost_data into PERIODS=[_N_] {oil in OILS}
      <cost[oil,_N_]=col(oil)>;

   var Buy {OILS, PERIODS} >= 0;
   var Use {OILS, PERIODS} >= 0;
   impvar Manufacture {period in PERIODS} = sum {oil in OILS} Use[oil,period];

   num last_period = max {period in PERIODS} period;
   var Store {OILS, PERIODS union {0}} >= 0 <= &store_ub;
   for {oil in OILS} do;
      fix Store[oil,0]           = &init_storage;
      fix Store[oil,last_period] = &init_storage;
   end;

   set VEG = {oil in OILS: substr(oil,1,3) = 'veg'};
   set NONVEG = OILS diff VEG;

   impvar Revenue =
      sum {period in PERIODS} &revenue_per_ton * Manufacture[period];
   impvar RawCost =
      sum {oil in OILS, period in PERIODS} cost[oil,period] * Buy[oil,period];
   impvar StorageCost =
      sum {oil in OILS, period in PERIODS}
         &storage_cost_per_ton * Store[oil,period];
   max Profit = Revenue - RawCost - StorageCost;

   con Veg_ub_con {period in PERIODS}:
      sum {oil in VEG} Use[oil,period] <= &veg_ub;

   con Nonveg_ub_con {period in PERIODS}:
      sum {oil in NONVEG} Use[oil,period] <= &nonveg_ub;

   con Flow_balance_con {oil in OILS, period in PERIODS}:
      Store[oil,period-1] + Buy[oil,period]
         = Use[oil,period] + Store[oil,period];

   con Hardness_ub_con {period in PERIODS}:
      sum {oil in OILS} hardness[oil] * Use[oil,period]
      >= &hardness_lb * Manufacture[period];

   con Hardness_lb_con {period in PERIODS}:
      sum {oil in OILS} hardness[oil] * Use[oil,period]
      <= &hardness_ub * Manufacture[period];

The remaining statements are new in this example. The BINARY option in the following VAR statement declares IsUsed to be a binary variable:

   var IsUsed {OILS, PERIODS} binary;

The .ub variable suffix imposes an upper bound on the Use variable, in preparation for the subsequent Link constraint. The validity of this upper bound follows from the Veg_ub_con and Nonveg_ub_con constraints.

   for {period in PERIODS} do;
      for {oil in VEG}    Use[oil,period].ub = &veg_ub;
      for {oil in NONVEG} Use[oil,period].ub = &nonveg_ub;
   end;

The following Link constraint enforces the rule that $\Variable{Use[oil,period]} > 0$ implies that $\Variable{IsUsed[oil,period]} = 1$:

   con Link {oil in OILS, period in PERIODS}:
      Use[oil,period] <= Use[oil,period].ub * IsUsed[oil,period];

The following Logical1, Logical2, and Logical3 constraints correspond directly to the three extra conditions in the problem statement:

   con Logical1 {period in PERIODS}:
      sum {oil in OILS} IsUsed[oil,period] <= &max_num_oils_used;

   con Logical2 {oil in OILS, period in PERIODS}:
      Use[oil,period] >= &min_oil_used_threshold * IsUsed[oil,period];

   con Logical3 {oil in {'veg1','veg2'}, period in PERIODS}:
      IsUsed[oil,period] <= IsUsed['oil3',period];

   num hardness_sol {period in PERIODS} =
      (sum {oil in OILS} hardness[oil] * Use[oil,period].sol)
         / Manufacture[period].sol;

Because PROC OPTMODEL automatically recognizes that this model is a mixed integer linear programming problem, the following SOLVE statement calls the MILP solver, as shown in Figure 2.1:

   solve;

Figure 2.1: Summaries from Mixed Integer Linear Programming Solver

The OPTMODEL Procedure

Problem Summary
Objective Sense Maximization
Objective Function Profit
Objective Type Linear
   
Number of Variables 125
Bounded Above 0
Bounded Below 30
Bounded Below and Above 85
Free 0
Fixed 10
Binary 30
Integer 0
   
Number of Constraints 132
Linear LE (<=) 66
Linear EQ (=) 30
Linear GE (>=) 36
Linear Range 0
   
Constraint Coefficients 384

Performance Information
Execution Mode Single-Machine
Number of Threads 4

Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function Profit
Solution Status Optimal within Relative Gap
Objective Value 100278.70394
   
Relative Gap 0.0000982655
Absolute Gap 9.8549012096
Primal Infeasibility 2.096101E-13
Bound Infeasibility 4.940492E-14
Integer Infeasibility 1.0566756E-6
   
Best Bound 100288.55884
Nodes 359
Iterations 6333
Presolve Time 0.01
Solution Time 0.22



The following PRINT statement creates the output shown in Figure 2.2:

   print Buy Use Store IsUsed Manufacture hardness_sol Logical1.body;

The .body constraint suffix accesses the left-hand side value of the Logical1 constraint. For each period, the solution uses no more than three oils, as shown in Figure 2.2. The following CREATE DATA statements create multiple output data sets, as in Chapter 1:

   create data sol_data1 from [oil period] Buy Use Store IsUsed;
   create data sol_data2 from [period] Manufacture;
quit;

Figure 2.2: Output from Mixed Integer Linear Programming Solver

[1] [2] Buy Use Store IsUsed
oil1 0     500.00  
oil1 1 0.00 0.00000000 500.00 0.0000000000
oil1 2 0.00 0.00000000 500.00 0.0000000000
oil1 3 0.00 0.00000000 500.00 0.0000000000
oil1 4 0.00 0.00000000 500.00 0.0000000000
oil1 5 -0.00 -0.00000000 500.00 0.0000000000
oil1 6 -0.00 0.00001304 500.00 0.0000000521
oil2 0     500.00  
oil2 1 0.00 0.00000000 500.00 0.0000000000
oil2 2 190.00 230.00000000 460.00 1.0000000000
oil2 3 0.00 0.00000000 460.00 0.0000000000
oil2 4 -0.00 230.00000000 230.00 1.0000000000
oil2 5 0.00 230.00000000 0.00 1.0000000000
oil2 6 730.00 230.00000696 500.00 0.9999999433
oil3 0     500.00  
oil3 1 0.00 250.00000000 250.00 1.0000000000
oil3 2 -0.00 20.00000000 230.00 1.0000000000
oil3 3 40.00 250.00000000 20.00 1.0000000000
oil3 4 0.00 20.00000000 0.00 1.0000000000
oil3 5 540.00 20.00000000 520.00 1.0000000000
oil3 6 -0.00 19.99998001 500.00 0.9999990003
veg1 0     500.00  
veg1 1 0.00 85.18518519 414.81 1.0000000000
veg1 2 0.00 0.00000000 414.81 0.0000000000
veg1 3 -0.00 85.18518519 329.63 1.0000000000
veg1 4 -0.00 155.00000000 174.63 1.0000000000
veg1 5 -0.00 155.00000000 19.63 1.0000000000
veg1 6 480.37 0.00017144 500.00 0.0000010567
veg2 0     500.00  
veg2 1 0.00 114.81481481 385.19 1.0000000000
veg2 2 0.00 200.00000000 185.19 1.0000000000
veg2 3 0.00 114.81481481 70.37 1.0000000000
veg2 4 0.00 0.00000000 70.37 0.0000000000
veg2 5 0.00 0.00000000 70.37 0.0000000000
veg2 6 629.63 199.99980006 500.00 0.9999990003

[1] Manufacture hardness_sol Logical1.BODY
1 450 6.00 3
2 450 5.08 3
3 450 6.00 3
4 405 6.00 3
5 405 6.00 3
6 450 5.08 3



Note that the maximum profit of £100,279 is smaller than in Chapter 1. This result is expected because this model contains additional constraints.