284. Linear Programming
284.1. Mathematical Programs
284.1.1. Formulation
- : Number of constraints
- : Number of variables
- : decision variables
- : constraint coefficients
- : right-hand-side values (RHS)
- : objective coefficients
Vector
Matrix
284.1.2. Transformation
- Min and Max
- and
- E.g.,
|
|
|
|
284.1.3. Constraints
- Sign Constraints
- Functional Constraints
284.1.4. Feasible Solutions
- Feasible solution: Satisfies all constants
- Infeasable solution: violates at least one constraint
284.1.5. Feasible Region and Optimal Solution
-
Feasible Region: Set of feasible solutions
-
Optimal Solution: Attains largest (maximization) or smallest (minimization) objective value
284.1.6. Binding Constraint
Let be an inequality constraint and be a solution. is binding at if
Example
284.1.7. Strict and Weak Inequalities
-
Strict: The two sides cannot be equal (e.g., )
-
Weak: The two sides can be equal (e.g., )
284.1.8. Graphical Approach
Example
284.1.9. Types of LP
284.1.10. LP Formulation
Example
Production
We produce desks and tables
- Producing a desk requires 3 units of wood, 1 hour of labor and 50 minutes of machine time
- Producing a table requires 5 units of wood, 2 hours of labor and 20 minutes of machine time
For each day, we have
- 200 workers that each work 8 hours
- 50 machines that each run for 16 hours
- A supply of 3600 units of wood
Desks and tables are sold $700 and $900 per unit, respectively
Everything that is produced is sold
1. Define Variables
: number of desks produced per day
: number of tables produced per day
2. Formulate Objective Function
3. Formulate Constraints
| Resource | Consumption per | Total supply | |
| Desk | Table | ||
| Wood | 3 units | 5 units | 3600 units |
| Labor | 1 hours | 2 hours | 200 workers 8 hours = 1600 hours |
| Machine time |
50 minutes | 20 minutes | 50 machines 16 hours = 800 hours |
4. Complete Formulation
Compact Formulation
Where:
- : number of products
- : number of resources
- : indices of products
- : indices of resources
- : unit sale price of product
- : supply limit of resource
- : unit of resource to produce one unit of product
- : production quantity for product ,
model.py
from pyomo.environ import *
from pyomo.dataportal import DataPortal
model = AbstractModel()
# Sets
model.Products = Set()
model.Resources = Set()
# Parameters
model.Profit = Param(model.Products)
model.Supply = Param(model.Resources)
model.Consumption = Param(model.Resources, model.Products)
# Variables
model.x = Var(model.Products, domain=NonNegativeReals)
# Objective: Maximize profit
def objective_rule(model):
return sum(model.Profit[j] * model.x[j] for j in model.Products)
model.OBJ = Objective(rule=objective_rule, sense=maximize)
# Constraints: Do not exceed resource supply
def constraint_rule(model, i):
return sum(model.Consumption[i, j] * model.x[j] for j in model.Products) <= model.Supply[i]
model.ResourceConstraint = Constraint(model.Resources, rule=constraint_rule)
# Load data from .dat file
data = DataPortal()
data.load(filename='data.dat', model=model)
# Create an instance of the model
instance = model.create_instance(data)
# Create solver
solver = SolverFactory('glpk')
solver.options['tmlim'] = 60
# Solve with solver timeout (optional)
results = solver.solve(instance, tee=True)
# Display results
instance.display()
data.dat
set Products := Desk Table ;
set Resources := Wood Labor Machine ;
param Profit :=
Desk 700
Table 900 ;
param Supply :=
Wood 3600
Labor 1600
Machine 48000 ;
param Consumption:
Desk Table :=
Wood 3 5
Labor 1 2
Machine 50 20 ;
Output:
Variables:
x : Size=2, Index=Products
Key : Lower : Value : Upper : Fixed : Stale : Domain
Desk : 0 : 884.210526315789 : None : False : False : NonNegativeReals
Table : 0 : 189.473684210526 : None : False : False : NonNegativeReals
Objectives:
OBJ : Size=1, Index=None, Active=True
Key : Active : Value
None : True : 789473.6842105257
Constraints:
ResourceConstraint : Size=3
Key : Lower : Body : Upper
Labor : None : 1263.157894736841 : 1600.0
Machine : None : 47999.99999999997 : 48000.0
Wood : None : 3599.999999999997 : 3600.0
)
Example
Multi Period (Inventory)
We produce and sell products
For the coming 4 days, the demand will be
- Days 1: 100
- Days 2: 150
- Days 3: 200
- Days 4: 170
The unit production costs are different for different days
- Days 1: $9
- Days 2: $12
- Days 3: $10
- Days 4: $12
Prices are all fixed. So maximizing profit is equivalent to minimizing costs.
We may store products and sell them later. Inventory cost is $1 per unit per day.
E.g., producing 620 units on day 1 to fulfill all demands:
-
: inevntory at the end of day (i.e., beginning inventory for day )
-
: units produced on day
-
: demand (or sales) on dat
-
: inventory at the end of day
Inventory costs are calculated according to ending inventory
-
: production quantity of day ,
-
: ending inventory of day ,
Objective function:
Inventory balancing constraints:
-
Day 1:
-
Day 2:
-
Day 3:
-
Day 4:
Demand fulfillment constraints:
Non-negativity constraints:
Complete Formulation
Simplification (Redundant Constraints)
-
Inventory balancing & non-negativity imply fulfillment
- E.g., in day 1, and means
- No need to have ending inventory in period 4 (costly but useless)
Compact Formulation
Where:
- : demand on day
- : ending inventory of day
- : unit production cost on day
Example
Personnel Scheduling
Scheduling employees
Each employee must work for 5 consecutive days and then take 2 consecutive rest days
Number of employees required for each day
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
| 110 | 80 | 150 | 30 | 70 | 160 | 120 |
Seven shifts
- Mon to Fri
- Tue to Sat
- …
Minimize number of employees hired
Let be the number of employees assigned to work from day for 5 consecutive days
Objective function:
Demand Fullfilment Constraints
- 110 employeeds needed Monday
An employee that works on Tues () or Wed () does not work on Mon ()
- 80 employees needed Tuesday
An employee that works on Wed () or Thu () does not work on Tue ()
- 120 employees needed Sunday
An employee that works on Mon () or Tue () does not work on Sun ()
Non-Nagativity Constraints
Complete Formulation
model.py
from pyomo.environ import *
from pyomo.dataportal import DataPortal
model = AbstractModel()
# Sets
model.Days = Set(ordered=True) # Days 1..7 (Mon..Sun)
model.Shifts = Set(ordered=True) # Shifts starting on days 1..7
# Parameters
model.Demand = Param(model.Days) # Daily staffing requirements
model.Cover = Param(model.Days, model.Shifts, within=Binary) # Coverage matrix (1 if shift j covers day i)
# Variables
model.x = Var(model.Shifts, domain=NonNegativeReals)
# Objective: Minimize total employees hired
def obj_rule(model):
return sum(model.x[s] for s in model.Shifts)
model.OBJ = Objective(rule=obj_rule, sense=minimize)
# Constraints: Cover daily demand
def demand_rule(model, d):
return sum(model.Cover[d, s] * model.x[s] for s in model.Shifts) >= model.Demand[d]
model.DemandConstraint = Constraint(model.Days, rule=demand_rule)
# Load data from .dat file
data = DataPortal()
data.load(filename='data.dat', model=model)
# Create an instance of the model
instance = model.create_instance(data)
# Create solver
solver = SolverFactory('glpk')
solver.options['tmlim'] = 60
# Solve with solver timeout (optional)
results = solver.solve(instance, tee=True)
# Display results
instance.display()
data.dat
set Days := Mon Tue Wed Thu Fri Sat Sun ;
set Shifts := s1 s2 s3 s4 s5 s6 s7 ;
param Demand :=
Mon 110
Tue 80
Wed 150
Thu 30
Fri 70
Sat 160
Sun 120 ;
# Each shift covers 5 consecutive days starting on the shift's day
# 1 if shift s_j covers day d_i, 0 otherwise
param Cover:
s1 s2 s3 s4 s5 s6 s7 :=
Mon 1 0 0 1 1 1 1
Tue 1 1 0 0 1 1 1
Wed 1 1 1 0 0 1 1
Thu 1 1 1 1 0 0 1
Fri 1 1 1 1 1 0 0
Sat 0 1 1 1 1 1 0
Sun 0 0 1 1 1 1 1 ;
Output:
Variables:
x : Size=7, Index=Shifts
Key : Lower : Value : Upper : Fixed : Stale : Domain
s1 : 0 : 3.33333333333333 : None : False : False : NonNegativeReals
s2 : 0 : 40.0 : None : False : False : NonNegativeReals
s3 : 0 : 13.3333333333333 : None : False : False : NonNegativeReals
s4 : 0 : 0.0 : None : False : False : NonNegativeReals
s5 : 0 : 13.3333333333333 : None : False : False : NonNegativeReals
s6 : 0 : 93.3333333333333 : None : False : False : NonNegativeReals
s7 : 0 : 0.0 : None : False : False : NonNegativeReals
Objectives:
OBJ : Size=1, Index=None, Active=True
Key : Active : Value
None : True : 163.33333333333323
Constraints:
DemandConstraint : Size=7
Key : Lower : Body : Upper
Fri : 70.0 : 69.99999999999993 : None
Mon : 110.0 : 109.99999999999993 : None
Sat : 160.0 : 159.9999999999999 : None
Sun : 120.0 : 119.9999999999999 : None
Thu : 30.0 : 56.66666666666663 : None
Tue : 80.0 : 149.99999999999994 : None
Wed : 150.0 : 149.99999999999994 : None