|
5 | 5 | # -------------------------------------------------------------------------- |
6 | 6 |
|
7 | 7 | """ |
8 | | -A company has 10 stores. Each store must be supplied by one warehouse. The |
9 | | -company has five possible locations where it has property and can build a |
10 | | -supplier warehouse: Bonn, Bordeaux, London, Paris, and Rome. The warehouse |
11 | | -locations have different capacities. A warehouse built in Bordeaux or Rome |
12 | | -could supply only one store. A warehouse built in London could supply two |
13 | | -stores; a warehouse built in Bonn could supply three stores; and a warehouse |
| 8 | +A company has 8 stores. |
| 9 | +Each store must be supplied by one warehouse. |
| 10 | +The company has 5 possible locations where it has property and can build a |
| 11 | +supplier warehouse: Bonn, Bordeaux, London, Paris, and Rome. |
| 12 | +
|
| 13 | +The warehouse locations have different capacities. A warehouse built in Bordeaux |
| 14 | +or Rome could supply only one store ; a warehouse built in London could supply |
| 15 | +two stores; a warehouse built in Bonn could supply three stores; and a warehouse |
14 | 16 | built in Paris could supply four stores. |
15 | 17 |
|
16 | 18 | The supply costs vary for each store, depending on which warehouse is the |
|
26 | 28 | Please refer to documentation for appropriate setup of solving configuration. |
27 | 29 | """ |
28 | 30 |
|
29 | | -from docplex.cp.model import * |
| 31 | +from docplex.cp.model import CpoModel |
| 32 | +from collections import namedtuple |
30 | 33 |
|
31 | 34 | ############################################################################## |
32 | 35 | ## Problem data |
33 | 36 | ############################################################################## |
34 | 37 |
|
35 | | -nbLocations = 5 |
36 | | -nbStores = 8 |
37 | | -capacity = (3, 1, 2, 4, 1) |
38 | | -fixedCost = (480, 200, 320, 340, 300) |
39 | | -cost = ((24, 74, 31, 51, 84), |
40 | | - (57, 54, 86, 61, 68), |
41 | | - (57, 67, 29, 91, 71), |
42 | | - (54, 54, 65, 82, 94), |
43 | | - (98, 81, 16, 61, 27), |
44 | | - (13, 92, 34, 94, 87), |
45 | | - (54, 72, 41, 12, 78), |
46 | | - (54, 64, 65, 89, 89)) |
| 38 | +Warehouse = namedtuple('Wharehouse', ('city', # Name of the city |
| 39 | + 'capacity', # Capacity of the warehouse |
| 40 | + 'cost', # Warehouse building cost |
| 41 | + )) |
| 42 | + |
| 43 | +# List of warehouses |
| 44 | +WAREHOUSES = (Warehouse("Bonn", 3, 480), |
| 45 | + Warehouse("Bordeaux", 1, 200), |
| 46 | + Warehouse("London", 2, 320), |
| 47 | + Warehouse("Paris", 4, 340), |
| 48 | + Warehouse("Rome", 1, 300)) |
| 49 | +NB_WAREHOUSES = len(WAREHOUSES) |
| 50 | + |
| 51 | +# Number of stores |
| 52 | +NB_STORES = 8 |
| 53 | + |
| 54 | +# Supply cost for each store and warehouse |
| 55 | +SUPPLY_COST = ((24, 74, 31, 51, 84), |
| 56 | + (57, 54, 86, 61, 68), |
| 57 | + (57, 67, 29, 91, 71), |
| 58 | + (54, 54, 65, 82, 94), |
| 59 | + (98, 81, 16, 61, 27), |
| 60 | + (13, 92, 34, 94, 87), |
| 61 | + (54, 72, 41, 12, 78), |
| 62 | + (54, 64, 65, 89, 89)) |
47 | 63 |
|
48 | 64 |
|
49 | 65 | ############################################################################## |
|
53 | 69 | # Create CPO model |
54 | 70 | mdl = CpoModel() |
55 | 71 |
|
56 | | -supplier = integer_var_list(nbStores, 0, nbLocations - 1, "supplier") |
57 | | -open = integer_var_list(nbLocations, 0, 1, "open") |
58 | | - |
| 72 | +# Create one variable per store to contain the index of its supplying warehouse |
| 73 | +NB_WAREHOUSES = len(WAREHOUSES) |
| 74 | +supplier = mdl.integer_var_list(NB_STORES, 0, NB_WAREHOUSES - 1, "supplier") |
| 75 | + |
| 76 | +# Create one variable per warehouse to indicate if it is open (1) or not (0) |
| 77 | +open = mdl.integer_var_list(NB_WAREHOUSES, 0, 1, "open") |
| 78 | + |
| 79 | +# Add constraints stating that the supplying warehouse of each store must be open |
59 | 80 | for s in supplier: |
60 | | - mdl.add(element(open, s) == 1) |
| 81 | + mdl.add(mdl.element(open, s) == 1) |
61 | 82 |
|
62 | | -for j in range(nbLocations): |
63 | | - mdl.add(count(supplier, j) <= capacity[j]) |
64 | | - |
65 | | -obj = scal_prod(open, fixedCost) |
66 | | -for i in range(nbStores): |
67 | | - obj = obj + element(supplier[i], cost[i]) |
| 83 | +# Add constraints stating that the number of stores supplied by each warehouse must not exceed its capacity |
| 84 | +for wx in range(NB_WAREHOUSES): |
| 85 | + mdl.add(mdl.count(supplier, wx) <= WAREHOUSES[wx].capacity) |
68 | 86 |
|
69 | | -# Add minimization objective |
70 | | -mdl.add(minimize(obj)) |
| 87 | +# Build an expression that computes total cost |
| 88 | +total_cost = mdl.scal_prod(open, [w.cost for w in WAREHOUSES]) |
| 89 | +for sx in range(NB_STORES): |
| 90 | + total_cost = total_cost + mdl.element(supplier[sx], SUPPLY_COST[sx]) |
| 91 | + |
| 92 | +# Minimize total cost |
| 93 | +mdl.add(mdl.minimize(total_cost)) |
71 | 94 |
|
72 | 95 |
|
73 | 96 | ############################################################################## |
|
77 | 100 | # Solve model |
78 | 101 | print("\nSolving model....") |
79 | 102 | msol = mdl.solve(TimeLimit=10) |
80 | | -msol.print_solution() |
| 103 | + |
| 104 | +# Print solution |
| 105 | +if msol: |
| 106 | + for wx in range(NB_WAREHOUSES): |
| 107 | + if msol[open[wx]] == 1: |
| 108 | + print("Warehouse '{}' open to supply stores: {}" |
| 109 | + .format(WAREHOUSES[wx].city, |
| 110 | + ", ".join(str(sx) for sx in range(NB_STORES) if msol[supplier[sx]] == wx))) |
| 111 | + print("Total cost is: {}".format(msol.get_objective_values()[0])) |
| 112 | +else: |
| 113 | + print("No solution found.") |
0 commit comments