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