Integer programming: a warehouse location problem
Describes the problem and presents the model and data files.
Warehouse location is a typical discrete optimization problem. A company is considering a number
of locations for building warehouses to supply a set of stores. Each possible warehouse has a fixed
operating cost and a maximum capacity specifying how many stores it can support. In addition, each
store must be supplied by exactly one warehouse and the cost to supply a store depends on the
warehouse selected. The model consists of choosing which warehouses to build and which warehouse to
assign to each store in order to minimize the total cost, i.e., the sum of the fixed and supply
costs. Consider an example with five warehouses and ten stores. The fixed costs for the warehouses
are all identical and equal to 30. The instance data for the problem, shown in the following table,
reflects the transportation costs and the capacity constraints defined in the data file
warehouse.dat.
| Warehouses | Bonn | Bordeaux | London | Paris | Rome |
|---|---|---|---|---|---|
| Capacity | 1 | 4 | 2 | 1 | 3 |
| store1 | 20 | 24 | 11 | 25 | 30 |
| store2 | 28 | 27 | 82 | 83 | 74 |
| store3 | 74 | 97 | 71 | 96 | 70 |
| store4 | 2 | 55 | 73 | 69 | 61 |
| store5 | 46 | 96 | 59 | 83 | 4 |
| store6 | 42 | 22 | 29 | 67 | 59 |
| store7 | 1 | 5 | 73 | 59 | 56 |
| store8 | 10 | 73 | 13 | 43 | 96 |
| store9 | 93 | 35 | 63 | 85 | 46 |
| store10 | 47 | 65 | 55 | 71 | 95 |
To represent our warehouse location problem as an integer program,
the model, warehouse.mod, uses a 0-1 Boolean
variable for each combination of warehouse and store to represent
whether or not a warehouse supplies a store. In addition, the model
associates a variable with each warehouse to indicate whether the
warehouse is selected. Once these variables are declared, the constraints
state that each store must be supplied by a warehouse, that each store
can be supplied by only an open warehouse, and that each warehouse
cannot deliver more stores than its allowed capacity.
Warehouse
location, as a discrete optimization problem (warehouse.mod)
int Fixed = ...;
{string} Warehouses = ...;
int NbStores = ...;
range Stores = 0..NbStores-1;
int Capacity[Warehouses] = ...;
int SupplyCost[Stores][Warehouses] = ...;
dvar boolean Open[Warehouses];
dvar boolean Supply[Stores][Warehouses];
minimize
sum( w in Warehouses )
Fixed * Open[w] +
sum( w in Warehouses , s in Stores )
SupplyCost[s][w] * Supply[s][w];
subject to{
forall( s in Stores )
ctEachStoreHasOneWarehouse:
sum( w in Warehouses )
Supply[s][w] == 1;
forall( w in Warehouses, s in Stores )
ctUseOpenWarehouses:
Supply[s][w] <= Open[w];
forall( w in Warehouses )
ctMaxUseOfWarehouse:
sum( s in Stores )
Supply[s][w] <= Capacity[w];
}
{int} Storesof[w in Warehouses] = { s | s in Stores : Supply[s][w] == 1 };
execute DISPLAY_RESULTS{
writeln("Open=",Open);
writeln("Storesof=",Storesof);
}
The most delicate aspect of the modeling is expressing that a warehouse can supply a store only when it is open. These constraints can be expressed by inequalities of the form
supply[w][s] <= open[w];
which ensure that when warehouse w is not open,
it cannot supply store s. This follows from the fact
that open[w] == 0 implies supply[w][s] ==
0. In fact, these constraints can be combined with the capacity
constraints to obtain
forall( w in Warehouses, s in Stores )
ctUseOpenWarehouses:
Supply[s][w] <= Open[w];
forall( w in Warehouses )
ctMaxUseOfWarehouse:
sum( s in Stores )
Supply[s][w] <= Capacity[w];
This formulation implies that a closed warehouse has no capacity.
The statement declares the warehouses and the stores, the fixed cost of the warehouses, and the supply cost of a store for each warehouse. The problem variables
dvar boolean Supply[Stores][Warehouses];
represent which warehouses supply the stores, i.e., supply[s][w] is
1 if warehouse w supplies store s, and
zero otherwise.
The objective function
minimize
sum( w in Warehouses )
Fixed * Open[w] +
sum( w in Warehouses , s in Stores )
SupplyCost[s][w] * Supply[s][w];
expresses the goal that the model minimizes the fixed cost of the selected warehouse and the supply costs of stores.
The constraint
forall( s in Stores )
ctEachStoreHasOneWarehouse:
sum( w in Warehouses )
Supply[s][w] == 1;
states that a store must be supplied by exactly one warehouse.
The constraints
forall( w in Warehouses, s in Stores )
ctUseOpenWarehouses:
Supply[s][w] <= Open[w];
forall( w in Warehouses )
ctMaxUseOfWarehouse:
sum( s in Stores )
Supply[s][w] <= Capacity[w];
express the capacity constraints for the warehouses and make sure that a warehouse supplies a store only if the warehouse is open.
A solution to warehouse.mod
Final Solution with objective 383.0000:
open = [1 1 1 0 1];
supply = [[0 0 0 0 1]
[0 1 0 0 0]
[0 0 0 0 1]
[1 0 0 0 0]
[0 0 0 0 1]
[0 1 0 0 0]
[0 1 0 0 0]
[0 0 1 0 0]
[0 1 0 0 0]
[0 0 1 0 0]];