def genealogy_plot(history: tools.support.History, toolbox: base.Toolbox) -> np.ndarray: ''' plotting function for genealogical history of the GA run. :param history: dict, dict with history :param toolbox: gp.toolbox, for using the appropriate eval :return: ndarray, 3-Channel RGB array from plot ''' graph = networkx.DiGraph(history.genealogy_tree) graph = graph.reverse() # Make the graph top-down fig, ax = plt.subplots(figsize=(8, 6), dpi=120) try: colors = [ toolbox.evaluate(history.genealogy_history[i])[0] for i in graph ] except: # catch all for failures colors = [i for i in range(history.genealogy_index)] positions = graphviz_layout(graph, prog="dot") networkx.draw(graph, positions, node_color=colors, with_labels=True, font_size1=10, alpha=0.75, ax=ax) plt.title('Evolution: Genealogy Tree', fontsize='xx-large') fig.canvas.draw() image = np.frombuffer(fig.canvas.tostring_rgb(), dtype='uint8') image = image.reshape(fig.canvas.get_width_height()[::-1] + (3, )) plt.close(fig) return image
def execute(toolbox: base.Toolbox, cases: int = 100) -> List[str]: population = toolbox.population(n=POPULATION_SIZE) hall_of_fame = tools.ParetoFront() stats = tools.Statistics(lambda i: i.fitness.values) stats.register("avg", numpy.mean, axis=0) stats.register("std", numpy.std, axis=0) stats.register("min", numpy.min, axis=0) stats.register("max", numpy.max, axis=0) logbook = tools.Logbook() logbook.header = "gen", "evals", "std", "min", "avg", "max", "best" # Evaluate every individuals for individual in population: individual.fitness.values = toolbox.evaluate(individual) hall_of_fame.update(population) record = stats.compile(population) logbook.record(gen=0, evals=len(population), **record) print(logbook.stream) generated_cases = list last_fitness = float('inf') current_fitness = None generation_count = 1 while generation_count <= MAX_GENERATIONS and ( last_fitness != current_fitness or current_fitness == float('inf')): last_fitness = current_fitness # Select the next generation individuals offspring = toolbox.select(population, floor(POPULATION_SIZE * 0.9)) # Clone the selected individuals offspring = list(toolbox.map(toolbox.clone, offspring)) # Add new individuals from the population offspring += toolbox.population(n=POPULATION_SIZE - len(offspring)) # Apply crossover and mutation on the offspring for child1, child2 in zip(offspring[::2], offspring[1::2]): if not random() < MATE_RATIO: continue toolbox.mate(child1, child2) del child1.fitness.values del child2.fitness.values for mutant in offspring: if not random() < MUTATION_RATIO: continue toolbox.mutate(mutant) del mutant.fitness.values # Evaluate the individuals with an invalid fitness invalid_ind = [ individual for individual in offspring if not individual.fitness.valid ] for individual in offspring: individual.fitness.values = toolbox.evaluate(individual) generated_cases = tools.selBest(population, k=cases) current_fitness = sum( toolbox.map(op.itemgetter(0), toolbox.map(toolbox.evaluate, generated_cases))) best = choice(generated_cases) word = "".join(best) # Select the next generation population population = toolbox.select(population + offspring, POPULATION_SIZE) record = stats.compile(population) logbook.record(gen=generation_count, evals=len(invalid_ind), best=word, **record) print(logbook.stream) generation_count += 1 return [''.join(case) for case in generated_cases]