HLPL / VerTeX Modelling Language Documentation

← lessons

Facility location — open or not?

Pay to open, save on transport.

Chapter: XIII — Facility location · lesson id facility-uncapacitated · practice lesson


Two candidate facilities, three customers. Opening facility f costs f_f. Serving customer c from facility f costs c_{c,f}. Each customer must be served by exactly one facility, and a facility can only serve a customer if it's open.

Two variable families: y_f binary (open / not), x_{c,f} binary (assignment). The coupling constraint x_{c,f} ≤ y_f is what makes this an integer programme rather than two independent problems.

Open costs {5, 6}, transport costs [[2, 4], [3, 1], [4, 2]]. Optimum: open only facility 2, total cost 6 + (4 + 1 + 2) = 13.

Predict before running

Setup costs {5, 6}, transport per customer-facility. Without capacities, how many facilities open?

Starter code

model facility
set F = {1, 2}
set C = {1, 2, 3}
const f = {5, 6}, forall j in F
const t = {{2, 4}, {3, 1}, {4, 2}}, forall i in C, forall j in F
bin y, forall j in F
bin x, forall i in C, forall j in F
constr sum_{j in F}{x_{i,j}} = 1, forall i in C
constr x_{i,j} <= y_{j}, forall i in C, forall j in F
min sum_{j in F}{f_{j} * y_{j}} + sum_{i in C}{sum_{j in F}{t_{i,j} * x_{i,j}}}
end

import elytica
def main():
  elytica.init_model("facility")
  elytica.run_model("facility")
  for i in [1,2]:
    print("y"+str(i), "=", elytica.get_variable_value("facility", "y"+str(i)))
  for i in [1,2,3]:
    for j in [1,2]:
      name = "x"+str(i)+","+str(j)
      print(name, "=", elytica.get_variable_value("facility", name))
  print("obj =", elytica.get_best_primal_bound("facility"))
  return 0

Hint

Open just facility 2 — pays 6, then serves all three customers for 4+1+2 = 7. Total 13.

What counts as correct

Mastery variant

New setup and transport costs. Which facility is worth opening this time?

model facility_v
set F = {1, 2}
set C = {1, 2, 3}
const f = {6, 3}, forall j in F
const t = {{4, 2}, {5, 1}, {3, 2}}, forall i in C, forall j in F
bin y, forall j in F
bin x, forall i in C, forall j in F
constr sum_{j in F}{x_{i,j}} = 1, forall i in C
constr x_{i,j} <= y_{j}, forall i in C, forall j in F
min sum_{j in F}{f_{j} * y_{j}} + sum_{i in C}{sum_{j in F}{t_{i,j} * x_{i,j}}}
end

import elytica
def main():
  elytica.init_model("facility_v")
  elytica.run_model("facility_v")
  for i in [1,2]:
    print("y"+str(i), "=", elytica.get_variable_value("facility_v", "y"+str(i)))
  for i in [1,2,3]:
    for j in [1,2]:
      name = "x"+str(i)+","+str(j)
      print(name, "=", elytica.get_variable_value("facility_v", name))
  print("obj =", elytica.get_best_primal_bound("facility_v"))
  return 0

Read this through MCP: read with path: "lessons/facility-uncapacitated", or resource hlpl://lessons/facility-uncapacitated.