PySCIPOpt  5.1.1
Python Interface for the SCIP Optimization Suite
tsp.py
Go to the documentation of this file.
1 
3 """
4 minimize the travel cost for visiting n customers exactly once
5 approach:
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
11 
12 Copyright (c) by Joao Pedro PEDROSO and Mikio KUBO, 2012
13 """
14 import math
15 import random
16 
17 import networkx
18 from pyscipopt import Model, quicksum
19 
20 
21 def solve_tsp(V, c):
22  """solve_tsp -- solve the traveling salesman problem
23  - start with assignment model
24  - add cuts until there are no sub-cycles
25  Parameters:
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.
29  """
30 
31  def addcut(cut_edges):
32  G = networkx.Graph()
33  G.add_edges_from(cut_edges)
34  Components = list(networkx.connected_components(G))
35  if len(Components) == 1:
36  return False
37  model.freeTransform()
38  for S in Components:
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))
41  return True
42 
43  def addcut2(cut_edges):
44  G = networkx.Graph()
45  G.add_edges_from(cut_edges)
46  Components = list(networkx.connected_components(G))
47 
48  if len(Components) == 1:
49  return False
50  model.freeTransform()
51  for S in Components:
52  T = set(V) - set(S)
53  print("S:", S)
54  print("T:", T)
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]))
58  return True
59 
60  # main part of the solution process:
61  model = Model("tsp")
62 
63  model.hideOutput() # silent/verbose mode
64  x = {}
65  for i in V:
66  for j in V:
67  if j > i:
68  x[i, j] = model.addVar(ub=1, name="x(%s,%s)" % (i, j))
69 
70  for i in V:
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)
73 
74  model.setObjective(quicksum(c[i, j] * x[i, j] for i in V for j in V if j > i), "minimize")
75 
76  EPS = 1.e-6
77  isMIP = False
78  while True:
79  model.optimize()
80  edges = []
81  for (i, j) in x:
82  if model.getVal(x[i, j]) > EPS:
83  edges.append((i, j))
84 
85  if addcut(edges) == False:
86  if isMIP: # integer variables, components connected: solution found
87  break
88  model.freeTransform()
89  for (i, j) in x: # all components connected, switch to integer model
90  model.chgVarType(x[i, j], "B")
91  isMIP = True
92 
93  return model.getObjVal(), edges
94 
95 
96 def distance(x1, y1, x2, y2):
97  """distance: euclidean distance between (x1,y1) and (x2,y2)"""
98  return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
99 
100 
101 def make_data(n):
102  """make_data: compute matrix distance based on euclidean distance"""
103  V = range(1, n + 1)
104  x = dict([(i, random.random()) for i in V])
105  y = dict([(i, random.random()) for i in V])
106  c = {}
107  for i in V:
108  for j in V:
109  if j > i:
110  c[i, j] = distance(x[i], y[i], x[j], y[j])
111  return V, c
112 
113 
114 if __name__ == "__main__":
115  import sys
116 
117  # Parse argument
118  if len(sys.argv) < 2:
119  print("Usage: %s instance" % sys.argv[0])
120  print("Using randomized example instead")
121  n = 200
122  seed = 1
123  random.seed(seed)
124  V, c = make_data(n)
125  else:
126  from read_tsplib import read_tsplib
127 
128  try:
129  V, c, x, y = read_tsplib(sys.argv[1])
130  except:
131  print("Cannot read TSPLIB file", sys.argv[1])
132  exit(1)
133 
134  obj, edges = solve_tsp(V, c)
135 
136  print("\nOptimal tour:", edges)
137  print("Optimal cost:", obj)
pyscipopt.expr.quicksum
def quicksum(termlist)
Definition: expr.pxi:357
tsp.make_data
def make_data(n)
Definition: tsp.py:101
set
tsp.distance
def distance(x1, y1, x2, y2)
Definition: tsp.py:96
tsp.solve_tsp
def solve_tsp(V, c)
Definition: tsp.py:21
read_tsplib
Definition: read_tsplib.py:1