The first several PROC OPTMODEL statements declare index sets and parameters and then read the input data:
proc optmodel; set <str> RAWS; num supply {RAWS}; read data raw_material_data into RAWS=[raw] supply; set <str> PRODUCTS; num prev_demand {PRODUCTS}; num prev_price {PRODUCTS}; num percent {PRODUCTS, RAWS}; read data product_data into PRODUCTS=[product] {raw in RAWS} <percent[product,raw]=col(raw)> prev_demand prev_price; num elasticity {PRODUCTS, PRODUCTS} init 0; read data elasticity_data into [i j] elasticity;
The following model declaration statements correspond directly to the mathematical programming formulation that is described earlier:
var Price {PRODUCTS} >= 0; var Demand {PRODUCTS} >= 0; max TotalRevenue = sum {product in PRODUCTS} Price[product] * Demand[product]; con Demand_con {i in PRODUCTS}: (Demand[i] - prev_demand[i]) / prev_demand[i] = sum {j in PRODUCTS} elasticity[i,j] * (Price[j] - prev_price[j]) / prev_price[j]; con Supply_con {raw in RAWS: supply[raw] ne .}: sum {product in PRODUCTS} (percent[product,raw]/100) * Demand[product] <= supply[raw]; con Price_index_con: sum {product in PRODUCTS} prev_demand[product] * Price[product] <= sum {product in PRODUCTS} prev_demand[product] * prev_price[product];
In this example, all variables are real, the objective function is quadratic, and all constraints are linear. So PROC OPTMODEL automatically recognizes that this model is a quadratic programming problem, and the first SOLVE statement calls the quadratic programming solver. In this case, the QP solver detects that this maximization problem has a nonconcave objective, and PROC OPTMODEL instead calls the default nonlinear programming algorithm, which is the interior point algorithm.
solve; print Price Demand; print Price_index_con.dual;
Figure 21.1 shows the output when you use the (default) NLP interior point algorithm.
Figure 21.1: Output from NLP Interior Point Algorithm
Problem Summary | |
---|---|
Objective Sense | Maximization |
Objective Function | TotalRevenue |
Objective Type | Quadratic |
Number of Variables | 8 |
Bounded Above | 0 |
Bounded Below | 8 |
Bounded Below and Above | 0 |
Free | 0 |
Fixed | 0 |
Number of Constraints | 7 |
Linear LE (<=) | 3 |
Linear EQ (=) | 4 |
Linear GE (>=) | 0 |
Linear Range | 0 |
Constraint Coefficients | 22 |
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 4 |
Solution Summary | |
---|---|
Solver | NLP |
Algorithm | Interior Point |
Objective Function | TotalRevenue |
Solution Status | Optimal |
Objective Value | 1991585756.6 |
Optimality Error | 7.8188336E-7 |
Infeasibility | 7.8188336E-7 |
Iterations | 36 |
Presolve Time | 0.00 |
Solution Time | 0.31 |
[1] | Price | Demand |
---|---|---|
Butter | 667.31 | 383231 |
Cheese1 | 889.57 | 251767 |
Cheese2 | 1066.21 | 57091 |
Milk | 303.84 | 4775602 |
Price_index_con.DUAL |
---|
0.6142 |
To invoke the active set algorithm (which is not the default NLP algorithm), you can use the ALGORITHM= option in the SOLVE
WITH NLP statement:
solve with NLP / algorithm=activeset; print Price Demand; print Price_index_con.dual; quit;
Figure 21.2 shows the output when you use the ALGORITHM=ACTIVESET option to invoke the active set algorithm.
Figure 21.2: Output from NLP Active Set Algorithm
Problem Summary | |
---|---|
Objective Sense | Maximization |
Objective Function | TotalRevenue |
Objective Type | Quadratic |
Number of Variables | 8 |
Bounded Above | 0 |
Bounded Below | 8 |
Bounded Below and Above | 0 |
Free | 0 |
Fixed | 0 |
Number of Constraints | 7 |
Linear LE (<=) | 3 |
Linear EQ (=) | 4 |
Linear GE (>=) | 0 |
Linear Range | 0 |
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 4 |
Solution Summary | |
---|---|
Solver | NLP |
Algorithm | Active Set |
Objective Function | TotalRevenue |
Solution Status | Optimal |
Objective Value | 1991586428.8 |
Optimality Error | 4.594317E-13 |
Infeasibility | 6.5999232E-7 |
Iterations | 63 |
Presolve Time | 0.00 |
Solution Time | 0.07 |
[1] | Price | Demand |
---|---|---|
Butter | 667.29 | 383255 |
Cheese1 | 889.89 | 251695 |
Cheese2 | 1066.17 | 57101 |
Milk | 303.83 | 4775681 |
Price_index_con.DUAL |
---|
0.6161 |
The optimal solutions and dual values for the two algorithms agree.
You can also replace the Demand
and Demand_con declarations with the following IMPVAR and CON statements to perform the substitutions that are described
on page 299 of Williams (1999):
impvar Demand {i in PRODUCTS} = prev_demand[i] * (1 + sum {j in PRODUCTS} elasticity[i,j] * (Price[j] - prev_price[j]) / prev_price[j]); con Demand_nonnegative {i in PRODUCTS}: Demand[i] >= 0;
The resulting formulation is mathematically equivalent but yields a concave objective function, as shown in Williams (1999).
Figure 21.3 shows the output when you use the (default) quadratic programming solver on the reformulated problem.
Figure 21.3: Output from Quadratic Programming Solver, Reformulated Problem
Problem Summary | |
---|---|
Objective Sense | Maximization |
Objective Function | TotalRevenue |
Objective Type | Quadratic |
Number of Variables | 4 |
Bounded Above | 0 |
Bounded Below | 4 |
Bounded Below and Above | 0 |
Free | 0 |
Fixed | 0 |
Number of Constraints | 7 |
Linear LE (<=) | 3 |
Linear EQ (=) | 0 |
Linear GE (>=) | 4 |
Linear Range | 0 |
Constraint Coefficients | 16 |
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 4 |
Solution Summary | |
---|---|
Solver | QP |
Algorithm | Interior Point |
Objective Function | TotalRevenue |
Solution Status | Optimal |
Objective Value | 1991585591.9 |
Primal Infeasibility | 0 |
Dual Infeasibility | 3.407224E-17 |
Bound Infeasibility | 0 |
Duality Gap | 2.394259E-16 |
Complementarity | 0 |
Iterations | 10 |
Presolve Time | 0.00 |
Solution Time | 0.00 |
[1] | Price | Demand |
---|---|---|
Butter | 667.29 | 383255 |
Cheese1 | 889.89 | 251695 |
Cheese2 | 1066.17 | 57101 |
Milk | 303.83 | 4775678 |
Price_index_con.DUAL |
---|
0.6161 |
Figure 21.4 shows the output when you use the WITH NLP option to invoke the nonlinear programming interior point algorithm on the reformulated problem.
Figure 21.4: Output from NLP Interior Point Algorithm, Reformulated Problem
Problem Summary | |
---|---|
Objective Sense | Maximization |
Objective Function | TotalRevenue |
Objective Type | Quadratic |
Number of Variables | 4 |
Bounded Above | 0 |
Bounded Below | 4 |
Bounded Below and Above | 0 |
Free | 0 |
Fixed | 0 |
Number of Constraints | 7 |
Linear LE (<=) | 3 |
Linear EQ (=) | 0 |
Linear GE (>=) | 4 |
Linear Range | 0 |
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 4 |
Solution Summary | |
---|---|
Solver | NLP |
Algorithm | Interior Point |
Objective Function | TotalRevenue |
Solution Status | Optimal |
Objective Value | 1991585591.9 |
Optimality Error | 5E-7 |
Infeasibility | 0 |
Iterations | 7 |
Presolve Time | 0.00 |
Solution Time | 0.01 |
[1] | Price | Demand |
---|---|---|
Butter | 667.29 | 383255 |
Cheese1 | 889.89 | 251696 |
Cheese2 | 1066.17 | 57101 |
Milk | 303.83 | 4775678 |
Price_index_con.DUAL |
---|
0.6161 |
Figure 21.5 shows the output when you use the ALGORITHM=ACTIVESET option to invoke the active set algorithm on the reformulated problem.
Figure 21.5: Output from NLP Active Set Algorithm, Reformulated Problem
Problem Summary | |
---|---|
Objective Sense | Maximization |
Objective Function | TotalRevenue |
Objective Type | Quadratic |
Number of Variables | 4 |
Bounded Above | 0 |
Bounded Below | 4 |
Bounded Below and Above | 0 |
Free | 0 |
Fixed | 0 |
Number of Constraints | 7 |
Linear LE (<=) | 3 |
Linear EQ (=) | 0 |
Linear GE (>=) | 4 |
Linear Range | 0 |
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 4 |
Solution Summary | |
---|---|
Solver | NLP |
Algorithm | Active Set |
Objective Function | TotalRevenue |
Solution Status | Optimal |
Objective Value | 1991585591.9 |
Optimality Error | 5.702343E-10 |
Infeasibility | 0 |
Iterations | 7 |
Presolve Time | 0.00 |
Solution Time | 0.01 |
[1] | Price | Demand |
---|---|---|
Butter | 667.29 | 383255 |
Cheese1 | 889.89 | 251695 |
Cheese2 | 1066.17 | 57101 |
Milk | 303.83 | 4775678 |
Price_index_con.DUAL |
---|
0.61608 |
The optimal solutions and dual values for all three algorithms agree with the previous results.