For completeness, all statements are shown. Statements that are new or changed from Chapter 16 are indicated.
proc optmodel; set PERIODS; num length {PERIODS}; num demand {PERIODS}; read data period_data into PERIODS=[_N_] length demand; set TYPES; num num_avail {TYPES}; num min_level {TYPES}; num max_level {TYPES}; num unit_cost {TYPES}; num excess_cost {TYPES}; num startup_cost {TYPES}; read data type_data into TYPES=[_N_] num_avail min_level max_level unit_cost excess_cost startup_cost; var NumWorking {PERIODS, type in TYPES} >= 0 <= num_avail[type] integer; var Excess {PERIODS, TYPES} >= 0; var NumStartup {PERIODS, type in TYPES} >= 0 <= num_avail[type] integer; impvar Output {period in PERIODS, type in TYPES} = min_level[type] * NumWorking[period,type] + Excess[period,type];
The following statements declare the additional index set and parameters and then read the additional input data:
set <str> HYDROS; num hydro_level {HYDROS}; num hydro_unit_cost {HYDROS}; num hydro_depth_rate {HYDROS}; num hydro_startup_cost {HYDROS}; read data hydro_data into HYDROS=[hydro] hydro_level=level hydro_unit_cost=unit_cost hydro_depth_rate=depth_rate hydro_startup_cost=startup_cost;
The following statements declare additional variables and fix the value of Depth[1]
:
var HydroNumWorking {PERIODS, HYDROS} binary; var HydroNumStartup {PERIODS, HYDROS} binary; var Depth {PERIODS} >= &min_depth <= &max_depth; fix Depth[1] = &midnight_depth; var Pump {PERIODS} >= 0;
The following IMPVAR statement declares HydroOutput
as a new implicit variable:
impvar HydroOutput {period in PERIODS, hydro in HYDROS} = hydro_level[hydro] * HydroNumWorking[period,hydro];
The following MIN statement is a modification of the objective declaration from Chapter 16:
min TotalCost = sum {period in PERIODS, type in TYPES} ( unit_cost[type] * length[period] * NumWorking[period,type] + excess_cost[type] * length[period] * Excess[period,type] + startup_cost[type] * NumStartup[period,type]) + sum {period in PERIODS, hydro in HYDROS} ( hydro_unit_cost[hydro] * length[period] * HydroNumWorking[period,hydro] + hydro_startup_cost[hydro] * HydroNumStartup[period,hydro]);
The following two CON statements are modified from Chapter 16:
con Demand_con {period in PERIODS}: sum {type in TYPES} Output[period,type] + sum {hydro in HYDROS} HydroOutput[period,hydro] - Pump[period] >= demand[period]; con Reserve_con {period in PERIODS}: sum {type in TYPES} max_level[type] * NumWorking[period,type] + sum {hydro in HYDROS} hydro_level[hydro] * HydroNumWorking[period,hydro].ub >= (1 + &reserve) * demand[period]; con Excess_ub {period in PERIODS, type in TYPES}: Excess[period,type] <= (max_level[type] - min_level[type]) * NumWorking[period,type]; con Startup_con {period in PERIODS, type in TYPES}: NumStartup[period,type] >= NumWorking[period,type] - (if period - 1 in PERIODS then NumWorking[period-1,type] else NumWorking[card(PERIODS),type]);
The following two CON statements declare the final two additional constraints:
con Hydro_startup_con {period in PERIODS, hydro in HYDROS}: HydroNumStartup[period,hydro] >= HydroNumWorking[period,hydro] - (if period - 1 in PERIODS then HydroNumWorking[period-1,hydro] else HydroNumWorking[card(PERIODS),hydro]); con Depth_con {period in PERIODS}: (if period + 1 in PERIODS then Depth[period+1] else Depth[1]) = Depth[period] + &meters_per_mwh * length[period] * Pump[period] - sum {hydro in HYDROS} hydro_depth_rate[hydro] * length[period] * HydroNumWorking[period,hydro];
The following statements call the mixed integer linear programming solver, print the optimal solution, and create several data sets that contain various parts of the optimal solution, with variables grouped according to their index sets:
solve; print NumWorking NumStartup Excess Output; print HydroNumWorking HydroNumStartup HydroOutput; print Pump Depth; create data sol_data1 from [period type] NumWorking NumStartup Excess Output; create data sol_data2 from [period hydro] HydroNumWorking HydroNumStartup HydroOutput; create data sol_data3 from [period] Pump Depth; quit;
Figure 17.1 shows the output from the mixed integer linear programming solver.
Figure 17.1: Output from Mixed Integer Linear Programming Solver
Problem Summary | |
---|---|
Objective Sense | Minimization |
Objective Function | TotalCost |
Objective Type | Linear |
Number of Variables | 75 |
Bounded Above | 0 |
Bounded Below | 20 |
Bounded Below and Above | 54 |
Free | 0 |
Fixed | 1 |
Binary | 20 |
Integer | 30 |
Number of Constraints | 55 |
Linear LE (<=) | 15 |
Linear EQ (=) | 5 |
Linear GE (>=) | 35 |
Linear Range | 0 |
Constraint Coefficients | 190 |
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 1 |
Solution Summary | |
---|---|
Solver | MILP |
Algorithm | Branch and Cut |
Objective Function | TotalCost |
Solution Status | Optimal within Relative Gap |
Objective Value | 986630 |
Relative Gap | 0.0000715274 |
Absolute Gap | 70.566037736 |
Primal Infeasibility | 3.552714E-15 |
Bound Infeasibility | 0 |
Integer Infeasibility | 0 |
Best Bound | 986559.43396 |
Nodes | 30 |
Iterations | 264 |
Presolve Time | 0.00 |
Solution Time | 0.09 |
[1] | [2] | NumWorking | NumStartup | Excess | Output |
---|---|---|---|---|---|
1 | 1 | 12 | 0 | 365 | 10565 |
1 | 2 | 3 | 0 | 1500 | 5250 |
1 | 3 | 0 | 0 | 0 | 0 |
2 | 1 | 12 | 0 | 4050 | 14250 |
2 | 2 | 9 | 6 | 4500 | 15750 |
2 | 3 | 0 | 0 | 0 | 0 |
3 | 1 | 12 | 0 | 0 | 10200 |
3 | 2 | 9 | 0 | 4500 | 15750 |
3 | 3 | 0 | 0 | 0 | 0 |
4 | 1 | 12 | 0 | 11150 | 21350 |
4 | 2 | 9 | 0 | 4500 | 15750 |
4 | 3 | 1 | 1 | 0 | 1500 |
5 | 1 | 12 | 0 | 0 | 10200 |
5 | 2 | 9 | 0 | 4500 | 15750 |
5 | 3 | 0 | 0 | 0 | 0 |
[1] | [2] | HydroNumWorking | HydroNumStartup | HydroOutput |
---|---|---|---|---|
1 | A | 0 | 0 | 0 |
1 | B | 0 | 0 | 0 |
2 | A | 0 | 0 | 0 |
2 | B | 0 | 0 | 0 |
3 | A | 0 | 0 | 0 |
3 | B | 0 | 0 | 0 |
4 | A | 0 | 0 | 0 |
4 | B | 1 | 1 | 1400 |
5 | A | 0 | 0 | 0 |
5 | B | 1 | 0 | 1400 |
[1] | Pump | Depth |
---|---|---|
1 | 815 | 16.00 |
2 | 0 | 17.63 |
3 | 950 | 17.63 |
4 | 0 | 19.53 |
5 | 350 | 18.12 |