def nsga2_replacement(new_pop, old_pop): """ Replaces the old population with the new population using NSGA-II replacement. Both new and old populations are combined, pareto fronts and crowding distance are calculated, and the replacement population is computed based on crowding distance per pareto front. :param new_pop: The new population (e.g. after selection, variation, & evaluation). :param old_pop: The previous generation population. :return: The 'POPULATION_SIZE' new population. """ # Combine both populations (R_t = P_t union Q_t) new_pop.extend(old_pop) # Compute the pareto fronts and crowding distance pareto = compute_pareto_metrics(new_pop) # Size of the new population pop_size = params['POPULATION_SIZE'] # New population to replace the last one temp_pop, i = [], 0 while len(temp_pop) < pop_size: # Populate the replacement population if len(pareto.fronts[i]) <= pop_size - len(temp_pop): temp_pop.extend(pareto.fronts[i]) else: # Sort the current pareto front with respect to crowding distance. pareto.fronts[i] = sorted( pareto.fronts[i], key=lambda item: pareto.crowding_distance[item]) # Get number of individuals to add in temp to achieve the pop_size diff_size = pop_size - len(temp_pop) # Extend the replacement population temp_pop.extend(pareto.fronts[i][:diff_size]) # Increment counter. i += 1 return temp_pop
def nsga2_replacement(new_pop, old_pop): """ Replaces the old population with the new population using NSGA-II replacement. Both new and old populations are combined, pareto fronts and crowding distance are calculated, and the replacement population is computed based on crowding distance per pareto front. :param new_pop: The new population (e.g. after selection, variation, & evaluation). :param old_pop: The previous generation population. :return: The 'POPULATION_SIZE' new population. """ # Combine both populations (R_t = P_t union Q_t) new_pop.extend(old_pop) # Compute the pareto fronts and crowding distance pareto = compute_pareto_metrics(new_pop) # Size of the new population pop_size = params['POPULATION_SIZE'] # New population to replace the last one temp_pop, i = [], 0 while len(temp_pop) < pop_size: # Populate the replacement population if len(pareto.fronts[i]) <= pop_size - len(temp_pop): temp_pop.extend(pareto.fronts[i]) else: # Sort the current pareto front with respect to crowding distance. pareto.fronts[i] = sorted(pareto.fronts[i], key=lambda item: pareto.crowding_distance[item]) # Get number of individuals to add in temp to achieve the pop_size diff_size = pop_size - len(temp_pop) # Extend the replacement population temp_pop.extend(pareto.fronts[i][:diff_size]) # Increment counter. i += 1 return temp_pop
def nsga2_selection(population): """Apply NSGA-II selection operator on the *population*. Usually, the size of *population* will be larger than *k* because any individual present in *population* will appear in the returned list at most once. Having the size of *population* equals to *k* will have no effect other than sorting the population according to their front rank. The list returned contains references to the input *population*. For more details on the NSGA-II operator see [Deb2002]_. :param population: A population from which to select individuals. :returns: A list of selected individuals. .. [Deb2002] Deb, Pratab, Agarwal, and Meyarivan, "A fast elitist non-dominated sorting genetic algorithm for multi-objective optimization: NSGA-II", 2002. """ selection_size = params['GENERATION_SIZE'] tournament_size = params['TOURNAMENT_SIZE'] # Initialise list of tournament winners. winners = [] # The flag "INVALID_SELECTION" allows for selection of invalid individuals. if params['INVALID_SELECTION']: available = population else: available = [i for i in population if not i.invalid] # Compute pareto front metrics. pareto = compute_pareto_metrics(available) while len(winners) < selection_size: # Return the single best competitor. winners.append(pareto_tournament(available, pareto, tournament_size)) return winners
def nsga2_selection(population): """Apply NSGA-II selection operator on the *population*. Usually, the size of *population* will be larger than *k* because any individual present in *population* will appear in the returned list at most once. Having the size of *population* equals to *k* will have no effect other than sorting the population according to their front rank. The list returned contains references to the input *population*. For more details on the NSGA-II operator see [Deb2002]_. :param population: A population from which to select individuals. :returns: A list of selected individuals. .. [Deb2002] Deb, Pratab, Agarwal, and Meyarivan, "A fast elitist non-dominated sorting genetic algorithm for multi-objective optimization: NSGA-II", 2002. """ selection_size = params['GENERATION_SIZE'] tournament_size = params['TOURNAMENT_SIZE'] # Initialise list of tournament winners. winners = [] # The flag "INVALID_SELECTION" allows for selection of invalid individuals. if params['INVALID_SELECTION']: available = population else: available = [i for i in population if not i.invalid] # Compute pareto front metrics. pareto = compute_pareto_metrics(available) while len(winners) < selection_size: # Return the single best competitor. winners.append(pareto_tournament(available, pareto, tournament_size)) return winners
def get_moo_stats(individuals, end): """ Generate the statistics for an evolutionary run with multiple objectives. Save statistics to utilities.trackers.stats_list. Print statistics. Save fitness plot information. :param individuals: A population of individuals for which to generate statistics. :param end: Boolean flag for indicating the end of an evolutionary run. :return: Nothing. """ # Compute the pareto front metrics for the population. pareto = compute_pareto_metrics(individuals) # Save first front in trackers. Sort arbitrarily along first objective. trackers.best_ever = sorted(pareto.fronts[0], key=lambda x: x.fitness[0]) # Store stats about pareto fronts. stats['pareto_fronts'] = len(pareto.fronts) stats['first_front'] = len(pareto.fronts[0]) if end or params['VERBOSE'] or not params['DEBUG']: # Update all stats. update_stats(individuals, end) # Save fitness plot information if params['SAVE_PLOTS'] and not params['DEBUG']: # Initialise empty array for fitnesses for all inds on first pareto # front. all_arr = [[] for _ in range(params['FITNESS_FUNCTION'].num_obj)] # Generate array of fitness values. fitness_array = [ind.fitness for ind in trackers.best_ever] # Add paired fitnesses to array for graphing. for fit in fitness_array: for o in range(params['FITNESS_FUNCTION'].num_obj): all_arr[o].append(fit[o]) if not end: trackers.first_pareto_list.append(all_arr) # Append empty array to best fitness list. trackers.best_fitness_list.append([]) # Get best fitness for each objective. for o, ff in \ enumerate(params['FITNESS_FUNCTION'].fitness_functions): # Get sorted list of all fitness values for objective "o" fits = sorted(all_arr[o], reverse=ff.maximise) # Append best fitness to trackers list. trackers.best_fitness_list[-1].append(fits[0]) if params['VERBOSE'] or end: # Plot best fitness for each objective. for o, ff in \ enumerate(params['FITNESS_FUNCTION'].fitness_functions): to_plot = [i[o] for i in trackers.best_fitness_list] # Plot fitness data for objective o. plotname = ff.__class__.__name__ + str(o) save_plot_from_data(to_plot, plotname) # TODO: PonyGE2 can currently only plot moo problems with 2 objectives. # Check that the number of fitness objectives is not greater than 2 if params['FITNESS_FUNCTION'].num_obj > 2: s = "stats.stats.get_moo_stats\n" \ "Warning: Plotting of more than 2 simultaneous " \ "objectives is not yet enabled in PonyGE2." print(s) else: save_pareto_fitness_plot() # Print statistics if params['VERBOSE'] and not end: print_generation_stats() print_first_front_stats() elif not params['SILENT']: # Print simple display output. perc = stats['gen'] / (params['GENERATIONS'] + 1) * 100 stdout.write("Evolution: %d%% complete\r" % perc) stdout.flush() # Generate test fitness on regression problems if hasattr(params['FITNESS_FUNCTION'], "training_test") and end: for ind in trackers.best_ever: # Iterate over all individuals in the first front. # Save training fitness. ind.training_fitness = copy(ind.fitness) # Evaluate test fitness. ind.test_fitness = params['FITNESS_FUNCTION'](ind, dist='test') # Set main fitness as training fitness. ind.fitness = ind.training_fitness # Save stats to list. if params['VERBOSE'] or (not params['DEBUG'] and not end): trackers.stats_list.append(copy(stats)) # Save stats to file. if not params['DEBUG']: if stats['gen'] == 0: save_stats_headers(stats) save_stats_to_file(stats, end) if params['SAVE_ALL']: save_first_front_to_file(stats, end, stats['gen']) elif params['VERBOSE'] or end: save_first_front_to_file(stats, end) if end and not params['SILENT']: print_final_moo_stats()
def get_moo_stats(individuals, end): """ Generate the statistics for an evolutionary run with multiple objectives. Save statistics to utilities.trackers.stats_list. Print statistics. Save fitness plot information. :param individuals: A population of individuals for which to generate statistics. :param end: Boolean flag for indicating the end of an evolutionary run. :return: Nothing. """ # Compute the pareto front metrics for the population. pareto = compute_pareto_metrics(individuals) # Save first front in trackers. Sort arbitrarily along first objective. trackers.best_ever = sorted(pareto.fronts[0], key=lambda x: x.fitness[0]) # Store stats about pareto fronts. stats['pareto_fronts'] = len(pareto.fronts) stats['first_front'] = len(pareto.fronts[0]) if end or params['VERBOSE'] or not params['DEBUG']: # Update all stats. update_stats(individuals, end) # Save fitness plot information if params['SAVE_PLOTS'] and not params['DEBUG']: # Initialise empty array for fitnesses for all inds on first pareto # front. all_arr = [[] for _ in range(params['FITNESS_FUNCTION'].num_obj)] # Generate array of fitness values. fitness_array = [ind.fitness for ind in trackers.best_ever] # Add paired fitnesses to array for graphing. for fit in fitness_array: for o in range(params['FITNESS_FUNCTION'].num_obj): all_arr[o].append(fit[o]) if not end: trackers.first_pareto_list.append(all_arr) # Append empty array to best fitness list. trackers.best_fitness_list.append([]) # Get best fitness for each objective. for o, ff in \ enumerate(params['FITNESS_FUNCTION'].fitness_functions): # Get sorted list of all fitness values for objective "o" fits = sorted(all_arr[o], reverse=ff.maximise) # Append best fitness to trackers list. trackers.best_fitness_list[-1].append(fits[0]) if params['VERBOSE'] or end: # Plot best fitness for each objective. for o, ff in \ enumerate(params['FITNESS_FUNCTION'].fitness_functions): to_plot = [i[o] for i in trackers.best_fitness_list] # Plot fitness data for objective o. plotname = ff.__class__.__name__ + str(o) save_plot_from_data(to_plot, plotname) # TODO: PonyGE2 can currently only plot moo problems with 2 objectives. # Check that the number of fitness objectives is not greater than 2 if params['FITNESS_FUNCTION'].num_obj > 2: s = "stats.stats.get_moo_stats\n" \ "Warning: Plotting of more than 2 simultaneous " \ "objectives is not yet enabled in PonyGE2." print(s) else: save_pareto_fitness_plot() # Print statistics if params['VERBOSE'] and not end: print_generation_stats() print_first_front_stats() elif not params['SILENT']: # Print simple display output. perc = stats['gen'] / (params['GENERATIONS'] + 1) * 100 stdout.write("Evolution: %d%% complete\r" % perc) stdout.flush() # Generate test fitness on regression problems if hasattr(params['FITNESS_FUNCTION'], "training_test") and end: for ind in trackers.best_ever: # Iterate over all individuals in the first front. # Save training fitness. ind.training_fitness = copy(ind.fitness) # Evaluate test fitness. ind.test_fitness = params['FITNESS_FUNCTION'](ind, dist='test') # Set main fitness as training fitness. ind.fitness = ind.training_fitness # Save stats to list. if params['VERBOSE'] or (not params['DEBUG'] and not end): trackers.stats_list.append(copy(stats)) # Save stats to file. if not params['DEBUG']: if stats['gen'] == 0: save_stats_headers(stats) save_stats_to_file(stats, end) if params['SAVE_ALL']: save_first_front_to_file(stats, end, stats['gen']) elif params['VERBOSE'] or end: save_first_front_to_file(stats, end) if end and not params['SILENT']: print_final_moo_stats()