PySCIPOpt  5.1.1
Python Interface for the SCIP Optimization Suite
atsp.py
Go to the documentation of this file.
1 
3 
4 """
5 
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
11 
12 Copyright (c) by Joao Pedro PEDROSO and Mikio KUBO, 2012
13 """
14 from pyscipopt import Model, quicksum
15 
16 
17 def mtz(n, c):
18  """mtz: Miller-Tucker-Zemlin's model for the (asymmetric) traveling salesman problem
19  (potential formulation)
20  Parameters:
21  - n: number of nodes
22  - c[i,j]: cost for traversing arc (i,j)
23  Returns a model, ready to be solved.
24  """
25 
26  model = Model("atsp - mtz")
27 
28  x, u = {}, {}
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):
32  if i != j:
33  x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j))
34 
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)
38 
39  for i in range(1, n + 1):
40  for j in range(2, n + 1):
41  if i != j:
42  model.addCons(u[i] - u[j] + (n - 1) * x[i, j] <= n - 2, "MTZ(%s,%s)" % (i, j))
43 
44  model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize")
45 
46  model.data = x, u
47  return model
48 
49 
50 def mtz_strong(n, c):
51  """mtz_strong: Miller-Tucker-Zemlin's model for the (asymmetric) traveling salesman problem
52  (potential formulation, adding stronger constraints)
53  Parameters:
54  n - number of nodes
55  c[i,j] - cost for traversing arc (i,j)
56  Returns a model, ready to be solved.
57  """
58 
59  model = Model("atsp - mtz-strong")
60 
61  x, u = {}, {}
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):
65  if i != j:
66  x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j))
67 
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)
71 
72  for i in range(1, n + 1):
73  for j in range(2, n + 1):
74  if i != j:
75  model.addCons(u[i] - u[j] + (n - 1) * x[i, j] + (n - 3) * x[j, i] <= n - 2, "LiftedMTZ(%s,%s)" % (i, j))
76 
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)
80 
81  model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize")
82 
83  model.data = x, u
84  return model
85 
86 
87 def scf(n, c):
88  """scf: single-commodity flow formulation for the (asymmetric) traveling salesman problem
89  Parameters:
90  - n: number of nodes
91  - c[i,j]: cost for traversing arc (i,j)
92  Returns a model, ready to be solved.
93  """
94  model = Model("atsp - scf")
95 
96  x, f = {}, {}
97  for i in range(1, n + 1):
98  for j in range(1, n + 1):
99  if i != j:
100  x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j))
101  if i == 1:
102  f[i, j] = model.addVar(lb=0, ub=n - 1, vtype="C", name="f(%s,%s)" % (i, j))
103  else:
104  f[i, j] = model.addVar(lb=0, ub=n - 2, vtype="C", name="f(%s,%s)" % (i, j))
105 
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)
109 
110  model.addCons(quicksum(f[1, j] for j in range(2, n + 1)) == n - 1, "FlowOut")
111 
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)
115 
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):
119  if i != j:
120  model.addCons(f[i, j] <= (n - 2) * x[i, j], "FlowUB(%s,%s)" % (i, j))
121 
122  model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize")
123 
124  model.data = x, f
125  return model
126 
127 
128 def mcf(n, c):
129  """mcf: multi-commodity flow formulation for the (asymmetric) traveling salesman problem
130  Parameters:
131  - n: number of nodes
132  - c[i,j]: cost for traversing arc (i,j)
133  Returns a model, ready to be solved.
134  """
135  model = Model("mcf")
136 
137  x, f = {}, {}
138  for i in range(1, n + 1):
139  for j in range(1, n + 1):
140  if i != j:
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):
144  if i != k:
145  f[i, j, k] = model.addVar(ub=1, vtype="C", name="f(%s,%s,%s)" % (i, j, k))
146 
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)
150 
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)
154 
155  for i in range(2, n + 1):
156  if i != k:
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))
160 
161  for (i, j, k) in f:
162  model.addCons(f[i, j, k] <= x[i, j], "FlowUB(%s,%s,%s)" % (i, j, k))
163 
164  model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize")
165 
166  model.data = x, f
167  return model
168 
169 
170 def sequence(arcs):
171  """sequence: make a list of cities to visit, from set of arcs"""
172  succ = {}
173  for (i, j) in arcs:
174  succ[i] = j
175  curr = 1 # first node being visited
176  sol = [curr]
177  for i in range(len(arcs) - 2):
178  curr = succ[curr]
179  sol.append(curr)
180  return sol
181 
182 
183 if __name__ == "__main__":
184  n = 5
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,
190  }
191 
192  model = mtz(n, c)
193  model.hideOutput() # silent mode
194  model.optimize()
195  cost = model.getObjVal()
196  print()
197  print("Miller-Tucker-Zemlin's model:")
198  print("Optimal value:", cost)
199  # model.printAttr("X")
200  for v in model.getVars():
201  if model.getVal(v) > 0.001:
202  print(v.name, "=", model.getVal(v))
203 
204  x, u = model.data
205  sol = [i for (p, i) in sorted([(int(model.getVal(u[i]) + .5), i) for i in range(1, n + 1)])]
206  print(sol)
207  arcs = [(i, j) for (i, j) in x if model.getVal(x[i, j]) > .5]
208  sol = sequence(arcs)
209  print(sol)
210  # assert cost == 5
211 
212  model = mtz_strong(n, c)
213  model.hideOutput() # silent mode
214  model.optimize()
215  cost = model.getObjVal()
216  print()
217  print("Miller-Tucker-Zemlin's model with stronger constraints:")
218  print("Optimal value:", cost)
219  # model.printAttr("X")
220  for v in model.getVars():
221  if model.getVal(v) > 0.001:
222  print(v.name, "=", model.getVal(v))
223 
224  x, u = model.data
225  sol = [i for (p, i) in sorted([(int(model.getVal(u[i]) + .5), i) for i in range(1, n + 1)])]
226  print(sol)
227  arcs = [(i, j) for (i, j) in x if model.getVal(x[i, j]) > .5]
228  sol = sequence(arcs)
229  print(sol)
230  # assert cost == 5
231 
232  model = scf(n, c)
233  model.hideOutput() # silent mode
234  model.optimize()
235  cost = model.getObjVal()
236  print()
237  print("Single-commodity flow formulation:")
238  print("Optimal value:", cost)
239  # model.printAttr("X")
240  for v in model.getVars():
241  if model.getVal(v) > 0.001:
242  print(v.name, "=", model.getVal(v))
243 
244  x, f = model.data
245  arcs = [(i, j) for (i, j) in x if model.getVal(x[i, j]) > .5]
246  sol = sequence(arcs)
247  print(sol)
248  # assert cost == 5
249 
250  model = mcf(n, c)
251  model.hideOutput() # silent mode
252  model.optimize()
253  cost = model.getObjVal()
254  print()
255  print("Multi-commodity flow formulation:")
256  print("Optimal value:", cost)
257  # model.printAttr("X")
258  for v in model.getVars():
259  if model.getVal(v) > 0.001:
260  print(v.name, "=", model.getVal(v))
261 
262  x, f = model.data
263  arcs = [(i, j) for (i, j) in x if model.getVal(x[i, j]) > .5]
264  sol = sequence(arcs)
265  print(sol)
266  # assert cost == 5
atsp.mtz_strong
def mtz_strong(n, c)
Definition: atsp.py:50
pyscipopt.expr.quicksum
def quicksum(termlist)
Definition: expr.pxi:357
atsp.mtz
def mtz(n, c)
Definition: atsp.py:17
atsp.sequence
def sequence(arcs)
Definition: atsp.py:170
atsp.scf
def scf(n, c)
Definition: atsp.py:87
atsp.mcf
def mcf(n, c)
Definition: atsp.py:128