6 formulations implemented:
7 - mtz -- Miller-Tucker-Zemlin's potential formulation
8 - mtz_strong -- Miller-Tucker-Zemlin's potential formulation with stronger constraint
9 - scf -- single-commodity flow formulation
10 - mcf -- multi-commodity flow formulation
12 Copyright (c) by Joao Pedro PEDROSO and Mikio KUBO, 2012
14 from pyscipopt
import Model, quicksum
18 """mtz: Miller-Tucker-Zemlin's model for the (asymmetric) traveling salesman problem
19 (potential formulation)
22 - c[i,j]: cost for traversing arc (i,j)
23 Returns a model, ready to be solved.
26 model = Model(
"atsp - mtz")
29 for i
in range(1, n + 1):
30 u[i] = model.addVar(lb=0, ub=n - 1, vtype=
"C", name=
"u(%s)" % i)
31 for j
in range(1, n + 1):
33 x[i, j] = model.addVar(vtype=
"B", name=
"x(%s,%s)" % (i, j))
35 for i
in range(1, n + 1):
36 model.addCons(
quicksum(x[i, j]
for j
in range(1, n + 1)
if j != i) == 1,
"Out(%s)" % i)
37 model.addCons(
quicksum(x[j, i]
for j
in range(1, n + 1)
if j != i) == 1,
"In(%s)" % i)
39 for i
in range(1, n + 1):
40 for j
in range(2, n + 1):
42 model.addCons(u[i] - u[j] + (n - 1) * x[i, j] <= n - 2,
"MTZ(%s,%s)" % (i, j))
44 model.setObjective(
quicksum(c[i, j] * x[i, j]
for (i, j)
in x),
"minimize")
51 """mtz_strong: Miller-Tucker-Zemlin's model for the (asymmetric) traveling salesman problem
52 (potential formulation, adding stronger constraints)
55 c[i,j] - cost for traversing arc (i,j)
56 Returns a model, ready to be solved.
59 model = Model(
"atsp - mtz-strong")
62 for i
in range(1, n + 1):
63 u[i] = model.addVar(lb=0, ub=n - 1, vtype=
"C", name=
"u(%s)" % i)
64 for j
in range(1, n + 1):
66 x[i, j] = model.addVar(vtype=
"B", name=
"x(%s,%s)" % (i, j))
68 for i
in range(1, n + 1):
69 model.addCons(
quicksum(x[i, j]
for j
in range(1, n + 1)
if j != i) == 1,
"Out(%s)" % i)
70 model.addCons(
quicksum(x[j, i]
for j
in range(1, n + 1)
if j != i) == 1,
"In(%s)" % i)
72 for i
in range(1, n + 1):
73 for j
in range(2, n + 1):
75 model.addCons(u[i] - u[j] + (n - 1) * x[i, j] + (n - 3) * x[j, i] <= n - 2,
"LiftedMTZ(%s,%s)" % (i, j))
77 for i
in range(2, n + 1):
78 model.addCons(-x[1, i] - u[i] + (n - 3) * x[i, 1] <= -2, name=
"LiftedLB(%s)" % i)
79 model.addCons(-x[i, 1] + u[i] + (n - 3) * x[1, i] <= n - 2, name=
"LiftedUB(%s)" % i)
81 model.setObjective(
quicksum(c[i, j] * x[i, j]
for (i, j)
in x),
"minimize")
88 """scf: single-commodity flow formulation for the (asymmetric) traveling salesman problem
91 - c[i,j]: cost for traversing arc (i,j)
92 Returns a model, ready to be solved.
94 model = Model(
"atsp - scf")
97 for i
in range(1, n + 1):
98 for j
in range(1, n + 1):
100 x[i, j] = model.addVar(vtype=
"B", name=
"x(%s,%s)" % (i, j))
102 f[i, j] = model.addVar(lb=0, ub=n - 1, vtype=
"C", name=
"f(%s,%s)" % (i, j))
104 f[i, j] = model.addVar(lb=0, ub=n - 2, vtype=
"C", name=
"f(%s,%s)" % (i, j))
106 for i
in range(1, n + 1):
107 model.addCons(
quicksum(x[i, j]
for j
in range(1, n + 1)
if j != i) == 1,
"Out(%s)" % i)
108 model.addCons(
quicksum(x[j, i]
for j
in range(1, n + 1)
if j != i) == 1,
"In(%s)" % i)
110 model.addCons(
quicksum(f[1, j]
for j
in range(2, n + 1)) == n - 1,
"FlowOut")
112 for i
in range(2, n + 1):
113 model.addCons(
quicksum(f[j, i]
for j
in range(1, n + 1)
if j != i) - \
114 quicksum(f[i, j]
for j
in range(1, n + 1)
if j != i) == 1,
"FlowCons(%s)" % i)
116 for j
in range(2, n + 1):
117 model.addCons(f[1, j] <= (n - 1) * x[1, j],
"FlowUB(%s,%s)" % (1, j))
118 for i
in range(2, n + 1):
120 model.addCons(f[i, j] <= (n - 2) * x[i, j],
"FlowUB(%s,%s)" % (i, j))
122 model.setObjective(
quicksum(c[i, j] * x[i, j]
for (i, j)
in x),
"minimize")
129 """mcf: multi-commodity flow formulation for the (asymmetric) traveling salesman problem
132 - c[i,j]: cost for traversing arc (i,j)
133 Returns a model, ready to be solved.
138 for i
in range(1, n + 1):
139 for j
in range(1, n + 1):
141 x[i, j] = model.addVar(vtype=
"B", name=
"x(%s,%s)" % (i, j))
142 if i != j
and j != 1:
143 for k
in range(2, n + 1):
145 f[i, j, k] = model.addVar(ub=1, vtype=
"C", name=
"f(%s,%s,%s)" % (i, j, k))
147 for i
in range(1, n + 1):
148 model.addCons(
quicksum(x[i, j]
for j
in range(1, n + 1)
if j != i) == 1,
"Out(%s)" % i)
149 model.addCons(
quicksum(x[j, i]
for j
in range(1, n + 1)
if j != i) == 1,
"In(%s)" % i)
151 for k
in range(2, n + 1):
152 model.addCons(
quicksum(f[1, i, k]
for i
in range(2, n + 1)
if (1, i, k)
in f) == 1,
"FlowOut(%s)" % k)
153 model.addCons(
quicksum(f[i, k, k]
for i
in range(1, n + 1)
if (i, k, k)
in f) == 1,
"FlowIn(%s)" % k)
155 for i
in range(2, n + 1):
157 model.addCons(
quicksum(f[j, i, k]
for j
in range(1, n + 1)
if (j, i, k)
in f) == \
158 quicksum(f[i, j, k]
for j
in range(1, n + 1)
if (i, j, k)
in f),
159 "FlowCons(%s,%s)" % (i, k))
162 model.addCons(f[i, j, k] <= x[i, j],
"FlowUB(%s,%s,%s)" % (i, j, k))
164 model.setObjective(
quicksum(c[i, j] * x[i, j]
for (i, j)
in x),
"minimize")
171 """sequence: make a list of cities to visit, from set of arcs"""
177 for i
in range(len(arcs) - 2):
183 if __name__ ==
"__main__":
185 c = {(1, 1): 0, (1, 2): 1989, (1, 3): 102, (1, 4): 102, (1, 5): 103,
186 (2, 1): 104, (2, 2): 0, (2, 3): 11, (2, 4): 104, (2, 5): 108,
187 (3, 1): 107, (3, 2): 108, (3, 3): 0, (3, 4): 19, (3, 5): 102,
188 (4, 1): 109, (4, 2): 102, (4, 3): 107, (4, 4): 0, (4, 5): 15,
189 (5, 1): 13, (5, 2): 103, (5, 3): 104, (5, 4): 101, (5, 5): 0,
195 cost = model.getObjVal()
197 print(
"Miller-Tucker-Zemlin's model:")
198 print(
"Optimal value:", cost)
200 for v
in model.getVars():
201 if model.getVal(v) > 0.001:
202 print(v.name,
"=", model.getVal(v))
205 sol = [i
for (p, i)
in sorted([(int(model.getVal(u[i]) + .5), i)
for i
in range(1, n + 1)])]
207 arcs = [(i, j)
for (i, j)
in x
if model.getVal(x[i, j]) > .5]
215 cost = model.getObjVal()
217 print(
"Miller-Tucker-Zemlin's model with stronger constraints:")
218 print(
"Optimal value:", cost)
220 for v
in model.getVars():
221 if model.getVal(v) > 0.001:
222 print(v.name,
"=", model.getVal(v))
225 sol = [i
for (p, i)
in sorted([(int(model.getVal(u[i]) + .5), i)
for i
in range(1, n + 1)])]
227 arcs = [(i, j)
for (i, j)
in x
if model.getVal(x[i, j]) > .5]
235 cost = model.getObjVal()
237 print(
"Single-commodity flow formulation:")
238 print(
"Optimal value:", cost)
240 for v
in model.getVars():
241 if model.getVal(v) > 0.001:
242 print(v.name,
"=", model.getVal(v))
245 arcs = [(i, j)
for (i, j)
in x
if model.getVal(x[i, j]) > .5]
253 cost = model.getObjVal()
255 print(
"Multi-commodity flow formulation:")
256 print(
"Optimal value:", cost)
258 for v
in model.getVars():
259 if model.getVal(v) > 0.001:
260 print(v.name,
"=", model.getVal(v))
263 arcs = [(i, j)
for (i, j)
in x
if model.getVal(x[i, j]) > .5]