def fitness(p, x_train, y_train, x_test, y_test): # Init fitness fitness_indi = 0 N = Individual() p = N.individual_decode(p) N = N.individual_model(p, num_class=2, x_train=x_train, y_train=y_train, x_test=x_test, y_test=y_test) fitness_indi = N.evaluate(x=x_test, y=y_test, verbose=0)[1] return fitness_indi
def crossover(self, parent_1: Individual, parent_2: Individual) -> Individual: """Crossover two parents using the Periodic crossover with Intersections (PIX) algorithm, as defined in Vidal et al. (2011).""" # logger.debug("Beginning crossover") # logger.debug(f"Par 1 chrom: {parent_1.giant_tour_chromosome}") # logger.debug(f"Par 2 chrom: {parent_2.giant_tour_chromosome}") child_vehicle_type_chromosome: Union[None, Dict[int, List[int]]] = {} child_giant_tour_chromosome: Dict[int, List[Location]] = {} for vehicle_type in self.possible_vehicle_types: child_giant_tour_chromosome[vehicle_type.data_index] = [] num_vehicle_types = len(self.possible_vehicle_types) # Step 0: Inheritance Rule # Figure out which tours are inherited from P1, which from P2 and which others are mixed # In Vidal's paper, the tours are per-period and per-depot, so each pairing needs to be accounted for. # In my implementation, there are only the vehicle_index types to account for. if num_vehicle_types > 1: cuts = sample(range(num_vehicle_types), 2) if cuts[0] < cuts[1]: n_1 = cuts[0] n_2 = cuts[1] else: n_1 = cuts[1] n_2 = cuts[0] # Put the vehicle_index types into a randomly ordered list vehicle_type_list = list(self.possible_vehicle_types) shuffle(vehicle_type_list) # Divide up the vehicle_index types into the sets to be inherited set_1 = vehicle_type_list[0:n_1] set_2 = vehicle_type_list[n_1:n_2] set_mix = vehicle_type_list[n_2:num_vehicle_types] else: # If there is only one vehicle type, it goes into the mixed set set_1 = [] set_2 = [] set_mix = list(self.possible_vehicle_types) # logger.debug(f"Crossover sets: {set_1},\t{set_2},\t{set_mix}") # Step 1: Inherit data from P1 # Set 1 inherits the whole tours for vehicle_type in set_1: if parent_1.giant_tour_chromosome.get( vehicle_type.data_index) is None: continue child_giant_tour_chromosome[vehicle_type.data_index] = \ [copy(stop) for stop in parent_1.giant_tour_chromosome[vehicle_type.data_index]] for child in child_giant_tour_chromosome[vehicle_type.data_index]: append_to_chromosome(child_vehicle_type_chromosome, child.data_index, vehicle_type, False) # Mixed set inherits pieces of the tours for vehicle_type in set_mix: if parent_1.giant_tour_chromosome.get( vehicle_type.data_index) is None: continue tour_length = len( parent_1.giant_tour_chromosome[vehicle_type.data_index]) cut_a = randint(0, tour_length) cut_b = cut_a if tour_length > 1: while cut_b == cut_a: # logger.debug(f"{tour_length}: {cut_a}, {cut_b}") cut_b = randint(0, tour_length) if cut_a < cut_b: child_tour = [ copy(stop) for stop in parent_1.giant_tour_chromosome[ vehicle_type.data_index][cut_a:cut_b] ] else: child_tour = [ copy(stop) for stop in [ *parent_1.giant_tour_chromosome[ vehicle_type.data_index][0:cut_b], *parent_1.giant_tour_chromosome[ vehicle_type.data_index][cut_a:tour_length] ] ] child_giant_tour_chromosome[vehicle_type.data_index] = child_tour for child in child_giant_tour_chromosome[vehicle_type.data_index]: append_to_chromosome(child_vehicle_type_chromosome, child.data_index, vehicle_type, False) # logger.debug(f"Data inherited from P1") # all_stops = [stop_t for vehicle_type_t in [*set_1, *set_mix] for stop_t in # parent_1.giant_tour_chromosome.get(vehicle_type_t.data_index)] # if len(child_giant_tour_chromosome.keys()) == 0 and len(all_stops) > 0: # raise ValueError(f"No keys in child chromosome. All stops {all_stops}") # Step 2: Inherit data from P2 # For all vehicle_index types in set 2 and mix, loop through the customers in parent 2. # If the customer either has a matching vehicle_index type or none in the child's vehicle_index chromosome, # add it to this type's tour. Recall that the vehicle_index types are in a random order in the sets. # This allows customers to be reassigned between vehicle_index types, while vaguely keeping the parent's order. for vehicle_type in [*set_2, *set_mix]: if parent_2.giant_tour_chromosome.get(vehicle_type.data_index): for stop in parent_2.giant_tour_chromosome[ vehicle_type.data_index]: customer_vehicles = child_vehicle_type_chromosome.get( stop.data_index) if customer_vehicles is None or vehicle_type in customer_vehicles: append_to_chromosome(child_giant_tour_chromosome, vehicle_type.data_index, stop) append_to_chromosome(child_vehicle_type_chromosome, stop.data_index, vehicle_type, False) # logger.debug(f"Data inherited from P2") # logger.debug(f"Child chrom: {child_giant_tour_chromosome}") # Step 3: Complete customer services child = Individual( child_giant_tour_chromosome, vehicle_type_chromosome=child_vehicle_type_chromosome, possible_locations=self.possible_locations) # child.update_all_routes_location_indices() # child.complete_customer_services(self.allow_split_deliveries) # if len(child_giant_tour_chromosome.keys()) == 0: # raise ValueError(f"No keys in child chromosome.") # child.complete_customer_services_slow() child.evaluate() # logger.debug(f"Completed customer services") # Create and return the child return child