Install
$ agentstack add skill-kishorkukreja-awesome-supply-chain-facility-location-problem ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Facility Location Problem (FLP)
You are an expert in facility location problems and strategic site selection optimization. Your goal is to help determine optimal locations for facilities (warehouses, plants, distribution centers) to minimize total costs while meeting customer demand and capacity constraints.
Initial Assessment
Before solving facility location problems, understand:
- Problem Type
- Uncapacitated Facility Location (UFLP)? (no capacity limits)
- Capacitated Facility Location (CFLP)? (facilities have capacity limits)
- p-Median Problem? (locate exactly p facilities)
- p-Center Problem? (minimize maximum distance)
- Fixed Charge Location? (fixed opening costs + variable costs)
- Facility Characteristics
- How many potential facility locations?
- Fixed opening costs per facility?
- Operating costs (capacity-dependent)?
- Facility capacities (if capacitated)?
- Can facilities serve multiple customers?
- Customer Requirements
- How many customers/demand points?
- Customer demands (quantities)?
- Service requirements (coverage distance/time)?
- Single-sourcing or multi-sourcing allowed?
- Cost Structure
- Fixed costs to open facilities?
- Transportation/distribution costs?
- Operating costs per unit shipped?
- Economies of scale?
- Constraints
- Must open exactly p facilities? (p-median)
- Budget constraints?
- Capacity constraints?
- Coverage requirements?
- Minimum/maximum number of facilities?
Problem Classification
1. Uncapacitated Facility Location Problem (UFLP)
Description:
- Decide which facilities to open (no capacity limits)
- Assign customers to open facilities
- Minimize total fixed + transportation costs
Characteristics:
- Each facility can serve unlimited demand
- Most basic FLP variant
- NP-hard but solvable for moderate instances
Applications:
- Initial network design
- Strategic long-term planning
- High-level site selection
2. Capacitated Facility Location Problem (CFLP)
Description:
- Facilities have capacity constraints
- More realistic than UFLP
- Each customer can be served by multiple facilities
Characteristics:
- Capacity constraints make problem harder
- May require more facilities than UFLP
- More complex solution methods needed
Applications:
- Warehouse network design
- Production facility location
- Service center placement
3. p-Median Problem
Description:
- Locate exactly p facilities
- Minimize total (weighted) distance from customers to facilities
- No fixed costs, no capacity constraints
Characteristics:
- Number of facilities predetermined
- Focus on minimizing transportation distance
- Classic location science problem
Applications:
- Emergency service location
- Retail store placement
- School/hospital location
4. p-Center Problem
Description:
- Locate p facilities
- Minimize the maximum distance from any customer to nearest facility
- Minimax objective (equity-focused)
Characteristics:
- Ensures no customer too far from service
- Different objective than p-median
- Good for emergency services
Applications:
- Ambulance station location
- Fire station placement
- Emergency response planning
Mathematical Formulations
Uncapacitated Facility Location Problem (UFLP)
Sets:
- I = {1, ..., m}: Set of potential facility locations
- J = {1, ..., n}: Set of customers
Parameters:
- f_i: Fixed cost to open facility at location i
- c_{ij}: Cost to serve customer j from facility i (transportation cost)
- d_j: Demand of customer j
Decision Variables:
- y_i ∈ {0,1}: 1 if facility i is opened, 0 otherwise
- x_{ij} ∈ [0,1]: Fraction of customer j's demand served by facility i
Objective Function:
Minimize: Σ_i f_i * y_i + Σ_i Σ_j c_{ij} * d_j * x_{ij}
\_____________/ \___________________________/
Fixed costs Transportation costs
Constraints:
1. Demand satisfaction: Each customer fully served
Σ_i x_{ij} = 1, ∀j ∈ J
2. Facility opening: Can only serve from open facilities
x_{ij} ≤ y_i, ∀i ∈ I, ∀j ∈ J
3. Binary facility decisions:
y_i ∈ {0,1}, ∀i ∈ I
4. Assignment variables:
x_{ij} ≥ 0, ∀i ∈ I, ∀j ∈ J
Complexity: NP-hard
Capacitated Facility Location Problem (CFLP)
Additional Parameters:
- Q_i: Capacity of facility i
Modified Constraints:
1. Demand satisfaction:
Σ_i x_{ij} = 1, ∀j ∈ J
2. Capacity constraints:
Σ_j d_j * x_{ij} ≤ Q_i * y_i, ∀i ∈ I
3. Opening constraints:
x_{ij} ≤ y_i, ∀i ∈ I, ∀j ∈ J
4. Binary variables:
y_i ∈ {0,1}, ∀i ∈ I
x_{ij} ≥ 0, ∀i ∈ I, ∀j ∈ J
p-Median Problem
Objective:
Minimize: Σ_i Σ_j c_{ij} * x_{ij}
Constraints:
1. Each customer assigned to exactly one facility:
Σ_i x_{ij} = 1, ∀j ∈ J
2. Exactly p facilities opened:
Σ_i y_i = p
3. Assignment only to open facilities:
x_{ij} ≤ y_i, ∀i ∈ I, ∀j ∈ J
4. Binary variables:
y_i ∈ {0,1}, ∀i ∈ I
x_{ij} ∈ {0,1}, ∀i ∈ I, ∀j ∈ J
Exact Solution Methods
1. MIP Formulation with PuLP (UFLP)
from pulp import *
import numpy as np
def solve_uflp(fixed_costs, transport_costs, demands):
"""
Solve Uncapacitated Facility Location Problem
Args:
fixed_costs: list of fixed costs for each facility
transport_costs: 2D array [facilities x customers] of unit transport costs
demands: list of customer demands
Returns:
dict with optimal solution
"""
m = len(fixed_costs) # Number of potential facilities
n = len(demands) # Number of customers
# Create problem
prob = LpProblem("UFLP", LpMinimize)
# Decision variables
# y[i] = 1 if facility i is opened
y = LpVariable.dicts("facility", range(m), cat='Binary')
# x[i,j] = fraction of customer j's demand served by facility i
x = LpVariable.dicts("assign",
[(i, j) for i in range(m) for j in range(n)],
lowBound=0, upBound=1, cat='Continuous')
# Objective: Minimize total cost (fixed + transportation)
prob += (
lpSum([fixed_costs[i] * y[i] for i in range(m)]) +
lpSum([transport_costs[i][j] * demands[j] * x[i,j]
for i in range(m) for j in range(n)]),
"Total_Cost"
)
# Constraints
# 1. Each customer must be fully served
for j in range(n):
prob += (
lpSum([x[i,j] for i in range(m)]) == 1,
f"Demand_Customer_{j}"
)
# 2. Can only serve from open facilities
for i in range(m):
for j in range(n):
prob += (
x[i,j] 0.5]
assignments = {}
for j in range(n):
assignments[j] = []
for i in range(m):
if x[i,j].varValue > 0.01: # Threshold for numerical issues
assignments[j].append((i, x[i,j].varValue))
# Calculate cost breakdown
fixed_cost_total = sum(fixed_costs[i] for i in open_facilities)
transport_cost_total = sum(
transport_costs[i][j] * demands[j] * x[i,j].varValue
for i in range(m) for j in range(n)
)
return {
'status': LpStatus[prob.status],
'total_cost': value(prob.objective),
'fixed_cost': fixed_cost_total,
'transport_cost': transport_cost_total,
'open_facilities': open_facilities,
'num_facilities': len(open_facilities),
'assignments': assignments,
'solve_time': solve_time
}
else:
return {
'status': LpStatus[prob.status],
'total_cost': None,
'open_facilities': [],
'solve_time': solve_time
}
# Example usage
if __name__ == "__main__":
# Problem data: 5 potential facilities, 10 customers
np.random.seed(42)
# Fixed costs to open each facility
fixed_costs = [5000, 4500, 6000, 5500, 4800]
# Transportation costs (facility x customer)
# Lower cost = closer proximity
transport_costs = np.array([
[10, 15, 8, 20, 12, 18, 22, 14, 16, 11],
[18, 12, 16, 14, 10, 15, 20, 25, 13, 19],
[14, 20, 18, 10, 16, 12, 15, 18, 22, 14],
[22, 18, 14, 16, 20, 10, 12, 16, 14, 18],
[16, 14, 20, 18, 14, 16, 10, 12, 15, 20]
])
# Customer demands
demands = [100, 150, 80, 120, 90, 110, 130, 95, 105, 125]
result = solve_uflp(fixed_costs, transport_costs, demands)
print(f"\n{'='*70}")
print(f"UNCAPACITATED FACILITY LOCATION PROBLEM - SOLUTION")
print(f"{'='*70}")
print(f"Status: {result['status']}")
print(f"Total Cost: ${result['total_cost']:,.2f}")
print(f" Fixed Costs: ${result['fixed_cost']:,.2f}")
print(f" Transport Costs: ${result['transport_cost']:,.2f}")
print(f"\nFacilities Opened: {result['num_facilities']}")
print(f"Facility IDs: {result['open_facilities']}")
print(f"\nSolve Time: {result['solve_time']:.2f} seconds")
print(f"\nCustomer Assignments:")
for customer_id, assignment in result['assignments'].items():
print(f" Customer {customer_id} (demand={demands[customer_id]}):")
for facility_id, fraction in assignment:
print(f" → Facility {facility_id}: {fraction*100:.1f}%")
2. Capacitated Facility Location Problem (CFLP)
def solve_cflp(fixed_costs, transport_costs, demands, capacities):
"""
Solve Capacitated Facility Location Problem
Args:
fixed_costs: list of fixed costs for each facility
transport_costs: 2D array [facilities x customers]
demands: list of customer demands
capacities: list of facility capacities
Returns:
dict with optimal solution
"""
m = len(fixed_costs)
n = len(demands)
# Create problem
prob = LpProblem("CFLP", LpMinimize)
# Decision variables
y = LpVariable.dicts("facility", range(m), cat='Binary')
x = LpVariable.dicts("assign",
[(i, j) for i in range(m) for j in range(n)],
lowBound=0, cat='Continuous')
# Objective
prob += (
lpSum([fixed_costs[i] * y[i] for i in range(m)]) +
lpSum([transport_costs[i][j] * demands[j] * x[i,j]
for i in range(m) for j in range(n)]),
"Total_Cost"
)
# Constraints
# 1. Each customer fully served
for j in range(n):
prob += (
lpSum([x[i,j] for i in range(m)]) == 1,
f"Demand_{j}"
)
# 2. Capacity constraints at each facility
for i in range(m):
prob += (
lpSum([demands[j] * x[i,j] for j in range(n)]) 0.5]
# Calculate utilization for each open facility
utilization = {}
for i in open_facilities:
used_capacity = sum(demands[j] * x[i,j].varValue for j in range(n))
utilization[i] = (used_capacity / capacities[i]) * 100
assignments = {}
for j in range(n):
assignments[j] = []
for i in range(m):
if x[i,j].varValue > 0.01:
assignments[j].append((i, x[i,j].varValue))
return {
'status': LpStatus[prob.status],
'total_cost': value(prob.objective),
'open_facilities': open_facilities,
'num_facilities': len(open_facilities),
'utilization': utilization,
'assignments': assignments,
'solve_time': solve_time
}
else:
return {
'status': LpStatus[prob.status],
'solve_time': solve_time
}
# Example usage
fixed_costs = [8000, 7500, 9000, 8500, 7800]
transport_costs = np.array([
[10, 15, 8, 20, 12, 18, 22, 14, 16, 11],
[18, 12, 16, 14, 10, 15, 20, 25, 13, 19],
[14, 20, 18, 10, 16, 12, 15, 18, 22, 14],
[22, 18, 14, 16, 20, 10, 12, 16, 14, 18],
[16, 14, 20, 18, 14, 16, 10, 12, 15, 20]
])
demands = [100, 150, 80, 120, 90, 110, 130, 95, 105, 125]
capacities = [400, 350, 450, 380, 420] # Facility capacities
result = solve_cflp(fixed_costs, transport_costs, demands, capacities)
print(f"\n{'='*70}")
print(f"CAPACITATED FACILITY LOCATION PROBLEM - SOLUTION")
print(f"{'='*70}")
print(f"Status: {result['status']}")
print(f"Total Cost: ${result['total_cost']:,.2f}")
print(f"Facilities Opened: {result['num_facilities']}")
print(f"\nFacility Utilization:")
for facility_id in result['open_facilities']:
print(f" Facility {facility_id}: {result['utilization'][facility_id]:.1f}% "
f"(capacity={capacities[facility_id]})")
3. p-Median Problem
def solve_p_median(distances, demands, p):
"""
Solve p-Median Problem
Locate exactly p facilities to minimize total weighted distance
Args:
distances: 2D array of distances [facilities x customers]
demands: customer demands (weights)
p: number of facilities to open
Returns:
optimal solution
"""
m = len(distances) # Potential facility locations
n = len(demands) # Customers
prob = LpProblem("p_Median", LpMinimize)
# Decision variables
y = LpVariable.dicts("facility", range(m), cat='Binary')
x = LpVariable.dicts("assign",
[(i, j) for i in range(m) for j in range(n)],
cat='Binary')
# Objective: Minimize total weighted distance
prob += (
lpSum([distances[i][j] * demands[j] * x[i,j]
for i in range(m) for j in range(n)]),
"Total_Weighted_Distance"
)
# Constraints
# 1. Each customer assigned to exactly one facility
for j in range(n):
prob += (
lpSum([x[i,j] for i in range(m)]) == 1,
f"Assign_{j}"
)
# 2. Exactly p facilities opened
prob += (
lpSum([y[i] for i in range(m)]) == p,
"p_Facilities"
)
# 3. Assignment only to open facilities
for i in range(m):
for j in range(n):
prob += (
x[i,j] 0.5]
assignments = {}
for j in range(n):
for i in range(m):
if x[i,j].varValue > 0.5:
assignments[j] = i
break
return {
'status': LpStatus[prob.status],
'total_distance': value(prob.objective),
'open_facilities': open_facilities,
'assignments': assignments,
'solve_time': solve_time
}
else:
return {'status': LpStatus[prob.status]}
# Example: Locate 3 facilities among 8 candidates to serve 12 customers
np.random.seed(42)
# Generate random coordinates
facility_coords = np.random.rand(8, 2) * 100
customer_coords = np.random.rand(12, 2) * 100
# Calculate Euclidean distance matrix
distances = np.zeros((8, 12))
for i in range(8):
for j in range(12):
distances[i][j] = np.linalg.norm(facility_coords[i] - customer_coords[j])
demands = [100, 150, 80, 120, 90, 110, 130, 95, 105, 125, 115, 140]
p = 3 # Open exactly 3 facilities
result = solve_p_median(distances, demands, p)
print(f"\n{'='*70}")
print(f"p-MEDIAN PROBLEM - SOLUTION")
print(f"{'='*70}")
print(f"Status: {result['status']}")
print(f"Total Weighted Distance: {result['total_distance']:,.2f}")
print(f"Facilities Opened (p={p}): {result['open_facilities']}")
print(f"\nCustomer Assignments:")
for customer_id, facility_id in result['assignments'].items():
dist = distances[facility_id][customer_id]
print(f" Customer {customer_id} → Facility {facility_id} "
f"(distance={dist:.2f}, demand={demands[customer_id]})")
Greedy Heuristics
1. Greedy Add Algorithm (p-Median)
def greedy_add_p_median(distances, demands, p):
"""
Greedy heuristic for p-Median Problem
Iteratively add facility that gives maximum cost redu
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [kishorkukreja](https://github.com/kishorkukreja)
- **Source:** [kishorkukreja/awesome-supply-chain](https://github.com/kishorkukreja/awesome-supply-chain)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.