The OPTMODEL Procedure

Example 9.3 Model Construction

This example uses PROC OPTMODEL features to simplify the construction of a mathematically formulated model. The model is based on the example "An Assignment Problem" in Chapter 4, "The LP Procedure" (SAS/OR User's Guide: Mathematical Programming Legacy Procedures). A single invocation of PROC OPTMODEL replaces several steps in the PROC LP statements.

The model assigns production of various grades of cloth to a set of machines in order to maximize profit while meeting customer demand. Each machine has different capacities to produce the various grades of cloth. (See the PROC LP example "An Assignment Problem" for more details.) The mathematical formulation, where x Subscript i j k represents the amount of cloth of grade j to produce on machine k for customer i, follows:

StartLayout 1st Row 1st Column max 2nd Column sigma-summation Underscript i j k Endscripts r Subscript i j k Baseline x Subscript i j k 3rd Column Blank 2nd Row 1st Column normal s normal u normal b normal j normal e normal c normal t normal t normal o 2nd Column sigma-summation Underscript k Endscripts x Subscript i j k Baseline equals d Subscript i j Baseline 3rd Column for all i and j 3rd Row 1st Column Blank 2nd Column sigma-summation Underscript i j Endscripts c Subscript j k Baseline x Subscript i j k Baseline less-than-or-equal-to a Subscript k Baseline 3rd Column for all k 4th Row 1st Column Blank 2nd Column x Subscript i j k Baseline greater-than-or-equal-to 0 3rd Column for all i comma j comma and k EndLayout

The OBJECT, DEMAND, and RESOURCE data sets are the same as in the PROC LP example. A new data set, GRADE, is added to help separate the data from the model.

title 'An Assignment Problem';

data grade(drop=i);
   do i = 1 to 6;
      grade = 'grade'||put(i,1.);
      output;
   end;
run;
data object;
   input machine customer
         grade1 grade2 grade3 grade4 grade5 grade6;
   datalines;
1 1 102 140 105 105 125 148
1 2 115 133 118 118 143 166
1 3  70 108  83  83  88  86
1 4  79 117  87  87 107 105
1 5  77 115  90  90 105 148
2 1 123 150 125 124 154   .
2 2 130 157 132 131 166   .
2 3 103 130 115 114 129   .
2 4 101 128 108 107 137   .
2 5 118 145 130 129 154   .
3 1  83   .   .  97 122 147
3 2 119   .   . 133 163 180
3 3  67   .   .  91 101 101
3 4  85   .   . 104 129 129
3 5  90   .   . 114 134 179
4 1 108 121  79   . 112 132
4 2 121 132  92   . 130 150
4 3  78  91  59   .  77  72
4 4 100 113  76   . 109 104
4 5  96 109  77   . 105 145
;
data demand;
   input customer
         grade1 grade2 grade3 grade4 grade5 grade6;
   datalines;
1 100 100 150  150  175  250
2 300 125 300  275  310  325
3 400   0 400  500  340    0
4 250   0 750  750    0    0
5   0 600 300    0  210  360
;
data resource;
   input machine
         grade1 grade2 grade3 grade4 grade5 grade6 avail;
   datalines;
1 .250 .275 .300  .350  .310  .295  744
2 .300 .300 .305  .315  .320  .     244
3 .350 .    .     .320  .315  .300  790
4 .280 .275 .260  .     .250  .295  672
;

The following PROC OPTMODEL statements read the data sets, build the linear programming model, solve the model, and output the optimal solution to a SAS data set called SOLUTION:

proc optmodel;
   /* declare index sets */
   set CUSTOMERS;
   set <str> GRADES;
   set MACHINES;

   /* declare parameters */
   num return {CUSTOMERS, GRADES, MACHINES} init 0;
   num demand {CUSTOMERS, GRADES};
   num cost {GRADES, MACHINES} init 0;
   num avail {MACHINES};

   /* read the set of grades */
   read data grade into GRADES=[grade];

   /* read the set of customers and their demands */
   read data demand
      into CUSTOMERS=[customer]
      {j in GRADES} <demand[customer,j]=col(j)>;

   /* read the set of machines, costs, and availability */
   read data resource nomiss
      into MACHINES=[machine]
      {j in GRADES} <cost[j,machine]=col(j)>
      avail;

   /* read objective data */
   read data object nomiss
      into [machine customer]
      {j in GRADES} <return[customer,j,machine]=col(j)>;

   /* declare the model */
   var AmountProduced {CUSTOMERS, GRADES, MACHINES} >= 0;
   max TotalReturn = sum {i in CUSTOMERS, j in GRADES, k in MACHINES}
      return[i,j,k] * AmountProduced[i,j,k];
   con req_demand {i in CUSTOMERS, j in GRADES}:
      sum {k in MACHINES} AmountProduced[i,j,k] = demand[i,j];
   con req_avail {k in MACHINES}:
      sum {i in CUSTOMERS, j in GRADES}
         cost[j,k] * AmountProduced[i,j,k] <= avail[k];

   /* call the solver and save the results */
   solve;
   create data solution
      from [customer grade machine] = {i in CUSTOMERS, j in GRADES,
         k in MACHINES: AmountProduced[i,j,k].sol >= 1e-6}
      amount=AmountProduced;
quit;

The statements use both numeric (NUM) and character (STR) index sets, which are populated from the corresponding data set variables in the READ DATA statements. The OPTMODEL parameters can be either single-dimensional (AVAIL) or multiple-dimensional (COST, DEMAND, RETURN). The RETURN and COST parameters are given initial values of 0, and the NOMISS option in the READ DATA statement tells PROC OPTMODEL to read only the nonmissing values from the input data sets. The model declaration is nearly identical to the mathematical formulation. The logical condition AmountProduced[i,j,k].sol >= 1e-6 in the CREATE DATA statement ensures that only the nonzero parts of the solution appear in the SOLUTION data set. In the PROC LP example, the creation of this data set required postprocessing of the PROC LP output data set.

The solver produces the following problem summary and solution summary:

Output 9.3.1: LP Solver Result

An Assignment Problem

Problem Summary
Objective SenseMaximization
Objective FunctionTotalReturn
Objective TypeLinear
  
Number of Variables120
Bounded Above0
Bounded Below120
Bounded Below and Above0
Free0
Fixed0
  
Number of Constraints34
Linear LE (<=)4
Linear EQ (=)30
Linear GE (>=)0
Linear Range0
  
Constraint Coefficients220

Solution Summary
SolverLP
AlgorithmDual Simplex
Objective FunctionTotalReturn
Solution StatusOptimal
Objective Value871426.03763
  
Primal Infeasibility1.326346E-15
Dual Infeasibility2.450147E-16
Bound Infeasibility9.094947E-13
  
Iterations46
Presolve Time0.00
Solution Time0.00


The SOLUTION data set can be processed by PROC PRINT as follows to create a compact representation of the solution:

proc sort data=solution;
   by grade;
run;
proc print data=solution;
   id machine customer;
   by grade;
run;

These statements produce the table shown in Output 9.3.2.

Output 9.3.2: An Assignment Problem

An Assignment Problem

machinecustomeramount
41100
42300
43400
44250

machinecustomeramount
11100.000
1592.270
42125.000
45507.730

machinecustomeramount
11150.000
12300.000
13256.721
14750.000
23143.279
25300.000

machinecustomeramount
11150.000
13210.312
32275.000
33289.688
34750.000

machinecustomeramount
11175
23340
32310
35210

machinecustomeramount
11250
32325
35360


Last updated: June 22, 2026