def sa_optimize_step(nodes, solution, number_of_nodes, t): global nn # Pick X and Y at random. ci = random.randint(0, number_of_nodes - 1) yi = (ci + 1) % number_of_nodes xi = random.randint(0, number_of_nodes - 1) zi = (xi + 1) % number_of_nodes if xi != ci and xi != yi: c = solution[ci] y = solution[yi] x = solution[xi] z = solution[zi] cy = length(c, y) xz = length(x, z) cx = length(c, x) yz = length(y, z) gain = (cy + xz) - (cx + yz) if gain < 0: # We only accept a negative gain conditionally # The probability is based on the magnitude of the gain # and the temperature. u = math.exp(gain / t) elif gain > 0.05: u = 1 # always except a good gain. else: u = 0 # No idea why I did this.... # random chance, picks a number in [0,1) if (random.random() < u): nn = nn + 1 #print " ", gain # Make a new solution with both edges swapped. new_solution = range(0, number_of_nodes) new_solution[0] = solution[ci] n = 1 while xi != yi: new_solution[n] = solution[xi] n = n + 1 xi = (xi - 1) % number_of_nodes new_solution[n] = solution[yi] n = n + 1 while zi != ci: new_solution[n] = solution[zi] n = n + 1 zi = (zi + 1) % number_of_nodes # Create an animation frame for this step if anim: frame(nodes, new_solution, number_of_nodes, t, c, y, x, z, gain) return new_solution else: return solution else: return solution
def area_triangle(n1, n2, n3): # Area of triangle via Heron's Formula # <https://en.wikipedia.org/wiki/Heron%27s_formula> a = length(n1, n2) b = length(n2, n3) c = length(n3, n1) p = (a + b + c)/2.0 area = math.sqrt(p*(p-a)*(p-b)*(p-c)) return area
def sa_optimize_step(nodes, solution, number_of_nodes, t): global nn # Pick X and Y at random. ci = random.randint(0, number_of_nodes-1) yi = (ci + 1) % number_of_nodes xi = random.randint(0, number_of_nodes-1) zi = (xi + 1) % number_of_nodes if xi != ci and xi != yi: c = solution[ci] y = solution[yi] x = solution[xi] z = solution[zi] cy = length(c, y) xz = length(x, z) cx = length(c, x) yz = length(y, z) gain = (cy + xz) - (cx + yz) if gain < 0: # We only accept a negative gain conditionally # The probability is based on the magnitude of the gain # and the temperature. u = math.exp( gain / t ) elif gain > 0.05: u = 1 # always except a good gain. else: u = 0 # No idea why I did this.... # random chance, picks a number in [0,1) if (random.random() < u): nn = nn + 1 #print " ", gain # Make a new solution with both edges swapped. new_solution = range(0,number_of_nodes) new_solution[0] = solution[ci] n = 1 while xi != yi: new_solution[n] = solution[xi] n = n + 1 xi = (xi-1)%number_of_nodes new_solution[n] = solution[yi] n = n + 1 while zi != ci: new_solution[n] = solution[zi] n = n + 1 zi = (zi+1)%number_of_nodes # Create an animation frame for this step frame(nodes, new_solution, number_of_nodes, t, c, y, x, z, gain) return new_solution else: return solution else: return solution
def optimize(nodes, solution, sn, t): global nn # Pick X and Y at random. ci = random.randint(0, sn - 1) yi = (ci + 1) % sn xi = random.randint(0, sn - 1) zi = (xi + 1) % sn if xi != ci and xi != yi: c = solution[ci] y = solution[yi] x = solution[xi] z = solution[zi] cy = length(c, y) xz = length(x, z) cx = length(c, x) yz = length(y, z) gain = (cy + xz) - (cx + yz) if gain < 0: # For a negative gain we only except # it depending on the magnitude in combination # with the temperature. u = math.exp(gain / t) elif gain > 0.05: u = 1 # always except a good gain. else: u = 0 # No idea why I did this.... # random chance, picks a number in [0,1) if (random.random() < u): nn = nn + 1 #print " ", gain # Make a new solution with both edges swapped. new_solution = range(0, sn) new_solution[0] = solution[ci] n = 1 while xi != yi: new_solution[n] = solution[xi] n = n + 1 xi = (xi - 1) % sn new_solution[n] = solution[yi] n = n + 1 while zi != ci: new_solution[n] = solution[zi] n = n + 1 zi = (zi + 1) % sn frame(nodes, new_solution, sn, t, c, y, x, z, gain) return new_solution else: return solution else: return solution
def optimize( nodes, solution, sn, t ): global nn ci = random.randint(0, sn-1) yi = (ci + 1) % sn xi = random.randint(0, sn-1) zi = (xi + 1) % sn if xi != ci and xi != yi: c = solution[ ci ] y = solution[ yi ] x = solution[ xi ] z = solution[ zi ] cy = length( c, y ) xz = length( x, z ) cx = length( c, x ) yz = length( y, z ) gain = (cy + xz) - (cx + yz) if gain < 0: u = math.exp( gain / t ) elif gain > 0.05: u = 1 else: u = 0 if (random.random() < u): nn = nn + 1 #print " ", gain new_solution = range(0,sn) new_solution[0] = solution[ci] n = 1 while xi != yi: new_solution[n] = solution[xi] n = n + 1 xi = (xi-1)%sn new_solution[n] = solution[yi] n = n + 1 while zi != ci: new_solution[n] = solution[zi] n = n + 1 zi = (zi+1)%sn frame( nodes, new_solution, sn, t, c,y,x,z, gain ) return new_solution else: return solution else: return solution
def optimize2opt( nodes, solution, sn, t ): best = 0 best_move = None for ci in range(0, sn): for xi in range(0, sn): yi = (ci + 1) % sn zi = (xi + 1) % sn c = solution[ ci ] y = solution[ yi ] x = solution[ xi ] z = solution[ zi ] cy = length( c, y ) xz = length( x, z ) cx = length( c, x ) yz = length( y, z ) if xi != ci and xi != yi: gain = (cy + xz) - (cx + yz) if gain > best: best_move = (ci,yi,xi,zi) best = gain print best_move, best if best_move is not None: (ci,yi,xi,zi) = best_move c = solution[ ci ] y = solution[ yi ] x = solution[ xi ] z = solution[ zi ] new_solution = range(0,sn) new_solution[0] = solution[ci] n = 1 while xi != yi: new_solution[n] = solution[xi] n = n + 1 xi = (xi-1)%sn new_solution[n] = solution[yi] n = n + 1 while zi != ci: new_solution[n] = solution[zi] n = n + 1 zi = (zi+1)%sn frame4( nodes, new_solution, sn, t, c,y,x,z, gain ) return (True,new_solution) else: return (False,solution)
def greedy_algorithm(nodes): # Greedy Algorithm print('Computing greedy path') free_nodes = nodes[:] solution = [] n = free_nodes[0] free_nodes.remove(n) solution.append( n ) while len(free_nodes) > 0: print(len(free_nodes)) min_l = None min_n = None for c in free_nodes: l = length( c, n ) if min_l is None: min_l = l min_n = c elif l < min_l: min_l = l min_n = c solution.append(min_n) free_nodes.remove(min_n) n = min_n return solution
def greedy_algorithm(nodes): # Greedy Algorithm print 'Computing greedy path' free_nodes = nodes[:] solution = [] n = free_nodes[0] free_nodes.remove(n) solution.append( n ) while len(free_nodes) > 0: print(len(free_nodes)) min_l = None min_n = None for c in free_nodes: l = length( c, n ) if min_l is None: min_l = l min_n = c elif l < min_l: min_l = l min_n = c solution.append(min_n) free_nodes.remove(min_n) n = min_n return solution
def miss_perry_s_compass(nodes, number_of_nodes): # Compute Center of all nodes sum_x = 0 sum_y = 0 for n in nodes: sum_x += n.x sum_y += n.y c_x = sum_x / number_of_nodes c_y = sum_y / number_of_nodes # Make a node for this center. center_node = Node(-1, c_x, c_y) sorted_nodes = [] done = [False] * number_of_nodes # Sort the nodes based on the distance from the center node. for i in range(number_of_nodes): max_l = -1 furthest = None for j in range(number_of_nodes): if done[j]: pass else: l = length(center_node, nodes[j]) if l > max_l: furthest = j max_l = l sorted_nodes.append(nodes[furthest]) done[furthest] = True # Create initial polygon solution = [sorted_nodes[0], sorted_nodes[1], sorted_nodes[2]] for i in range(3, number_of_nodes): new_node = sorted_nodes[i] closest = sorted_nodes[0] min_l = length(closest, new_node) index_in_list = 0 for j in range(1, i): l = length(sorted_nodes[j], new_node) if l < min_l: index_in_list = j closest = sorted_nodes[j] min_l = l # Is the node inside or outside the polygon? if point_in_poly(new_node.x, new_node.y, solution): idx_before = (index_in_list - 1) % i idx_after = (index_in_list + 1) % i # it is Inside area1 = area_triangle(new_node, closest, solution[idx_before]) area2 = area_triangle(new_node, closest, solution[idx_after]) if area1 < area2: # Insert new node between closest and next pass else: # Insert pass pass else: # it is outside pass return sorted_nodes
def optimize2opt(nodes, solution, number_of_nodes): best = 0 best_move = None # For all combinations of the nodes for ci in range(0, number_of_nodes): for xi in range(0, number_of_nodes): yi = (ci + 1) % number_of_nodes # C is the node before Y zi = (xi + 1) % number_of_nodes # Z is the node after X c = solution[ ci ] y = solution[ yi ] x = solution[ xi ] z = solution[ zi ] # Compute the lengths of the four edges. cy = length( c, y ) xz = length( x, z ) cx = length( c, x ) yz = length( y, z ) # Only makes sense if all nodes are distinct if xi != ci and xi != yi: # What will be the reduction in length. gain = (cy + xz) - (cx + yz) # Is is any better then best one sofar? if gain > best: # Yup, remember the nodes involved best_move = (ci,yi,xi,zi) best = gain print(best_move, best) if best_move is not None: (ci,yi,xi,zi) = best_move # This four are needed for the animation later on. c = solution[ ci ] y = solution[ yi ] x = solution[ xi ] z = solution[ zi ] # Create an empty solution new_solution = list(range(0,number_of_nodes)) # In the new solution C is the first node. # This we we only need two copy loops instead of three. new_solution[0] = solution[ci] n = 1 # Copy all nodes between X and Y including X and Y # in reverse direction to the new solution while xi != yi: new_solution[n] = solution[xi] n = n + 1 xi = (xi-1)%number_of_nodes new_solution[n] = solution[yi] n = n + 1 # Copy all the nodes between Z and C in normal direction. while zi != ci: new_solution[n] = solution[zi] n = n + 1 zi = (zi+1)%number_of_nodes # Create a new animation frame frame4(nodes, new_solution, number_of_nodes, c, y, x, z, gain) return (True,new_solution) else: return (False,solution)
def create_animation( nodes ): global nn global l_min sn = len( nodes ) print 'Size {}'.format( sn ) if True: # Greedy Algorithm print 'Computing greedy path' free_nodes = nodes[:] solution = [] n = free_nodes[0] free_nodes.remove(n) solution.append( n ) while len( free_nodes ) > 0: print len( free_nodes ), min_l = None min_n = None for c in free_nodes: l = length( c, n ) if min_l is None: min_l = l min_n = c elif l < min_l: min_l = l min_n = c solution.append(min_n) free_nodes.remove(min_n) n = min_n else: solution = [ n for n in nodes ] if True: # Only cities solution0 = [ n for n in nodes ] for i in range(2,sn): s = solution0[0:i] framec(s,sn) for i in range(20): framec(s,sn) # Random Search for i in range(2,sn): s = solution0[0:i] frame0(s,solution0, total_length(nodes,s), "(1) Random Path") s = solution0 for i in range(60): frame0(s,solution, total_length(nodes,s), "(1) Random Path") # Greedy for i in range(2,sn): s = solution[0:i] frame0(s,solution, total_length(nodes,s), "(2) Greedy Search") s = solution for i in range(60): frame0(s,solution, total_length(nodes,s), "(2) Greedy Search") print "2-Opt" solution = [ n for n in nodes ] t = 100 go = True while go: (go,solution) = optimize2opt( nodes, solution, sn, t ) s = solution for i in range(60): frame0(s,solution, total_length(nodes,s), "(3) 2-Opt") print "SA" solution = [ n for n in nodes ] t = 100 l_min = total_length( nodes, solution ) best_solution = [] i = 0 while True: i = i + 1 solution = optimize( nodes, solution, sn, t ) if i >= 200: i = 0 l = total_length( nodes, solution ) print " ", l, t, nn t = t*0.9995 if l_min is None: l_min = l elif l < l_min: l_min = l print "++", l, t best_solution = solution[:] else: pass if t < 0.1: break s = best_solution for i in range(60): frame0(s, solution, total_length(nodes,s), "(4) SA") return best_solution
def optimize2opt(nodes, solution, number_of_nodes): best = 0 best_move = None # For all combinations of the nodes for ci in range(0, number_of_nodes): for xi in range(0, number_of_nodes): yi = (ci + 1) % number_of_nodes # C is the node before Y zi = (xi + 1) % number_of_nodes # Z is the node after X c = solution[ ci ] y = solution[ yi ] x = solution[ xi ] z = solution[ zi ] # Compute the lengths of the four edges. cy = length( c, y ) xz = length( x, z ) cx = length( c, x ) yz = length( y, z ) # Only makes sense if all nodes are distinct if xi != ci and xi != yi: # What will be the reduction in length. gain = (cy + xz) - (cx + yz) # Is is any better then best one sofar? if gain > best: # Yup, remember the nodes involved best_move = (ci,yi,xi,zi) best = gain print best_move, best if best_move is not None: (ci,yi,xi,zi) = best_move # This four are needed for the animation later on. c = solution[ ci ] y = solution[ yi ] x = solution[ xi ] z = solution[ zi ] # Create an empty solution new_solution = range(0,number_of_nodes) # In the new solution C is the first node. # This we we only need two copy loops instead of three. new_solution[0] = solution[ci] n = 1 # Copy all nodes between X and Y including X and Y # in reverse direction to the new solution while xi != yi: new_solution[n] = solution[xi] n = n + 1 xi = (xi-1)%number_of_nodes new_solution[n] = solution[yi] n = n + 1 # Copy all the nodes between Z and C in normal direction. while zi != ci: new_solution[n] = solution[zi] n = n + 1 zi = (zi+1)%number_of_nodes # Create a new animation frame frame4(nodes, new_solution, number_of_nodes, c, y, x, z, gain) return (True,new_solution) else: return (False,solution)
def create_animation(nodes): global nn global l_min sn = len(nodes) print 'Size {}'.format(sn) if True: # Greedy Algorithm print 'Computing greedy path' free_nodes = nodes[:] solution = [] n = free_nodes[0] free_nodes.remove(n) solution.append(n) while len(free_nodes) > 0: print len(free_nodes), min_l = None min_n = None for c in free_nodes: l = length(c, n) if min_l is None: min_l = l min_n = c elif l < min_l: min_l = l min_n = c solution.append(min_n) free_nodes.remove(min_n) n = min_n else: solution = [n for n in nodes] if True: # Only cities solution0 = [n for n in nodes] for i in range(2, sn): s = solution0[0:i] framec(s, sn) # Show all cities for an additional 20 frames. for i in range(20): framec(s, sn) # Random Search for i in range(2, sn): s = solution0[0:i] frame0(s, solution0, total_length(nodes, s), "(1) Random Path") s = solution0 for i in range(60): frame0(s, solution, total_length(nodes, s), "(1) Random Path") # Greedy for i in range(2, sn): s = solution[0:i] frame0(s, solution, total_length(nodes, s), "(2) Greedy Search") s = solution for i in range(60): frame0(s, solution, total_length(nodes, s), "(2) Greedy Search") print "2-Opt" # Create an initial solution solution = [n for n in nodes] t = 100 go = True # Try to optimize the solution with 2opt until # no further optimization is possible. while go: (go, solution) = optimize2opt(nodes, solution, sn, t) s = solution for i in range(60): frame0(s, solution, total_length(nodes, s), "(3) 2-Opt") #=== Simulated Annealing print "SA" # Create an initial solution that we can improve upon. solution = [n for n in nodes] # The temperature t. This is the most important parameter # of the SA algorithm. It starts at a high temperature and # is then slowly decreased. Both rate of decrease and # initial values are parameters that need to be tuned to # get a good solution. # The initial temperature. # This should be high enough to allow the algorithm to # explore many sections of the search space. # Set too high it will waste a lot of computation time randomly # bouncing around the search space. t = 100 # Length of the best solution so far. l_min = total_length(nodes, solution) best_solution = [] i = 0 while True: i = i + 1 solution = optimize(nodes, solution, sn, t) # every ~200 steps if i >= 200: i = 0 # Compute the length of the solution l = total_length(nodes, solution) print " ", l, t, nn # Lower the temperature. # The slower we do this, the better then final solution # but also the more times it takes. t = t * 0.9995 # See if current solution is a better solution then the previous # best one. if l_min is None: # TODO: This can be removed, as l_min is set above. l_min = l elif l < l_min: # Yup it is, remember it. l_min = l print "++", l, t best_solution = solution[:] else: pass if t < 0.1: # TODO: This should be part of the while condition. break # Show the best solution for an additional 60 frames. s = best_solution for i in range(60): frame0(s, solution, total_length(nodes, s), "(4) SA") return best_solution