def scramble_mutation(offspring: list) -> list: # aka IVM mutated_offspring = [] for o in offspring: route_len = len(o.route_stops) cutoff_1 = random.randrange(route_len + 1) cutoff_2 = random.randrange(route_len + 1) cut_start = min(cutoff_1, cutoff_2) cut_end = max(cutoff_1, cutoff_2) cut_piece = o.route_stops[cut_start:cut_end] random.shuffle(cut_piece) mutated_o = Route(RouteManager.INSTANCE) for i in range(cut_start): mutated_o.route_stops.append(o.route_stops[i]) for s in cut_piece: mutated_o.route_stops.append(s) for i in range(cut_end, route_len): mutated_o.route_stops.append(o.route_stops[i]) mutated_o.build_spf() mutated_offspring.append(mutated_o) return mutated_offspring
def simple_inversion_mutation(offspring: list) -> list: # aka SIM mutated_offspring = [] for o in offspring: route_len = len(o.route_stops) cutoff_1 = random.randrange(route_len + 1) cutoff_2 = random.randrange(route_len + 1) cut_start = min(cutoff_1, cutoff_2) cut_end = max(cutoff_1, cutoff_2) mutated_o = Route(RouteManager.INSTANCE) for i in range(cut_start): mutated_o.route_stops.append(o.route_stops[i]) for i in range(cut_end - cut_start): mutated_o.route_stops.append(o.route_stops[cut_end - i - 1]) for i in range(cut_end, route_len): mutated_o.route_stops.append(o.route_stops[i]) mutated_o.build_spf() mutated_offspring.append(mutated_o) return mutated_offspring
def inversion_mutation(offspring: list) -> list: # aka IVM mutated_offspring = [] for o in offspring: route_len = len(o.route_stops) cutoff_1 = random.randrange(route_len + 1) cutoff_2 = random.randrange(route_len + 1) cut_start = min(cutoff_1, cutoff_2) cut_end = max(cutoff_1, cutoff_2) cut_route = list(reversed(o.route_stops[cut_start:cut_end])) leftovers = o.route_stops[:cut_start] + o.route_stops[cut_end:] try: insert_at = random.randrange(len(leftovers)) except: insert_at = 0 mutated_o = Route(RouteManager.INSTANCE) mutated_o.route_stops = leftovers[:insert_at] + cut_route + leftovers[insert_at:] mutated_o.build_spf() mutated_offspring.append(mutated_o) return mutated_offspring
def get_variable_length_route(self) -> Route: # Generates a route between random stations, but keeps track of sations inbetween, so that we attempt # to avoid duplicated stations. On avg gives wtt=1000, but the length of the route varies - no idea # how to work with that r = Route(self) unused_stations = set(list(range(1, len(self.stations) + 1))) def _take_one_from_unused(remove=True) -> int: elem = random.choice(tuple(unused_stations)) if remove: unused_stations.remove(elem) return elem stops = [self.stations[_take_one_from_unused() - 1]] while len(unused_stations) != 0: st_from = stops[-1] st_to = self.stations[_take_one_from_unused(False) - 1] info = get_path_info(self.graph, self.stations, st_from, st_to) for s in info["stations"]: unused_stations.discard(s.id) stops.append(s) r.route_stops = stops r.build_spf() return r
def get_fixed_length_route(self) -> Route: # Always gets a route of fixed length of #total stations, but definitely has a lot of duplicate # stations en-route. On avg gives wtt=3000, but it is the best option for crossover methods r = Route(self) mixed_stops = list(range(1, len(self.stations) + 1)) random.shuffle(mixed_stops) r.route_stops = [self.stations[x - 1] for x in mixed_stops] r.build_spf() return r
stations = load_stations_from_file() rm = RouteManager(stations) # The best route with wtt=522, tournament selection, ordered crossover, simple_inversion mutation # ADJUSTED NOTES: put 10 right after 14, to have less transfers and walking around best_route = Route(rm) best_route.route_stops = [ stations[id - 1] for id in [ 20, 21, 22, 23, 24, 25, 26, 27, 29, 60, 59, 57, 58, 61, 62, 63, 49, 28, 41, 38, 39, 40, 42, 47, 48, 46, 45, 44, 43, 52, 55, 56, 54, 53, 51, 50, 11, 12, 70, 71, 69, 68, 67, 66, 65, 64, 13, 31, 33, 34, 37, 36, 35, 32, 30, 16, 19, 18, 17, 15, 14, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ] ] best_route.build_spf() print( f"Route's wtt={best_route.get_wtt()}, fitness={best_route.get_fitness()}" ) time_offset = 420 # We want to start the route at 7:00am <=> 420 minutes into the day t = 0 for s in range(len(best_route.route_stops)): st_from = best_route.route_stops[s] print( f"{format_minutes(time_offset + int(t))}, {st_from.line}, {st_from.name}" )
def cycle_crossover(mating_pool : list, offspring_len=1000) -> list: # aka (CX) offspring = [] for i in range(0, offspring_len, 2): parent_1 = random.choice(mating_pool) parent_2 = random.choice(mating_pool) #print("\nParents:") #print([s.id for s in parent_1.route_stops]) #print([s.id for s in parent_2.route_stops]) offspring_1 = Route(RouteManager.INSTANCE) offspring_2 = Route(RouteManager.INSTANCE) offspring_1.route_stops = [ None for s in parent_1.route_stops ] offspring_2.route_stops = [ None for s in parent_1.route_stops ] i_1 = 0 while True: offspring_1.route_stops[i_1] = parent_1.route_stops[i_1] lookup = parent_2.route_stops[i_1] for i in range(len(parent_1.route_stops)): if parent_1.route_stops[i].id == lookup.id: i_1 = i break if i_1 == 0: break i_2 = 0 while True: offspring_2.route_stops[i_2] = parent_2.route_stops[i_2] lookup = parent_1.route_stops[i_2] for i in range(len(parent_2.route_stops)): if parent_2.route_stops[i].id == lookup.id: i_2 = i break if i_2 == 0: break for i in range(len(parent_1.route_stops)): if offspring_1.route_stops[i] == None: offspring_1.route_stops[i] = parent_2.route_stops[i] if offspring_2.route_stops[i] == None: offspring_2.route_stops[i] = parent_1.route_stops[i] offspring_1.build_spf() offspring_2.build_spf() #print("Offspring:") #print([s.id if s != None else None for s in offspring_1.route_stops]) #print([s.id if s != None else None for s in offspring_2.route_stops]) offspring.append(offspring_1) offspring.append(offspring_2) return offspring
def ordered_crossover(mating_pool : list, offspring_len=1000) -> list: # aka (OX) offspring = [] for i in range(0, offspring_len, 2): parent_1 = random.choice(mating_pool) parent_2 = random.choice(mating_pool) #print("\nParents:") #print([s.id for s in parent_1.route_stops]) #print([s.id for s in parent_2.route_stops]) route_len = len(parent_1.route_stops) offspring_1 = Route(RouteManager.INSTANCE) offspring_2 = Route(RouteManager.INSTANCE) offspring_1.route_stops = [ None for s in parent_1.route_stops ] offspring_2.route_stops = [ None for s in parent_1.route_stops ] cutoff_1 = random.randrange(route_len + 1) cutoff_2 = random.randrange(route_len + 1) cut_start = min(cutoff_1, cutoff_2) cut_end = max(cutoff_1, cutoff_2) #print("Cuts:") #print(cut_start, cut_end) # Exchange the cutodd point for i in range(cut_start, cut_end): offspring_1.route_stops[i] = parent_1.route_stops[i] offspring_2.route_stops[i] = parent_2.route_stops[i] j_1 = cut_end % route_len j_2 = cut_end % route_len for i in range(route_len): i_conv = (cut_end + i) % route_len route_stop_1 = parent_1.route_stops[i_conv] route_stop_2 = parent_2.route_stops[i_conv] if not offspring_2.has_station(route_stop_1): offspring_2.route_stops[j_2] = route_stop_1 j_2 = (j_2 + 1) % route_len if not offspring_1.has_station(route_stop_2): offspring_1.route_stops[j_1] = route_stop_2 j_1 = (j_1 + 1) % route_len offspring_1.build_spf() offspring_2.build_spf() #print("Offspring:") #print([s.id for s in offspring_1.route_stops]) #print([s.id for s in offspring_2.route_stops]) offspring.append(offspring_1) offspring.append(offspring_2) return offspring