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 bestEdgesSearch(parentA, parentB, cities): n = len(parentA) A = parentA[:] B = parentB[:] # Retrieve best vertices from best edges bestVerticesA = getBestEdgeVertices(A, cities) bestVerticesB = getBestEdgeVertices(B, cities) # Marking vertices that aren't in best edges as -1 bestVerticesA = [-1 if x not in bestVerticesA else x for x in A] bestVerticesB = [-1 if x not in bestVerticesB else x for x in B] # Making offspring offSpringA = makePermBestEdges(bestVerticesA, B) offSpringB = makePermBestEdges(bestVerticesB, A) assert tsp.is_good_perm(offSpringA) assert tsp.is_good_perm(offSpringB) return offSpringA, offSpringB
def orderCrossover(parentA, parentB): assert tsp.is_good_perm(parentA) assert tsp.is_good_perm(parentB) assert len(parentA) == len(parentB) n = len(parentA) firstCutPoint, secondCutPoint = generateCrosspoints(n) # Split the parents up to sublists # - parent 1 leftParentA, middleParentA, rightParentA = splitParent( parentA, firstCutPoint, secondCutPoint) # - parent 2 leftParentB, middleParentB, rightParentB = splitParent( parentB, firstCutPoint, secondCutPoint) offspringA = makeOffSpringOrder(middleParentA, rightParentB + leftParentB + middleParentB, firstCutPoint) offspringB = makeOffSpringOrder(middleParentB, rightParentA + leftParentA + middleParentA, firstCutPoint) return offspringA, offspringB
def partiallyMappedCrossover(parentA, parentB): assert tsp.is_good_perm(parentA) assert tsp.is_good_perm(parentB) assert len(parentA) == len(parentB) n = len(parentA) # Generate cut points for partitoning firstCutPoint, secondCutPoint = generateCrosspoints(n) # Split the parents up to sublists # - parent 1 leftParentA, middleParentA, rightParentA = splitParent( parentA, firstCutPoint, secondCutPoint) # - parent 2 leftParentB, middleParentB, rightParentB = splitParent( parentB, firstCutPoint, secondCutPoint) # Make offspring offspringA = makeOffspringPartialMap(leftParentA, rightParentA, middleParentA, middleParentB) offspringB = makeOffspringPartialMap(leftParentB, rightParentB, middleParentB, middleParentA) return offspringA, offspringB
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_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_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