4 minimize the travel cost for visiting n customers exactly once
6 - start with assignment model
7 - add cuts until there are no sub-cycles
8 - two cutting plane possibilities (called inside "solve_tsp"):
9 - addcut: limit the number of edges in a connected component S to |S|-1
10 - addcut2: require the number of edges between two connected component to be >= 2
12 Copyright (c) by Joao Pedro PEDROSO and Mikio KUBO, 2012
18 from pyscipopt
import Model, quicksum
22 """solve_tsp -- solve the traveling salesman problem
23 - start with assignment model
24 - add cuts until there are no sub-cycles
26 - V: set/list of nodes in the graph
27 - c[i,j]: cost for traversing edge (i,j)
28 Returns the optimum objective value and the list of edges used.
31 def addcut(cut_edges):
33 G.add_edges_from(cut_edges)
34 Components = list(networkx.connected_components(G))
35 if len(Components) == 1:
39 model.addCons(
quicksum(x[i, j]
for i
in S
for j
in S
if j > i) <= len(S) - 1)
40 print(
"cut: len(%s) <= %s" % (S, len(S) - 1))
43 def addcut2(cut_edges):
45 G.add_edges_from(cut_edges)
46 Components = list(networkx.connected_components(G))
48 if len(Components) == 1:
55 model.addCons(
quicksum(x[i, j]
for i
in S
for j
in T
if j > i) +
56 quicksum(x[i, j]
for i
in T
for j
in S
if j > i) >= 2)
57 print(
"cut: %s >= 2" %
"+".join([(
"x[%s,%s]" % (i, j))
for i
in S
for j
in T
if j > i]))
68 x[i, j] = model.addVar(ub=1, name=
"x(%s,%s)" % (i, j))
71 model.addCons(
quicksum(x[j, i]
for j
in V
if j < i) + \
72 quicksum(x[i, j]
for j
in V
if j > i) == 2,
"Degree(%s)" % i)
74 model.setObjective(
quicksum(c[i, j] * x[i, j]
for i
in V
for j
in V
if j > i),
"minimize")
82 if model.getVal(x[i, j]) > EPS:
85 if addcut(edges) ==
False:
90 model.chgVarType(x[i, j],
"B")
93 return model.getObjVal(), edges
97 """distance: euclidean distance between (x1,y1) and (x2,y2)"""
98 return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
102 """make_data: compute matrix distance based on euclidean distance"""
104 x = dict([(i, random.random())
for i
in V])
105 y = dict([(i, random.random())
for i
in V])
110 c[i, j] =
distance(x[i], y[i], x[j], y[j])
114 if __name__ ==
"__main__":
118 if len(sys.argv) < 2:
119 print(
"Usage: %s instance" % sys.argv[0])
120 print(
"Using randomized example instead")
126 from read_tsplib
import read_tsplib
131 print(
"Cannot read TSPLIB file", sys.argv[1])
136 print(
"\nOptimal tour:", edges)
137 print(
"Optimal cost:", obj)