diff --git a/README b/README deleted file mode 100644 index 17c7ffd..0000000 --- a/README +++ /dev/null @@ -1,22 +0,0 @@ -Python Ant Colony TSP Solver ------------------------------ - -Uses Ant Colony Optimization to solve the TSP. See http://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms - -anttsp.py is the file to run. It reads from citiesAndDistances.pickled, which is a pickled 2D array with this format: -CityName1 CityName2 ... CitNameN -0 23 34 -10 0 22 -. -. -. - -It is not necessary for the matrix to be symmetric i.e. the distance traveling from A to B need not be the distance from B to A (if you have ever been to Italy and dealt with the mess of one-way streets you will understand how this applies). - -Run without additional arguments, it solves the 10-city TSP - -You can also try this: -python anttsp.py 14 - -Other values <= 14 tested as well - diff --git a/README.md b/README.md new file mode 100644 index 0000000..961ed4d --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# Python Ant Colony TSP Solver + +Uses Ant Colony Optimization to solve the TSP. +See http://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms + +**anttsp.py** is the file to run. It reads from citiesAndDistances.pickled, which is a pickled 2D array with this format: + +| CityName1 | CityName2 | ... | CitNameN | +|-----------|-----------|-----|----------| +| 0 | 23 | ... | 34 | +| 10 | 0 | ... | 22 | +| . | . | . | . | +| . | . | . | . | + +It is not necessary for the matrix to be symmetric i.e. the distance traveling from A to B need not be the distance from B to A (if you have ever been to Italy and dealt with the mess of one-way streets you will understand how this applies). + +Run without additional arguments, it solves the 10-city TSP + +You can also try this: +``` +$ python anttsp.py 14 +``` + +Other values <= 14 tested as well + diff --git a/ant.py b/ant.py index d34f12d..15ddb06 100644 --- a/ant.py +++ b/ant.py @@ -4,11 +4,12 @@ from threading import * class Ant(Thread): - def __init__(self, ID, start_node, colony): + def __init__(self, ID, start_node, colony, logs=True): Thread.__init__(self) self.ID = ID self.start_node = start_node self.colony = colony + self.logs = logs self.curr_node = self.start_node self.graph = self.colony.graph @@ -47,7 +48,10 @@ def run(self): self.path_vec.append(new_node) self.path_mat[self.curr_node][new_node] = 1 #adjacency matrix representing path - print "Ant %s : %s, %s" % (self.ID, self.path_vec, self.path_cost,) + if self.logs: + print ("Ant %s : %s, %s" % (self.ID, self.path_vec, self.path_cost)) + else: + print("") # this is necessary self.local_updating_rule(self.curr_node, new_node) graph.lock.release() @@ -59,7 +63,9 @@ def run(self): # send our results to the colony self.colony.update(self) - print "Ant thread %s terminating." % (self.ID,) + + if self.logs: + print ("Ant thread %s terminating." % (self.ID,)) # allows thread to be restarted (calls Thread.__init__) self.__init__(self.ID, self.start_node, self.colony) @@ -74,7 +80,8 @@ def state_transition_rule(self, curr_node): max_node = -1 if q < self.Q0: - print "Exploitation" + if self.logs: + print ("Exploitation") max_val = -1 val = None @@ -87,7 +94,8 @@ def state_transition_rule(self, curr_node): max_val = val max_node = node else: - print "Exploration" + if self.logs: + print ("Exploration") sum = 0 node = -1 @@ -100,12 +108,14 @@ def state_transition_rule(self, curr_node): avg = sum / len(self.nodes_to_visit) - print "avg = %s" % (avg,) + if self.logs: + print ("avg = %s" % (avg,)) for node in self.nodes_to_visit.values(): p = graph.tau(curr_node, node) * math.pow(graph.etha(curr_node, node), self.Beta) if p > avg: - print "p = %s" % (p,) + if self.logs: + print ("p = %s" % (p,)) max_node = node if max_node == -1: @@ -124,3 +134,5 @@ def local_updating_rule(self, curr_node, next_node): val = (1 - self.Rho) * graph.tau(curr_node, next_node) + (self.Rho * graph.tau0) graph.update_tau(curr_node, next_node, val) + def set_logs(self, logs): + self.logs = logs diff --git a/antcolony.py b/antcolony.py index 54e83e7..a64b8ce 100644 --- a/antcolony.py +++ b/antcolony.py @@ -5,7 +5,8 @@ import sys class AntColony: - def __init__(self, graph, num_ants, num_iterations): + def __init__(self, graph, num_ants, num_iterations, logs=True): + self.logs = logs self.graph = graph self.num_ants = num_ants self.num_iterations = num_iterations @@ -17,7 +18,7 @@ def __init__(self, graph, num_ants, num_iterations): self.reset() def reset(self): - self.best_path_cost = sys.maxint + self.best_path_cost = sys.maxsize self.best_path_vec = None self.best_path_mat = None self.last_best_path_iteration = 0 @@ -45,9 +46,15 @@ def iteration(self): self.avg_path_cost = 0 self.ant_counter = 0 self.iter_counter += 1 - print "iter_counter = %s" % (self.iter_counter,) + + if self.logs: + print ("iter_counter = %s" % (self.iter_counter,)) + for ant in self.ants: - print "starting ant = %s" % (ant.ID) + if self.logs: + print ("starting ant = %s" % (ant.ID)) + + ant.set_logs(self.logs) ant.start() def num_ants(self): @@ -66,7 +73,9 @@ def update(self, ant): #outfile = open("results.dat", "a") - print "Update called by %s" % (ant.ID,) + if self.logs: + print ("Update called by asd" % (ant.ID)) + self.ant_counter += 1 self.avg_path_cost += ant.path_cost @@ -80,7 +89,8 @@ def update(self, ant): if self.ant_counter == len(self.ants): self.avg_path_cost /= len(self.ants) - print "Best: %s, %s, %s, %s" % (self.best_path_vec, self.best_path_cost, self.iter_counter, self.avg_path_cost,) + if self.logs: + print ("Best: %s, %s, %s, %s" % (self.best_path_vec, self.best_path_cost, self.iter_counter, self.avg_path_cost,)) #outfile.write("\n%s\t%s\t%s" % (self.iter_counter, self.avg_path_cost, self.best_path_cost,)) self.cv.acquire() self.cv.notify() @@ -96,7 +106,8 @@ def create_ants(self): self.reset() ants = [] for i in range(0, self.num_ants): - ant = Ant(i, random.randint(0, self.graph.num_nodes - 1), self) + ant = Ant(i, random.randint(0, self.graph.num_nodes - 1), self, logs=self.logs) + ant.set_logs(self.logs) ants.append(ant) return ants diff --git a/antgraph.py b/antgraph.py index 472440c..e14de36 100644 --- a/antgraph.py +++ b/antgraph.py @@ -1,8 +1,12 @@ from threading import Lock class AntGraph: - def __init__(self, num_nodes, delta_mat, tau_mat=None): - print len(delta_mat) + def __init__(self, num_nodes, delta_mat, tau_mat=None, logs=True): + self.logs = logs + + if self.logs: + print (len(delta_mat)) + if len(delta_mat) != num_nodes: raise Exception("len(delta) != num_nodes") @@ -41,8 +45,9 @@ def reset_tau(self): # initial tau self.tau0 = 1.0 / (self.num_nodes * 0.5 * avg) - print "Average = %s" % (avg,) - print "Tau0 = %s" % (self.tau0) + if self.logs: + print ("Average = %s" % (avg,)) + print ("Tau0 = %s" % (self.tau0)) for r in range(0, self.num_nodes): for s in range(0, self.num_nodes): diff --git a/anttsp.py b/anttsp.py index 2118a63..3161716 100644 --- a/anttsp.py +++ b/anttsp.py @@ -21,7 +21,12 @@ num_iterations = 20 num_repetitions = 1 - stuff = pickle.load(open("citiesAndDistances.pickled", "r")) + f = open("citiesAndDistances.pickled", "rb") + u = pickle._Unpickler(f) + u.encoding = 'latin1' + stuff = u.load() + f.close() + cities = stuff[0] cost_mat = stuff[1] @@ -30,12 +35,12 @@ for i in range(0, num_nodes): cost_mat[i] = cost_mat[i][0:num_nodes] - print cost_mat + print (cost_mat) try: graph = AntGraph(num_nodes, cost_mat) best_path_vec = None - best_path_cost = sys.maxint + best_path_cost = sys.maxsize for i in range(0, num_repetitions): graph.reset_tau() ant_colony = AntColony(graph, num_ants, num_iterations) @@ -44,14 +49,14 @@ best_path_vec = ant_colony.best_path_vec best_path_cost = ant_colony.best_path_cost - print "\n------------------------------------------------------------" - print " Results " - print "------------------------------------------------------------" - print "\nBest path = %s" % (best_path_vec,) + print ("\n------------------------------------------------------------") + print (" Results ") + print ("------------------------------------------------------------") + print ("\nBest path = %s" % (best_path_vec,)) for node in best_path_vec: - print cities[node] + " ", - print "\nBest path cost = %s\n" % (best_path_cost,) + print (cities[node] + " ",) + print ("\nBest path cost = %s\n" % (best_path_cost,)) - except Exception, e: - print "exception: " + str(e) + except Exception as e: + print ("exception: " + str(e)) traceback.print_exc()