Sas Guide PDF
Sas Guide PDF
Sas Guide PDF
Technical Review Manoj Chari, Ed Hughes, Yu-Min Lin, Leo Lopes, Michelle Opp
vi
Introduction
This book contains all 29 examples from the classic book Model Building in Mathematical Programming by
H. Paul Williams. For each example, the problem statement is first repeated verbatim from Williams (1999)
for the first 24 chapters and from Williams (2013) for the remaining chapters.1 Then the problem is solved
using the OPTMODEL procedure in SAS/OR software.
The examples cover linear programming, mixed integer linear programming, and quadratic programming. In
most cases, the problem is solved with a single call to one of the mathematical programming solvers available
in PROC OPTMODEL. The purpose of this book is to supplement the SAS/OR User’s Guide: Mathematical
Programming with additional examples that demonstrate best practices.
Each chapter contains five sections, described as follows.
Problem Statement:
Repeats verbatim the problem description, including any tables and figures, from Williams (1999) or
Williams (2013).
Input Data:
Creates the input data sets and macro variables to be used by PROC OPTMODEL.
Features Demonstrated:
Lists the important PROC OPTMODEL features demonstrated in this example.
1 Figuresand tables are numbered differently so that they match the chapter organization of this book. To be consistent with the
verbatim problem statement, all other sections use British spelling. However, for clarity, large numbers and decimals are punctuated
in American style (for example, 10,000 instead of 10 000 and 0.5 instead of 05), words are occasionally added or changed (with the
changes shown inside square brackets), and punctuation is occasionally changed.
2 F CONTENTS
Although PROC OPTMODEL is case-insensitive, in the interest of clarity a few typographical conventions
are observed regarding capitalization of names:
The examples shown here are small and not computationally challenging. Throughout, a separation between
data and model is maintained so that you can solve larger or more difficult instances without modifying the
PROC OPTMODEL statements. A user who learns the techniques demonstrated in these examples will
be well-prepared to use PROC OPTMODEL to tackle similar modeling challenges that arise in real-world
problems.
Chapter 1
Food Manufacture 1: When to Buy and How to
Blend
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Problem Statement
A food is manufactured by refining raw oils and blending them together.1 The raw oils come in two categories:
Each oil may be purchased for immediate delivery (January) or bought on the futures market for delivery in a
subsequent month. Prices now and in the futures market are given below (in £/ton):
It is possible to store up to 1000 tons of each raw oil for use later. The cost of storage for vegetable and
non-vegetable oil is £5 per ton per month. The final product cannot be stored, nor can refined oils be stored.
There is a technological restriction of hardness on the final product. In the units in which hardness is measured
this must lie between 3 and 6. It is assumed that hardness blends linearly and that the hardnesses of the raw
oils are
VEG 1 8.8
VEG 2 6.1
OIL 1 2.0
OIL 2 4.2
OIL 3 5.0
What buying and manufacturing policy should the company pursue in order to maximize profit?
At present there are 500 tons of each type of raw oil in storage. It is required that these stocks will also exist
at the end of June.
oil 2 OILS
period 2 PERIODS
Parameters
Table 1.1 shows the parameters that are used in this example.
Variables
Table 1.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following profit function, where Revenue, RawCost, and StorageCost are
linear functions of Manufacture, Buy, and Store, respectively:
Constraints
The following constraints are used in this example:
Input Data
The following data sets contain the input data that are used in this example:
data cost_data;
input veg1-veg2 oil1-oil3;
datalines;
110 120 130 110 115
130 130 110 90 115
110 140 130 100 95
120 110 120 120 125
100 120 150 110 105
90 100 140 80 135
;
data hardness_data;
input oil $ hardness;
datalines;
PROC OPTMODEL Statements and Output F 7
veg1 8.8
veg2 6.1
oil1 2.0
oil2 4.2
oil3 5.0
;
It is possible to store the other (scalar) parameters in an additional data set that contains one observation, with
one data set variable per parameter. But the SAS macro language is used instead, with one macro variable
per parameter.
proc optmodel;
set <str> OILS;
num hardness {OILS};
read data hardness_data into OILS=[oil] hardness;
print hardness;
The PRINT statement results in the first section of output, shown in Figure 1.1.
[1] hardness
oil1 2.0
oil2 4.2
oil3 5.0
veg1 8.8
veg2 6.1
The second READ DATA statement populates the PERIODS index set and uses the already-populated OILS
index set to loop across data set variables when reading the two-dimensional cost data. The PERIODS index
set is numeric and is populated by using the automatic variable _N_ from the cost_data data set, rather than
by using the month names.
8 F Chapter 1: Food Manufacture 1
set PERIODS;
num cost {OILS, PERIODS};
read data cost_data into PERIODS=[_N_] {oil in OILS}
<cost[oil,_N_]=col(oil)>;
print cost;
The PRINT statement results in the second section of output, shown in Figure 1.2.
cost
1 2 3 4 5 6
oil1 130 110 130 120 150 140
oil2 110 90 100 120 110 80
oil3 115 115 95 125 105 135
veg1 110 130 110 120 100 90
veg2 120 130 140 110 120 100
You can declare implicit variables with the IMPVAR statement, instead of defining explicit variables by using
the VAR statement with an additional constraint. When you use the IMPVAR statement, PROC OPTMODEL
performs an algebraic substitution, thereby reducing the number of variables and constraints passed to the
solver.
The following statements declare implicit variables, the objective, and constraints:
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;
expand;
This optional statement is useful for debugging purposes, to make sure that the model that PROC OPTMODEL
creates is what you intended.
10 F Chapter 1: Food Manufacture 1
By using the .sol suffix, the numeric parameter hardness_sol computes hardness of the final product from
the optimal decision variable values returned by the solver:
solve;
print Buy Use Store Manufacture hardness_sol;
Multiple CREATE DATA statements, with the variables of interest grouped according to their index sets,
create multiple output data sets (not shown):
Figure 1.4 shows the output when you use the (default) dual simplex algorithm.
Problem Summary
Objective Sense Maximization
Objective Function Profit
Objective Type Linear
Number of Variables 95
Bounded Above 0
Bounded Below 60
Bounded Below and Above 25
Free 0
Fixed 10
Number of Constraints 54
Linear LE (<=) 18
Linear EQ (=) 30
Linear GE (>=) 6
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Profit
Solution Status Optimal
Objective Value 107842.59259
Iterations 66
Presolve Time 0.00
Solution Time 0.00
16 F Chapter 1: Food Manufacture 1
Figure 1.5 shows the output when you use the ALGORITHM=PS option to invoke the primal simplex
algorithm.
Problem Summary
Objective Sense Maximization
Objective Function Profit
Objective Type Linear
Number of Variables 95
Bounded Above 0
Bounded Below 60
Bounded Below and Above 25
Free 0
Fixed 10
Number of Constraints 54
Linear LE (<=) 18
Linear EQ (=) 30
Linear GE (>=) 6
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Primal Simplex
Objective Function Profit
Solution Status Optimal
Objective Value 107842.59259
Iterations 56
Presolve Time 0.00
Solution Time 0.00
18 F Chapter 1: Food Manufacture 1
Figure 1.6 shows the output when you use the ALGORITHM=IP option to invoke the interior point algorithm.
Problem Summary
Objective Sense Maximization
Objective Function Profit
Objective Type Linear
Number of Variables 95
Bounded Above 0
Bounded Below 60
Bounded Below and Above 25
Free 0
Fixed 10
Number of Constraints 54
Linear LE (<=) 18
Linear EQ (=) 30
Linear GE (>=) 6
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver LP
Algorithm Interior Point
Objective Function Profit
Solution Status Optimal
Objective Value 107842.59259
Iterations 9
Iterations2 17
Presolve Time 0.60
Solution Time 0.60
20 F Chapter 1: Food Manufacture 1
Figure 1.7 shows the output when you use the ALGORITHM=NS option to invoke the network simplex
algorithm.
Problem Summary
Objective Sense Maximization
Objective Function Profit
Objective Type Linear
Number of Variables 95
Bounded Above 0
Bounded Below 60
Bounded Below and Above 25
Free 0
Fixed 10
Number of Constraints 54
Linear LE (<=) 18
Linear EQ (=) 30
Linear GE (>=) 6
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Network Simplex
Objective Function Profit
Solution Status Optimal
Objective Value 107842.59259
Iterations 38
Iterations2 41
Presolve Time 0.00
Solution Time 0.00
22 F Chapter 1: Food Manufacture 1
Features Demonstrated
The following features are demonstrated in this example:
FIX statement
IMPVAR statement
SUBSTR function
range constraint
EXPAND statement
ALGORITHM= option
24
Chapter 2
Food Manufacture 2: Limiting the Number of
Ingredients and Adding Extra Conditions
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Problem Statement
It is wished to impose the following extra conditions on the food manufacture problem:1
(1) The food may never be made up of more than three oils in any month.
(3) If either of VEG 1 or VEG 2 is used in a month then OIL 3 must also be used.
Extend the food manufacture model to encompass these restrictions and find the new optimal solution.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, p. 232).
26 F Chapter 2: Food Manufacture 2
Parameters
Table 2.1 shows the additional parameters that are used in this example.
Variables
Table 2.2 shows the additional variables that are used in this example.
Objective
The objective is the same as in Chapter 1.
Constraints
The following additional constraints are used in this example:
IsUsed[oil,period] IsUsed[’oil3’,period]
Input Data F 27
Input Data
The following macro variables contain the additional input data that are used in this example:
%let max_num_oils_used = 3;
%let min_oil_used_threshold = 20;
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)>;
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;
solve;
PROC OPTMODEL Statements and Output F 29
Problem Summary
Objective Sense Maximization
Objective Function Profit
Objective Type Linear
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
The following PRINT statement creates the output shown in Figure 2.2:
create data sol_data1 from [oil period] Buy Use Store IsUsed;
create data sol_data2 from [period] Manufacture;
quit;
Note that the maximum profit of £100,279 is smaller than in Chapter 1. This result is expected because this
model contains additional constraints.
Features Demonstrated
The following features are demonstrated in this example:
FIX statement
IMPVAR statement
SUBSTR function
BINARY option
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Problem Statement
An engineering factory makes seven products (PROD 1 to PROD 7) on the following machines: four
grinders, two vertical drills, three horizontal drills, one borer, and one planer.1 Each product yields a certain
contribution to profit (defined as £/unit selling price minus cost of raw materials). These quantities (in £/unit)
together with the unit production times (hours) required on each process are given below. A dash indicates
that a product does not require a process.
In the present month (January) and the five subsequent months certain machines will be down for maintenance.
These machines will be:
January 1 grinder
February 2 horizontal drills
March 1 borer
April 1 vertical drill
May 1 grinder and 1 vertical drill
June 1 planer and 1 horizontal drill
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 233–234).
34 F Chapter 3: Factory Planning 1
There are marketing limitations on each product in each month. These are:
1 2 3 4 5 6 7
January 500 1000 300 300 800 200 100
February 600 500 200 0 400 300 150
March 300 600 0 0 500 400 100
April 200 300 400 500 200 0 100
May 0 100 500 100 1000 300 0
June 500 500 100 300 1100 500 60
It is possible to store up to 100 of each product at a time at a cost of £0.5 per unit per month. There are no
stocks at present but it is desired to have a stock of 50 of each type of product at the end of June.
The factory works a 6 day week with two shifts of 8 hours each day.
No sequencing problems need to be considered.
When and what should the factory make in order to maximize the total profit? Recommend any price
increases and the value of acquiring any new machines.
N.B. It may be assumed that each month consists of only 24 working days.
product 2 PRODUCTS
machine_type 2 MACHINE_TYPES
period 2 PERIODS
Parameters F 35
Parameters
Table 3.1 shows the parameters that are used in this example.
Variables
Table 3.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following function, where StorageCost is a linear function of Store:
X X
TotalProfit D profit[product] Sell[product,period] StorageCost
product2PRODUCTS period2PERIODS
36 F Chapter 3: Factory Planning 1
Constraints
The following constraints are used in this example:
num_hours_per_period num_machines_per_period[machine_type,period]
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data product_data;
input product $ profit;
datalines;
prod1 10
prod2 6
prod3 8
prod4 4
prod5 11
prod6 9
prod7 3
;
data demand_data;
input prod1-prod7;
datalines;
500 1000 300 300 800 200 100
600 500 200 0 400 300 150
300 600 0 0 500 400 100
200 300 400 500 200 0 100
0 100 500 100 1000 300 0
500 500 100 300 1100 500 60
;
data machine_type_data;
input machine_type $ num_machines;
PROC OPTMODEL Statements and Output F 37
datalines;
grinder 4
vdrill 2
hdrill 3
borer 1
planer 1
;
data machine_type_period_data;
input machine_type $ period num_down;
datalines;
grinder 1 1
hdrill 2 2
borer 3 1
vdrill 4 1
grinder 5 1
vdrill 5 1
planer 6 1
hdrill 6 1
;
data machine_type_product_data;
input machine_type $ prod1-prod7;
datalines;
grinder 0.5 0.7 0 0 0.3 0.2 0.5
vdrill 0.1 0.2 0 0.3 0 0.6 0
hdrill 0.2 0 0.8 0 0 0 0.6
borer 0.05 0.03 0 0.07 0.1 0 0.08
planer 0 0 0.01 0 0.05 0 0.05
;
proc optmodel;
set <str> PRODUCTS;
num profit {PRODUCTS};
read data product_data into PRODUCTS=[product] profit;
set PERIODS;
num demand {PRODUCTS, PERIODS};
read data demand_data into PERIODS=[_N_]
{product in PRODUCTS} <demand[product,_N_]=col(product)>;
But this problem also has sparse two-dimensional data: for most .machine_type; period/ pairs, the number
of machines down is 0. In the following statements, the INIT option in the second NUM statement initializes
num_machines_down_per_period to 0. The read of the sparse data set machine_type_period_data populates
only the nonzero values. The subsequent computation of num_machines_per_period[machine_type,period]
then uses the initial value of num_machines_down_per_period[machine_type,period] when no other value
has been supplied:
num_machines_per_period
1 2 3 4 5 6
borer 1 1 0 1 1 1
grinder 3 4 4 4 3 4
hdrill 3 1 3 3 3 2
planer 1 1 1 1 1 0
vdrill 2 2 2 1 1 2
impvar StorageCost =
sum {product in PRODUCTS, period in PERIODS}
&storage_cost_per_unit * Store[product,period];
max TotalProfit =
sum {product in PRODUCTS, period in PERIODS}
profit[product] * Sell[product,period]
- StorageCost;
solve;
print Make Sell Store;
40 F Chapter 3: Factory Planning 1
Problem Summary
Objective Sense Maximization
Objective Function TotalProfit
Objective Type Linear
Number of Constraints 72
Linear LE (<=) 30
Linear EQ (=) 42
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalProfit
Solution Status Optimal
Objective Value 93715.178571
Iterations 32
Presolve Time 0.00
Solution Time 0.00
PROC OPTMODEL Statements and Output F 41
You can use the .dual constraint suffix to access the optimal dual variables returned by the solver:
print Machine_hours_con.dual;
create data sol_data1 from [product period] Make Sell Store;
quit;
These values, shown in Figure 3.3, suggest the change in optimal objective value if the factory acquires
an additional machine in that period. For this test instance, it turns out that the positive dual variables all
correspond to machines that are down.
Machine_hours_con.DUAL
1 2 3 4 5 6
borer 0.0000 0.0000 200.0000 0.0000 0.0000 0.0000
grinder 8.5714 0.0000 0.0000 0.0000 0.0000 0.0000
hdrill 0.0000 0.6250 0.0000 0.0000 0.0000 0.0000
planer 0.0000 0.0000 0.0000 0.0000 0.0000 800.0000
vdrill 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
Features Demonstrated
The following features are demonstrated in this example:
INIT option
FIX statement
IMPVAR statement
IF-THEN/ELSE expression
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Problem Statement
Instead of stipulating when each machine is down for maintenance in the factory planning problem, it is
desired to find the best month for each machine to be down.1
Each machine must be down for maintenance in one month of the six apart from the grinding machines, only
two of which need be down in any six months.
Extend the model to allow it to make these extra decisions. How much is the extra flexibility of allowing
down times to be chosen worth?
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, p. 234).
44 F Chapter 4: Factory Planning 2
Parameters
Table 4.1 shows the additional parameters that are used in this example.
Variables
Table 4.2 shows the additional variables that are used in this example.
Objective
The objective is the same as in Chapter 3.
Constraints
The following additional constraints are used in this example:
X
production_time[product,machine_type] Make[product,period]
product2PRODUCTS
Input Data
Ignore machine_type_period_data from Chapter 3, and replace machine_type_data as follows:
data machine_type_data;
input machine_type $ num_machines num_machines_needing_maintenance;
datalines;
grinder 4 2
vdrill 2 2
hdrill 3 3
borer 1 1
planer 1 1
;
proc optmodel;
set <str> PRODUCTS;
num profit {PRODUCTS};
read data product_data into PRODUCTS=[product] profit;
set PERIODS;
num demand {PRODUCTS, PERIODS};
read data demand_data into PERIODS=[_N_]
{product in PRODUCTS} <demand[product,_N_]=col(product)>;
impvar StorageCost =
sum {product in PRODUCTS, period in PERIODS}
&storage_cost_per_unit * Store[product,period];
max TotalProfit =
sum {product in PRODUCTS, period in PERIODS}
profit[product] * Sell[product,period]
- StorageCost;
Most of the remaining statements are new or modified from Chapter 3. The INTEGER option in the following
VAR statement declares NumMachinesDown to be an integer variable:
solve;
print Make Sell Store;
print NumMachinesDown;
create data sol_data1 from [product period] Make Sell Store;
create data sol_data2 from [machine_type period] NumMachinesDown;
quit;
The solver determines when machines should be down and obtains a total profit of £108,855, as shown in
Figure 4.1. This objective value represents an increase of £15,140 from the optimal objective in Chapter 3.
PROC OPTMODEL Statements and Output F 47
Problem Summary
Objective Sense Maximization
Objective Function TotalProfit
Objective Type Linear
Number of Constraints 77
Linear LE (<=) 30
Linear EQ (=) 47
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalProfit
Solution Status Optimal within Relative Gap
Objective Value 108855
NumMachinesDown
1 2 3 4 5 6
borer 0 -0 0 1 0 0
grinder 0 0 0 0 2 0
hdrill 1 0 2 0 0 0
planer 0 0 -0 1 0 0
vdrill 0 1 0 0 1 0
As expected, the optimal numbers of machines down differ from the num_machines_down_per_period
parameter values in Chapter 3.
Features Demonstrated
The following features are demonstrated in this example:
FIX statement
IMPVAR statement
IF-THEN/ELSE expression
INTEGER option
50
Chapter 5
Manpower Planning: How to Recruit, Retrain,
Make Redundant, or Overman
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Problem Statement
A company is undergoing a number of changes which will affect its manpower requirements in future years.1
Owing to the installation of new machinery, fewer unskilled but more skilled and semi-skilled workers will
be required. In addition to this a downturn in trade is expected in the next year which will reduce the need for
workers in all categories. The estimated manpower requirements for the next three years are as follows:
The company wishes to decide its policy with regard to the following over the next three years:
(1) Recruitment
(2) Retraining
(3) Redundancy
There is a natural wastage of labour. A fairly large number of workers leave during their first year. After this
the rate is much smaller. Taking this into account, the wastage rates can be taken as below:
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 234–236).
52 F Chapter 5: Manpower Planning
There has been no recent recruitment and all workers in the current labour force have been employed for
more than one year.
Recruitment
It is possible to recruit a limited number of workers from outside. In any one year the numbers which can be
recruited in each category are:
Retraining
It is possible to retrain up to 200 unskilled workers per year to make them semi-skilled. This costs £400 per
worker. The retraining of semi-skilled workers to make them skilled is limited to no more than one quarter of
the skilled labour at the time as some training is done on the job. To retrain a semi-skilled worker in this way
costs £500.
Downgrading of workers to a lower skill is possible but 50% of such workers leave, although it costs the
company nothing. (This wastage is additional to the ‘natural wastage’ described above.)
Redundancy
The redundancy payment to an unskilled worker is £200 and to a semi-skilled or skilled worker £500.
Overmanning
It is possible to employ up to 150 more workers over the whole company than are needed but the extra costs
per employee per year are:
Short-time Working
Up to 50 workers in each category of skill can be put on short-time working. The cost of this (per employee
per year) is:
worker 2 WORKERS
period 2 PERIODS0
Parameters
Table 5.1 shows the parameters that are used in this example.
Variables
Table 5.2 shows the variables that are used in this example.
Objectives
One objective is to minimize the following function:
X X
Redundancy D NumRedundant[worker,period]
worker2WORKERS period2PERIODS
Constraints
The following constraints are used in this example:
bounds on variables
NumWorkers[worker,period]
.1 shorttime_frac / NumShortTime[worker,period]
NumExcess[worker,period]
D demand[worker,period]
NumWorkers[worker,period]
D .1 waste_old[worker] / NumWorkers[worker,period 1]
C .1 waste_new[worker] / NumRecruits[worker,period]
X
C .1 waste_old[worker] / NumRetrain[i,worker,period]
.i;worker/2RETRAIN_PAIRS
X
C .1 downgrade_leave_frac / NumDowngrade[i,worker,period]
.i;worker/2DOWNGRADE_PAIRS
X
NumRetrain[worker,j,period]
.worker;j/2RETRAIN_PAIRS
X
NumDowngrade[worker,j,period]
.worker;j/2DOWNGRADE_PAIRS
NumRedundant[worker,period]
56 F Chapter 5: Manpower Planning
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data demand_data;
input period unskilled semiskilled skilled;
datalines;
0 2000 1500 1000
1 1000 1400 1000
2 500 2000 1500
3 0 2500 2000
;
data worker_data;
input worker $12. waste_new waste_old recruit_ub redundancy_cost
overmanning_cost shorttime_ub shorttime_cost;
datalines;
unskilled 0.25 0.10 500 200 1500 50 500
semiskilled 0.20 0.05 800 500 2000 50 400
skilled 0.10 0.05 500 500 3000 50 400
;
data retrain_data;
input worker1 $12. worker2 $12. retrain_ub retrain_cost;
datalines;
unskilled semiskilled 200 400
semiskilled skilled . 500
;
data downgrade_data;
input worker1 $12. worker2 $12.;
datalines;
semiskilled unskilled
skilled semiskilled
skilled unskilled
;
proc optmodel;
set <str> WORKERS;
num waste_new {WORKERS};
num waste_old {WORKERS};
num recruit_ub {WORKERS};
num redundancy_cost {WORKERS};
num overmanning_cost {WORKERS};
num shorttime_ub {WORKERS};
num shorttime_cost {WORKERS};
read data worker_data into WORKERS=[worker]
waste_new waste_old recruit_ub redundancy_cost overmanning_cost
shorttime_ub shorttime_cost;
set PERIODS0;
num demand {WORKERS, PERIODS0};
read data demand_data into PERIODS0=[period]
{worker in WORKERS} <demand[worker,period]=col(worker)>;
The following Flow_balance_con constraint uses an implicit slice to express a few of the summations
compactly:
<i,(worker)> in RETRAIN_PAIRS
is equivalent to
i in slice(<*,worker>,RETRAIN_PAIRS)
which is equivalent to
min Redundancy =
sum {worker in WORKERS, period in PERIODS} NumRedundant[worker,period];
min Cost =
sum {worker in WORKERS, period in PERIODS} (
redundancy_cost[worker] * NumRedundant[worker,period]
+ shorttime_cost[worker] * NumShorttime[worker,period]
+ overmanning_cost[worker] * NumExcess[worker,period])
+ sum {<i,j> in RETRAIN_PAIRS, period in PERIODS}
retrain_cost[i,j] * NumRetrain[i,j,period];
The LP solver is called twice, and each SOLVE statement includes the OBJ option to specify which objective
to optimize. The first PRINT statement after each SOLVE statement reports the values of both objectives
even though only one objective is optimized at a time:
print NumDowngrade;
create data sol_data1 from [worker period]
NumWorkers NumRecruits NumRedundant NumShortTime NumExcess;
create data sol_data2 from [worker1 worker2 period] NumRetrain NumDowngrade;
Problem Summary
Objective Sense Minimization
Objective Function Redundancy
Objective Type Linear
Number of Variables 63
Bounded Above 0
Bounded Below 39
Bounded Below and Above 21
Free 0
Fixed 3
Number of Constraints 24
Linear LE (<=) 6
Linear EQ (=) 18
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
60 F Chapter 5: Manpower Planning
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Redundancy
Solution Status Optimal
Objective Value 841.796875
Iterations 14
Presolve Time 0.02
Solution Time 0.02
Redundancy Cost
841.8 1441390
Figure 5.2 shows the output that results from the second SOLVE statement.
Problem Summary
Objective Sense Minimization
Objective Function Cost
Objective Type Linear
Number of Variables 63
Bounded Above 0
Bounded Below 39
Bounded Below and Above 21
Free 0
Fixed 3
Number of Constraints 24
Linear LE (<=) 6
Linear EQ (=) 18
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
62 F Chapter 5: Manpower Planning
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Cost
Solution Status Optimal
Objective Value 498677.28532
Iterations 9
Presolve Time 0.00
Solution Time 0.00
Redundancy Cost
1423.7 498677
Features Demonstrated
The following features are demonstrated in this example:
sets of tuples
FIX statement
SLICE expression
implicit slice
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Problem Statement
An oil refinery purchases two crude oils (crude 1 and crude 2).1 These crude oils are put through four
processes: distillation, reforming, cracking, and blending, to produce petrols and fuels which are sold.
Distillation
Distillation separates each crude oil into fractions known as light naphtha, medium naphtha, heavy naphtha,
light oil, heavy oil and residuum according to their boiling points. Light, medium and heavy naphthas have
octane numbers of 90, 80 and 70 respectively. The fractions into which one barrel of each type of crude splits
are given in the table:
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 236–238).
66 F Chapter 6: Refinery Optimization
Reforming
The naphthas can be used immediately for blending into different grades of petrol or can go through a process
known as reforming. Reforming produces a product known as reformed gasoline with an octane number of
115. The yields of reformed gasoline from each barrel of the different naphthas are given below:
Cracking
The oils (light and heavy) can either be used directly for blending into jet fuel or fuel oil or be put through
a process known as catalytic cracking. The catalytic cracker produces cracked oil and cracked gasoline.
Cracked gasoline has an octane number of 105.
1 barrel of light oil yields 0.68 barrels of cracked oil and 0.28 barrels of
cracked gasoline;
1 barrel of heavy oil yields 0.75 barrels of cracked oil and 0.2 barrels of
cracked gasoline.
Cracked oil is used for blending fuel oil and jet fuel; cracked gasoline is used for blending petrol.
Residuum can be used for either producing lube-oil or blending into jet fuel and fuel oil:
Blending
Petrols (Motor Fuel)
There are two sorts of petrol, regular and premium, obtained by blending the naphtha, reformed gasoline and
cracked gasoline. The only stipulations concerning them are that regular must have an octane number of
at least 84 and that premium must have an octane number of at least 94. It is assumed that octane numbers
blend linearly by volume.
Jet Fuel
The stipulation concerning jet fuel is that its vapour pressure must not exceed 1 kilogram per square centimetre.
The vapour pressures for light, heavy and cracked oils and residuum are 1.0, 0.6, 1.5 and 0.05 kilograms per
square centimetre respectively. It may again be assumed that vapour pressures blend linearly by volume.
Mathematical Programming Formulation F 67
Fuel Oil
To produce fuel oil, light oil, cracked oil, heavy oil and residuum must be blended in the ratio 10:4:3:1.
There are availability and capacity limitations on the quantities and processes used:
(f) The daily production of lube oil must be between 500 and 1000 barrels.
(g) Premium motor fuel production must be at least 40% of regular motor fuel production.
The profit contributions from the sale of the final products are (in pence per barrel)
How should the operations of the refinery be planned in order to maximize total profit?
i 2 NODES
.i; j / 2 ARCS
product 2 FINAL_PRODUCTS
crude 2 CRUDES
oil 2 OILS
oil 2 CRACKED_OILS
petrol 2 PETROLS
Parameters F 69
Parameters
Table 6.1 shows the parameters that are used in this example.
Variables
Table 6.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following function:
X
TotalProfit D profit[i] Flow[i,‘sink’]
i 2FINAL_PRODUCTS
70 F Chapter 6: Refinery Optimization
Constraints
The following constraints are used in this example:
bounds on variables
Flow[i,j] D CrudeDistilled[i]
Flow[i,j] D OilCracked[i]
X
CrudeDistilled[i] crude_total_ub
i 2CRUDES
X
Flow[i,‘reformed_gasoline’] naphtha_ub
.i;‘reformed_gasoline’/2ARCSW
index(i ,‘naphtha’)>0
X
Flow[i,‘cracked_oil’] cracked_oil_ub
.i;‘cracked_oil’/2ARCS
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data crude_data;
input crude $ crude_ub;
datalines;
crude1 20000
crude2 30000
;
data arc_data;
input i $18. j $18. multiplier;
datalines;
source crude1 6
source crude2 6
crude1 light_naphtha 0.1
crude1 medium_naphtha 0.2
crude1 heavy_naphtha 0.2
crude1 light_oil 0.12
crude1 heavy_oil 0.2
crude1 residuum 0.13
crude2 light_naphtha 0.15
crude2 medium_naphtha 0.25
crude2 heavy_naphtha 0.18
crude2 light_oil 0.08
crude2 heavy_oil 0.19
crude2 residuum 0.12
light_naphtha regular_petrol .
light_naphtha premium_petrol .
medium_naphtha regular_petrol .
medium_naphtha premium_petrol .
heavy_naphtha regular_petrol .
heavy_naphtha premium_petrol .
light_naphtha reformed_gasoline 0.6
medium_naphtha reformed_gasoline 0.52
heavy_naphtha reformed_gasoline 0.45
light_oil jet_fuel .
light_oil fuel_oil .
heavy_oil jet_fuel .
heavy_oil fuel_oil .
light_oil light_oil_cracked 2
light_oil_cracked cracked_oil 0.68
light_oil_cracked cracked_gasoline 0.28
heavy_oil heavy_oil_cracked 2
heavy_oil_cracked cracked_oil 0.75
heavy_oil_cracked cracked_gasoline 0.2
cracked_oil jet_fuel .
cracked_oil fuel_oil .
reformed_gasoline regular_petrol .
reformed_gasoline premium_petrol .
cracked_gasoline regular_petrol .
72 F Chapter 6: Refinery Optimization
cracked_gasoline premium_petrol .
residuum lube_oil 0.5
residuum jet_fuel .
residuum fuel_oil .
;
data octane_data;
input i $18. octane;
datalines;
light_naphtha 90
medium_naphtha 80
heavy_naphtha 70
reformed_gasoline 115
cracked_gasoline 105
;
data petrol_data;
input petrol $15. octane_lb;
datalines;
regular_petrol 84
premium_petrol 94
;
data vapour_pressure_data;
input oil $12. vapour_pressure;
datalines;
light_oil 1.0
heavy_oil 0.6
cracked_oil 1.5
residuum 0.05
;
data fuel_oil_ratio_data;
input oil $12. coefficient;
datalines;
light_oil 10
cracked_oil 4
heavy_oil 3
residuum 1
;
data final_product_data;
input product $15. profit;
datalines;
premium_petrol 700
regular_petrol 600
jet_fuel 400
fuel_oil 350
lube_oil 150
;
%let vapour_pressure_ub = 1;
%let crude_total_ub = 45000;
%let naphtha_ub = 10000;
PROC OPTMODEL Statements and Output F 73
proc optmodel;
set <str,str> ARCS;
num arc_mult {ARCS} init 1;
read data arc_data nomiss into ARCS=[i j] arc_mult=multiplier;
var Flow {ARCS} >= 0;
The SETOF operator, used together with the concatenation operator (jj) in the following statements, enables
you to create one index set from another:
con Blending_jet_fuel:
sum {<i,'jet_fuel'> in ARCS}
vapour_pressure[i] * arc_mult[i,'jet_fuel'] * Flow[i,'jet_fuel']
<= &vapour_pressure_ub *
sum {<i,'jet_fuel'> in ARCS} arc_mult[i,'jet_fuel'] * Flow[i,'jet_fuel'];
Similarly, the following CON statement linearizes the fuel oil ratio constraints by clearing the denominators:
con Crude_total_ub_con:
sum {i in CRUDES} CrudeDistilled[i] <= &crude_total_ub;
PROC OPTMODEL Statements and Output F 75
The following CON statement uses the SAS function INDEX together with the colon operator (:) to select
the subset of arcs whose tail node contains ‘naphtha’ in its name:
con Naphtha_ub_con:
sum {<i,'reformed_gasoline'> in ARCS: index(i,'naphtha') > 0}
Flow[i,'reformed_gasoline']
<= &naphtha_ub;
con Cracked_oil_ub_con:
sum {<i,'cracked_oil'> in ARCS} Flow[i,'cracked_oil'] <= &cracked_oil_ub;
con Lube_oil_range_con:
&lube_oil_lb <= Flow['lube_oil','sink'] <= &lube_oil_ub;
As expressed on page 70, the premium ratio constraint involves a ratio of linear functions of the decision
variables. The following CON statement linearizes the nonlinear ratio constraint by clearing the denominator:
con Premium_ratio_con:
sum {<'premium_petrol',j> in ARCS} Flow['premium_petrol',j]
>= &premium_ratio *
sum {<'regular_petrol',j> in ARCS} Flow['regular_petrol',j];
num vapour_pressure_sol =
(sum {<i,'jet_fuel'> in ARCS} vapour_pressure[i] *
arc_mult[i,'jet_fuel'] * Flow[i,'jet_fuel'].sol)
/ (sum {<i,'jet_fuel'> in ARCS} arc_mult[i,'jet_fuel'] *
Flow[i,'jet_fuel'].sol);
solve;
print CrudeDistilled;
print OilCracked Flow;
print octane_sol octane_lb;
Although the previous PRINT statements print all values of the given parameters, the following two PRINT
statements use an index set to print a specified subset of the values:
Figure 6.2 shows the output from the linear programming solver. For this test instance, it turns out that the
optimal solution contains no fuel oil.
Problem Summary
Objective Sense Maximization
Objective Function TotalProfit
Objective Type Linear
Number of Variables 51
Bounded Above 0
Bounded Below 49
Bounded Below and Above 2
Free 0
Fixed 0
Number of Constraints 46
Linear LE (<=) 4
Linear EQ (=) 38
Linear GE (>=) 3
Linear Range 1
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalProfit
Solution Status Optimal
Objective Value 211365.13477
Iterations 22
Presolve Time 0.00
Solution Time 0.00
[1] CrudeDistilled
crude1 15000
crude2 30000
[1] OilCracked
heavy_oil_cracked 3800
light_oil_cracked 4200
PROC OPTMODEL Statements and Output F 77
[1] vapour_pressure
cracked_oil 1.50
heavy_oil 0.60
light_oil 1.00
residuum 0.05
vapour_pressure_sol
0.77372
Features Demonstrated
The following features are demonstrated in this example:
problem type: linear programming (generalized network flow with side constraints)
NOMISS option
sets of tuples
range constraint
INDEX function
implicit slice
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Problem Statement
A mining company is going to continue operating in a certain area for the next five years.1 There are four
mines in this area but it can operate at most three in any one year. Although a mine may not operate in a
certain year it is still necessary to keep it ‘open’, in the sense that royalties are payable, should it be operated
in a future year. Clearly if a mine is not going to be worked again it can be closed down permanently and no
more royalties need be paid. The yearly royalties payable on each mine kept ‘open’ are
Mine 1 £5 million
Mine 2 £4 million
Mine 3 £4 million
Mine 4 £5 million
There is an upper limit to the amount of ore which can be extracted from each mine in a year. These upper
limits are:
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 238–239).
82 F Chapter 7: Mining
The ore from the different mines is of varying quality. This quality is measured on a scale so that blending
ores together results in a linear combination of the quality measurements, e.g. if equal quantities of two ores
were combined the resultant ore would have a quality measurement half way between that of the ingredient
ores. Measured in these units the qualities of the ores from the mines are given below:
Mine 1 1.0
Mine 2 0.7
Mine 3 1.5
Mine 4 0.5
In each year it is necessary to combine the total outputs from each mine to produce a blended ore of exactly
some stipulated quality. For each year these qualities are
Year 1 0.9
Year 2 0.8
Year 3 1.2
Year 4 0.6
Year 5 1.0
The final blended ore sells for £10 per ton each year. Revenue and expenditure for future years must be
discounted at a rate of 10% per annum.
Which mines should be operated each year and how much should they produce?
mine 2 MINES
year 2 YEARS
Parameters F 83
Parameters
Table 7.1 shows the parameters that are used in this example.
Variables
Table 7.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following function, where TotalRevenue is a linear function of Extracted-
PerYear, and TotalCost is a linear function of IsOpen:
Constraints
The following constraints are used in this example:
bounds on variables
84 F Chapter 7: Mining
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data mine_data;
input mine $ cost extract_ub quality;
datalines;
mine1 5 2 1.0
mine2 4 2.5 0.7
mine3 4 1.3 1.5
mine4 5 3 0.5
;
data year_data;
input year quality_required;
datalines;
1 0.9
2 0.8
3 1.2
4 0.6
5 1.0
;
%let max_num_worked_per_year = 3;
%let revenue_per_ton = 10;
%let discount_rate = 0.10;
PROC OPTMODEL Statements and Output F 85
proc optmodel;
set <str> MINES;
num cost {MINES};
num extract_ub {MINES};
num quality {MINES};
read data mine_data into MINES=[mine] cost extract_ub quality;
set YEARS;
num quality_required {YEARS};
read data year_data into YEARS=[year] quality_required;
impvar TotalRevenue =
&revenue_per_ton * sum {year in YEARS} discount[year] *
ExtractedPerYear[year];
impvar TotalCost =
sum {mine in MINES, year in YEARS} discount[year] * cost[mine] *
IsOpen[mine,year];
max TotalProfit = TotalRevenue - TotalCost;
[1] discount
1 1.00000
2 0.90909
3 0.82645
4 0.75131
5 0.68301
86 F Chapter 7: Mining
The following Link constraint enforces the rule that Extract[mine,year] > 0 implies that
IsWorked[mine,year] D 1 (as in Chapter 2):
solve;
print IsOpen IsWorked Extract;
print ExtractedPerYear quality_sol quality_required;
create data sol_data1 from [mine year] IsOpen IsWorked Extract;
create data sol_data2 from [year] ExtractedPerYear;
quit;
PROC OPTMODEL Statements and Output F 87
Figure 7.2 shows the output from the mixed integer linear programming solver. The values of quality_sol and
quality_required agree, as enforced by the Quality_con constraint.
Problem Summary
Objective Sense Maximization
Objective Function TotalProfit
Objective Type Linear
Number of Variables 60
Bounded Above 0
Bounded Below 0
Bounded Below and Above 60
Free 0
Fixed 0
Binary 40
Integer 0
Number of Constraints 66
Linear LE (<=) 61
Linear EQ (=) 5
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalProfit
Solution Status Optimal
Objective Value 146.86197436
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 1.643108E-16
Bound Infeasibility 0
Integer Infeasibility 2E-11
Features Demonstrated
The following features are demonstrated in this example:
IMPVAR statement
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Problem Statement
A farmer wishes to plan production on his 200 acre farm over the next five years.1
At present he has a herd of 120 cows. This is made up of 20 heifers and 100 milk-producing cows. Each
heifer needs 2/3 acre to support it and each dairy cow 1 acre. A dairy cow produces an average of 1.1 calves
per year. Half of these calves will be bullocks which are sold almost immediately for an average of £30 each.
The remaining heifers can be either sold almost immediately for £40 or reared to become milk-producing
cows at two years old. It is intended that all dairy cows be sold at 12 years old for an average of £120 each,
although there will probably be an annual loss of 5% per year among heifers and 2% among dairy cows. At
present there are 10 cows of each age from newborn to 11 years old. The decision of how many heifers to
sell in the current year has already been taken and implemented.
The milk from a cow yields an annual revenue of £370. A maximum of 130 cows can be housed at the present
time. To provide accommodation for each cow beyond this number will entail a capital outlay of £200 per
cow. Each milk-producing cow requires 0.6 tons of grain and 0.7 tons of sugar beet per year. Grain and sugar
beet can both be grown on the farm. Each acre yields 1.5 tons of sugar beet. Only 80 acres are suitable for
growing grain. They can be divided into four groups whose yields are as follows:
Grain can be bought for £90 per ton and sold for £75 per ton. Sugar beet can be bought for £70 per ton and
sold for £58 per ton.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 239–240).
92 F Chapter 8: Farm Planning
Labour costs for the farm are at present £4000 per year and provide 5500 hours labour. Any labour needed
above this will cost £1.20 per hour.
How should the farmer operate over the next five years to maximize profit? Any capital expenditure would
be financed by a 10 year loan at 15% annual interest. The interest and capital repayment would be paid in 10
equally sized yearly instalments. In no year can the cash flow be negative. Lastly, the farmer would not wish
to reduce the total number of dairy cows at the end of the five year period by more than 50% nor increase the
number by more than 75%.
age 2 AGES
year 2 YEARS
group 2 GROUPS
Parameters F 93
Parameters
Table 8.1 shows the parameters that are used in this example.
Variables
Table 8.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following function, where Profit[year] D Revenue[year] Cost[year] and
Revenue and Cost are linear functions of other variables:
TotalProfit D
X
.Profit[year] yearly_loan_payment .num_years 1 C year/ CapitalOutlay[year]/
year2YEARS
Constraints
The following constraints are used in this example:
bounds on variables
Constraints F 95
num_acres
C sugar_beet_labour_req SugarBeetAcres[year]
nominal_labour_hours C NumExcessLabourHours[year]
Profit[year] 0
NumCows[age,num_years]
P
age2AGESW
age2
1 max_decrease_ratio P 1 C max_increase_ratio
init_num_cows[age]
age2AGESW
age2
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data cow_data;
do age = 0 to 11;
init_num_cows = 10;
if age < 2 then do;
acres_needed = 2/3;
annual_loss = 0.05;
bullock_yield = 0;
heifer_yield = 0;
milk_revenue = 0;
grain_req = 0;
sugar_beet_req = 0;
labour_req = 10;
other_costs = 50;
end;
else do;
acres_needed = 1;
annual_loss = 0.02;
bullock_yield = 1.1/2;
heifer_yield = 1.1/2;
milk_revenue = 370;
grain_req = 0.6;
sugar_beet_req = 0.7;
labour_req = 42;
other_costs = 100;
end;
output;
end;
run;
PROC OPTMODEL Statements and Output F 97
data grain_data;
input group $ acres yield;
datalines;
group1 20 1.1
group2 30 0.9
group3 20 0.8
group4 10 0.65
;
%let num_years = 5;
%let num_acres = 200;
%let bullock_revenue = 30;
%let heifer_revenue = 40;
%let dairy_cow_selling_age = 12;
%let dairy_cow_selling_revenue = 120;
%let max_num_cows = 130;
%let sugar_beet_yield = 1.5;
%let grain_cost = 90;
%let grain_revenue = 75;
%let grain_labour_req = 4;
%let grain_other_costs = 15;
%let sugar_beet_cost = 70;
%let sugar_beet_revenue = 58;
%let sugar_beet_labour_req = 14;
%let sugar_beet_other_costs = 10;
%let nominal_labour_cost = 4000;
%let nominal_labour_hours = 5500;
%let excess_labour_cost = 1.2;
%let capital_outlay_unit = 200;
%let num_loan_years = 10;
%let annual_interest_rate = 0.15;
%let max_decrease_ratio = 0.50;
%let max_increase_ratio = 0.75;
proc optmodel;
set AGES;
num init_num_cows {AGES};
num acres_needed {AGES};
num annual_loss {AGES};
num bullock_yield {AGES};
num heifer_yield {AGES};
num milk_revenue {AGES};
num grain_req {AGES};
num sugar_beet_req {AGES};
num cow_labour_req {AGES};
num cow_other_costs {AGES};
98 F Chapter 8: Farm Planning
num yearly_loan_payment =
-finance('pmt', &annual_interest_rate, &num_loan_years,
&capital_outlay_unit);
print yearly_loan_payment;
The resulting value of yearly_loan_payment (shown in Figure 8.1) differs from the value given in Williams
(1999), perhaps because of rounding in intermediate calculations by Williams. The formula
annual_interest_rate capital_outlay_unit
yearly_loan_payment D num_loan_years
1 .1 C annual_interest_rate/
yields the same value as the FINANCE function. For the given input data, it turns out that the optimal solution
has no capital outlay and agrees with the solution reported in Williams (1999).
PROC OPTMODEL Statements and Output F 99
yearly_loan_payment
39.85
The following IMPVAR statements declare Revenue, Cost, and Profit as linear functions of the decision
variables:
max TotalProfit =
sum {year in YEARS} (Profit[year]
- yearly_loan_payment * (num_years - 1 + year) * CapitalOutlay[year]);
The following model declaration statements are straightforward:
con Final_dairy_cows_range:
1 - &max_decrease_ratio
<= (sum {age in AGES: age >= 2} NumCows[age,num_years])
/ (sum {age in AGES: age >= 2} init_num_cows[age])
<= 1 + &max_increase_ratio;
solve;
The following CREATE DATA statement writes dense two-dimensional data to a data set:
Problem Summary
Objective Sense Maximization
Objective Function TotalProfit
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 1
102 F Chapter 8: Farm Planning
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalProfit
Solution Status Optimal
Objective Value 121719.17286
Iterations 49
Presolve Time 0.00
Solution Time 0.00
NumCows
0 1 2 3 4 5
0 10.0000 22.8000 11.5844 0.0000 0.0000 0.0000
1 10.0000 9.5000 21.6600 11.0052 0.0000 0.0000
2 10.0000 9.5000 9.0250 20.5770 10.4549 0.0000
3 10.0000 9.8000 9.3100 8.8445 20.1655 10.2458
4 10.0000 9.8000 9.6040 9.1238 8.6676 19.7622
5 10.0000 9.8000 9.6040 9.4119 8.9413 8.4943
6 10.0000 9.8000 9.6040 9.4119 9.2237 8.7625
7 10.0000 9.8000 9.6040 9.4119 9.2237 9.0392
8 10.0000 9.8000 9.6040 9.4119 9.2237 9.0392
9 10.0000 9.8000 9.6040 9.4119 9.2237 9.0392
10 10.0000 9.8000 9.6040 9.4119 9.2237 9.0392
11 10.0000 9.8000 9.6040 9.4119 9.2237 9.0392
12 0.0000 9.8000 9.6040 9.4119 9.2237 9.0392
GrainAcres
1 2 3 4 5
group1 20.0000 20.0000 20.0000 20.0000 20.0000
group2 0.0000 0.0000 3.1342 0.0000 0.0000
group3 0.0000 0.0000 0.0000 0.0000 0.0000
group4 0.0000 0.0000 0.0000 0.0000 0.0000
PROC OPTMODEL Statements and Output F 103
GrainGrown
1 2 3 4 5
group1 22.0000 22.0000 22.0000 22.0000 22.0000
group2 0.0000 0.0000 2.8207 0.0000 0.0000
group3 0.0000 0.0000 0.0000 0.0000 0.0000
group4 0.0000 0.0000 0.0000 0.0000 0.0000
Final_dairy_cows_range.BODY
0.92461
104 F Chapter 8: Farm Planning
Features Demonstrated
The following features are demonstrated in this example:
FIX statement
IMPVAR statement
FINANCE function
range constraint
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Problem Statement
An economy consists of three industries: coal, steel and transport.1 Each unit produced by one of the
industries (a unit will be taken as £l’s worth of value of production) requires inputs from possibly its own
industry as well as other industries. The required inputs as well as the manpower requirements (also measured
in £) are given in Table 9.1. There is a time lag in the economy so that output in year t C 1 requires an input
in year t.
Output from an industry may also be used to build productive capacity for itself or other industries in future
years. The inputs required to give unit increases (capacity for £l’s worth of extra production) in productive
capacity are given in Table 9.2. Input from an industry in year t results in a (permanent) increase in productive
capacity in year t C 2.
Table 9.1
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 240–241).
106 F Chapter 9: Economic Planning
Table 9.2
Table 9.3
Year 0
Stocks Productive capacity
Coal 150 300
Steel 80 350
Transport 100 280
Stocks of goods may be held from year to year. At present (year 0) the stocks and productive capacities (per
year) are given in Table 9.3 (in £m). There is a limited yearly manpower capacity of £470m.
It is wished to investigate different possible growth patterns for the economy over the next five years.
In particular it is desirable to know the growth patterns which would result from pursuing the following
objectives:
(i) Maximizing total productive capacity at the end of the five years while meeting an exogenous con-
sumption requirement of £60m of coal, £60m of steel, and £30m of transport in every year (apart from
year 0).
(ii) Maximizing total production (rather than productive capacity) in the fourth and fifth years, but ignoring
exogenous demand in each year.
(iii) Maximizing the total manpower requirement (ignoring the manpower capacity limitation) over the
period while meeting the yearly exogenous demands of (i).
year 2 YEARS
i; j 2 INDUSTRIES
i 2 INPUTS
Parameters
Table 9.4 shows the parameters that are used in this example.
Variables
Table 9.5 shows the variables that are used in this example.
Objectives
The first objective is to maximize the following function:
X
TotalProductiveCapacity D ProductiveCapacity[i,num_years]
i 2INDUSTRIES
108 F Chapter 9: Economic Planning
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 INDUSTRIES,
X
StaticProduction[i] D demand[i] C production_coeff[i,j] StaticProduction[j]
j 2INDUSTRIES
C Stock[i,year C 1]
manpower_capacity
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data industry_data;
input industry $9. init_stocks init_productive_capacity demand;
datalines;
coal 150 300 60
steel 80 350 60
transport 100 280 30
;
data production_data;
input input $9. coal steel transport;
datalines;
coal 0.1 0.5 0.4
steel 0.1 0.1 0.2
transport 0.2 0.1 0.2
manpower 0.6 0.3 0.2
;
data productive_capacity_data;
input input $9. coal steel transport;
datalines;
coal 0.0 0.7 0.9
steel 0.1 0.1 0.2
transport 0.2 0.1 0.2
manpower 0.4 0.2 0.1
;
proc optmodel;
num num_years = &num_years;
set YEARS = 1..num_years;
set YEARS0 = {0} union YEARS;
solve;
print StaticProduction;
Figure 9.1 shows the output from the linear programming solver for the static model.
Figure 9.1 Output from Linear Programming Solver for Static Leontief Input-Output Model
The OPTMODEL Procedure
Problem Summary
Objective Sense Minimization
Objective Function Zero
Objective Type Constant
Number of Variables 3
Bounded Above 0
Bounded Below 3
Bounded Below and Above 0
Free 0
Fixed 0
Number of Constraints 3
Linear LE (<=) 0
Linear EQ (=) 3
Linear GE (>=) 0
Linear Range 0
Constraint Coefficients 9
Performance Information
Execution Mode Single-Machine
Number of Threads 1
PROC OPTMODEL Statements and Output F 111
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Zero
Solution Status Optimal
Objective Value 0
Iterations 0
Presolve Time 0.00
Solution Time 0.00
[1] StaticProduction
coal 166.397
steel 105.668
transport 92.308
The following NUM and assignment statements declare the final_demand parameter and use the .sol
variable suffix to populate final_demand with the solution from the static model:
max TotalProductiveCapacity =
sum {i in INDUSTRIES} ProductiveCapacity[i,num_years];
max TotalProduction =
sum {i in INDUSTRIES, year in 4..5} Production[i,year];
max TotalManpower =
sum {i in INDUSTRIES, year in YEARS} (
production_coeff['manpower',i] * Production[i,year+1]
+ productive_capacity_coeff['manpower',i] * ExtraCapacity[i,year+2]);
112 F Chapter 9: Economic Planning
for {i in INDUSTRIES}
Production[i,num_years+1].lb = final_demand[i];
Figure 9.2 shows the output from the linear programming solver for Problem1.
Problem Summary
Objective Sense Maximization
Objective Function TotalProductiveCapacity
Objective Type Linear
Number of Variables 63
Bounded Above 0
Bounded Below 51
Bounded Below and Above 0
Free 0
Fixed 12
Number of Constraints 42
Linear LE (<=) 24
Linear EQ (=) 18
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalProductiveCapacity
Solution Status Optimal
Objective Value 2141.8751967
Iterations 47
Presolve Time 0.00
Solution Time 0.02
114 F Chapter 9: Economic Planning
[1] Manpower_con.BODY
1 224.99
2 270.66
3 367.04
4 470.00
5 150.00
6 150.00
Figure 9.3 shows the output from the linear programming solver for Problem2.
Problem Summary
Objective Sense Maximization
Objective Function TotalProduction
Objective Type Linear
Number of Variables 63
Bounded Above 0
Bounded Below 51
Bounded Below and Above 0
Free 0
Fixed 12
Number of Constraints 42
Linear LE (<=) 24
Linear EQ (=) 18
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalProduction
Solution Status Optimal
Objective Value 2618.5791147
Iterations 45
Presolve Time 0.00
Solution Time 0.00
116 F Chapter 9: Economic Planning
[1] Manpower_con.BODY
1 240.41
2 321.55
3 384.17
4 470.00
5 470.00
6 150.00
For Problem3, the right-hand side of each Continuity_con[i,year] constraint changes back to demand[i] :
Figure 9.4 shows the output from the linear programming solver for Problem3.
Problem Summary
Objective Sense Maximization
Objective Function TotalManpower
Objective Type Linear
Number of Variables 63
Bounded Above 0
Bounded Below 51
Bounded Below and Above 0
Free 0
Fixed 12
Number of Constraints 36
Linear LE (<=) 18
Linear EQ (=) 18
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalManpower
Solution Status Optimal
Objective Value 2450.0266228
Iterations 50
Presolve Time 0.00
Solution Time 0.00
118 F Chapter 9: Economic Planning
[1] Manpower_con.BODY
1 226.63
2 279.98
3 333.73
4 539.77
5 636.82
6 659.72
Features Demonstrated F 119
Features Demonstrated
The following features are demonstrated in this example:
IMPVAR statement
IF-THEN/ELSE expression
using the .lb and .ub constraint suffixes to modify the right-hand side of a constraint
multiple objectives
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Problem Statement
A large company wishes to move some of its departments out of London.1 There are benefits to be derived
from doing this (cheaper housing, government incentives, easier recruitment, etc.) which have been costed.
Also, however, there will be greater costs of communication between departments. These have also been
costed for all possible locations of each department.
Where should each department be located so as to minimize overall yearly cost?
The company comprises five departments (A, B, C, D, E). The possible cities for relocation are Bristol and
Brighton, or a department may be kept in London. None of these cities (including London) may be the
location for more than three of the departments.
Benefits to be derived from each relocation are given below (in thousands of pounds per year):
A B C D E
Bristol 10 15 10 20 5
Brighton 10 20 15 15 15
Communication costs are of the form Ci k Dj l where Ci k is the quantity of communication between depart-
ments i and k per year and Dj l is the cost per unit of communication between cities j and l. Ci k and Dj l are
given by the tables below:
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, p. 242).
122 F Chapter 10: Decentralization
Quantities of communication Ci k
(in thousands of units)
A B C D E
A 0.0 1.0 1.5 0.0
B 1.4 1.2 0.0
C 0.0 2.0
D 0.7
dept; i; k 2 DEPTS
city; j; l 2 CITIES
Parameters
Table 10.1 shows the parameters that are used in this example.
Variables
Table 10.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following quadratic function:
X X X
NetBenefit D benefit[i,j] Assign[i,j] comm[i,k] cost[j,l] Product[i,j,k,l]
i2DEPTS j 2CITIES .i;j;k;l/2IJKL
where
Constraints
The following constraints are used in this example:
bounds on variables
X X
TotalBenefit D benefit[i,j] Assign[i,j]
i 2DEPTS j 2CITIES
X
TotalCost D comm[i,k] cost[j,l] Product[i,j,k,l]
.i;j;k;l/2IJKL
Product[i,j,k,l] Assign[i,j]
Product[i,j,k,l] Assign[k,l]
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data dept_data;
input dept $ @@;
datalines;
A B C D E
;
data city_data;
input city $;
datalines;
Bristol
Brighton
London
;
data benefit_data;
input city $ A B C D E;
datalines;
Bristol 10 15 10 20 5
Brighton 10 20 15 15 15
;
data comm_data;
input i $ j $ comm;
datalines;
PROC OPTMODEL Statements and Output F 125
A B 0.0
A C 1.0
A D 1.5
A E 0.0
B C 1.4
B D 1.2
B E 0.0
C D 0.0
C E 2.0
D E 0.7
;
data cost_data;
input i $ j $ cost;
datalines;
Bristol Bristol 5
Bristol Brighton 14
Bristol London 13
Brighton Brighton 5
Brighton London 9
London London 10
;
%let max_num_depts = 3;
proc optmodel;
set <str> DEPTS;
read data dept_data into DEPTS=[dept];
CITIES=[city]
Doing so would have removed London from the CITIES index set, because London does not appear in the
benefit_data data set. Figure 10.1 shows the resulting values of benefit .
126 F Chapter 10: Decentralization
benefit
Brighton Bristol London
A 10 10 0
B 20 15 0
C 15 10 0
D 15 20 0
E 15 5 0
The following NUM and assignment statements read an upper triangular matrix and use these values to
populate the lower triangular part. The INIT option initializes the parameter comm to a missing value, and
the body of the FOR loop replaces each missing value with the value obtained by reflection across the main
diagonal.
comm
A B C D E
A 0.0 0.0 1.0 1.5 0.0
B 0.0 0.0 1.4 1.2 0.0
C 1.0 1.4 0.0 0.0 2.0
D 1.5 1.2 0.0 0.0 0.7
E 0.0 0.0 2.0 0.7 0.0
Similar statements are used to populate the cost parameter, but instead the main diagonal is read from the
cost_data data set:
cost
Brighton Bristol London
Brighton 5 14 9
Bristol 14 5 13
London 9 13 10
impvar TotalBenefit
= sum {i in DEPTS, j in CITIES} benefit[i,j] * Assign[i,j];
impvar TotalCost
= sum {<i,j,k,l> in IJKL} comm[i,k] * cost[j,l] * Product[i,j,k,l];
max NetBenefit = TotalBenefit - TotalCost;
solve;
Figure 10.4 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Maximization
Objective Function NetBenefit
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function NetBenefit
Solution Status Optimal
Objective Value 14.9000091
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 2.622306E-15
Bound Infeasibility 0
Integer Infeasibility 3E-6
TotalBenefit TotalCost
80 65.1
Assign
Brighton Bristol London
A 0.000001 0.999998 0.000001
B 1.000000 0.000000 0.000000
C 1.000000 0.000000 0.000000
D 0.000000 0.999999 0.000001
E 0.999999 0.000000 0.000001
An alternative “compact linearization” formulation involves fewer constraints (Liberti 2007). The following
DROP statement removes three families of constraints from the original formulation:
solve;
Figure 10.5 shows the output from the mixed integer linear programming solver for the compact linearization
formulation.
Figure 10.5 Output from Mixed Integer Linear Programming Solver (Compact Linearization)
Problem Summary
Objective Sense Maximization
Objective Function NetBenefit
Objective Type Linear
Number of Constraints 68
Linear LE (<=) 3
Linear EQ (=) 65
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function NetBenefit
Solution Status Optimal
Objective Value 14.900004725
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 4.50608E-16
Bound Infeasibility 5E-7
Integer Infeasibility 1.25E-6
TotalBenefit TotalCost
80 65.1
Assign
Brighton Bristol London
A 5.0E-07 1.0E+00 0.0E+00
B 1.0E+00 -5.0E-07 0.0E+00
C 1.0E+00 7.5E-07 0.0E+00
D 5.0E-07 1.0E+00 0.0E+00
E 1.0E+00 7.5E-07 0.0E+00
As expected, this solution agrees with the solution reported in Figure 10.4 for the original formulation.
In both formulations, the Product variable can be relaxed to be nonnegative instead of binary. The integrality
of Assign, together with the various Product_def* constraints, automatically implies integrality of Product.
For real-world problems, you should try both ways to determine which alternative performs better in specific
cases.
Similarly, the compact formulation is weaker but contains fewer constraints than the original formulation. The
net effect on total solve time is difficult to predict. For real-world problems, you should try both formulations.
Features Demonstrated
The following features are demonstrated in this example:
set of tuples
INIT option
IMPVAR statement
DROP statement
compact linearization
132
Chapter 11
Curve Fitting: Fitting a Curve to a Set of Data
Points
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Problem Statement
A quantity y is known to depend upon another quantity x.1 A set of corresponding values has been collected
for x and y and is presented in Table 11.
x 0.0 0.5 1.0 1.5 1.9 2.5 3.0 3.5 4.0 4.5
y 1.0 0.9 0.7 1.5 2.0 2.4 3.2 2.0 2.7 3.5
(1) Fit the ‘best’ straight line y D bx C a to this set of data points. The objective is to minimize the sum
of absolute deviations of each observed value of y from the value predicted by the linear relationship.
(2) Fit the ‘best’ straight line where the objective is to minimize the maximum deviation of all the observed
values of y from the value predicted by the linear relationship.
(3) Fit the ‘best’ quadratic curve y D cx 2 C bx C a to this set of data points using the same objectives as
in (1) and (2).
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 242–243).
134 F Chapter 11: Curve Fitting
i 2 POINTS
Parameters
Table 11.1 shows the parameters that are used in this example.
Variables
Table 11.2 shows the variables that are used in this example.
Objectives
The first objective is to minimize the following (nonlinear, nondifferentiable) L1 norm function:
X
Objective1 D jEstimate[i] y[i] j
i 2POINTS
Constraints F 135
The second objective is to minimize the following (nonlinear, nondifferentiable) L1 norm function:
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 POINTS,
order
X
Estimate[i] D Beta[0] C Beta[k] x[i] k
kD1
for i 2 POINTS,
for i 2 POINTS,
Input Data
The following data set contains the input data that are used in this example:
data xy_data;
input x y;
datalines;
0.0 1.0
0.5 0.9
1.0 0.7
1.5 1.5
1.9 2.0
2.5 2.4
3.0 3.2
3.5 2.0
4.0 2.7
4.5 3.5
5.0 1.0
5.5 4.0
6.0 3.6
6.6 2.7
7.0 5.7
7.6 4.6
136 F Chapter 11: Curve Fitting
8.5 6.0
9.0 6.8
10.0 7.3
;
proc optmodel;
set POINTS;
num x {POINTS};
num y {POINTS};
read data xy_data into POINTS=[_N_] x y;
The following NUM statement declares the order parameter, which is later set to 1 for Problems (1) and (2)
and set to 2 for Problem (3):
num order;
var Beta {0..order};
impvar Estimate {i in POINTS}
= Beta[0] + sum {k in 1..order} Beta[k] * x[i]^k;
The following statements encode the linearization of the L1 norm:
var MinMax;
min Objective2 = MinMax;
con MinMax_con {i in POINTS}:
MinMax >= Surplus[i] + Slack[i];
PROC OPTMODEL Statements and Output F 137
The following statements (which are not used but match the formulation in Williams (1999)) encode an
alternative linearization of the L1 norm that requires the same number of variables but twice as many
constraints:
var MinMax;
min Objective2 = MinMax;
con MinMax_con1 {i in POINTS}:
MinMax >= Surplus[i];
con MinMax_con2 {i in POINTS}:
MinMax >= Slack[i];
The following NUM statements use the ABS function, the .sol variable suffix, and the MAX aggregation
operator to compute the two norms from the optimal solution:
problem L1 include
Beta Surplus Slack
Objective1
Abs_dev_con;
The following PROBLEM statement specifies the additional variables, objective, and constraints for L1
minimization:
order = 1;
use problem L1;
solve;
print sum_abs_dev max_abs_dev;
print Beta;
print x y Estimate Surplus Slack;
create data sol_data1 from [POINTS] x y Estimate;
138 F Chapter 11: Curve Fitting
Figure 11.1 shows the output from the linear programming solver for Problem (1).
Figure 11.1 Output from Linear Programming Solver for Problem (1)
The OPTMODEL Procedure
Problem Summary
Objective Sense Minimization
Objective Function Objective1
Objective Type Linear
Number of Variables 40
Bounded Above 0
Bounded Below 38
Bounded Below and Above 0
Free 2
Fixed 0
Number of Constraints 19
Linear LE (<=) 0
Linear EQ (=) 19
Linear GE (>=) 0
Linear Range 0
Constraint Coefficients 75
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Objective1
Solution Status Optimal
Objective Value 11.46625
Iterations 24
Presolve Time 0.00
Solution Time 0.00
sum_abs_dev max_abs_dev
11.466 2.7688
[1] Beta
0 0.58125
1 0.63750
PROC OPTMODEL Statements and Output F 139
The following statements switch the focus to problem Linf, solve Problem (2), print the results, and store the
y-values that are predicted by the optimal solution:
Figure 11.2 shows the output from the linear programming solver for Problem (2).
Figure 11.2 Output from Linear Programming Solver for Problem (2)
Problem Summary
Objective Sense Minimization
Objective Function Objective2
Objective Type Linear
Number of Variables 41
Bounded Above 0
Bounded Below 38
Bounded Below and Above 0
Free 3
Fixed 0
Number of Constraints 38
Linear LE (<=) 0
Linear EQ (=) 19
Linear GE (>=) 19
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Objective2
Solution Status Optimal
Objective Value 1.725
Iterations 27
Presolve Time 0.00
Solution Time 0.00
sum_abs_dev max_abs_dev
19.95 1.725
[1] Beta
0 -0.400
1 0.625
PROC OPTMODEL Statements and Output F 141
The following statements specify a quadratic curve fit, solve both parts of Problem (3), print the results, and
store the y-values that are predicted by the optimal solutions:
order = 2;
use problem L1;
solve;
print sum_abs_dev max_abs_dev;
print Beta;
print x y Estimate Surplus Slack;
create data sol_data3 from [POINTS] x y Estimate;
Figure 11.3 shows the output from the linear programming solver for the first part of Problem (3).
Figure 11.3 Output from Linear Programming Solver for First Part of Problem (3)
Problem Summary
Objective Sense Minimization
Objective Function Objective1
Objective Type Linear
Number of Variables 41
Bounded Above 0
Bounded Below 38
Bounded Below and Above 0
Free 3
Fixed 0
Number of Constraints 19
Linear LE (<=) 0
Linear EQ (=) 19
Linear GE (>=) 0
Linear Range 0
Constraint Coefficients 93
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Objective1
Solution Status Optimal
Objective Value 10.458964706
Iterations 21
Presolve Time 0.00
Solution Time 0.00
sum_abs_dev max_abs_dev
10.459 2.298
[1] Beta
0 0.982353
1 0.294510
2 0.033725
PROC OPTMODEL Statements and Output F 143
Figure 11.4 shows the output from the linear programming solver for the second part of Problem (3).
Figure 11.4 Output from Linear Programming Solver for Second Part of Problem (3)
Problem Summary
Objective Sense Minimization
Objective Function Objective2
Objective Type Linear
Number of Variables 42
Bounded Above 0
Bounded Below 38
Bounded Below and Above 0
Free 4
Fixed 0
Number of Constraints 38
Linear LE (<=) 0
Linear EQ (=) 19
Linear GE (>=) 19
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
144 F Chapter 11: Curve Fitting
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Objective2
Solution Status Optimal
Objective Value 1.475
Iterations 29
Presolve Time 0.00
Solution Time 0.00
sum_abs_dev max_abs_dev
16.758 1.475
[1] Beta
0 2.475
1 -0.625
2 0.125
You can find a higher-order polynomial fit simply by increasing the value of the order parameter. The
dimensions of the Beta and Estimate variables are automatically updated when order changes.
PROC OPTMODEL Statements and Output F 145
The following PROC SGPLOT statements use the output data sets that are created by PROC OPTMODEL to
display the results from Problems (1) and (2) in one plot:
data plot1;
merge sol_data1(rename=(Estimate=Line1)) sol_data2(rename=(Estimate=Line2));
run;
The following PROC SGPLOT statements use the output data sets that are created by PROC OPTMODEL to
display the results from both parts of Problem (3) in one plot:
data plot2;
merge sol_data3(rename=(Estimate=Curve1))
sol_data4(rename=(Estimate=Curve2));
run;
Features Demonstrated
The following features are demonstrated in this example:
IMPVAR statement
multiple objectives
ABS function
SGPLOT procedure
148
Chapter 12
Logical Design: Constructing an Electronic
System with a Minimum Number of
Components
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Problem Statement
Logical circuits have a given number of inputs and one output.1 Impulses may be applied to the inputs of a
given logical circuit and it will respond either by giving an output (signal 1) or by giving no output (signal 0).
The input impulses are of the same kind as the outputs, i.e. 1 (positive input) or 0 (no input).
In this example a logical circuit is to be built up of NOR gates. A NOR gate is a device with two inputs and
one output. It has the property that there is positive output (signal 1) if and only if neither input is positive, i.e.
both inputs have value 0. By connecting such gates together with outputs from one gate possibly being inputs
into another gate it is possible to construct a circuit to perform any desired logical function. For example the
circuit illustrated in Figure 12.1 will respond to the inputs A and B in the way indicated by the truth table in
Table 12.1.
The problem here is to construct a circuit using the minimum number of NOR gates which will perform the
logical function specified by the truth table in Table 12.2. This problem, together with further references to it,
is discussed in Williams (1974).
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 243–244).
150 F Chapter 12: Logical Design
Figure 12.1
Table 12.1
Inputs Output
A B
0 0 0
0 1 0
1 0 0
1 1 1
Table 12.2
Inputs Output
A B
0 0 0
0 1 1
1 0 1
1 1 0
‘Fan-in’ and ‘fan-out’ are not permitted. That is, more than one output from a NOR gate cannot lead into one
input, nor can one output lead into more than one input.
Mathematical Programming Formulation F 151
It may be assumed throughout that the optimal design is a ‘subnet’ of the ‘maximal’ net shown in Figure 12.2.
Figure 12.2
row 2 ROWS
Parameters
Table 12.3 shows the parameters that are used in this example.
Variables
Table 12.4 shows the variables that are used in this example.
Objective
The objective is to minimize the following function:
X
NumGatesUsed D UseGate[gate]
gate2GATES
Constraints
The following constraints are used in this example:
bounds on variables
AssignAGate[gate] UseGate[gate]
AssignBGate[gate] UseGate[gate]
Output[1,row] D target_output[row]
Output[gate,row] UseGate[gate]
Input Data F 153
Output[pred,row] 1 Output[gate,row]
UseGate[gate] Output[gate,row]
Input Data
The following data sets contain the input data that are used in this example:
data arc_data;
input i j;
datalines;
4 2
5 2
6 3
7 3
2 1
3 1
;
proc optmodel;
set <num,num> ARCS;
read data arc_data into ARCS=[i j];
Each arc corresponds to a connection from one NOR gate to another in Figure 12.2, and the following SET
statement declares and populates the index set GATES by taking a union over ARCS, as in previous examples:
set ROWS;
num inputA {ROWS};
num inputB {ROWS};
num target_output {ROWS};
read data truth_data into ROWS=[_N_] inputA=A inputB=B target_output=output;
The following VAR and FIX statements declare the Output variable and fix the output of Gate 1 to the desired
values specified in target_output :
solve;
print UseGate AssignAGate AssignBGate;
print Output;
create data sol_data1 from [gate] UseGate AssignAGate AssignBGate;
create data sol_data2 from [gate row] Output;
quit;
156 F Chapter 12: Logical Design
Figure 12.3 shows the output from the mixed integer linear programming solver. In this case, five gates are
used in the optimal solution.
Problem Summary
Objective Sense Minimization
Objective Function NumGatesUsed
Objective Type Linear
Number of Variables 49
Bounded Above 0
Bounded Below 0
Bounded Below and Above 45
Free 0
Fixed 4
Binary 49
Integer 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function NumGatesUsed
Solution Status Optimal
Objective Value 5
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
Best Bound 5
Nodes 1
Iterations 4
Presolve Time 0.01
Solution Time 0.01
Features Demonstrated F 157
Output
1 2 3 4
1 0 1 1 0
2 0 0 0 1
3 1 0 0 0
4 1 0 1 0
5 1 1 0 0
6 0 0 0 0
7 0 0 0 0
Features Demonstrated
The following features are demonstrated in this example:
set of tuples
implicit slice
FIX statement
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Problem Statement
A large company has two divisions D1 and D2.1 The company supplies retailers with oil and spirit.
It is desired to allocate each retailer to either division D1 or division D2. This division will be the retailer’s
supplier. As far as possible this division must be made so that D1 controls 40% of the market and D2 the
remaining 60%. The retailers are listed below as M1 to M23. Each retailer has an estimated market for oil
and spirit. Retailers M1 to M8 are in region 1; retailers M9 to M18 are in region 2; retailers M19 to M23 are
in region 3. Certain retailers are considered to have good growth prospects and categorized as group A and
the others are in group B. Each retailer has a certain number of delivery points as given below. It is desired to
make the 40/60 split between D1 and D2 in each of the following respects:
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 244–245).
160 F Chapter 13: Market Sharing
Table 13.1
There is a certain flexibility in that any share may vary by ˙5%. That is, the share can vary between the
limits 35/65 and 45/55.
The primary aim is to find a feasible solution. If, however, there is some choice, then possible objectives are
(i) to minimize the sum of the percentage deviations from the 40/60 split and (ii) to minimize the maximum
such deviation.
Build a model to see if the problem has a feasible solution and if so find the optimal solutions.
The numerical data are given in Table 13.1.
retailer 2 RETAILERS
r; reg 2 REGIONS
g; group 2 GROUPS
retailer 2 RETAILERS_region[region]
retailer 2 RETAILERS_group[group]
division 2 DIVISIONS
category 2 CATEGORIES
Parameters
Table 13.2 shows the parameters that are used in this example.
Variables
Table 13.3 shows the variables that are used in this example.
Objectives
The first objective is to minimize the following (nonlinear, nondifferentiable) L1 norm function:
X
Objective1 D jMarketShare[category,division] target[division] j
category2CATEGORIES;
division2DIVISIONS
The second objective is to minimize the following (nonlinear, nondifferentiable) L1 norm function:
Objective2 D max jMarketShare[category,division] target[division] j
category2CATEGORIES;
division2DIVISIONS
Constraints
The following constraints are used in this example:
bounds on variables
for retailer 2 RETAILERS,
X
Assign[retailer,division] D 1
division2DIVISIONS
oil[retailer] Assign[retailer,division]
P
retailer2RETAILERS_region[reg]
MarketShare[‘oil’||reg,division] D P
oil[retailer]
retailer2RETAILERS_region[reg]
Assign[retailer,division]
P
retailer2RETAILERS_group[group]
MarketShare[‘growth’||group,division] D
jRETAILERS_group[group]j
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data retailer_data;
input region oil delivery spirit growth $;
datalines;
1 9 11 34 A
1 13 47 411 A
1 14 44 82 A
1 17 25 157 B
1 18 10 5 A
1 19 26 183 A
1 23 26 14 B
1 21 54 215 B
2 9 18 102 B
2 11 51 21 A
2 17 20 54 B
2 18 105 0 B
2 18 7 6 B
2 17 16 96 B
2 22 34 118 A
2 24 100 112 B
2 36 50 535 B
2 43 21 8 B
3 6 11 53 B
3 15 19 28 A
3 15 14 69 B
3 25 10 65 B
3 39 11 27 B
;
164 F Chapter 13: Market Sharing
data division_data;
input target;
datalines;
0.40
0.60
;
proc optmodel;
set RETAILERS;
num region {RETAILERS};
num oil {RETAILERS};
num delivery {RETAILERS};
num spirit {RETAILERS};
str growth {RETAILERS};
read data retailer_data into RETAILERS=[_N_]
region oil delivery spirit growth;
The following statements declare parameters and index sets, which are initialized to be empty and then
populated within a FOR loop. Note that both RETAILERS_region and RETAILERS_group are sets that are
indexed by other sets:
set DIVISIONS;
num target {DIVISIONS};
read data division_data into DIVISIONS=[_N_] target;
min Objective1 =
sum {category in CATEGORIES, division in DIVISIONS}
(Surplus[category,division] + Slack[category,division]);
num sum_abs_dev =
sum {category in CATEGORIES, division in DIVISIONS}
abs(MarketShare[category,division].sol - target[division]);
num max_abs_dev =
max {category in CATEGORIES, division in DIVISIONS}
abs(MarketShare[category,division].sol - target[division]);
166 F Chapter 13: Market Sharing
The MILP solver is called twice, and each SOLVE statement includes the OBJ option to specify which
objective to optimize. The first PRINT statement after each SOLVE statement reports the values of both
objectives even though only one objective is optimized at a time:
Figure 13.1 Output from First SOLVE Statement, Minimizing Sum of Deviations
The OPTMODEL Procedure
Problem Summary
Objective Sense Minimization
Objective Function Objective1
Objective Type Linear
Number of Variables 88
Bounded Above 0
Bounded Below 0
Bounded Below and Above 74
Free 14
Fixed 0
Binary 46
Integer 0
Number of Constraints 51
Linear LE (<=) 0
Linear EQ (=) 51
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
PROC OPTMODEL Statements and Output F 167
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function Objective1
Solution Status Optimal
Objective Value 0.1059523594
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 1.110223E-16
Bound Infeasibility 2.220446E-16
Integer Infeasibility 2.220446E-16
sum_abs_dev max_abs_dev
0.10595 0.025
Assign
1 2
1 1 0
2 1 0
3 1 0
4 1 0
5 0 1
6 0 1
7 0 1
8 0 1
9 0 1
10 0 1
11 1 -0
12 0 1
13 0 1
14 0 1
15 0 1
16 1 0
17 0 1
18 1 0
19 0 1
20 0 1
21 1 0
22 1 0
23 0 1
168 F Chapter 13: Market Sharing
The following statements declare the additional variable, objective, and constraints for problem (ii), with the
tighter linearization of the L1 norm as in Chapter 11:
Figure 13.2 shows the output that results from the second SOLVE statement.
Figure 13.2 Output from Second SOLVE Statement, Minimizing Maximum Deviation
Problem Summary
Objective Sense Minimization
Objective Function Objective2
Objective Type Linear
Number of Variables 89
Bounded Above 0
Bounded Below 1
Bounded Below and Above 74
Free 14
Fixed 0
Binary 46
Integer 0
Number of Constraints 65
Linear LE (<=) 0
Linear EQ (=) 51
Linear GE (>=) 14
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function Objective2
Solution Status Optimal
Objective Value 0.025
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 1.110223E-16
Bound Infeasibility 2.220446E-16
Integer Infeasibility 2.220446E-16
sum_abs_dev max_abs_dev
0.10595 0.025
Assign
1 2
1 1 0
2 1 0
3 1 0
4 1 0
5 0 1
6 0 1
7 0 1
8 0 1
9 0 1
10 0 1
11 1 -0
12 0 1
13 0 1
14 0 1
15 0 1
16 1 0
17 0 1
18 1 0
19 0 1
20 0 1
21 1 0
22 1 0
23 0 1
Features Demonstrated
The following features are demonstrated in this example:
string concatenation
CARD function
ABS function
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Problem Statement
A company has obtained permission to opencast mine within a square plot 200 ft 200 ft.1 The angle of
slip of the soil is such that it is not possible for the sides of the excavation to be steeper than 45ı . The
company has obtained estimates for the value of the ore in various places at various depths. Bearing in mind
the restrictions imposed by the angle of slip, the company decides to consider the problem as one of the
extracting of rectangular blocks. Each block has horizontal dimensions 50 ft 50 ft and a vertical dimension
of 25 ft. If the blocks are chosen to lie above one another, as illustrated in vertical section in Figure 14.1, then
it is only possible to excavate blocks forming an upturned pyramid. (In a three-dimensional representation
Figure 14.1 would show four blocks lying above each lower block.)
Figure 14.1
If the estimates of ore value are applied to give values (in percentage of pure metal) for each block in the
maximum pyramid which can be extracted then the following values are obtained:
The cost of extraction increases with depth. At successive levels the cost of extracting a block is:
Level 1 £3000
Level 2 £6000
Level 3 £8000
Level 4 £10,000
The revenue obtained from a ‘100% value block’ would be £200,000. For each block here the revenue is
proportional to ore value.
Build a model to help decide the best blocks to extract. The objective is to maximize revenue cost.
block; i; j 2 BLOCKS
level 2 LEVELS
Parameters
Table 14.1 shows the parameters that are used in this example.
Variables
Table 14.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following function:
X
TotalProfit D profit[block] Extract[block]
block2BLOCKS
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 BLOCKS and j 2 BLOCKS such that level[j] D level[i] 1 and row[j] 2 frow[i] ; row[i] C 1g
and column[j] 2 fcolumn[i] ; column[i] C 1g,
Extract[i] Extract[j]
Input Data
The following data sets and macro variable contain the input data that are used in this example:
data block_data;
input level row column percent;
datalines;
1 1 1 1.5
1 1 2 1.5
1 1 3 1.5
1 1 4 0.75
1 2 1 1.5
1 2 2 2.0
1 2 3 1.5
1 2 4 0.75
1 3 1 1.0
1 3 2 1.0
176 F Chapter 14: Opencast Mining
1 3 3 0.75
1 3 4 0.5
1 4 1 0.75
1 4 2 0.75
1 4 3 0.5
1 4 4 0.25
2 1 1 4.0
2 1 2 4.0
2 1 3 2.0
2 2 1 3.0
2 2 2 3.0
2 2 3 1.0
2 3 1 2.0
2 3 2 2.0
2 3 3 0.5
3 1 1 12.0
3 1 2 6.0
3 2 1 5.0
3 2 2 4.0
4 1 1 6.0
;
data level_data;
input cost;
datalines;
3000
6000
8000
10000
;
proc optmodel;
set BLOCKS;
num level {BLOCKS};
num row {BLOCKS};
num column {BLOCKS};
num revenue {BLOCKS};
read data block_data into BLOCKS=[_N_] level row column revenue=percent;
for {block in BLOCKS} revenue[block] = &full_value * revenue[block] / 100;
set LEVELS;
num cost {LEVELS};
read data level_data into LEVELS=[_N_] cost;
The following statements declare binary decision variables and the objective:
solve;
print Extract profit;
The following CREATE DATA statement uses the colon operator (:) to output only the blocks that are used
in the optimal solution:
Figure 14.2 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Maximization
Objective Function TotalProfit
Objective Type Linear
Number of Variables 30
Bounded Above 0
Bounded Below 0
Bounded Below and Above 30
Free 0
Fixed 0
Binary 30
Integer 0
Number of Constraints 56
Linear LE (<=) 56
Linear EQ (=) 0
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalProfit
Solution Status Optimal
Objective Value 17500
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
Features Demonstrated
The following features are demonstrated in this example:
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Problem Statement
A number of power stations are committed to meeting the following electricity load demands over a day:1
There are three types of generating unit available: 12 of type 1, 10 of type 2, and five of type 3. Each
generator has to work between a minimum and a maximum level. There is an hourly cost of running each
generator at minimum level. In addition there is an extra hourly cost for each megawatt at which a unit is
operated above minimum level. To start up a generator also involves a cost. All this information is given in
Table 15.1 (with costs in £).
In addition to meeting the estimated load demands there must be sufficient generators working at any time to
make it possible to meet an increase in load of up to 15%. This increase would have to be accomplished by
adjusting the output of generators already operating within their permitted limits.
Which generators should be working in which periods of the day to minimize total cost?
What is the marginal cost of production of electricity in each period of the day; i.e. what tariffs should be
charged?
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, p. 247).
182 F Chapter 15: Tariff Rates (Power Generation)
What would be the saving of lowering the 15% reserve output guarantee; i.e. what does this security of supply
guarantee cost?
Table 15.1
period 2 PERIODS
type 2 TYPES
Parameters
Table 15.2 shows the parameters that are used in this example.
Variables
Table 15.3 shows the variables that are used in this example.
Objective
The objective is to minimize the following function:
X
TotalCost D .unit_cost[type] length[period] NumWorking[period,type]
period2PERIODS;
type2TYPES
Constraints
The following constraints are used in this example:
bounds on variables
NumStartup[period,type] NumWorking[period,type]
.if period 1 2 PERIODS, then NumWorking[period 1; type]I
else NumWorking[jPERIODSj; type]/
Input Data
The following data sets and macro variable contain the input data that are used in this example:
data period_data;
input length demand;
datalines;
6 15000
3 30000
6 25000
3 40000
6 27000
;
data type_data;
input num_avail min_level max_level unit_cost excess_cost startup_cost;
datalines;
12 850 2000 1000 2 2000
10 1250 1750 2600 1.30 1000
5 1500 4000 3000 3 500
;
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};
PROC OPTMODEL Statements and Output F 185
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]);
The following CON statements declare the constraints, with an IF-THEN/ELSE expression in the last
constraint to account for a boundary condition in the first period:
solve;
print NumWorking NumStartup Excess Output;
create data sol_data from [period type] NumWorking NumStartup Excess Output;
186 F Chapter 15: Tariff Rates (Power Generation)
Figure 15.1 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Minimization
Objective Function TotalCost
Objective Type Linear
Number of Variables 45
Bounded Above 0
Bounded Below 15
Bounded Below and Above 30
Free 0
Fixed 0
Binary 0
Integer 30
Number of Constraints 40
Linear LE (<=) 15
Linear EQ (=) 0
Linear GE (>=) 25
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalCost
Solution Status Optimal
Objective Value 988540
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 8.881784E-16
Bound Infeasibility 0
Integer Infeasibility 3.552714E-15
The following statements fix the integer variables to their optimal values, call the linear programming solver,
and use the .dual constraint suffix to compute marginal costs. The RELAXINT option in the SOLVE
statement relaxes the integer variables to be continuous.
fix NumWorking;
fix NumStartup;
solve with LP relaxint;
print NumWorking NumStartup Excess Output;
print {period in PERIODS} (demand_con[period].dual / length[period]);
Figure 15.2 shows the output from the linear programming solver when the integer variables are fixed to their
optimal values. As expected, the same optimal solution is obtained; the point of calling the LP solver is to
obtain the dual variables used to compute the marginal costs, as shown in Figure 15.3.
188 F Chapter 15: Tariff Rates (Power Generation)
Figure 15.2 Output from Linear Programming Solver, Integer Variables Fixed
Problem Summary
Objective Sense Minimization
Objective Function TotalCost
Objective Type Linear
Number of Variables 45
Bounded Above 0
Bounded Below 15
Bounded Below and Above 0
Free 0
Fixed 30
Binary 16
Integer 8
Number of Constraints 40
Linear LE (<=) 15
Linear EQ (=) 0
Linear GE (>=) 25
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalCost
Solution Status Optimal
Objective Value 988540
Iterations 7
Presolve Time 0.00
Solution Time 0.00
PROC OPTMODEL Statements and Output F 189
[1]
1 1.3
2 2.0
3 2.0
4 2.0
5 2.0
The following statements unfix the integer variables, call the linear programming solver, and use the .dual
constraint suffix to compute marginal costs:
unfix NumWorking;
unfix NumStartup;
solve with LP relaxint;
print NumWorking NumStartup Excess Output;
print {period in PERIODS} (demand_con[period].dual / length[period]);
print {period in PERIODS} (reserve_con[period].dual / length[period]);
quit;
190 F Chapter 15: Tariff Rates (Power Generation)
Figure 15.4 shows the output from the linear programming solver when the integer variables are unfixed and
relaxed to be continuous. As expected, some relaxed integer variables now take fractional values, and the
total cost is slightly less than before. Figure 15.5 and Figure 15.6 show the resulting marginal costs.
Figure 15.4 Output from Linear Programming Solver, Integer Variables Unfixed and Relaxed
Problem Summary
Objective Sense Minimization
Objective Function TotalCost
Objective Type Linear
Number of Variables 45
Bounded Above 0
Bounded Below 15
Bounded Below and Above 30
Free 0
Fixed 0
Binary 0
Integer 30
Number of Constraints 40
Linear LE (<=) 15
Linear EQ (=) 0
Linear GE (>=) 25
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalCost
Solution Status Optimal
Objective Value 985164.28571
Iterations 26
Presolve Time 0.00
Solution Time 0.00
PROC OPTMODEL Statements and Output F 191
[1]
1 1.7619
2 2.0000
3 1.7857
4 2.0000
5 1.8601
[1]
1 0.000000
2 0.000000
3 0.000000
4 0.041667
5 0.000000
192 F Chapter 15: Tariff Rates (Power Generation)
Features Demonstrated
The following features are demonstrated in this example:
IMPVAR statement
IF-THEN/ELSE expression
CARD function
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Problem Statement
This is an extension of the Tariff Rates (Power Generation) problem of Section 12.15 [Chapter 15].1 In
addition to the thermal generators a reservoir powers two hydro generators: one of type A and one of type
B. When a hydro generator is running, it operates at a fixed level and the depth of the reservoir decreases.
The costs associated with each hydro generator are a fixed start-up cost and a running cost per hour. The
characteristics of each type of generator are shown in Table 16.1.
Table 16.1
For environmental reasons, the reservoir must be maintained at a depth of between 15 and 20 metres. Also, at
midnight each night, the reservoir must be 16 metres deep. Thermal generators can be used to pump water
into the reservoir. To increase the level of the reservoir by 1 metre requires 3000 MWh of electricity. You
may assume that rainfall does not affect the reservoir level.
At any time it must be possible to meet an increase in demand for electricity of up to 15%. This can be
achieved by any combination of the following: switching on a hydro generator (even if this would cause the
reservoir depth to fall below 15 metres); using the output of a thermal generator which is used for pumping
water into the reservoir; and increasing the operating level of a thermal generator to its maximum. Thermal
generators cannot be switched on instantaneously to meet increased demand (although hydro generators can
be).
Which generators should be working in which periods of the day, and how should the reservoir be maintained
to minimize the total cost?
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 247–248).
194 F Chapter 16: Hydro Power
hydro 2 HYDROS
Parameters
Table 16.2 shows the additional parameters that are used in this example.
Variables
Table 16.3 shows the additional variables that are used in this example.
Objective
The objective is to minimize the following function:
X
TotalCost D .unit_cost[type] length[period] NumWorking[period,type]
period2PERIODS;
type2TYPES
Chydro_startup_cost[hydro] HydroNumStartup[period,hydro]/
Constraints
The following modified and additional constraints are used in this example:
demand[period]
.1 C reserve/ demand[period]
HydroNumStartup[period,hydro]
HydroNumWorking[period,hydro]
.if period 1 2 PERIODS, then HydroNumWorking[period 1; hydro]I
else HydroNumWorking[|PERIODS|, hydro]/
196 F Chapter 16: Hydro Power
Input Data
The following data sets and macro variables contain the additional input data that are used in this example:
data hydro_data;
input hydro $ level unit_cost depth_rate startup_cost;
datalines;
A 900 90 0.31 1500
B 1400 150 0.47 1200
;
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;
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 15:
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;
PROC OPTMODEL Statements and Output F 199
Figure 16.1 shows the output from the 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
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalCost
Solution Status Optimal
Objective Value 986630
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 1.219944E-15
Bound Infeasibility 0
Integer Infeasibility 0
Features Demonstrated
The following features are demonstrated in this example:
FIX statement
IMPVAR statement
IF-THEN/ELSE expression
CARD function
202
Chapter 17
Three-Dimensional Noughts and Crosses: A
Combinatorial
Chapter 24 Problem
Module Library
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
ContentsInput Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Overview . . . . . .Statements
PROC OPTMODEL . . . . . . and
. . Output
. . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 1079
206
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Overview
Problem Statement
The IMLMLIB library contains modules written in the SAS/IML language. The library contains both func-
tions and subroutines. You do not have to explicitly load these modules: they are automatically1 loaded at
Twenty-seven cells are arranged 3 3 3 in a three-dimensional array as shown in Figure 17.1.
run time when they are called by a SAS/IML program.
Figure 24.1
Figure 17.1
Three cells are regarded as lying in the same line if they are on the same horizontal or vertical line or the
same diagonal. Diagonals exist on each horizontal and vertical section and connecting opposite vertices of
the cube. (There are 49 lines altogether.)
Given 13 white balls (noughts) and 14 black balls (crosses), arrange them, one to a cell, so as to minimize the
number of lines with balls all of one colour.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 248–249).
204 F Chapter 17: Three-Dimensional Noughts and Crosses
.i; j; k/ 2 CELLS
color 2 COLORS
line 2 LINES
.i; j; k/ 2 CELLS_lineŒline
Parameters
Table 17.1 shows the parameters that are used in this example.
Variables
Table 17.2 shows the variables that are used in this example.
Objective
The objective is to minimize the following function:
X
NumMonochromaticLines D IsMonochromatic[line]
line2LINES
Constraints
The following constraints are used in this example:
bounds on variables
Input Data
The following data set and macro variable contain the input data that are used in this example:
data color_data;
input num_balls;
datalines;
13
14
;
%let n = 3;
206 F Chapter 17: Three-Dimensional Noughts and Crosses
proc optmodel;
num n = &n;
set CELLS = 1..n cross 1..n cross 1..n;
set COLORS;
num num_balls {COLORS};
read data color_data into COLORS=[_N_] num_balls;
The following statements declare the IsColor variables and the first two families of constraints:
The following FOR loops use the SETOF operator to populate CELLS_line for each face diagonal:
num_lines = num_lines + 1;
CELLS_line[num_lines] = setof {t in 1..n} <t,t,t>;
num_lines = num_lines + 1;
CELLS_line[num_lines] = setof {t in 1..n} <t,t,n+1-t>;
num_lines = num_lines + 1;
CELLS_line[num_lines] = setof {t in 1..n} <t,n+1-t,t>;
num_lines = num_lines + 1;
CELLS_line[num_lines] = setof {t in 1..n} <t,n+1-t,n+1-t>;
The following PUT statements demonstrate that num_lines is ..n C 2/3 n3 /=2, which is 49 when n D 3.
put num_lines=;
put (((n+2)^3 - n^3) / 2)=;
The following CON statement enforces the rule that if all cells in a line are the same color, then
IsMonochromatic[line] D 1:
solve;
num assigned_color {CELLS};
for {<i,j,k> in CELLS} do;
for {color in COLORS: IsColor[i,j,k,color].sol > 0.5} do;
assigned_color[i,j,k] = color;
leave;
end;
end;
208 F Chapter 17: Three-Dimensional Noughts and Crosses
The following statements print the values of assigned_color[i,j,k] for each i and display in the log which cells
make up each monochromatic line:
for {i in 1..n}
print {j in 1..n, k in 1..n} assigned_color[i,j,k];
for {line in LINES: IsMonochromatic[line].sol > 0.5}
put CELLS_line[line]=;
By default, the PUT statement writes to the log. You can use the following FILE statement to redirect log
output to the listing:
file print;
for {line in LINES: IsMonochromatic[line].sol > 0.5}
put CELLS_line[line]=;
quit;
Figure 17.2 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Minimization
Objective Function NumMonochromaticLines
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
PROC OPTMODEL Statements and Output F 209
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function NumMonochromaticLines
Solution Status Optimal
Objective Value 4
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
Best Bound 4
Nodes 258
Iterations 4491
Presolve Time 0.01
Solution Time 0.10
assigned_color
1 2 3
1 2 2 1
2 1 1 2
3 2 2 1
assigned_color
1 2 3
1 1 2 2
2 2 1 2
3 1 1 2
assigned_color
1 2 3
1 2 1 1
2 1 2 2
3 2 1 1
CELLS_line[15]={<2,1,3>,<2,2,3>,<2,3,3>}
CELLS_line[24]={<1,2,3>,<2,2,3>,<3,2,3>}
CELLS_line[40]={<1,1,1>,<2,2,1>,<3,3,1>}
CELLS_line[41]={<1,3,1>,<2,2,1>,<3,1,1>}
210 F Chapter 17: Three-Dimensional Noughts and Crosses
Features Demonstrated
The following features are demonstrated in this example:
sets of tuples
CARD function
PUT statement
FILE statement
Chapter 18
Optimizing a Constraint: Reconstructing an
Integer Programming Constraint More Simply
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
Problem Statement
In an integer programming problem the following constraint occurs:1
All the variables occurring in this constraint are 0-1 variables, i.e. they can only take the value of 0 or 1.
Find the ‘simplest’ version of this constraint. The objective is to find another constraint involving these
variables which is logically equivalent to the original constraint but which has the smallest possible absolute
value of the right-hand side (with all coefficients of similar signs to the original coefficients).
If the objective were to find an equivalent constraint where the sum of the absolute values of the coefficients
(apart from the right-hand side coefficient) were a minimum what would be the result?
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, p. 249).
212 F Chapter 18: Optimizing a Constraint
j 2 VARS
point 2 FEAS_POINTS
point 2 INFEAS_POINTS
Parameters
Table 18.1 shows the parameters that are used in this example.
Variables
Table 18.2 shows the variables that are used in this example.
Objectives
The first objective is to minimize the absolute value of the new right-hand side:
The second objective is to minimize the sum of absolute values of the new left-hand side coefficients:
X
Objective2 D ja[j] j Scale[j]
j 2VARS
Constraints
The following constraints are used in this example:
bounds on variables
for j 2 VARS0,
Input Data
The following data set and macro variables contain the input data that are used in this example:
data a_data;
input a @@;
datalines;
9 13 -14 17 13 -19 23 21
;
%let b = 37;
data condata_feas(drop=j);
length _type_ $8;
array x[&n];
set trans;
_type_ = 'le';
_rhs_ = &b;
output;
do j = 1 to &n;
x[j] = 1;
end;
_type_ = 'binary';
_rhs_ = .;
output;
run;
The following PROC CLP statements find all feasible solutions and save them in the out_feas data set:
data condata_infeas;
set condata_feas;
if _N_ = 1 then do;
_type_ = 'ge';
_rhs_ = _rhs_ + 1;
end;
run;
The following PROC CLP statements find all such solutions and save them in the out_infeas data set:
The first several PROC OPTMODEL statements declare sets and parameters and read the original constraint
data:
proc optmodel;
set VARS;
set VARS0 = VARS union {0};
num a {VARS0};
read data a_data into VARS=[_N_] a;
a[0] = &b;
The following statements declare the FEAS_POINTS set and the x_feas parameter and populate them by
reading the out_feas data set:
set FEAS_POINTS;
num x_feas {FEAS_POINTS, VARS};
read data out_feas into FEAS_POINTS=[_N_]
{j in VARS} <x_feas[_N_,j]=col('x'||j)>;
The following statements declare the INFEAS_POINTS set and the x_infeas parameter and populate them
by reading the out_infeas data set:
set INFEAS_POINTS;
num x_infeas {INFEAS_POINTS, VARS};
read data out_infeas into INFEAS_POINTS=[_N_]
{j in VARS} <x_infeas[_N_,j]=col('x'||j)>;
The following statements declare the variables and constraints:
Figure 18.1 shows the output from the linear programming solver for the first objective.
Problem Summary
Objective Sense Minimization
Objective Function Objective1
Objective Type Linear
Number of Variables 9
Bounded Above 0
Bounded Below 9
Bounded Below and Above 0
Free 0
Fixed 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Objective1
Solution Status Optimal
Objective Value 25
Iterations 24
Presolve Time 0.00
Solution Time 0.02
PROC OPTMODEL Statements and Output F 217
The following statements solve the problem by using the second objective and then print the solution:
Problem Summary
Objective Sense Minimization
Objective Function Objective2
Objective Type Linear
Number of Variables 9
Bounded Above 0
Bounded Below 9
Bounded Below and Above 0
Free 0
Fixed 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
218 F Chapter 18: Optimizing a Constraint
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Objective2
Solution Status Optimal
Objective Value 89
Iterations 19
Presolve Time 0.00
Solution Time 0.00
For this test instance, it turns out that the optimal solutions for the two different objectives agree.
In SAS/OR 13.2, you can also access the CLP solver from within PROC OPTMODEL by using the SOLVE
WITH CLP statement. The first several PROC OPTMODEL statements are the same as before:
proc optmodel;
set VARS;
set VARS0 = VARS union {0};
num a {VARS0};
read data a_data into VARS=[_N_] a;
a[0] = &b;
The following statements declare variables and a constraint for the CLP problem:
The following statements call the CLP solver and use the FINDALLSOLNS option to find all solutions,
and then they use the predeclared numeric parameter _NSOL_ and the .sol variable suffix to retrieve the
resulting solutions:
CLP_con.lb = CLP_con.ub + 1;
CLP_con.ub = constant('BIG');
The following statements call the CLP solver again and retrieve the resulting solutions:
solve;
print a Scale Alpha;
Features Demonstrated
The following features are demonstrated in this example:
CLP procedure
IMPVAR statement
ABS function
multiple objectives
multiple solutions
using the .lb and .ub constraint suffixes to modify the right-hand side of a constraint
CONSTANT function
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
Problem Statement
A company has two factories, one at Liverpool and one at Brighton.1 In addition it has four depots with
storage facilities at Newcastle, Birmingham, London and Exeter. The company sells its product to six
customers C1, C2, . . . , C6. Customers can be supplied either from a depot or from the factory direct (see
Figure 19.1).
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 249–251).
222 F Chapter 19: Distribution 1
Figure 19.1
Problem Statement F 223
Table 19.1
Suppliera
Liverpool Brighton Newcastle Birmingham London Exeter
Supplied to factory factory depot depot depot depot
Depots
Newcastle 0.5 —
Birmingham 0.5 0.3
London 1.0 0.5
Exeter 0.2 0.2
Customers
C1 1.0 2.0 — 1.0 — —
C2 — — 1.5 0.5 1.5 —
C3 1.5 — 0.5 0.5 2.0 0.2
C4 2.0 — 1.5 1.0 — 1.5
C5 — — — 0.5 0.5 0.5
C6 1.0 — 1.0 — 1.5 1.5
aA dash indicates the impossibility of certain suppliers for certain depots or customers.
The distribution costs (which are borne by the company) are known; they are given in Table 19.1 (in £ per ton
delivered).
Certain customers have expressed preferences for being supplied from factories or depots which they are
used to. The preferred suppliers are
C1 Liverpool (factory)
C2 Newcastle (depot)
C3 No preferences
C4 No preferences
C5 Birmingham (depot)
C6 Exeter or London (depots)
Each factory has a monthly capacity given below which cannot be exceeded:
Each depot has a maximum monthly throughput given below which cannot be exceeded:
Each customer has a monthly requirement given below which must be met:
C1 50,000 tons
C2 10,000 tons
C3 40,000 tons
C4 35,000 tons
C5 60,000 tons
C6 20,000 tons
(2) What the effect of increasing factory and depot capacities would be on distribution costs?
(3) What the effects of small changes in costs, capacities and requirements would be on the distribution
pattern?
(4) Would it be possible to meet all customers preferences regarding suppliers and if so what would the
extra cost of doing this be?
.i; j / 2 ARCS
i; factory 2 FACTORIES
i; depot 2 DEPOTS
i; customer 2 CUSTOMERS
i 2 NODES
.i; j / 2 PREFERRED_ARCS
j 2 CUSTOMERS_WITH_PREFERENCES
Parameters F 225
Parameters
Table 19.2 shows the parameters that are used in this example.
Variables
Table 19.3 shows the variables that are used in this example.
Objectives
One objective is to minimize the following function:
X
TotalCost D cost[i,j] Flow[i,j]
.i;j /2ARCS
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 NODES,
X X
Flow[i,j] Flow[j,i] supply[i]
.i;j /2ARCS .j;i /2ARCS
226 F Chapter 19: Distribution 1
for i 2 DEPOTS,
X
Flow[i,j] throughput[i]
.i;j /2ARCS
NonpreferredFlow NonpreferredFlow.sol
Input Data
The following data sets contain the input data that are used in this example:
data arc_data;
input j $11. i $11. cost;
datalines;
Newcastle Liverpool 0.5
Birmingham Liverpool 0.5
Birmingham Brighton 0.3
London Liverpool 1.0
London Brighton 0.5
Exeter Liverpool 0.2
Exeter Brighton 0.2
C1 Liverpool 1.0
C1 Brighton 2.0
C1 Birmingham 1.0
C2 Newcastle 1.5
C2 Birmingham 0.5
C2 London 1.5
C3 Liverpool 1.5
C3 Newcastle 0.5
C3 Birmingham 0.5
C3 London 2.0
C3 Exeter 0.2
C4 Liverpool 2.0
C4 Newcastle 1.5
C4 Birmingham 1.0
C4 Exeter 1.5
C5 Birmingham 0.5
C5 London 0.5
C5 Exeter 0.5
C6 Liverpool 1.0
C6 Newcastle 1.0
C6 London 1.5
C6 Exeter 1.5
;
data customer_data;
input customer $ demand;
datalines;
C1 50000
C2 10000
PROC OPTMODEL Statements and Output F 227
C3 40000
C4 35000
C5 60000
C6 20000
;
data factory_data;
input factory $10. capacity;
datalines;
Liverpool 150000
Brighton 200000
;
data depot_data;
input depot $11. throughput;
datalines;
Newcastle 70000
Birmingham 50000
London 100000
Exeter 40000
;
data preferred_arc_data;
input j $ i $11.;
datalines;
C1 Liverpool
C2 Newcastle
C5 Birmingham
C6 Exeter
C6 London
;
proc optmodel;
set <str,str> ARCS;
num cost {ARCS};
read data arc_data into ARCS=[i j] cost;
The following statements use the UNION set operator to declare the NODES index set, declare the supply
parameter with an initial value of 0, and populate supply for both factories and customers:
Figure 19.2 shows the output when you use the (default) dual simplex algorithm.
Problem Summary
Objective Sense Minimization
Objective Function TotalCost
Objective Type Linear
Number of Variables 29
Bounded Above 0
Bounded Below 29
Bounded Below and Above 0
Free 0
Fixed 0
Number of Constraints 16
Linear LE (<=) 16
Linear EQ (=) 0
Linear GE (>=) 0
Linear Range 0
Constraint Coefficients 75
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalCost
Solution Status Optimal
Objective Value 198500
Primal Infeasibility 0
Dual Infeasibility 0
Bound Infeasibility 0
Iterations 15
Presolve Time 0.00
Solution Time 0.00
230 F Chapter 19: Distribution 1
The following statements call the network simplex linear programming algorithm and print the same solution
information as before:
Figure 19.3 shows the output when you use the ALGORITHM=NS option to invoke the network simplex
algorithm.
Problem Summary
Objective Sense Minimization
Objective Function TotalCost
Objective Type Linear
Number of Variables 29
Bounded Above 0
Bounded Below 29
Bounded Below and Above 0
Free 0
Fixed 0
Number of Constraints 16
Linear LE (<=) 16
Linear EQ (=) 0
Linear GE (>=) 0
Linear Range 0
Constraint Coefficients 75
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Network Simplex
Objective Function TotalCost
Solution Status Optimal
Objective Value 198500
Primal Infeasibility 0
Dual Infeasibility 0
Bound Infeasibility 0
Iterations 15
Iterations2 5
Presolve Time 0.00
Solution Time 0.00
232 F Chapter 19: Distribution 1
The following statements call the linear programming solver to minimize NonpreferredFlow and print both
objectives, the positive variables in the resulting optimal solution, and the flow along nonpreferred arcs:
Figure 19.4 shows the output from the linear programming solver.
Problem Summary
Objective Sense Minimization
Objective Function NonpreferredFlow
Objective Type Linear
Number of Variables 29
Bounded Above 0
Bounded Below 29
Bounded Below and Above 0
Free 0
Fixed 0
Number of Constraints 16
Linear LE (<=) 16
Linear EQ (=) 0
Linear GE (>=) 0
Linear Range 0
Constraint Coefficients 75
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function NonpreferredFlow
Solution Status Optimal
Objective Value 10000
Primal Infeasibility 0
Dual Infeasibility 0
Bound Infeasibility 0
Iterations 14
Presolve Time 0.00
Solution Time 0.00
TotalCost NonpreferredFlow
284000 10000
234 F Chapter 19: Distribution 1
The following CON statement declares a constraint that limits NonpreferredFlow to the minimum value
found in the previous solve:
con Objective_cut:
NonpreferredFlow <= NonpreferredFlow.sol;
The following statements call the linear programming solver to minimize TotalCost with a constrained
NonpreferredFlow and print the same solution information as before:
Figure 19.5 shows the output from the linear programming solver. As expected, NonpreferredFlow remains
at its minimum value and TotalCost is less than its value from Figure 19.4.
Figure 19.5 Output from Linear Programming Solver, Minimizing TotalCost with Constrained Nonpreferred-
Flow
Problem Summary
Objective Sense Minimization
Objective Function TotalCost
Objective Type Linear
Number of Variables 29
Bounded Above 0
Bounded Below 29
Bounded Below and Above 0
Free 0
Fixed 0
Number of Constraints 17
Linear LE (<=) 17
Linear EQ (=) 0
Linear GE (>=) 0
Linear Range 0
Constraint Coefficients 83
Performance Information
Execution Mode Single-Machine
Number of Threads 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function TotalCost
Solution Status Optimal
Objective Value 246000
Primal Infeasibility 0
Dual Infeasibility 2.220446E-16
Bound Infeasibility 0
Iterations 19
Presolve Time 0.00
Solution Time 0.00
TotalCost NonpreferredFlow
246000 10000
236 F Chapter 19: Distribution 1
Features Demonstrated
The following features are demonstrated in this example:
sets of tuples
INIT option
implicit slice
ALGORITHM= option
Chapter 20
Depot Location (Distribution 2): Where Should
New Depots Be Built
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 242
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Problem Statement
In the distribution problem there is a possibility of opening new depots at Bristol and Northampton as well as
of enlarging the Birmingham depot.1
It is not considered desirable to have more than four depots and if necessary Newcastle or Exeter (or both)
can be closed down.
The monthly costs (in interest charges) of the possible new depots and expansion at Birmingham are given in
Table 20.1 together with the potential monthly throughputs.
The monthly savings of closing down the Newcastle and Exeter depots are given in Table 20.2.
Table 20.1
Table 20.2
Saving (£1000)
Newcastle 10
Exeter 5
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 251–252).
238 F Chapter 20: Depot Location (Distribution 2)
Table 20.3
Supplier
Liverpool Brighton Bristol Northampton
Supplied to factory factory depot depot
New depots
Bristol 0.6 0.4
Northampton 0.4 0.3
Customers
C1 1.2 —
C2 0.6 0.4
C3 As given for 0.5 —
C4 distribution problem — 0.5
C5 0.3 0.6
C6 0.8 0.9
The distribution costs involving the new depots are given in Table 20.3 (in £ per ton delivered).
Which new depots should be built? Should Birmingham be expanded? Should Exeter or Newcastle be closed
down? What would be the best resultant distribution pattern to minimize overall costs?
i; depot 2 EXPAND_DEPOTS
Parameters F 239
Parameters
Table 20.4 shows the additional parameters that are used in this example.
Variables
Table 20.5 shows the additional variables that are used in this example.
Objective
The objective is to minimize the following function:
where
X
FixedCost D .open_cost[depot] IsOpen[depot] close_savings[depot] .1 IsOpen[depot]//
depot2DEPOTS
X
C expand_cost[depot] Expand[depot]
depot2EXPAND_DEPOTS
and
X
VariableCost D cost[i,j] Flow[i,j]
.i;j /2ARCS
240 F Chapter 20: Depot Location (Distribution 2)
Constraints
The following additional and modified constraints are used in this example:
bounds on variables
X
IsOpen[i] max_num_depots
i 2DEPOTS
for i 2 DEPOTS,
X
Flow[i,j] throughput[i] IsOpen[i]C.if i 2 EXPAND_DEPOTS, then expand_throughput[i] Expand[i]/
.i;j /2ARCS
for i 2 EXPAND_DEPOTS,
Expand[i] IsOpen[i]
Input Data
The following additional and modified data sets and macro variable contain the input data that are used in
this example:
data arc_data;
input j $12. i $12. cost;
datalines;
Newcastle Liverpool 0.5
Birmingham Liverpool 0.5
Birmingham Brighton 0.3
London Liverpool 1.0
London Brighton 0.5
Exeter Liverpool 0.2
Exeter Brighton 0.2
C1 Liverpool 1.0
C1 Brighton 2.0
C1 Birmingham 1.0
C2 Newcastle 1.5
C2 Birmingham 0.5
C2 London 1.5
C3 Liverpool 1.5
C3 Newcastle 0.5
C3 Birmingham 0.5
C3 London 2.0
C3 Exeter 0.2
C4 Liverpool 2.0
C4 Newcastle 1.5
C4 Birmingham 1.0
C4 Exeter 1.5
Input Data F 241
C5 Birmingham 0.5
C5 London 0.5
C5 Exeter 0.5
C6 Liverpool 1.0
C6 Newcastle 1.0
C6 London 1.5
C6 Exeter 1.5
Bristol Liverpool 0.6
Bristol Brighton 0.4
Northampton Liverpool 0.4
Northampton Brighton 0.3
C1 Bristol 1.2
C2 Bristol 0.6
C2 Northampton 0.4
C3 Bristol 0.5
C4 Northampton 0.5
C5 Bristol 0.3
C5 Northampton 0.6
C6 Bristol 0.8
C6 Northampton 0.9
;
data depot_data;
input depot $12. throughput cost savings;
datalines;
Newcastle 70000 0 10000
Birmingham 50000 0 .
London 100000 0 .
Exeter 40000 0 5000
Bristol 30000 12000 0
Northampton 25000 4000 0
;
data expand_depot_data;
input depot $12. throughput cost;
datalines;
Birmingham 20000 3000
;
%let max_num_depots = 4;
242 F Chapter 20: Depot Location (Distribution 2)
proc optmodel;
set <str,str> ARCS;
num cost {ARCS};
read data arc_data into ARCS=[i j] cost;
con Max_num_depots_con:
sum {i in DEPOTS} IsOpen[i] <= &max_num_depots;
impvar FixedCost =
sum {depot in DEPOTS}
(open_cost[depot] * IsOpen[depot] -
close_savings[depot] * (1 - IsOpen[depot]))
+ sum {depot in EXPAND_DEPOTS} expand_cost[depot] * Expand[depot];
impvar VariableCost = sum {<i,j> in ARCS} cost[i,j] * Flow[i,j];
min TotalCost = FixedCost + VariableCost;
The following statements call the mixed integer linear programming solver and then print the various parts of
the objective, the positive variables in the resulting optimal solution, and the additional decision variables:
solve;
print FixedCost VariableCost TotalCost;
print {<i,j> in ARCS: Flow[i,j].sol > 0} Flow;
print IsOpen Expand;
quit;
244 F Chapter 20: Depot Location (Distribution 2)
Figure 20.1 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Minimization
Objective Function TotalCost
Objective Type Linear
Number of Variables 49
Bounded Above 0
Bounded Below 42
Bounded Below and Above 5
Free 0
Fixed 2
Binary 7
Integer 0
Number of Constraints 22
Linear LE (<=) 22
Linear EQ (=) 0
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalCost
Solution Status Optimal
Objective Value 174000
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
Features Demonstrated
The following features are demonstrated in this example:
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Problem Statement
The government of a country wants to decide what prices should be charged for its dairy products, milk, butter
and cheese.1 All these products arise directly or indirectly from the country’s raw milk production. This raw
milk is usefully divided into the two components of fat and dry matter. After subtracting the quantities of fat
and dry matter which are used for making products for export or consumption on the farms there is a total
yearly availability of 600,000 tons of fat and 750,000 tons of dry matter. This is all available for producing
milk, butter and two kinds of cheese for domestic consumption.
The percentage compositions of the products are given in Table 21.1.
For the previous year the domestic consumption and prices for the products are given in Table 21.2.
Table 21.1
Table 21.2
Price elasticities of demand, relating consumer demand to the prices of each product, have been calculated
on the basis of past statistics. The price elasticity E of a product is defined by
percentage decrease in demand
ED :
percentage increase in price
For the two makes of cheese there will be some degree of substitution in consumer demand depending on
relative prices. This is measured by cross-elasticity of demand with respect to price. The cross-elasticity
EAB from a product A to a product B is defined by
percentage increase in demand for A
EAB D :
percentage increase in price of B
The elasticities and cross-elasticities are given in Table 21.3.
The objective is to determine what prices and resultant demand will maximize total revenue.
It is, however, politically unacceptable to allow a certain price index to rise. As a result of the way this index
is calculated this limitation simply demands that the new prices must be such that the total cost of last year’s
consumption would not be increased. A particularly important additional requirement is to quantify the
economic cost of this political limitation.
Table 21.3
Cheese 1 Cheese 2
to to
Milk Butter Cheese 1 Cheese 2 Cheese 2 Cheese 1
0.4 2.7 1.1 0.4 0.1 0.4
raw 2 RAWS
product; i; j 2 PRODUCTS
Parameters F 249
Parameters
Table 21.4 shows the parameters that are used in this example.
Variables
Table 21.5 shows the variables that are used in this example.
Objective
The objective is to maximize the following (bilinear) quadratic function:
X
TotalRevenue D Price[product] Demand[product]
product2PRODUCTS
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 PRODUCTS,
Demand[i] prev_demand[i] X Price[j] prev_price[j]
D elasticity[i,j]
prev_demand[i] prev_price[j]
j 2PRODUCTS
250 F Chapter 21: Agricultural Pricing
X
prev_demand[product] Price[product]
product2PRODUCTS
X
prev_demand[product] prev_price[product]
product2PRODUCTS
Input Data
The following data sets contain the input data that are used in this example:
data product_data;
input product $ Fat DryMatter Water prev_demand prev_price;
datalines;
Milk 4 9 87 4820000 297
Butter 80 2 18 320000 720
Cheese1 35 30 35 210000 1050
Cheese2 25 40 35 70000 815
;
data elasticity_data;
input i $ j $ elasticity;
datalines;
Milk Milk -0.4
Butter Butter -2.7
Cheese1 Cheese1 -1.1
Cheese2 Cheese2 -0.4
Cheese1 Cheese2 0.1
Cheese2 Cheese1 0.4
;
PROC OPTMODEL Statements and Output F 251
proc optmodel;
set <str> RAWS;
num supply {RAWS};
read data raw_material_data into RAWS=[raw] supply;
max TotalRevenue
= sum {product in PRODUCTS} Price[product] * Demand[product];
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.
252 F Chapter 21: Agricultural Pricing
solve;
print Price Demand;
print Price_index_con.dual;
Figure 21.1 shows the output when you use the (default) 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 1991585587.2
Iterations 48
Presolve Time 0.00
Solution Time 0.25
PROC OPTMODEL Statements and Output F 253
Price_index_con.DUAL
0.61609
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:
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
254 F Chapter 21: Agricultural Pricing
Solution Summary
Solver NLP
Algorithm Active Set
Objective Function TotalRevenue
Solution Status Best Feasible
Objective Value 1991585587.2
Iterations 50
Presolve Time 0.00
Solution Time 0.04
Price_index_con.DUAL
.
The optimal solutions for the two algorithms agree. The dual value is missing for the active set algorithm
because the solution status is Best Feasible.
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):
Figure 21.3 shows the output when you use the (default) quadratic programming solver on the 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 18
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
Iterations 10
Presolve Time 0.00
Solution Time 0.01
256 F Chapter 21: Agricultural Pricing
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
PROC OPTMODEL Statements and Output F 257
Solution Summary
Solver NLP
Algorithm Interior Point
Objective Function TotalRevenue
Solution Status Optimal
Objective Value 1991585591.9
Iterations 7
Presolve Time 0.00
Solution Time 0.01
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
258 F Chapter 21: Agricultural Pricing
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
Iterations 12
Presolve Time 0.00
Solution Time 0.02
Price_index_con.DUAL
0.6161
The optimal solutions and dual values for all three algorithms agree with the previous results.
Features Demonstrated
The following features are demonstrated in this example:
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Problem Statement
A car manufacturer wants to evaluate the efficiencies of different garages who have received a franchise to
sell its cars.1 The method to be used is Data Envelopment Analysis (DEA). References to this technique are
given in Section 3.2. Each garage has a certain number of measurable ‘inputs’. These are taken to be: Staff,
Showroom Space, Catchment Population in different economic categories and annual Enquiries for different
brands of car. Each garage also has a certain number of measurable ‘outputs’. These are taken to be: Number
Sold of different bgg it is not possible to find a mixture of proportions of other garages whose combined
inputs do not exceed those of the garage being considered, but whose outputs are equal to, or exceed, those
of the garage. Should this not be possible then the garage is deemed to be inefficient and the comparator
garages can be identified.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 253–255).
260 F Chapter 22: Efficiency Analysis
Table 22.1
Inputs Outputs
A linear programming model can be built to identify efficient and inefficient garages and their comparators.
i 2 INPUTS
i 2 OUTPUTS
j; k 2 GARAGES
j; g1 2 INEFFICIENT_GARAGES
j; g2 2 EFFICIENT_GARAGES
Parameters
Table 22.2 shows the parameters that are used in this example.
Variables
Table 22.3 shows the variables that are used in this example.
Objective
The objective is to maximize Inefficiency.
262 F Chapter 22: Efficiency Analysis
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 INPUTS,
X
input[i,j] Weight[j] input[i,k]
j 2GARAGES
for i 2 OUTPUTS,
X
output[i,j] Weight[j] output[i,k] Inefficiency
j 2GARAGES
Input Data
The following data sets contain the input data that are used in this example:
data inputs;
input input $9.;
datalines;
staff
showroom
pop1
pop2
alpha_enq
beta_enq
;
data outputs;
input output $11.;
datalines;
alpha_sales
beta_sales
profit
;
data garage_data;
input garage_name $12. staff showroom pop1 pop2 alpha_enq beta_enq
alpha_sales beta_sales profit;
datalines;
Winchester 7 8 10 12 8.5 4 2 0.6 1.5
Andover 6 6 20 30 9 4.5 2.3 0.7 1.6
Basingstoke 2 3 40 40 2 1.5 0.8 0.25 0.5
Poole 14 9 20 25 10 6 2.6 0.86 1.9
Woking 10 9 10 10 11 5 2.4 1 2
Newbury 24 15 15 13 25 19 8 2.6 4.5
PROC OPTMODEL Statements and Output F 263
proc optmodel;
set <str> INPUTS;
read data inputs into INPUTS=[input];
num k;
num efficiency_number {GARAGES};
num weight_sol {GARAGES, GARAGES};
264 F Chapter 22: Efficiency Analysis
The following statements correspond directly to the mathematical programming formulation that is described
earlier:
do k = GARAGES;
solve;
efficiency_number[k] = 1 / Inefficiency.sol;
for {j in GARAGES}
weight_sol[k,j] = (if Weight[j].sol > 1e-6 then Weight[j].sol else .);
end;
Note that the DO loop contains no declaration statements. As the value of k changes, the SOLVE statement
automatically updates the constraints to use the values of input[i,k] and output[i,k] . The approach shown here
is much more efficient than the following alternatives:
Enlarging the set of decision variables by including an additional index, resulting in variables Weight[k,j]
and Inefficiency[k]. Within the DO loop, you must then fix most of the variables to 0 and rely on the
presolver to remove them, but that approach uses much more memory and computational time.
In SAS/OR 13.1, you can instead solve the same set of problems in parallel by replacing the DO loop with
the following COFOR loop:
The following CREATE DATA statements write the inefficient garages and the corresponding multiples of
efficient garages to SAS data sets (in both dense and sparse form), as in Table 14.8 in Williams (1999):
The following statements sort the efficiency_data data set by efficiency and print the results, shown in
Figure 22.2:
proc print;
run;
The following statements sort the weight_data_dense data set by efficiency and print the results, shown in
Figure 22.3:
proc print;
run;
PROC OPTMODEL Statements and Output F 267
Obs w11 w15 w16 w18 w22 w23 w24 w25 w26 w27
1 . . . 0.015212 . . . 0.03409 0.67493 .
2 . 0.54441 1.19914 . . . 2.86247 0.13753 . .
3 . . 0.46969 . . . 0.78310 0.19489 . .
4 . 0.85714 . . . . . 0.21429 . .
5 . . 0.31973 . . . 0.14649 . . .
6 0.021078 . . . .009092662 . . 0.14838 . .
7 . . 0.75733 . . . 0.43442 0.34463 . .
8 . 0.79656 . . . . . 0.14524 0.01773 .
9 . 0.33333 0.09614 . . . . . . .
10 . 0.11929 0.75163 . . . 0.03532 . 0.47905 .
11 . 0.06651 0.47189 0.043482 . . . 0.00894 . .
12 . 0.33543 0.16523 . . . 0.23637 . 0.15424 .
13 . 0.19180 0.16807 . . . . . . .
The weight_data_sparse data set contains the same information in sparse format, as shown in Figure 22.4:
Features Demonstrated
The following features are demonstrated in this example:
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 276
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Problem Statement
A small milk processing company is committed to collecting milk from 20 farms and taking it back to the
depot for processing.1 The company has one tanker lorry with a capacity for carrying 80,000 litres of milk.
Eleven of the farms are small and need a collection only every other day. The other nine farms need a
collection every day. The positions of the farms in relation to the depot (numbered 1) are given in Table 23.1
together with their collection requirements.
Find the optimal route for the tanker lorry on each day, bearing in mind that it has to (i) visit all the ‘every
day’ farms, (ii) visit some of the ‘every other day’ farms, and (iii) work within its capacity. On alternate days
it must again visit the ‘every day’ farms but also visit the ‘every other day’ farms not visited on the previous
day.
For convenience a map of the area considered is given in Figure 23.1.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 255–256).
272 F Chapter 23: Milk Collection
Table 23.1
Position 10 miles:
Collection requirement
Farm East North Collection frequency (1000 litres)
1 (Depot) 0 0 — —
2 3 3 Every day 5
3 1 11 Every day 4
4 4 7 Every day 3
5 5 9 Every day 6
6 5 2 Every day 7
7 4 7 Every day 3
8 6 0 Every day 4
9 3 6 Every day 6
10 1 3 Every day 5
11 0 6 Every other day 4
12 6 4 Every other day 7
13 2 5 Every other day 3
14 2 8 Every other day 4
15 6 10 Every other day 5
16 1 8 Every other day 6
17 3 1 Every other day 8
18 6 5 Every other day 5
19 2 9 Every other day 7
20 6 5 Every other day 6
21 5 4 Every other day 6
Mathematical Programming Formulation F 273
Figure 23.1
i; j 2 NODES
.i; j / 2 EDGES
274 F Chapter 23: Milk Collection
d 2 DAYS
i; j 2 NODES_TEMP
.i; j / 2 EDGES_SOL[iter,d]
ci ; cj 2 COMPONENT_IDS
k 2 COMPONENTŒci
k 2 SUBTOURŒs
Parameters
Table 23.2 shows the parameters that are used in this example.
Variables
Table 23.3 shows the variables that are used in this example.
Objective
The objective is to minimize the following function:
X X
TotalDistance D distance[i,j] UseEdge[i,j,d]
.i;j /2EDGES d 2DAYS
Constraints
The following constraints are used in this example:
bounds on variables
for d 2 DAYS,
X
requirement[i] UseNode[i,d] capacity
i 2NODES
for i 2 NODES,
X
UseNode[i,d] D frequency[i]
d 2DAYS
Input Data
The following data set and macro variables contain the input data that are used in this example:
data farm_data;
farm = _N_;
input east north frequency requirement;
datalines;
0 0 2 0
-3 3 2 5
1 11 2 4
4 7 2 3
-5 9 2 6
-5 -2 2 7
-4 -7 2 3
6 0 2 4
3 -6 2 6
-1 -3 2 5
0 -6 1 4
6 4 1 7
2 5 1 3
-2 8 1 4
6 10 1 5
1 8 1 6
-3 1 1 8
-6 5 1 5
2 9 1 7
-6 -5 1 6
5 -4 1 6
;
proc optmodel;
set NODES;
num east {NODES};
num north {NODES};
num frequency {NODES};
num requirement {NODES};
read data farm_data into NODES=[_N_] east north frequency requirement;
PROC OPTMODEL Statements and Output F 277
min TotalDistance
= sum {<i,j> in EDGES, d in DAYS} distance[i,j] * UseEdge[i,j,d];
UseEdge[i,j,d]
+ sum {i in SUBTOUR[s], j in NODES diff SUBTOUR[s]: <i,j> in EDGES}
UseEdge[i,j,d]
>= 2 * UseNode[k,d];
The following statements declare the index sets and parameters that are needed to detect violated subtour
elimination constraints:
put num_components[d]=;
/* create subtour from each component not containing depot node */
for {k in COMPONENT_IDS: &depot not in COMPONENT[k]} do;
num_subtours = num_subtours + 1;
SUBTOUR[num_subtours] = COMPONENT[k];
put SUBTOUR[num_subtours]=;
end;
end;
print capacity_con.body capacity_con.ub;
print num_components;
end;
The body of the loop calls the mixed integer linear programming solver, finds the connected components
of the support graph of the resulting solution, and adds any subtours found. Note that the DO UNTIL
loop contains no declaration statements. As the value of num_subtours changes, the SOLVE statement
automatically updates the subtour elimination constraints. See Chapter 27 for an alternative approach that
instead uses the SOLVE WITH NETWORK statement together with the CONCOMP option to find the
connected components.
After the DO UNTIL loop terminates, the following statements output the edges that appear in each iteration
of subtour elimination and write the value of iter to a SAS macro variable named num_iters:
%macro showPlots;
%do iter = 1 %to &num_iters;
%do d = 1 %to &num_days;
/* create annotate data set to draw subtours */
data sganno(keep=drawspace linethickness function x1 y1 x2 y2);
retain drawspace "datavalue" linethickness 1;
set sol_data(rename=(xi=x1 yi=y1 xj=x2 yj=y2));
where iter = &iter and d = &d;
function = 'line';
run;
Figure 23.2 and Figure 23.3 show the output from the mixed integer linear programming solver for the first
iteration, before any subtour elimination constraints have been generated.
Figure 23.2 Output from Mixed Integer Linear Programming Solver, Iteration 1, Day 1
PROC OPTMODEL Statements and Output F 281
Figure 23.3 Output from Mixed Integer Linear Programming Solver, Iteration 1, Day 2
282 F Chapter 23: Milk Collection
Figure 23.4 and Figure 23.5 show the output from the mixed integer linear programming solver for the second
iteration, after the first round of subtour elimination constraints.
Figure 23.4 Output from Mixed Integer Linear Programming Solver, Iteration 2, Day 1
PROC OPTMODEL Statements and Output F 283
Figure 23.5 Output from Mixed Integer Linear Programming Solver, Iteration 2, Day 2
284 F Chapter 23: Milk Collection
Figure 23.6 and Figure 23.7 show the output from the mixed integer linear programming solver for the third
iteration, after the second round of subtour elimination constraints.
Figure 23.6 Output from Mixed Integer Linear Programming Solver, Iteration 3, Day 1
PROC OPTMODEL Statements and Output F 285
Figure 23.7 Output from Mixed Integer Linear Programming Solver, Iteration 3, Day 2
286 F Chapter 23: Milk Collection
Since no more subtour elimination constraints are violated, the DO UNTIL loop terminates with an optimal
solution. Figure 23.8 shows the final problem and solution summaries from the mixed integer linear
programming solver.
Figure 23.8 Final Problem and Solution Summaries from Mixed Integer Linear Programming Solver
Problem Summary
Objective Sense Minimization
Objective Function TotalDistance
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalDistance
Solution Status Optimal
Objective Value 1230.5623785
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 2.220446E-15
Bound Infeasibility 1.110223E-15
Integer Infeasibility 1.110223E-15
The optimal objective value differs slightly from the one given in Williams (1999), perhaps because of
rounding of distances by Williams.
Features Demonstrated
The following features are demonstrated in this example:
sets of tuples
INIT option
CARD function
symmetry-breaking constraints
row generation
connected components
CALL SYMPUT
SGPLOT procedure
288
Chapter 24
Yield Management: What Quantities of Airline
Tickets to Sell at What Prices and What Times
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
Problem Statement
An airline is selling tickets for flights to a particular destination.1 The flight will depart in three weeks’ time.
It can use up to six planes each costing £50,000 to hire. Each plane has:
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 1999, pp. 256–258).
290 F Chapter 24: Yield Management
Table 24.1
Demand is uncertain but will be affected by price. Forecasts have been made of these demands according
to a probability distribution which divides the demand levels into three scenarios for each period. The
probabilities of the three scenarios in each period are:
Scenario 1 0.1
Scenario 2 0.7
Scenario 3 0.2
Table 24.2
Table 24.3
period 2 PERIODS
class 2 CLASSES
option 2 OPTIONS
scenario; i 2 SCENARIOS
Parameters
Table 24.4 shows the parameters that are used in this example.
Variables
Table 24.5 shows the variables that are used in this example.
Objective
The objective is to maximize the following quadratic function:
ExpectedYield
0 1
B C
B X C
Bif current_period 1; then
B C
DB prob[i] R1[i,class,option]C
C
B i 2SCENARIOS; C
class2CLASSES;
@ A
0 option2OPTIONS 1
B C
B C
X
C Bif current_period 2; then
B C
B prob[i] prob[j] R2[i,j,class,option]C
C
B .i;j /2SCENARIOS2; C
class2CLASSES;
@ A
0 option2OPTIONS 1
B C
B C
X
C Bif current_period 3; then
B C
B prob[i] prob[j] prob[k] R3[i,j,k,class,option]C
C
B .i;j;k/2SCENARIOS3; C
class2CLASSES;
@ A
option2OPTIONS
X
C actual_revenue[period,class]
period21:::current_period 1;
class2CLASSES
plane_cost NumPlanes
where
Constraints
The following constraints are used in this example:
bounds on variables
C TransferFrom[i,j,k,class] TransferTo[i,j,k,class]
num_seats[class] NumPlanes
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data class_data;
input class $9. num_seats;
datalines;
First 37
Business 38
Economy 47
;
data price_data;
input period class $9. price1-price3;
datalines;
Input Data F 297
data scenario_data;
input prob;
datalines;
0.1
0.7
0.2
;
data demand_data;
input period scenario class $9. demand1-demand3;
datalines;
1 1 First 10 15 20
1 1 Business 20 25 35
1 1 Economy 45 55 60
1 2 First 20 25 35
1 2 Business 40 42 45
1 2 Economy 50 52 63
1 3 First 45 50 60
1 3 Business 45 46 47
1 3 Economy 55 56 64
2 1 First 20 25 35
2 1 Business 42 45 46
2 1 Economy 50 52 60
2 2 First 10 40 50
2 2 Business 50 60 80
2 2 Economy 60 65 90
2 3 First 50 55 80
2 3 Business 20 30 50
2 3 Economy 10 40 60
3 1 First 30 35 40
3 1 Business 40 50 55
3 1 Economy 50 60 80
3 2 First 30 40 60
3 2 Business 10 40 45
3 2 Economy 50 60 70
3 3 First 50 70 80
3 3 Business 40 45 60
3 3 Economy 60 65 70
;
data actual_demand_data;
input period class $9. demand1-demand3;
datalines;
298 F Chapter 24: Yield Management
1 First 25 30 40
1 Business 50 40 45
1 Economy 50 53 65
2 First 22 45 50
2 Business 45 55 75
2 Economy 50 60 80
3 First 45 60 75
3 Business 20 40 50
3 Economy 55 60 75
;
%let num_periods = 3;
%let num_planes = 6;
%let plane_cost = 50000;
%let transfer_fraction_ub = 0.10;
%let num_options = 3;
proc optmodel;
set PERIODS = 1..&num_periods;
set SCENARIOS;
num prob {SCENARIOS};
read data scenario_data into SCENARIOS=[_N_] prob;
set SCENARIOS2 = SCENARIOS cross SCENARIOS;
set SCENARIOS3 = SCENARIOS2 cross SCENARIOS;
num current_period;
The following VAR statements declare the decision variables:
The following CON statements declare the constraints that sales cannot exceed demand:
/* R1[i,class,option] =
price[1,class,option] * P1[class,option] * S1[i,class,option] */
con R1_con_a {i in SCENARIOS, class in CLASSES, option in OPTIONS}:
R1[i,class,option] <= price[1,class,option] * S1[i,class,option];
con R1_con_b {i in SCENARIOS, class in CLASSES, option in OPTIONS}:
price[1,class,option] * S1[i,class,option] - R1[i,class,option]
<= price[1,class,option] * demand[1,i,class,option] *
(1 - P1[class,option]);
/* R2[i,j,class,option] =
price[2,class,option] * P2[i,class,option] * S2[i,j,class,option] */
con R2_con_a {<i,j> in SCENARIOS2, class in CLASSES, option in OPTIONS}:
R2[i,j,class,option] <= price[2,class,option] * S2[i,j,class,option];
con R2_con_b {<i,j> in SCENARIOS2, class in CLASSES, option in OPTIONS}:
price[2,class,option] * S2[i,j,class,option] - R2[i,j,class,option]
<= price[2,class,option] * demand[2,j,class,option] *
(1 - P2[i,class,option]);
/* R3[i,j,k,class,option] =
price[3,class,option] * P3[i,j,class,option] * S3[i,j,k,class,option] */
con R3_con_a {<i,j,k> in SCENARIOS3, class in CLASSES, option in OPTIONS}:
R3[i,j,k,class,option] <= price[3,class,option] * S3[i,j,k,class,option];
con R3_con_b {<i,j,k> in SCENARIOS3, class in CLASSES, option in OPTIONS}:
price[3,class,option] * S3[i,j,k,class,option] - R3[i,j,k,class,option]
<= price[3,class,option] * demand[3,k,class,option] *
(1 - P3[i,j,class,option]);
An alternative “compact linearization” (not shown) involves fewer constraints, as in Chapter 10.
The following MAX statement declares the linearized objective, which depends on current_period :
max ExpectedYield =
(if current_period <= 1
then sum {i in SCENARIOS, class in CLASSES, option in OPTIONS}
prob[i] * R1[i,class,option])
+ (if current_period <= 2
then sum {<i,j> in SCENARIOS2, class in CLASSES, option in OPTIONS}
prob[i] * prob[j] * R2[i,j,class,option])
+ (if current_period <= 3
then sum {<i,j,k> in SCENARIOS3, class in CLASSES, option in OPTIONS}
prob[i] * prob[j] * prob[k] * R3[i,j,k,class,option])
+ sum {period in 1..current_period-1, class in CLASSES}
actual_revenue[period,class]
- &plane_cost * NumPlanes;
PROC OPTMODEL Statements and Output F 301
The following NUM statements use the .sol variable suffix to compute the recommended prices from the
optimal values of the decision variables:
current_period = 1;
solve;
for {i in SCENARIOS, class in CLASSES, option in OPTIONS}
S1[i,class,option] = round(S1[i,class,option].sol);
print price_sol_1;
print sell_up_to_1;
print {i in SCENARIOS, class in CLASSES, option in OPTIONS:
S1[i,class,option].sol > 0} S1;
print price_sol_2;
print price_sol_3;
print NumPlanes ExpectedYield;
The following statements fix the resulting prices for period 1 and use the MIN function to limit sales based
on actual demand:
end;
else fix P1[class,option] = 0;
end;
for {class in CLASSES}
actual_revenue[1,class] = actual_price[1,class] * actual_sales[1,class];
print actual_price actual_sales actual_revenue;
Figure 24.1 shows the output from the mixed integer linear programming solver for period 1.
Figure 24.1 Output from Mixed Integer Linear Programming Solver, Period 1
The OPTMODEL Procedure
Problem Summary
Objective Sense Maximization
Objective Function ExpectedYield
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
PROC OPTMODEL Statements and Output F 303
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function ExpectedYield
Solution Status Optimal
Objective Value 169543.624
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 1.421085E-14
Bound Infeasibility 2.697009E-12
Integer Infeasibility 1.110223E-16
[1] price_sol_1
Business 900
Economy 500
First 1200
[1] sell_up_to_1
Business 45
Economy 55
First 45
price_sol_2
1 2 3
Business 1100 1100 1100
Economy 700 700 700
First 1150 1150 1300
304 F Chapter 24: Yield Management
NumPlanes ExpectedYield
3 169544
The following statements drop the period 1 constraints and call the mixed integer linear programming solver
to determine the optimal prices for period 2:
print sell_up_to_2;
print {<i,j> in SCENARIOS2, class in CLASSES, option in OPTIONS:
i = 1 and S2[1,j,class,option].sol > 0} S2;
print price_sol_3;
print NumPlanes ExpectedYield;
The following statements fix the resulting prices for period 2 and use the MIN function to limit sales based
on actual demand:
Figure 24.2 Output from Mixed Integer Linear Programming Solver, Period 2
Problem Summary
Objective Sense Maximization
Objective Function ExpectedYield
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
306 F Chapter 24: Yield Management
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function ExpectedYield
Solution Status Optimal
Objective Value 172968.66
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 3.637979E-12
Bound Infeasibility 0
Integer Infeasibility 0
price_sol_2
1 2 3
Business 1100 1100 1100
Economy 700 700 700
First 1150 1150 1150
[1] sell_up_to_2
Business 50
Economy 60
First 60
NumPlanes ExpectedYield
3 172969
The following statements drop the period 2 constraints and call the mixed integer linear programming solver
to determine the optimal prices for period 3:
current_period = 3;
drop P2_con S2_con R2_con_a R2_con_b;
solve;
Figure 24.3 shows the output from the mixed integer linear programming solver for period 3.
Figure 24.3 Output from Mixed Integer Linear Programming Solver, Period 3
Problem Summary
Objective Sense Maximization
Objective Function ExpectedYield
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function ExpectedYield
Solution Status Optimal within Relative Gap
Objective Value 176392.4
[1] sell_up_to_3
Business 24
Economy 41
First 36
NumPlanes ExpectedYield
3 176392
PROC OPTMODEL Statements and Output F 311
The following statements print the expected yield that results from the optimal prices, with sales limited by
actual demands:
current_period = 4;
print ExpectedYield;
quit;
Figure 24.4 shows the final expected yield.
ExpectedYield
180380
Maximizing yield based on expected demands is much simpler than the stochastic programming approach
and requires only one solver call. The first several PROC OPTMODEL statements are the same as before:
proc optmodel;
set PERIODS = 1..&num_periods;
set SCENARIOS;
num prob {SCENARIOS};
read data scenario_data into SCENARIOS=[_N_] prob;
/* R[period,class,option] =
price[period,class,option] * P[period,class,option] *
S[period,class,option] */
con R_con_a {period in PERIODS, class in CLASSES, option in OPTIONS}:
R[period,class,option] <= price[period,class,option] *
S[period,class,option];
con R_con_b {period in PERIODS, class in CLASSES, option in OPTIONS}:
price[period,class,option] * S[period,class,option] -
R[period,class,option]
PROC OPTMODEL Statements and Output F 313
max Yield =
sum {period in PERIODS, class in CLASSES, option in OPTIONS}
R[period,class,option]
- &plane_cost * NumPlanes;
solve;
for {period in PERIODS, class in CLASSES, option in OPTIONS}
S[period,class,option] = round(S[period,class,option].sol);
print price_sol;
print {period in PERIODS, class in CLASSES, option in OPTIONS:
S[period,class,option].sol > 0} S;
print NumPlanes Yield;
for {period in PERIODS, class in CLASSES, option in OPTIONS} do;
if P[period,class,option].sol > 0.5 then do;
actual_price[period,class] = price_sol[period,class];
actual_sales[period,class] =
min(S[period,class,option], actual_demand[period,class,option]);
actual_revenue[period,class] =
actual_price[period,class] * actual_sales[period,class];
R[period,class,option] = actual_revenue[period,class];
end;
end;
print actual_price actual_sales actual_revenue;
print Yield;
314 F Chapter 24: Yield Management
Figure 24.5 shows the output from the mixed integer linear programming solver for the problem based on
expected demands.
Figure 24.5 Output from Mixed Integer Linear Programming Solver, Based on Expected Demands
The OPTMODEL Procedure
Problem Summary
Objective Sense Maximization
Objective Function Yield
Objective Type Linear
Number of Variables 88
Bounded Above 0
Bounded Below 54
Bounded Below and Above 34
Free 0
Fixed 0
Binary 27
Integer 1
Number of Constraints 94
Linear LE (<=) 84
Linear EQ (=) 10
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
PROC OPTMODEL Statements and Output F 315
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function Yield
Solution Status Optimal
Objective Value 180309
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 1.421085E-14
Bound Infeasibility 6.846607E-12
Integer Infeasibility 1.269065E-16
price_sol
Business Economy First
1 900 500 1200
2 1100 700 1150
3 800 480 1500
NumPlanes Yield
3 180309
316 F Chapter 24: Yield Management
Yield
174760
As anticipated, the yield is smaller than in Figure 24.4 because there is no opportunity here to change prices
based on actual demand from previous periods.
The following statements show the modifications to maximize yield based on actual demands:
solve;
for {period in PERIODS, class in CLASSES, option in OPTIONS}
S[period,class,option] = round(S[period,class,option].sol);
print price_sol;
print {period in PERIODS, class in CLASSES, option in OPTIONS:
S[period,class,option].sol > 0} S;
print NumPlanes Yield;
Since actual demand is considered directly in this formulation, the postprocessing steps do not need to reduce
sales to actual demand:
Figure 24.6 shows the output from the mixed integer linear programming solver for the problem based on
actual demands.
Figure 24.6 Output from Mixed Integer Linear Programming Solver, Based on Actual Demands
Problem Summary
Objective Sense Maximization
Objective Function Yield
Objective Type Linear
Number of Variables 88
Bounded Above 0
Bounded Below 54
Bounded Below and Above 34
Free 0
Fixed 0
Binary 27
Integer 1
Number of Constraints 94
Linear LE (<=) 84
Linear EQ (=) 10
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function Yield
Solution Status Optimal
Objective Value 193964
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
price_sol
Business Economy First
1 900 500 1200
2 1100 700 1300
3 820 480 1500
NumPlanes Yield
3 193964
As anticipated, the yield is highest here because optimal prices and sales are determined with perfect
knowledge of demand.
The stochastic programming formulation shown earlier represents a natural compromise between the deter-
ministic formulations based on expected demand or actual demand.
Features Demonstrated F 319
Features Demonstrated
The following features are demonstrated in this example:
problem type: mixed integer linear programming (stochastic programming with recourse)
sets of tuples
compact linearization
IF-THEN expression
ROUND function
IF-THEN statement
FIX statement
MIN function
DROP statement
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 328
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Problem Statement
A small (‘cut price’) car rental company, renting one type of car, has depots in Glasgow, Manchester,
Birmingham and Plymouth.1 There is an estimated demand for each day of the week except Sunday when
the company is closed. These estimates are given in Table 25.1. It is not necessary to meet all demand.
Table 25.1
Cars can be rented for one, two or three days and returned to either the depot from which rented or another
depot at the start of the next morning. For example, a 2-day rental on Thursday means that the car has to be
returned on Saturday morning; a 3-day rental on Friday means that the car has to be returned on Tuesday
morning. A 1-day rental on Saturday means that the car has to be returned on Monday morning and a 2-day
rental on Tuesday morning.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 2013, pp. 284–286).
322 F Chapter 25: Car Rental 1
Table 25.2
From To
Glasgow Manchester Birmingham Plymouth
Glasgow 60 20 10 10
Manchester 15 55 25 5
Birmingham 15 20 54 11
Plymouth 8 12 27 53
Table 25.3
From To
Glasgow Manchester Birmingham Plymouth
Glasgow — 20 30 50
Manchester 20 — 15 35
Birmingham 30 15 — 25
Plymouth 50 35 25 —
The rental period is independent of the origin and destination. From past data, the company knows the
distribution of rental periods: 55% of cars are hired for one day, 20% for two days and 25% for three days.
The current estimates of percentages of cars hired from each depot and returned to a given depot (independent
of day) are given in Table 25.2.
The marginal cost, to the company, of renting out a car (‘wear and tear’, administration etc.) is estimated as
follows:
The ‘opportunity cost’ (interest on capital, storage, servicing, etc.) of owning a car is £15 per week.
It is possible to transfer undamaged cars from one depot to another depot, irrespective of distance. Cars
cannot be rented out during the day in which they are transferred. The costs (£), per car, of transfer are given
in Table 25.3.
Ten percent of cars returned by customers are damaged. When this happens, the customer is charged an
excess of £100 (irrespective of the amount of damage that the company completely covers by its insurance).
In addition, the car has to be transferred to a repair depot, where it will be repaired the following day. The
cost of transferring a damaged car is the same as transferring an undamaged one (except when the repair
depot is the current depot, when it is zero). Again the transfer of a damaged car takes a day, unless it is
already at a repair depot. Having arrived at a repair depot, all types of repair (or replacement) take a day.
Only two of the depots have repair capacity. These are (cars/day) as follows:
Manchester 12
Birmingham 20
Problem Statement F 323
Having been repaired, the car is available for rental at the depot the next day or may be transferred to another
depot (taking a day). Thus, a car that is returned damaged on a Wednesday morning is transferred to a repair
depot (if not the current depot) during Wednesday, repaired on Thursday and is available for hire at the repair
depot on Friday morning.
The rental price depends on the number of days for which the car is hired and whether it is returned to the
same depot or not. The prices are given in Table 25.4 (in £).
Table 25.4
Return to Return to
Same Depot Another Depot
1-Day hire 50 70
2-Day hire 70 100
3-Day hire 120 150
There is a discount of £20 for hiring on a Saturday so long as the car is returned on Monday morning. This is
regarded as a 1-day hire.
For simplicity, we assume the following at the beginning of each day:
(6) If it is a repair depot, then the repaired cars are available for rental.
In order to maximise weekly profit, the company wants a ‘steady state’ solution in which the same expected
number will be located at the same depot on the same day of subsequent weeks.
How many cars should the company own and where should they be located at the start of each day?
This is a case where the integrality of the cars is not worth modelling. Rounded fractional solutions are
acceptable.
324 F Chapter 25: Car Rental 1
depot; i; j 2 DEPOTS
Parameters
Table 25.5 shows the parameters that are used in this example.
Variables
Table 25.6 shows the variables that are used in this example.
Objective
The objective is to maximize the following function:
X
Profit D .rental_price[i,j,day,length] cost[length] / NumCarsRented[i,j,day,length]
i 2DEPOTS;
j 2DEPOTS;
day2DAYS;
length2LENGTHS
X
C damage_prob damage_charge NumCarsRented_i_day[i,day]
i 2DEPOTS;
day2DAYS
X
transfer_cost[i,j] NumCarsTransferred[i,j,day]
i 2DEPOTS;
j 2DEPOTSnfi g;
day2DAYS
opportunity_cost_per_week NumCars
326 F Chapter 25: Car Rental 1
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 DEPOTS and j 2 DEPOTS and day 2 DAYS and length 2 LENGTHS,
NumCarsTransferred[i,j,day] D NumUndamagedCarsTransferred[i,j,day]CNumDamagedCarsTransferred[i,j,day]
NumUndamagedCarsStart[i,day]
X
D .1 damage_prob/ NumCarsRented[j,i,day-length,length]
j 2DEPOTS;
length2LENGTHS
X
C NumUndamagedCarsTransferred[j,i,day-transfer_length]
j 2DEPOTSnfi g
C NumDamagedCarsRepaired[i,day-repair_length]
C NumUndamagedCarsIdle[i,day-1]
NumDamagedCarsStart[i,day]
X
D damage_prob NumCarsRented[j,i,day-length,length]
j 2DEPOTS;
length2LENGTHS
X
C NumDamagedCarsTransferred[j,i,day-transfer_length]
j 2DEPOTSnfi g
C NumDamagedCarsIdle[i,day-1]
NumUndamagedCarsStart[i,day]
D NumCarsRented_i_day[i,day]
X
C NumUndamagedCarsTransferred[i,j,day]
j 2DEPOTSnfi g
C NumUndamagedCarsIdle[i,day]
Input Data F 327
NumDamagedCarsStart[i,day]
D NumDamagedCarsRepaired[i,day]
X
C NumDamagedCarsTransferred[i,j,day]
j 2DEPOTSnfi g
C NumDamagedCarsIdle[i,day]
X
NumCars D length_prob[3] NumCarsRented_i_day[i,0]
i2DEPOTS
3
X
C length_prob[length] NumCarsRented_i_day[i,1]
lengthD2
C NumUndamagedCarsStart[i,2] C NumDamagedCarsStart[i,2]
Input Data
The following data sets and macro variables contain the input data that are used in this example:
data depot_data;
input depot $10.;
datalines;
Glasgow
Manchester
Birmingham
Plymouth
;
data demand_data;
input day $10. Glasgow Manchester Birmingham Plymouth;
datalines;
Monday 100 250 95 160
Tuesday 150 143 195 99
Wednesday 135 80 242 55
Thursday 83 225 111 96
Friday 120 210 70 115
Saturday 230 98 124 80
;
data length_data;
input length prob cost price_same price_diff;
datalines;
1 0.55 20 50 70
2 0.20 25 70 100
3 0.25 30 120 150
;
328 F Chapter 25: Car Rental 1
data transition_prob_data;
input i $10. Glasgow Manchester Birmingham Plymouth;
datalines;
Glasgow 60 20 10 10
Manchester 15 55 25 5
Birmingham 15 20 54 11
Plymouth 8 12 27 53
;
data transfer_cost_data;
input i $10. Glasgow Manchester Birmingham Plymouth;
datalines;
Glasgow . 20 30 50
Manchester 20 . 15 35
Birmingham 30 15 . 25
Plymouth 50 35 25 .
;
data repair_data;
input depot $10. repair_capacity;
datalines;
Manchester 12
Birmingham 20
;
proc optmodel;
set <str> DEPOTS;
read data depot_data into DEPOTS=[depot];
set DAYS;
str day_name {DAYS};
num demand {DEPOTS, DAYS};
read data demand_data into DAYS=[_N_];
num num_days = card(DAYS);
DAYS = 0..num_days-1;
read data demand_data into [_N_]
{depot in DEPOTS} <demand[depot,_N_-1]=col(depot)>;
set LENGTHS;
PROC OPTMODEL Statements and Output F 329
max Profit =
sum {i in DEPOTS, j in DEPOTS, day in DAYS, length in LENGTHS}
(rental_price[i,j,day,length] - cost[length])
* NumCarsRented[i,j,day,length]
+ sum {i in DEPOTS, day in DAYS}
&damage_prob * &damage_charge * NumCarsRented_i_day[i,day]
- sum {i in DEPOTS, j in DEPOTS diff {i}, day in DAYS}
transfer_cost[i,j] * NumCarsTransferred[i,j,day]
- &opportunity_cost_per_week * NumCars;
con NumCars_con:
NumCars = sum {i in DEPOTS} (
length_prob[3] * NumCarsRented_i_day[i,0]
+ sum {length in 2..3} length_prob[length] * NumCarsRented_i_day[i,1]
+ NumUndamagedCarsStart[i,2]
+ NumDamagedCarsStart[i,2]);
The NumCars_con constraint expresses the fact that every car is rented on Monday for three days, rented on
Tuesday for two or three days, or at some depot at the beginning of Wednesday.
PROC OPTMODEL Statements and Output F 331
The following statements call the LP solver and use the generic problem symbols _NVAR_ and _VAR_ to
round all variables to integer values, as in Williams (2013):
solve;
for {j in 1.._NVAR_} _VAR_[j] = round(_VAR_[j].sol);
The following statements print the solution and use the .dual variable suffix to print the shadow prices for
repair capacity:
print NumCars;
print NumUndamagedCarsStart;
print NumDamagedCarsStart;
print NumCarsRented_i_day;
print {i in DEPOTS, j in DEPOTS diff {i}, day in DAYS:
NumDamagedCarsTransferred[i,j,day].sol > 0} NumDamagedCarsTransferred;
print NumDamagedCarsRepaired.dual;
quit;
Figure 25.1 shows the output from the linear programming solver.
Problem Summary
Objective Sense Maximization
Objective Function Profit
Objective Type Linear
Number of Constraints 97
Linear LE (<=) 0
Linear EQ (=) 97
Linear GE (>=) 0
Linear Range 0
Performance Information
Execution Mode Single-Machine
Number of Threads 1
332 F Chapter 25: Car Rental 1
Solution Summary
Solver LP
Algorithm Dual Simplex
Objective Function Profit
Solution Status Optimal
Objective Value 119302.04331
Iterations 82
Presolve Time 0.00
Solution Time 0.00
NumCars
681
NumUndamagedCarsStart
0 1 2 3 4 5
Birmingham 183 195 126 127 145 182
Glasgow 111 82 70 79 79 71
Manchester 163 104 99 126 110 100
Plymouth 67 44 42 48 47 43
NumDamagedCarsStart
0 1 2 3 4 5
Birmingham 25 20 22 20 20 20
Glasgow 4 8 8 13 13 8
Manchester 12 12 12 12 12 12
Plymouth 3 5 5 6 12 17
NumCarsRented_i_day
0 1 2 3 4 5
Birmingham 95 195 126 111 70 81
Glasgow 100 82 70 79 79 0
Manchester 163 104 80 126 110 0
Plymouth 67 44 42 48 47 0
Features Demonstrated F 333
NumDamagedCarsRepaired.DUAL
0 1 2 3 4 5
Birmingham 591.46 590.99 591.46 591.46 591.46 591.46
Glasgow 625.49 637.39 635.16 632.06 625.49 625.49
Manchester 607.36 602.62 617.62 615.27 610.84 610.84
Plymouth 622.55 634.02 632.50 630.10 625.55 625.55
The optimal solution, objective value, and shadow prices differ from Williams (2013), because of errors that
will be corrected in a subsequent printing by Wiley.
Features Demonstrated
The following features are demonstrated in this example:
problem type: linear programming (generalized network flow, periodic inventory optimization)
INIT option
NOMISS option
IMPVAR statement
IF-THEN/ELSE expression
MOD function
CARD function
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 338
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
Problem Statement
In the light of the solution to the problem stated in Chapter 25, the company wants to consider where it
might be most worthwhile to expand repair capacity.1 The weekly fixed costs, given below, include interest
payments on the necessary loans for expansion.
The options are as follows:
(1) Expand repair capacity at Birmingham by 5 cars per day at a fixed cost per week of £18,000.
(2) Further expand repair capacity at Birmingham by 5 cars per day at a fixed cost per week of £8000.
(3) Expand repair capacity at Manchester by 5 cars per day at a fixed cost per week of £20,000.
(4) Further expand repair capacity at Manchester by 5 cars per day at a fixed cost per week of £5000.
(5) Create repair capacity at Plymouth of 5 cars per day at a fixed cost per week of £19,000.
If any of these options is chosen, it must be carried out in its entirety, that is, there can be no partial expansion.
Also, a further expansion at a depot can be carried out only if the first expansion is also carried out, so
for example option (2) at Birmingham cannot be chosen unless option (1) is also chosen. If option (2) is
chosen, thereby also choosing option (1), these count as two options. Similar stipulations apply regarding the
expansions at Manchester. At most three of the options can be carried out.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 2013, p. 287).
336 F Chapter 26: Car Rental 2
expansion 2 EXPANSIONS
Parameters
Table 26.1 shows the additional parameters that are used in this example.
Variables
Table 26.2 shows the additional variables that are used in this example.
Objective
The objective is to maximize the following function:
X
Profit2 D Profit expansion_cost[expansion] ExpandCapacity[expansion]
expansion2EXPANSIONS
Constraints
The following additional constraints are used in this example:
NumDamagedCarsRepaired[i,day] repair_capacity[i]
X
C expansion_amount[expansion] ExpandCapacity[expansion]
expansion2EXPANSIONSW
expansion_depot[expansion] Di
ExpandCapacity[expansion] ExpandCapacity[expansion_prerequisite[expansion]]
X
ExpandCapacity[expansion] max_num_expansions
expansion2EXPANSIONS
Input Data
The following data set and macro variable contain the additional input data that are used in this example:
%let max_num_expansions = 3;
338 F Chapter 26: Car Rental 2
proc optmodel;
set <str> DEPOTS;
read data depot_data into DEPOTS=[depot];
set DAYS;
str day_name {DAYS};
num demand {DEPOTS, DAYS};
read data demand_data into DAYS=[_N_];
num num_days = card(DAYS);
DAYS = 0..num_days-1;
read data demand_data into [_N_]
{depot in DEPOTS} <demand[depot,_N_-1]=col(depot)>;
set LENGTHS;
num length_prob {LENGTHS};
num cost {LENGTHS};
num price_same {LENGTHS};
num price_diff {LENGTHS};
read data length_data into LENGTHS=[length]
length_prob=prob cost price_same price_diff;
max Profit =
sum {i in DEPOTS, j in DEPOTS, day in DAYS, length in LENGTHS}
(rental_price[i,j,day,length] - cost[length])
* NumCarsRented[i,j,day,length]
+ sum {i in DEPOTS, day in DAYS}
&damage_prob * &damage_charge * NumCarsRented_i_day[i,day]
- sum {i in DEPOTS, j in DEPOTS diff {i}, day in DAYS}
transfer_cost[i,j] * NumCarsTransferred[i,j,day]
- &opportunity_cost_per_week * NumCars;
con NumCars_con:
340 F Chapter 26: Car Rental 2
set EXPANSIONS;
str expansion_depot {EXPANSIONS};
num expansion_amount {EXPANSIONS};
num expansion_cost {EXPANSIONS};
num expansion_prerequisite {EXPANSIONS};
read data expansion_data into EXPANSIONS=[expansion]
expansion_depot expansion_amount expansion_cost expansion_prerequisite;
The BINARY option in the following VAR statement declares ExpandCapacity to be a binary variable:
con Cardinality:
sum {expansion in EXPANSIONS} ExpandCapacity[expansion]
<= &max_num_expansions;
PROC OPTMODEL Statements and Output F 341
The following objective declaration uses the previously declared objective function:
solve;
for {j in 1.._NVAR_} _VAR_[j] = round(_VAR_[j].sol);
print expansion_depot ExpandCapacity;
print NumDamagedCarsRepaired;
print NumCars;
quit;
Figure 26.1 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Maximization
Objective Function Profit2
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
342 F Chapter 26: Car Rental 2
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function Profit2
Solution Status Optimal
Objective Value 130792.96054
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 3.410605E-13
Bound Infeasibility 2.220446E-16
Integer Infeasibility 1E-6
NumDamagedCarsRepaired
0 1 2 3 4 5
Birmingham 20 20 20 20 20 20
Glasgow 0 0 0 0 0 0
Manchester 22 22 22 22 22 22
Plymouth 0 0 0 0 0 0
NumCars
955
Note that the resulting profit is higher than in Chapter 25. This result is expected because the repair capacity
expansion options allow more flexibility. The optimal solution and objective value differ from Williams
(2013), because of errors that will be corrected in a subsequent printing by Wiley.
Features Demonstrated F 343
Features Demonstrated
The following features are demonstrated in this example:
INIT option
NOMISS option
IMPVAR statement
IF-THEN/ELSE expression
MOD function
CARD function
CONSTANT function
fixed cost
cardinality constraint
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Problem Statement
A small company with six vans has a contract with a number of airlines to pick up lost or delayed baggage,
belonging to customers in the London area, from Heathrow airport at 6 p.m. each evening.1 The contract
stipulates that each customer must have [his or her] baggage delivered by 8 p.m. The company requires a
model, which they can solve quickly each evening, to advise them what is the minimum number of vans they
need to use and to which customers each van should deliver and in what order. There is no practical capacity
limitation on each van. All baggage that needs to be delivered in a two-hour period can be accommodated in
a van. Having ascertained the minimum number of vans needed, a solution is then sought, which minimises
the maximum time taken by any van.
On a particular evening, the places where deliveries need to be made and the times to travel between them (in
minutes) are given in Table 27.1. No allowance is made for drop off times. For convenience, Heathrow will
be regarded as the first location.
Formulate optimisation models that will minimise the number of vans that need to be used, and within this
minimum, minimise the time taken for the longest time delivery.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 2013, pp. 287–289).
346 F Chapter 27: Lost Baggage Distribution
Table 27.1
Heathrow 20 25 35 65 90 85 80 86 25 35 20 44 35 82
Harrow 15 35 60 55 57 85 90 25 35 30 37 20 40
Ealing 30 50 70 55 50 65 10 25 15 24 20 90
Holborn 45 60 53 55 47 12 22 20 12 10 21
Sutton 46 15 45 75 25 11 19 15 25 25
Dartford 15 15 25 45 65 53 43 63 70
Bromley 17 25 41 25 33 27 45 30
Greenwich 25 40 34 32 20 30 10
Barking 65 70 72 61 45 13
Hammersmith 20 8 7 15 25
Kingston 5 12 45 65
Richmond 14 34 56
Battersea 30 40
Islington 27
Woolwich
Mathematical Programming Formulation F 347
i; j 2 NODES
.i; j / 2 ARCS
v 2 VEHICLES
i; j 2 NODES_SOL
.i; j / 2 ARCS_SOL
ci 2 COMPONENT_IDS
k 2 COMPONENTŒci
k 2 SUBTOURŒs
Parameters
Table 27.2 shows the parameters that are used in this example.
Variables
Table 27.3 shows the variables that are used in this example.
Objectives
The first objective is to minimize the following function:
X
NumVehiclesUsed D UseVehicle[v]
v2VEHICLES
Constraints
The following constraints are used in this example:
bounds on variables
UseNode[i,v] UseVehicle[v]
for v 2 VEHICLES,
UseVehicle[v] UseNode[depot,v]
for v 2 VEHICLES,
X
TimeUsed[v] D travel_time[i,j] UseArc[i,j,v]
.i;j /2ARCS
for v 2 VEHICLES,
MaxTimeUsed TimeUsed[v]
Input Data
The following data set and macro variables contain the input data that are used in this example:
data time_data;
input location $11.
Heathrow Harrow Ealing Holborn Sutton Dartford Bromley Greenwich
Barking Hammersmith Kingston Richmond Battersea Islington Woolwich;
datalines;
Heathrow 0 20 25 35 65 90 85 80 86 25 35 20 44 35 82
Harrow . 0 15 35 60 55 57 85 90 25 35 30 37 20 40
Ealing . . 0 30 50 70 55 50 65 10 25 15 24 20 90
Holborn . . . 0 45 60 53 55 47 12 22 20 12 10 21
Sutton . . . . 0 46 15 45 75 25 11 19 15 25 25
Dartford . . . . . 0 15 15 25 45 65 53 43 63 70
Bromley . . . . . . 0 17 25 41 25 33 27 45 30
Greenwich . . . . . . . 0 25 40 34 32 20 30 10
Barking . . . . . . . . 0 65 70 72 61 45 13
Hammersmith . . . . . . . . . 0 20 8 7 15 25
Kingston . . . . . . . . . . 0 5 12 45 65
350 F Chapter 27: Lost Baggage Distribution
Richmond . . . . . . . . . . . 0 14 34 56
Battersea . . . . . . . . . . . . 0 30 40
Islington . . . . . . . . . . . . . 0 27
Woolwich . . . . . . . . . . . . . . 0
;
%let num_vehicles = 6;
%let time_limit = 120;
%let depot = Heathrow;
%macro findConnectedComponents;
if card(ARCS_SOL) > 0 then do;
solve with NETWORK /
links = (include=ARCS_SOL)
subgraph = (nodes=NODES_SOL)
concomp
out = (concomp=component_id);
COMPONENT_IDS = setof {i in NODES_SOL} component_id[i];
for {c in COMPONENT_IDS} COMPONENT[c] = {};
for {i in NODES_SOL} do;
ci = component_id[i];
COMPONENT[ci] = COMPONENT[ci] union {i};
end;
end;
else COMPONENT_IDS = {};
%mend findConnectedComponents;
The following SAS macro contains a DO UNTIL loop that implements dynamic generation of subtour
elimination constraints (“row generation”), as in Chapter 23:
%macro subtourEliminationLoop;
/* loop until each vehicle's support graph is connected */
do until (and {v in VEHICLES} num_components[v] <= 1);
solve;
/* find connected components for each vehicle */
for {v in VEHICLES} do;
NODES_SOL = {i in NODES: UseNode[i,v].sol > 0.5};
ARCS_SOL = {<i,j> in ARCS: UseArc[i,j,v].sol > 0.5};
%findConnectedComponents;
num_components[v] = card(COMPONENT_IDS);
/* create subtour from each component not containing depot node */
PROC OPTMODEL Statements and Output F 351
proc optmodel;
num num_vehicles init &num_vehicles;
set VEHICLES = 1..num_vehicles;
str depot = "&depot";
set <str> NODES;
read data time_data into NODES=[location];
set ARCS init NODES cross NODES;
num travel_time {ARCS};
read data time_data into [i=location]
{j in NODES} <travel_time[i,j]=col(j)>;
The following statements make the travel times symmetric, except that travel time back to the depot is set to
0:
The PRINT statement results in the first section of output, shown in Figure 27.1.
travel_time
Barking Battersea Bromley Dartford Ealing Greenwich Hammersmith Harrow Heathrow Holborn
Barking 61 25 25 65 25 65 90 0 47
Battersea 61 27 43 24 20 7 37 0 12
Bromley 25 27 15 55 17 41 57 0 53
Dartford 25 43 15 70 15 45 55 0 60
Ealing 65 24 55 70 50 10 15 0 30
Greenwich 25 20 17 15 50 40 85 0 55
Hammersmith 65 7 41 45 10 40 25 0 12
Harrow 90 37 57 55 15 85 25 0 35
Heathrow 86 44 85 90 25 80 25 20 35
Holborn 47 12 53 60 30 55 12 35 0
Islington 45 30 45 63 20 30 15 20 0 10
Kingston 70 12 25 65 25 34 20 35 0 22
Richmond 72 14 33 53 15 32 8 30 0 20
Sutton 75 15 15 46 50 45 25 60 0 45
Woolwich 13 40 30 70 90 10 25 40 0 21
travel_time
Islington Kingston Richmond Sutton Woolwich
Barking 45 70 72 75 13
Battersea 30 12 14 15 40
Bromley 45 25 33 15 30
Dartford 63 65 53 46 70
Ealing 20 25 15 50 90
Greenwich 30 34 32 45 10
Hammersmith 15 20 8 25 25
Harrow 20 35 30 60 40
Heathrow 35 35 20 65 82
Holborn 10 22 20 45 21
Islington 45 34 25 27
Kingston 45 5 11 65
Richmond 34 5 19 56
Sutton 25 11 19 25
Woolwich 27 65 56 25
The following model declaration statements correspond directly to the mathematical programming formula-
tion that is described earlier:
min NumVehiclesUsed =
PROC OPTMODEL Statements and Output F 353
The following statements declare the index sets and parameters that are needed to detect violated subtour
elimination constraints:
%subtourEliminationLoop;
num_vehicles = round(NumVehiclesUsed.sol);
Changing the value of num_vehicles automatically updates the VEHICLES index set and consequently all
the model declarations that depend on VEHICLES.
The following statements declare the additional variables, objective, and constraints that are needed to
minimize the makespan, given the minimum number of vehicles already found:
%subtourEliminationLoop;
for {v in VEHICLES: UseVehicle[v].sol > 0.5} do;
print v;
print {<i,j> in ARCS: UseArc[i,j,v].sol > 0.5} travel_time[i,j];
end;
quit;
PROC OPTMODEL Statements and Output F 355
Figure 27.2 through Figure 27.9 show the output from each iteration of subtour elimination.
Figure 27.10 shows the final problem and solution summaries from the mixed integer linear programming
solver.
Figure 27.10 Final Problem and Solution Summaries from Mixed Integer Linear Programming Solver
Problem Summary
Objective Sense Minimization
Objective Function Makespan
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function Makespan
Solution Status Optimal
Objective Value 100
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
Figure 27.11 shows the travel times for the arcs that are used by each vehicle in the final solution.
Figure 27.11 Travel Times for Arcs Used by Each Vehicle in the Final Solution
v
1
[1] [2]
Bromley Dartford 15
Dartford Heathrow 0
Ealing Hammersmith 10
Hammersmith Richmond 8
Harrow Ealing 15
Heathrow Harrow 20
Kingston Sutton 11
Richmond Kingston 5
Sutton Bromley 15
v
2
[1] [2]
Barking Heathrow 0
Battersea Greenwich 20
Greenwich Woolwich 10
Heathrow Islington 35
Holborn Battersea 12
Islington Holborn 10
Woolwich Barking 13
Features Demonstrated
The following features are demonstrated in this example:
sets of tuples
multiple objectives
INIT option
CARD function
Features Demonstrated F 359
symmetry-breaking constraints
row generation
connected components
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 365
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Problem Statement
This problem is based on one in the paper by Forrester and Greenberg (2008).1 It is a simplification of a
problem in molecular biology. We take a protein as consisting of a chain of amino acids. For the purpose of
this problem, the amino acids come in two forms: hydrophilic (water-loving) and hydrophobic (water-hating).
An example of such a chain is given in Figure 28.1, with the hydrophobic acids marked in bold.
Figure 28.1
Such a chain naturally folds so as to bring as many hydrophobic acids as possible close together. An optimum
folding for the chain, in two dimensions, is given in Figure 28.2, with the new matches marked by dashed
lines. The problem is to predict the optimum folding. (Forrester and Greenberg also impose a condition that
the resultant protein be confined to a given lattice of points. We do not impose that condition here). This
problem can be modelled by a number of integer programming formulations. Some of these are discussed in
the above reference. Another formulation is suggested in section 13.28 [of Williams (2013)]. The problem
posed here is to find the optimum folding for a chain of 50 amino acids with hydrophobic acids at positions 2,
4, 5, 6, 11, 12, 17, 20, 21, 25, 27, 28, 30, 31, 33, 37, 44 and 46 as shown in Figure 28.3.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 2013, pp. 289–290).
362 F Chapter 28: Protein Folding
Figure 28.2
Figure 28.3
Mathematical Programming Formulation F 363
i 2 POSITIONS
i; j 2 HYDROPHOBIC
.i; j / 2 PAIRS
Parameters
Table 28.1 shows the parameters that are used in this example.
Variables
Table 28.2 shows the variables that are used in this example.
Objective
The objective is to maximize the following function:
X
NumMatches D IsMatch[i,j]
.i;j /2PAIRS
Constraints
The following constraints are used in this example:
bounds on variables
IsMatch[i,j] C IsFold[k] 1
IsMatch[i,j] IsFold[(i+j-1)/2]
Input Data
The following data set and macro variable contain the input data that are used in this example:
data hydrophobic_data;
input position @@;
datalines;
2 4 5 6 11 12 17 20 21 25 27 28 30 31 33 37 44 46
;
proc optmodel;
num n = &num_acids;
set POSITIONS = 1..n;
set HYDROPHOBIC;
read data hydrophobic_data into HYDROPHOBIC=[position];
The following statement uses the MOD function to declare the set of hydrophobic pairs that can possibly be
matched (because they are not contiguous and are an even number of positions apart):
set PAIRS
= {i in HYDROPHOBIC, j in HYDROPHOBIC: i + 1 < j and mod(j-i-1,2) = 0};
The following model declaration statements correspond directly to the mathematical programming formula-
tion that is described earlier:
solve;
print {i in 1..n-1: IsFold[i].sol > 0.5} IsFold;
print {<i,j> in PAIRS: IsMatch[i,j].sol > 0.5} IsMatch;
366 F Chapter 28: Protein Folding
Figure 28.4 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Maximization
Objective Function NumMatches
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function NumMatches
Solution Status Optimal
Objective Value 10
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
Best Bound 10
Nodes 1
Iterations 114
Presolve Time 0.06
Solution Time 0.07
PROC OPTMODEL Statements and Output F 367
[1] IsFold
3 1
8 1
14 1
18 1
22 1
26 1
28 1
31 1
38 1
The optimal solution and objective value differ from Williams (2013), because of an error that will be
corrected in a subsequent printing by Wiley.
The following statements compute x and y coordinates for each position and write multiple output data sets
to be used by the SGPLOT procedure:
num x {POSITIONS};
num y {POSITIONS};
num xx init 0;
num yy init 0;
num dir init 1;
for {i in POSITIONS} do;
xx = xx + dir;
x[i] = xx;
y[i] = yy;
if i = n or IsFold[i].sol > 0.5 then do;
xx = xx + dir;
dir = -dir;
yy = yy - 1;
end;
end;
create data plot_data from [i] x y is_hydrophobic=(i in HYDROPHOBIC);
create data edge_data from [i]=(1..n-1)
x1=x[i] y1=y[i] x2=x[i+1] y2=y[i+1] linepattern=1;
create data match_data from [i j]={<i,j> in PAIRS: IsMatch[i,j].sol > 0.5}
x1=x[i] y1=y[i] x2=x[j] y2=y[j] linepattern=2;
quit;
368 F Chapter 28: Protein Folding
The following DATA step and PROC SGPLOT statements use the output data sets that are created by PROC
OPTMODEL to display the optimal folding that corresponds to the MILP solution:
Features Demonstrated
The following features are demonstrated in this example:
set of tuples
MOD function
SGPLOT procedure
370
Chapter 29
Protein Comparison
Contents
Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
Mathematical Programming Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
Input Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
PROC OPTMODEL Statements and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 374
Features Demonstrated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Problem Statement
This problem is also based on one in the paper by Forrester and Greenberg (2008).1 It is concerned with
measuring the similarities of two proteins. A protein can be represented by an (undirected) graph with the
acids represented by the nodes and the edges being present when two acids are within a threshold distance
of each other. This graphical representation is known as the contact map of the protein. Given two contact
maps, representing proteins, we would like to find the largest (measured by number of corresponding edges)
isomorphic subgraphs in each graph. The acids in each of the proteins are ordered. We need to preserve this
ordering in each of the subgraphs, which implies that there can be no crossovers in the comparison. This is
illustrated in Figure 29.1. If i < k in the contact map for the first protein then we cannot have l < j in the
second protein, if i is to be associated with j and k with l in the comparison.
Figure 29.1
i k
j l
This problem is well known for being very difficult to solve for even modestly sized proteins.
1 Reproduced with permission of John Wiley & Sons Ltd. (Williams 2013, pp. 290–291).
372 F Chapter 29: Protein Comparison
In Figure 29.2, we give an optimal comparison between two small contact maps leading to 5 corresponding
edges.
Figure 29.2
Map 1
Map 2
The problem we present here is to compare the contact maps given in Figure 29.3 and Figure 29.4.
Figure 29.3
Figure 29.4
g 2 f1; 2g
i 2 NODES[g]
.i; k/; .j; l/ 2 EDGES[g]
.i; j /; .k; l/ 2 IJ D NODES[1] NODES[2]
.i; j; k; l/ 2 EDGE_PAIRS: pairs of edges that can possibly correspond to each other
Variables F 373
Variables
Table 29.1 shows the variables that are used in this example.
Objective
The objective is to maximize the following function:
X
NumCorrespondingEdges D IsCorrespondingEdge[i,j,k,l]
.i;j;k;l/2EDGE_PAIRS
Constraints
The following constraints are used in this example:
bounds on variables
for i 2 NODES[1],
X
Assign[i,j] 1
.i;j /2IJ
for j 2 NODES[2],
X
Assign[i,j] 1
.i;j /2IJ
Assign[i,j] C Assign[k,l] 1
IsCorrespondingEdge[i,j,k,l] Assign[i,j]
IsCorrespondingEdge[i,j,k,l] Assign[k,l]
374 F Chapter 29: Protein Comparison
Input Data
The following data sets contain the input data that are used in this example:
data edge_data1;
input i j;
datalines;
1 2
2 9
3 4
3 5
5 6
6 7
7 9
8 9
;
data edge_data2;
input i j;
datalines;
1 4
2 3
4 6
4 7
5 6
6 8
7 8
7 10
9 10
10 11
;
proc optmodel;
set <num,num> EDGES {1..2};
read data edge_data1 into EDGES[1]=[i j];
read data edge_data2 into EDGES[2]=[i j];
The following statements declare and initialize the NODES[g] sets and then use the INTER operator to store
their elements in increasing order:
solve;
file print;
for {<i,j> in IJ: Assign[i,j].sol > 0.5}
put ('Node '||i||' in graph 1 corresponds to node '||j||' in graph 2.');
for {<i,j,k,l> in EDGE_PAIRS: IsCorrespondingEdge[i,j,k,l].sol > 0.5} do;
put ('Edge ('||i||','||k||') in graph 1 corresponds to') @@;
put ('edge ('||j||','||l||') in graph 2.');
end;
quit;
376 F Chapter 29: Protein Comparison
Figure 29.5 shows the output from the mixed integer linear programming solver.
Problem Summary
Objective Sense Maximization
Objective Function NumCorrespondingEdges
Objective Type Linear
Performance Information
Execution Mode Single-Machine
Number of Threads 4
Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function NumCorrespondingEdges
Solution Status Optimal
Objective Value 5
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 0
Bound Infeasibility 0
Integer Infeasibility 0
Best Bound 5
Nodes 1
Iterations 100
Presolve Time 0.12
Solution Time 0.13
Features Demonstrated F 377
Figure 29.7 shows the optimal solution as a comparison between contact maps, with the matched nodes
indicated by dashed lines and the edges of the isomorphic subgraphs highlighted.
Features Demonstrated
The following features are demonstrated in this example:
sets of tuples
CARD function
FILE statement
PUT statement
References
polynomial regression with L1 and L1 norms, 133 tuples, sets of, 57, 73, 127, 154, 206, 227, 242, 276,
problem type 298, 351
linear programming, 3, 33, 51, 65, 91, 105, 133,
181, 211, 221, 259, 321 .ub constraint suffix, 228
mixed integer linear programming, 25, 43, 81, modifying the right-hand side of a constraint, 114,
121, 149, 159, 173, 181, 193, 203, 237, 271, 219
289, 335, 345, 361, 371 .ub variable suffix, 28, 57, 73, 83, 86, 98, 111, 197,
nonlinear programming, 247 299, 340
quadratic programming, 247
product variable suffix
of binary variables, 127 .sol suffix, 219, 365
of continuous variable and binary variable, 300 in parameter declaration, 14, 27, 75, 83, 85, 137,
of decision variables, 251 165, 264, 301
.lb suffix, 111
quadratic assignment problem, 121 .sol suffix, 14, 207, 264, 278, 301, 350
quadratic program, 247 .ub suffix, 28, 57, 73, 83, 86, 98, 111, 197, 299,
340
range constraint, 9, 75, 100 vehicle routing, 271, 345
ratio constraint, 9, 74, 75, 86
reading data, 7, 37 writing data
dense, 7, 27, 38, 45, 57, 109, 125, 263, 328, 338 dense, 101, 265
dense (upper triangular), 351 sparse, 101, 265
sparse, 38, 57, 73, 251 two-dimensional, 101, 265
sparse (upper triangular), 126
two dimensional, 338
two-dimensional, 7, 27, 38, 45, 57, 73, 109, 125,
126, 251, 263, 351
row generation, 278, 350
DIFF set operator, 8, 27, 57, 73, 86, 99, 232, 264, 277, set operator
329, 338, 353, 365 CROSS, 73, 206, 298, 375
DO loop, calling a solver, 264 DIFF, 8, 27, 57, 73, 86, 99, 232, 264, 277, 353,
DO UNTIL loop, calling a solver, 278, 350 365
DROP statement, 129, 304 INTER, 374
SETOF, 74, 165, 207, 232, 350
EXPAND statement, 9 UNION, 8, 27, 73, 97, 109, 154, 164, 215, 228,
242, 278, 350, 374
FILE statement, 208, 375
SETOF set operator, 74, 165, 207, 232, 350
FINANCE function, 98
SGPLOT procedure, 145, 279, 367
FINDALLSOLNS option, SOLVE WITH CLP
SLICE expression, 58
statement, 219
SOLVE statement
FIX statement, 8, 27, 39, 45, 57, 97, 154, 187, 197,
ALGORITHM= option, 14, 230, 253
243, 301
multiple, 301
IF-THEN/ELSE expression, 39, 45, 111, 185, 197, OBJ option, 58
243, 300, 328, 338 WITH clause, 253
IF-THEN/ELSE statement, 301 SOLVE WITH CLP statement, 219
IMPVAR statement, 8, 27, 39, 45, 85, 99, 111, 127, FINDALLSOLNS option, 219
136, 185, 196, 215, 243, 254, 329, 338 SOLVE WITH LP statement, RELAXINT option, 187
IN expression, 177 SOLVE WITH MILP statement
INDEX function, 75 PRIMALIN option, 168
INIT option, VAR statement, 38, 126, 228, 242, 251, SYMMETRY= option, 277, 353
277, 328, 338, 353 SOLVE WITH NETWORK statement, 350
INTEGER option, VAR statement, 46 SUBSTR function, 8, 27
INTER set operator, 374
384 F Syntax Index
VAR statement
BINARY option, 28, 340
bounds, 8, 27, 39, 45, 57, 73, 85, 97
INIT option, 251, 277, 328, 338, 353
INTEGER option, 46
Discover all that you need on your journey to knowledge and empowerment.
support.sas.com/bookstore
for additional books and resources.
SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration. Other brand and product names are
trademarks of their respective companies. © 2013 SAS Institute Inc. All rights reserved. S107969US.0613