From 26599368c45a21abb84755f9235879af07613aad Mon Sep 17 00:00:00 2001 From: Johann Dreo Date: Tue, 18 Mar 2014 11:51:05 +0100 Subject: [PATCH] Use dictionaries instead of index list in ant_colony Everything use cities tuples as keys. --- ant_colony.py | 108 +++++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/ant_colony.py b/ant_colony.py index a34a52f..5a5cf12 100644 --- a/ant_colony.py +++ b/ant_colony.py @@ -4,6 +4,7 @@ import sys import math import random from collections import Counter +import path def log( *args ): @@ -23,40 +24,39 @@ def tour(lst): yield (a,b) -def euclidian_distance( ci, cj ): +def euclidian_distance( ci, cj, graph = None): return math.sqrt( float(ci[0] - cj[0])**2 + float(ci[1] - cj[1])**2 ) +def graph_distance( ci, cj, graph ): + p,c = path.astar( graph, ci, cj ) + return c + def cost( permutation, cost_func, cities ): dist = 0 - for i,j in tour(permutation): - dist += cost_func(cities[i],cities[j]) + for ci,cj in tour(permutation): + dist += cost_func( ci, cj, cities ) return dist -def random_permutation( cities ): - # like random.shuffle(cities) but on a copy - return sorted( cities, key=lambda i: random.random()) - - -def initialize_pheromone_matrix( nb_cities, init_value ): - rows = [] - for i in range(nb_cities): - cols = [] - for j in range(nb_cities): - cols.append( init_value ) - rows.append(cols) +def initialize_pheromone_matrix( cities, init_value ): + rows = {} + for i in cities: + cols = {} + for j in cities: + cols[j] = init_value + rows[i] = cols return rows -def choose( cities, last, exclude, pheromones, w_heuristic, w_history ): +def choose( cities, last, exclude, pheromones, w_heuristic, w_history, cost_func = graph_distance ): choices = [] - for i,city in enumerate(cities): - if i in exclude: + for city in cities: + if city in exclude: continue - c = {"city" : i} - c["history"] = pheromones[last][i] ** w_history - c["distance"] = euclidian_distance( cities[last], city ) + c = {"city" : city} + c["history"] = pheromones[last][city] ** w_history + c["distance"] = cost_func( last, city, cities ) c["heuristic"] = (1.0 / c["distance"]) ** w_heuristic c["proba"] = c["history"] * c["heuristic"] choices.append(c) @@ -64,7 +64,7 @@ def choose( cities, last, exclude, pheromones, w_heuristic, w_history ): def proba_select( choices ): - s = sum( c["proba"] for c in choices ) + s = float(sum( c["proba"] for c in choices )) if s == 0.0: return random.choice(choices)["city"] @@ -82,14 +82,14 @@ def greedy_select( choices ): return c["city"] -def walk( cities, pheromone, w_heuristic, c_greedy ): +def walk( cities, pheromone, w_heuristic, w_history, c_greedy, cost_func = graph_distance, ): assert( len(cities) > 0 ) # permutations are indices # randomly draw the first city index - permutation = [ random.randint(0,len(cities)-1) ] + permutation = [ random.choice( cities.keys() ) ] # then choose the next ones to build the permutation while len(permutation) < len(cities): - choices = choose( cities, permutation[-1], permutation, pheromone, w_heuristic, w_history = 1.0 ) + choices = choose( cities, permutation[-1], permutation, pheromone, w_heuristic, w_history, cost_func ) do_greedy = ( random.random() <= c_greedy ) if do_greedy: next_city = greedy_select( choices ) @@ -116,19 +116,25 @@ def update_local( pheromones, candidate, w_pheromone, init_pheromone ): pheromones[j][i] = value -def search( max_iterations, nb_ants, decay, w_heuristic, w_pheromone, c_greedy, cities): - best = { "permutation" : random_permutation(range(len(cities))) } - best["cost"] = cost( best["permutation"], euclidian_distance, cities ) +def random_permutation( cities ): + # like random.shuffle(cities) but on a copy + return sorted( cities, key=lambda i: random.random()) + + +def search( max_iterations, nb_ants, decay, w_heuristic, w_pheromone, w_history, c_greedy, cities, cost_func = graph_distance ): + best = { "permutation" : random_permutation(cities) } + best["cost"] = cost( best["permutation"], cost_func, cities ) init_pheromone = 1.0 / float(len(cities)) * best["cost"] - pheromone = initialize_pheromone_matrix( len(cities), init_pheromone ) + pheromone = initialize_pheromone_matrix( cities, init_pheromone ) + for i in range(max_iterations): log( i ) solutions = [] for j in range(nb_ants): log( "." ) candidate = {} - candidate["permutation"] = walk( cities, pheromone, w_heuristic, c_greedy ) - candidate["cost"] = cost( candidate["permutation"], euclidian_distance, cities ) + candidate["permutation"] = walk( cities, pheromone, w_heuristic, w_history, c_greedy, cost_func ) + candidate["cost"] = cost( candidate["permutation"], cost_func, cities ) if candidate["cost"] < best["cost"]: best = candidate update_local( pheromone, candidate, w_pheromone, init_pheromone ) @@ -142,21 +148,33 @@ if __name__ == "__main__": max_it = 40 num_ants = 10 decay = 0.1 - c_heur = 2.5 - c_local_phero = 0.1 + w_heur = 2.5 + w_local_phero = 0.1 c_greed = 0.9 + w_history = 1.0 - print "Berlin euclidian TSP" - berlin52 = [[565,575],[25,185],[345,750],[945,685],[845,655], - [880,660],[25,230],[525,1000],[580,1175],[650,1130],[1605,620], - [1220,580],[1465,200],[1530,5],[845,680],[725,370],[145,665], - [415,635],[510,875],[560,365],[300,465],[520,585],[480,415], - [835,625],[975,580],[1215,245],[1320,315],[1250,400],[660,180], - [410,250],[420,555],[575,665],[1150,1160],[700,580],[685,595], - [685,610],[770,610],[795,645],[720,635],[760,650],[475,960], - [95,260],[875,920],[700,500],[555,815],[830,485],[1170,65], - [830,610],[605,625],[595,360],[1340,725],[1740,245]] + print """Graph TSP: + -1 0 2 : x + 1 o o-----o + | | | + 0 o--o-----o + | | + | | + -2 o--o-----o + : + y + """ + G = { + ( 0, 0) : [(-1, 0),( 0, 1),( 2, 0),( 0,-2)], + ( 0, 1) : [( 0, 0),( 2, 1)], + ( 0,-2) : [( 0, 0),( 2,-2),(-1,-2)], + (-1, 0) : [(-1, 1),( 0, 0)], + (-1, 1) : [(-1, 0)], + (-1,-2) : [( 0,-2)], + ( 2, 0) : [( 2, 1),( 2,-2),( 0, 0)], + ( 2, 1) : [( 0, 1),( 2, 0)], + ( 2,-2) : [( 2, 0),( 0,-2)], + } - best = search( max_it, num_ants, decay, c_heur, c_local_phero, c_greed, berlin52 ) + best = search( max_it, num_ants, decay, w_heur, w_local_phero, w_history, c_greed, G, cost_func = graph_distance ) print best["cost"], best["permutation"] -