-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmaster.py
More file actions
66 lines (55 loc) · 2.57 KB
/
master.py
File metadata and controls
66 lines (55 loc) · 2.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Master problem for Benders decomposition of two-stage stochastic facility location
# Benders feasibility cuts and optimality cuts are added iteratively
from pyomo.environ import *
from utils import *
def build_master(data, capacity_rule: CapacityRule) -> ConcreteModel:
"""
Take a data dictionary and build the Benders master problem for the two-stage stochastic facility location problem.
If use_capacity_sufficiency is True, adds a feasibility "guard" constraint.
Returns a Pyomo model ready to be solved.
"""
model = ConcreteModel(name="FacilityLocation-BendersMaster")
# Indexing sets
model.FACILITIES = Set(initialize=data["FACILITIES"])
model.CUSTOMERS = Set(initialize=data["CUSTOMERS"])
model.SCENARIOS = Set(initialize=data["SCENARIOS"])
# Master-only Parameters
model.fixed_cost = Param(model.FACILITIES, initialize=data["fixed_cost"])
model.prob = Param(model.SCENARIOS, initialize=data["prob"])
# Master and Subproblem Parameters
model.facility_capacity = Param(
model.FACILITIES, initialize=data["facility_capacity"]
)
model.customer_demand = Param(
model.CUSTOMERS,
model.SCENARIOS,
initialize=data["customer_demand"].stack().to_dict(),
within=NonNegativeReals,
)
# Master Problem Variables
# First Stage Decisions
model.facility_open = Var(model.FACILITIES, within=Binary)
# Subproblem Objective Bound needed for Benders decomposition
model.sub_variable_cost = Var(model.SCENARIOS, within=NonNegativeReals)
# Objective
# Total Cost Objective: fixed + variable costs
def total_cost_rule(m):
fixed = sum(m.fixed_cost[i] * m.facility_open[i] for i in m.FACILITIES)
variable = sum(m.prob[s] * m.sub_variable_cost[s] for s in m.SCENARIOS)
return fixed + variable
model.objective = Objective(rule=total_cost_rule, sense=minimize)
# Constraints
# Sufficient production capacity constraint
def sufficient_production_capacity_rule(m):
# Determine the capacity threshold for sufficient production capacity (max means demand will be satisfied under all circumstances)
capacity_threshold = calculate_capacity_threshold(m, capacity_rule)
return (
sum(m.facility_capacity[i] * m.facility_open[i] for i in m.FACILITIES)
>= capacity_threshold
)
model.sufficient_production_capacity = Constraint(
rule=sufficient_production_capacity_rule
)
# Create container for holding Benders cuts during the algorithm
model.BendersCuts = ConstraintList()
return model