def optimizedBestSearch(fname, max_iter=100, pop_size=50, percentToSwitch=5): city_locs = tsp.load_city_locs(fname) n = len(city_locs) curr_gen = [tsp.rand_perm(n) for i in range(pop_size)] curr_gen = [(tsp.total_dist(p, city_locs), p) for p in curr_gen] curr_gen.sort() bestScore = curr_gen[0][0] bestPermuation = curr_gen[0][1] useMutateSearch = False print( f'Optimized bestEdges("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...' ) for i in range(max_iter): print("iteration: ", i) top_half = [p[1] for p in curr_gen[:int(pop_size / 2)]] next_gen = top_half[:] while len(next_gen) < pop_size: parentA = random.choice(top_half) parentB = random.choice(top_half) while parentA == parentB: parentA = random.choice(top_half) parentB = random.choice(top_half) if (useMutateSearch): first = parentA[:] second = parentB[:] else: first, second = bestEdgesSearch(parentA, parentB, city_locs) tsp.do_rand_swap(first) tsp.do_rand_swap(second) next_gen.append(first) next_gen.append(second) next_gen = next_gen[:pop_size] assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen.sort() useMutateSearch = ifSwitchToMutate(bestScore, curr_gen[0][0], percentToSwitch) if (curr_gen[0][0] < bestScore): bestScore = curr_gen[0][0] bestPermuation = curr_gen[0][1] print( f'... Optimized bestEdges("{fname}", max_iter={max_iter}, pop_size={pop_size})' ) print() print( f'After {max_iter} generations of {pop_size} permutations, the best is:' ) print(f'score = {bestScore}') print(bestPermuation) assert tsp.is_good_perm(bestPermuation)
def compareCrossovers(): cities = tsp.load_city_locs("cities1000.txt") permutationA = tsp.rand_perm(1000) permutationB = tsp.rand_perm(1000) print("Original A: ", tsp.total_dist(permutationA, cities)) print("Original B: ", tsp.total_dist(permutationB, cities)) # Order Crossover offSpringA, offSpringB = crossovers.orderCrossover(permutationA, permutationB) print("OffspringB Order: ", tsp.total_dist(offSpringA, cities)) print("OffspringB Order: ", tsp.total_dist(offSpringB, cities)) # Partially Mapped Crossover offSpringA, offSpringB = crossovers.partiallyMappedCrossover( permutationA, permutationB) print("OffspringB Partially Mapped: ", tsp.total_dist(offSpringA, cities)) print("OffspringB Partially Mapped: ", tsp.total_dist(offSpringB, cities)) # Best Edges Crossover offSpringA, offSpringB = bestEdgesSearch(permutationA, permutationB, cities) print("OffspringB Best Edges: ", tsp.total_dist(offSpringA, cities)) print("OffspringB Best Edges: ", tsp.total_dist(offSpringB, cities))
def orderCrossoverTest(fname, max_iter, pop_size): city_locs = tsp.load_city_locs(fname) n = len(city_locs) # generate permutations for a specific population size curr_gen = [tsp.rand_perm(n) for i in range(pop_size)] # per population calculate total distance curr_gen = [(tsp.total_dist(p, city_locs), p) for p in curr_gen] curr_gen.sort() assert len(curr_gen) == pop_size print( f'orderCrossover("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...' ) for i in range(max_iter): # copy the top 50% of the population to the next generation, and for the rest randomly # cross-breed pairs top_half = [p[1] for p in curr_gen[:int(pop_size / 2)]] next_gen = top_half[:] while len(next_gen) < pop_size: parentA = random.choice(top_half) parentB = random.choice(top_half) while parentA == parentB: parentA = random.choice(top_half) parentB = random.choice(top_half) first, second = orderCrossover(parentA, parentB) tsp.do_rand_swap(first) tsp.do_rand_swap(second) next_gen.append(first) next_gen.append(second) next_gen = next_gen[:pop_size] # create the next generation of (score, permutations) pairs assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen.sort() print( f'... orderCrossover("{fname}", max_iter={max_iter}, pop_size={pop_size})' ) print() print( f'After {max_iter} generations of {pop_size} permutations, the best is:' ) print(f'score = {curr_gen[0][0]}') # print(curr_gen[0][1]) assert tsp.is_good_perm(curr_gen[0][1])
def GA_top_NWOX(fname, max_iter, prev_pop): pop_size = len(prev_pop) city_locs = tsp.load_city_locs(fname) curr_gen = prev_pop scores = [] print(f'top_NWOX("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...') for i in range(max_iter): #record historic scores scores.append(curr_gen[0][0]) #select parents parents = selection_top(curr_gen) #gen childern -> next_gen next_gen = [] for pair in parents: #print(pair) first, second = crossover_NWOX(pair) next_gen.append(first) next_gen.append(second) #mutate childern next_gen = single_mutation(next_gen) #next_gen[-1] = curr_gen[0][1] #score childern assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen.sort() return curr_gen, scores
def gen_rand_pop(fname, n_pop): city_locs = tsp.load_city_locs(fname) n = len(city_locs) curr_gen = [tsp.rand_perm(n) for i in range(n_pop)] curr_gen = [(tsp.total_dist(p, city_locs), p) for p in curr_gen] curr_gen.sort() assert len(curr_gen) == n_pop return curr_gen
def GA_rw_pmx(fname, max_iter, prev_pop): pop_size = len(prev_pop) city_locs = tsp.load_city_locs(fname) curr_gen = prev_pop keep = math.floor(pop_size / 5) keep = 0 assert keep <= pop_size scores = [] print(f'rw_pmx("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...') for i in range(max_iter): #record historic scores scores.append(curr_gen[0][0]) #select parents parents = [] for i in range(0, keep, 2): parents.append((curr_gen[i][1], curr_gen[i + 1][1])) parents.extend(selection_rw(curr_gen, 1)) #gen childern -> next_gen next_gen = [] with concurrent.futures.ThreadPoolExecutor( max_workers=200) as executor: futures = { executor.submit(tsp.pmx, pair[0], pair[1]): pair for pair in parents[:pop_size] } for future in concurrent.futures.as_completed(futures): first, second = future.result() next_gen.append(first) next_gen.append(second) next_gen = next_gen[:pop_size] # next_gen = [] # for pair in parents: # #print(pair) # first, second = tsp.pmx(pair[0], pair[1]) # next_gen.append(first) # next_gen.append(second) #mutate childern next_gen = single_mutation(next_gen) #next_gen[-1] = curr_gen[0][1] #score childern assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen.sort() return curr_gen, scores
def GA_mutate_search(fname, max_iter, prev_pop): pop_size = len(prev_pop) city_locs = tsp.load_city_locs(fname) n = len(city_locs) curr_gen = prev_pop curr_gen.sort() scores = [] print( f'mutate_search("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...' ) for i in range(max_iter): # put best permutation from curr_gen into next generation unchanged scores.append(curr_gen[0][0]) best_curr_gen = curr_gen[0][1] next_gen = [best_curr_gen] # the rest of the next generation is filled with random swap-mutations # of best_curr_gen # for j in range(pop_size-1): # perm = best_curr_gen[:] # make a copy of best_curr_gen # tsp.do_rand_swap(perm) # randomly swap two cities # next_gen.append(perm) # add it to next_gen with concurrent.futures.ThreadPoolExecutor(max_workers=n) as executor: futures = { executor.submit(mutate_thread_full, best_curr_gen): j for j in range(pop_size - 1) } for future in concurrent.futures.as_completed(futures): next_gen.append(future.result()) # create the next generation of (score, permutations) pairs assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen.sort() # print(f'... mutate_search("{fname}", max_iter={max_iter}, pop_size={pop_size})') # print() # print(f'After {max_iter} generations of {pop_size} permutations, the best is:') # print(f'score = {curr_gen[0][0]}') # print(curr_gen[0][1]) assert tsp.is_good_perm(curr_gen[0][1]) return curr_gen, scores
def GA_sq_NWOX(fname, max_iter, prev_pop): pop_size = len(prev_pop) city_locs = tsp.load_city_locs(fname) curr_gen = prev_pop scores = [] print(f'sq_NWOX("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...') for i in range(max_iter): #record historic scores scores.append(curr_gen[0][0]) #select parents parents = selection_sq(curr_gen) #gen childern -> next_gen next_gen = [] with concurrent.futures.ThreadPoolExecutor( max_workers=200) as executor: futures = { executor.submit(crossover_NWOX, pair): pair for pair in parents } for future in concurrent.futures.as_completed(futures): first, second = future.result() next_gen.append(first) next_gen.append(second) # for pair in parents: # first, second = crossover_NWOX(pair) # next_gen.append(first) # next_gen.append(second) #mutate childern next_gen = single_mutation(next_gen) #next_gen[-1] = curr_gen[0][1] #score childern assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen.sort() return curr_gen, scores
def GA_crossover_search(fname, max_iter, prev_pop): pop_size = len(prev_pop) city_locs = tsp.load_city_locs(fname) n = len(city_locs) curr_gen = prev_pop scores = [] print( f'crossover_search("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...' ) for i in range(max_iter): # copy the top 50% of the population to the next generation, and for the rest randomly # cross-breed pairs scores.append(curr_gen[0][0]) top_half = [p[1] for p in curr_gen[:int(n / 2)]] next_gen = top_half[:] while len(next_gen) < pop_size: s = random.choice(top_half) t = random.choice(top_half) first, second = tsp.pmx(s, t) next_gen.append(first) next_gen.append(second) next_gen = next_gen[:pop_size] # create the next generation of (score, permutations) pairs assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen.sort() # print(f'... crossover_search("{fname}", max_iter={max_iter}, pop_size={pop_size})') # print() # print(f'After {max_iter} generations of {pop_size} permutations, the best is:') # print(f'score = {curr_gen[0][0]}') # print(curr_gen[0][1]) assert tsp.is_good_perm(curr_gen[0][1]) return curr_gen, scores
def GA_tabo(fname, max_iter, prev_pop): pop_size = len(prev_pop) city_locs = tsp.load_city_locs(fname) n = len(city_locs) curr_gen = prev_pop keep = math.floor(pop_size / 5) keep = 0 stalled = 0 assert keep <= pop_size scores = [] scores.append(curr_gen[0][0]) print(f'tabo("{fname}", max_iter={max_iter}, pop_size={pop_size}) ...') #generate tabo data print("Generating Tabo crossover data...", end='') d_map = [] dc = [] closest = [] B = 2 for i in range(0, n): d_i_to_js = [] for j in range(0, n): d_i_to_js.append(tsp.city_dist(i + 1, j + 1, city_locs)) d_map.append(d_i_to_js) for i in range(0, n): dc.append(sum(d_map[i]) / (B * (n - 1))) for i in range(0, n): d_js = d_map[i][:] order = [x + 1 for x in numpy.argsort(d_js)] closest.append(order) print("...Done") delta = 100 delta_lim = .1 for i in range(max_iter): best = curr_gen[0] #select parents parents = selection_rw(curr_gen, 2, True) #gen childern -> next_gen next_gen = [] for i in range(keep): next_gen.append(curr_gen[i][1]) with concurrent.futures.ThreadPoolExecutor( max_workers=200) as executor: futures = { executor.submit(crossover_tabo, pair, d_map, dc, closest): pair for pair in parents } for future in concurrent.futures.as_completed(futures): first = future.result() next_gen.append(first) next_gen = next_gen[:pop_size] #mutate childern next_gen = chuck_mutation(next_gen) next_gen = single_mutation(next_gen) #score childern assert len(next_gen) == pop_size curr_gen = [(tsp.total_dist(p, city_locs), p) for p in next_gen] curr_gen[-1] = best curr_gen.sort() #record historic scores scores.append(curr_gen[0][0]) if len(scores) > 2: delta = scores[-2] - scores[-1] if delta < delta_lim: stalled += 1 else: stalled = 0 if stalled > 25: print("delta limit at itteration:", i) break return curr_gen, scores