Skip to content

Commit

Permalink
Initial commit for the capacitated facility location
Browse files Browse the repository at this point in the history
  • Loading branch information
Ochibobo committed Jan 26, 2024
1 parent f5d1e28 commit f6be17f
Showing 1 changed file with 84 additions and 0 deletions.
84 changes: 84 additions & 0 deletions src/examples/csp/capacitated_facility_location.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#######################################################################################################################################
#
# This example was pulled from JuMP's Facility Location problem
#
# Link: https://jump.dev/JuMP.jl/stable/tutorials/linear/facility_location/#Capacitated-facility-location
#
# The objective is to minimize the cost of serving clients by also determining whether to open a facility or not. It also takes
# into account the client demands and facility capacities
#
#######################################################################################################################################
import Random
import LinearAlgebra
import Plots
include("../../JuliaCP.jl")
using .JuliaCP

Random.seed!(6789)

## Upper bound used for the random number integer generation for facility & client locations
LOCATION_UPPER_BOUND = 100
NUMBER_OF_CLIENTS = 12
NUMBER_OF_FACILITIES = 5
MAX_NUMBER_OF_FACILITIES_ASSIGNED = 1

## Generate the client locations
x_client, y_client = rand(1:LOCATION_UPPER_BOUND, NUMBER_OF_CLIENTS), rand(1:LOCATION_UPPER_BOUND, NUMBER_OF_CLIENTS)
x_facility, y_facility = rand(1:LOCATION_UPPER_BOUND, NUMBER_OF_FACILITIES), rand(1:LOCATION_UPPER_BOUND, NUMBER_OF_FACILITIES)

## Fixed cost of opening the facilites
facilities_opening_cost = ones(Int, NUMBER_OF_FACILITIES)

## The distance between a client and each facility
distances = zeros(Int, NUMBER_OF_CLIENTS, NUMBER_OF_FACILITIES)

for c in 1:NUMBER_OF_CLIENTS
for f in 1:NUMBER_OF_FACILITIES
distance = LinearAlgebra.norm([x_client[c] - x_facility[f], y_client[c] - y_facility[f]], 2)
distances[c, f] = floor(Int, distance)
end
end

## Demands from each client
demands = rand(1:5, NUMBER_OF_CLIENTS)

## Capacities for each facility
capacities = rand(12:20, NUMBER_OF_FACILITIES)

## Define the solver
solver = Engine.LearnieCP()

## Variable definition
## Shows whether a facility is open or closed
y = [Engine.BoolVar(solver) for _ in 1:NUMBER_OF_FACILITIES]

## Holds the assignment of a client to a facility
x = Matrix{Engine.BoolVar}(undef, NUMBER_OF_CLIENTS, NUMBER_OF_FACILITIES)

for c in 1:NUMBER_OF_CLIENTS
for f in 1:NUMBER_OF_FACILITIES
## Whether client c is assigned to facility f
x[c, f] = Engine.BoolVar(solver)

## A client can only be assigned to a facility if it's open
Engine.post(solver, Engine.LessOrEqual{Integer}(x[c, f], y[f]))
end

## A client can only be assigned to 1 facility
Engine.post(solver, Engine.Sum{Integer}(x[c, :], MAX_NUMBER_OF_FACILITIES_ASSIGNED))
end

## Cost of opening a facility
facility_cost = [y[f] * facilities_opening_cost[f] for f in 1:NUMBER_OF_FACILITIES]

## Compute the cost of assigning a client to facility (this is the cost to be minimized)
client_cost = Vector{Engine.AbstractVariable{Integer}}()
for c in 1:NUMBER_OF_CLIENTS
for f in 1:NUMBER_OF_FACILITIES
## Multiply the distance between the client & facility with the decision of whether the client was connected to
## the facility or not
push!(client_cost, distances[c, f] * x[c, f])
end
end

##

0 comments on commit f6be17f

Please sign in to comment.