Try our new documentation site (beta).
Filter Content By
Version
Text Search
${sidebar_list_label} - Back
Filter by Language
facility.py
#!/usr/bin/env python3.11 # Copyright 2024, Gurobi Optimization, LLC # Facility location: a company currently ships its product from 5 plants # to 4 warehouses. It is considering closing some plants to reduce # costs. What plant(s) should the company close, in order to minimize # transportation and fixed costs? # # Note that this example uses lists instead of dictionaries. Since # it does not work with sparse data, lists are a reasonable option. # # Based on an example from Frontline Systems: # http://www.solver.com/disfacility.htm # Used with permission. import gurobipy as gp from gurobipy import GRB # Warehouse demand in thousands of units demand = [15, 18, 14, 20] # Plant capacity in thousands of units capacity = [20, 22, 17, 19, 18] # Fixed costs for each plant fixedCosts = [12000, 15000, 17000, 13000, 16000] # Transportation costs per thousand units transCosts = [ [4000, 2000, 3000, 2500, 4500], [2500, 2600, 3400, 3000, 4000], [1200, 1800, 2600, 4100, 3000], [2200, 2600, 3100, 3700, 3200], ] # Range of plants and warehouses plants = range(len(capacity)) warehouses = range(len(demand)) # Model m = gp.Model("facility") # Plant open decision variables: open[p] == 1 if plant p is open. open = m.addVars(plants, vtype=GRB.BINARY, obj=fixedCosts, name="open") # Transportation decision variables: transport[w,p] captures the # optimal quantity to transport to warehouse w from plant p transport = m.addVars(warehouses, plants, obj=transCosts, name="trans") # You could use Python looping constructs and m.addVar() to create # these decision variables instead. The following would be equivalent # to the preceding two statements... # # open = [] # for p in plants: # open.append(m.addVar(vtype=GRB.BINARY, # obj=fixedCosts[p], # name="open[%d]" % p)) # # transport = [] # for w in warehouses: # transport.append([]) # for p in plants: # transport[w].append(m.addVar(obj=transCosts[w][p], # name="trans[%d,%d]" % (w, p))) # The objective is to minimize the total fixed and variable costs m.ModelSense = GRB.MINIMIZE # Production constraints # Note that the right-hand limit sets the production to zero if the plant # is closed m.addConstrs( (transport.sum("*", p) <= capacity[p] * open[p] for p in plants), "Capacity" ) # Using Python looping constructs, the preceding would be... # # for p in plants: # m.addConstr(sum(transport[w][p] for w in warehouses) # <= capacity[p] * open[p], "Capacity[%d]" % p) # Demand constraints m.addConstrs((transport.sum(w) == demand[w] for w in warehouses), "Demand") # ... and the preceding would be ... # for w in warehouses: # m.addConstr(sum(transport[w][p] for p in plants) == demand[w], # "Demand[%d]" % w) # Save model m.write("facilityPY.lp") # Guess at the starting point: close the plant with the highest fixed costs; # open all others # First open all plants for p in plants: open[p].Start = 1.0 # Now close the plant with the highest fixed cost print("Initial guess:") maxFixed = max(fixedCosts) for p in plants: if fixedCosts[p] == maxFixed: open[p].Start = 0.0 print(f"Closing plant {p}") break print("") # Use barrier to solve root relaxation m.Params.Method = 2 # Solve m.optimize() # Print solution print(f"\nTOTAL COSTS: {m.ObjVal:g}") print("SOLUTION:") for p in plants: if open[p].X > 0.99: print(f"Plant {p} open") for w in warehouses: if transport[w, p].X > 0: print(f" Transport {transport[w, p].X:g} units to warehouse {w}") else: print(f"Plant {p} closed!")