Benoît Legat

Practical 4 – Mixed-Integer Linear Programming in JuMP: The facility location problem


Inspired from a JuMP tutorial

using JuMP
import HiGHS
import LinearAlgebra
import Plots
import Random

Uncapacitated facility location

Problem description

We are given

Decision variables Decision variables are split into two categories:

Objective The objective is to minimize the total cost of serving all clients. This costs breaks down into two components:

In this example, this cost is fj=1, jf_{j} = 1, \ \forall j.

In this example, the cost ci,jc_{i, j} of serving client ii from facility jj is the Euclidean distance between the two.

Constraints

MILP formulation

The problem can be formulated as the following MILP:

minx,y i,jci,jxi,j+jfjyjs.t.jxi,j=1,iMxi,jyj,iM,jNxi,j,yj{0,1},iM,jN \begin{aligned} \min_{x, y} \ \ \ & \sum_{i, j} c_{i, j} x_{i, j} + \sum_{j} f_{j} y_{j} \\ s.t. & \sum_{j} x_{i, j} = 1, && \forall i \in M \\ & x_{i, j} \leq y_{j}, && \forall i \in M, j \in N \\ & x_{i, j}, y_{j} \in \{0, 1\}, && \forall i \in M, j \in N \end{aligned}

where the first set of constraints ensures that each client is served exactly once, and the second set of constraints ensures that no client is served from an unopened facility.

Problem data

Random.seed!(314)

number of clients

m = 12

number of facility locations

n = 5

Clients' locations

Xc = rand(m)
Yc = rand(m)

Facilities' potential locations

Xf = rand(n)
Yf = rand(n)

Fixed costs

f = ones(n);

Distance

c = zeros(m, n)
for i in 1:m
    for j in 1:n
        c[i, j] = LinearAlgebra.norm([Xc[i] - Xf[j], Yc[i] - Yf[j]], 2)
    end
end

Display the data

Plots.scatter(
    Xc,
    Yc,
    label = "Clients",
    markershape = :circle,
    markercolor = :blue,
)
Plots.scatter!(
    Xf,
    Yf,
    label = "Facility",
    markershape = :square,
    markercolor = :white,
    markersize = 6,
    markerstrokecolor = :red,
    markerstrokewidth = 2,
)

JuMP implementation

Create a JuMP model

ufl = Model(HiGHS.Optimizer)

Variables

@variable(ufl, y[1:n], Bin);
@variable(ufl, x[1:m, 1:n], Bin);

Each client is served exactly once

@constraint(ufl, client_service[i in 1:m], sum(x[i, j] for j in 1:n) == 1);

A facility must be open to serve a client

@constraint(ufl, open_facility[i in 1:m, j in 1:n], x[i, j] <= y[j]);

Objective

@objective(ufl, Min, f'y + sum(c .* x));

Solve the uncapacitated facility location problem with HiGHS

optimize!(ufl)
solution_summary(ufl)

Visualizing the solution

The threshold 1e-5 ensure that edges between clients and facilities are drawn when x[i, j] ≈ 1.

x_ = value.(x) .> 1 - 1e-5
y_ = value.(y) .> 1 - 1e-5

Display clients

p = Plots.scatter(
    Xc,
    Yc,
    markershape = :circle,
    markercolor = :blue,
    label = nothing,
)

Show open facility

mc = [(y_[j] ? :red : :white) for j in 1:n]
Plots.scatter!(
    Xf,
    Yf,
    markershape = :square,
    markercolor = mc,
    markersize = 6,
    markerstrokecolor = :red,
    markerstrokewidth = 2,
    label = nothing,
)

Show client-facility assignment

for i in 1:m
    for j in 1:n
        if x_[i, j] == 1
            Plots.plot!(
                [Xc[i], Xf[j]],
                [Yc[i], Yf[j]],
                color = :black,
                label = nothing,
            )
        end
    end
end

p

Homework: Capacitated facility location

Problem formulation

The capacitated variant introduces a capacity constraint on each facility, i.e., clients have a certain level of demand to be served, while each facility only has finite capacity which cannot be exceeded.

Specifically,

The capacity constraints then write

iaixi,jqjyjjN \begin{aligned} \sum_{i} a_{i} x_{i, j} &\leq q_{j} y_{j} && \forall j \in N \end{aligned}

Note that, if yjy_{j} is set to 00, the capacity constraint above automatically forces xi,jx_{i, j} to 00.

Thus, the capacitated facility location can be formulated as follows

minx,y   i,jci,jxi,j+jfjyjs.t.jxi,j=1,iMiaixi,jqjyj,jNxi,j,yj{0,1},iM,jN \begin{aligned} \min_{x, y} \ \ \ & \sum_{i, j} c_{i, j} x_{i, j} + \sum_{j} f_{j} y_{j} \\ s.t. & \sum_{j} x_{i, j} = 1, && \forall i \in M \\ & \sum_{i} a_{i} x_{i, j} \leq q_{j} y_{j}, && \forall j \in N \\ & x_{i, j}, y_{j} \in \{0, 1\}, && \forall i \in M, j \in N \end{aligned}

For simplicity, we will assume that there is enough capacity to serve the demand, i.e., there exists at least one feasible solution.

Random.seed!(314)

Demands

a = rand(1:3, m);

Capacities

q = rand(5:10, n);

Display the data

Plots.scatter(
    Xc,
    Yc,
    label = nothing,
    markershape = :circle,
    markercolor = :blue,
    markersize = 2 .* (2 .+ a),
)

Plots.scatter!(
    Xf,
    Yf,
    label = nothing,
    markershape = :rect,
    markercolor = :white,
    markersize = q,
    markerstrokecolor = :red,
    markerstrokewidth = 2,
)

This page was generated using Literate.jl.