def eaSteadyState(toolbox, population, ngen, halloffame=None): """The is the steady-state evolutionary algorithm """ _logger.info("Start of evolution") # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in population if not ind.fitness.valid] fitnesses = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit if halloffame is not None: halloffame.update(population) # Begin the generational process for gen in range(ngen): _logger.info("Evolving generation %i", gen) p1, p2 = toolbox.select(population, 2) p1 = toolbox.clone(p1) p2 = toolbox.clone(p2) toolbox.mate(p1, p2) child = random.choice([p1, p2]) toolbox.mutate(child) child.fitness.values = toolbox.evaluate(child) if halloffame is not None: halloffame.update(child) # Select the next generation population population[:] = toolbox.select(population + [child], len(population)) # Gather all the fitnesses in one list and print the stats fits = [ind.fitness.values for ind in population] fits_t = zip(*fits) # Transpose fitnesses for analysis minimums = map(min, fits_t) maximums = map(max, fits_t) length = len(population) sums = map(sum, fits_t) sums2 = [sum(x*x for x in fit) for fit in fits_t] means = [sum_ / length for sum_ in sums] std_devs = [abs(sum2 / length - mean**2)**0.5 for sum2, mean in zip(sums2, means)] _logger.debug("Min %s", ", ".join(map(str, minimums))) _logger.debug("Max %s", ", ".join(map(str, maximums))) _logger.debug("Avg %s", ", ".join(map(str, means))) _logger.debug("Std %s", ", ".join(map(str, std_devs))) _logger.info("End of (successful) evolution") return population
def eaSimple(toolbox, population, cxpb, mutpb, ngen, halloffame=None): """This algorithm reproduce the simplest evolutionary algorithm as presented in chapter 7 of Back, Fogel and Michalewicz, "Evolutionary Computation 1 : Basic Algorithms and Operators", 2000. It uses :math:`\lambda = \kappa = \mu` and goes as follow. It first initializes the population (:math:`P(0)`) by evaluating every individual presenting an invalid fitness. Then, it enters the evolution loop that begins by the selection of the :math:`P(g+1)` population. Then the crossover operator is applied on a proportion of :math:`P(g+1)` according to the *cxpb* probability, the resulting and the untouched individuals are placed in :math:`P'(g+1)`. Thereafter, a proportion of :math:`P'(g+1)`, determined by *mutpb*, is mutated and placed in :math:`P''(g+1)`, the untouched individuals are transfered :math:`P''(g+1)`. Finally, those new individuals are evaluated and the evolution loop continues until *ngen* generations are completed. Briefly, the operators are applied in the following order :: evaluate(population) for i in range(ngen): offsprings = select(population) offsprings = mate(offsprings) offsprings = mutate(offsprings) evaluate(offsprings) population = offsprings """ _logger.info("Start of evolution") # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in population if not ind.fitness.valid] fitnesses = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit _logger.debug("Evaluated %i individuals", len(invalid_ind)) if halloffame is not None: halloffame.update(population) # Begin the generational process for gen in range(ngen): _logger.info("Evolving generation %i", gen) # Select the next generation individuals offsprings = toolbox.select(population, n=len(population)) # Clone the selected individuals offsprings = map(toolbox.clone, offsprings) # Apply crossover and mutation on the offsprings for ind1, ind2 in zip(offsprings[::2], offsprings[1::2]): if random.random() < cxpb: toolbox.mate(ind1, ind2) del ind1.fitness.values del ind2.fitness.values for ind in offsprings: if random.random() < mutpb: toolbox.mutate(ind) del ind.fitness.values # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in offsprings if not ind.fitness.valid] fitnesses = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit _logger.debug("Evaluated %i individuals", len(invalid_ind)) if halloffame is not None: halloffame.update(offsprings) # The population is entirely replaced by the offsprings population[:] = offsprings print toolbox.info(population) _logger.info("End of (successful) evolution") return population
def eaSimpleMany(toolbox, population, cxpb, mutpb, ngen, halloffame=None): """ This algorithm is based on the Simple algorithm above, but designed to return as many perfect individuals as possible, given an upper bound. """ _logger.info("Start of evolution") # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in population if not ind.fitness.valid] fitnesses = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit _logger.debug("Evaluated %i individuals", len(invalid_ind)) if halloffame is not None: halloffame.update(population) perfect = set() # Begin the generational process for gen in range(ngen): _logger.info("Evolving generation %i", gen) # Select the next generation individuals offsprings = toolbox.select(population, n=len(population)) # Clone the selected individuals offsprings = map(toolbox.clone, offsprings) # Apply crossover and mutation on the offsprings for ind1, ind2 in zip(offsprings[::2], offsprings[1::2]): if random.random() < cxpb: toolbox.mate(ind1, ind2) del ind1.fitness.values del ind2.fitness.values for ind in offsprings: if random.random() < mutpb: toolbox.mutate(ind) del ind.fitness.values # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in offsprings if not ind.fitness.valid] fitnesses = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit _logger.debug("Evaluated %i individuals", len(invalid_ind)) if halloffame is not None: halloffame.update(offsprings) # The population is entirely replaced by the offsprings population[:] = offsprings for ind in population: if ind.fitness.values[0] == toolbox.perfect(): perfect.add(ind) print toolbox.info(population) _logger.info("End of (successful) evolution") return population
def eaMuCommaLambda(toolbox, population, mu, lambda_, cxpb, mutpb, ngen, halloffame=None): """This is the :math:`(\mu~,~\lambda)` evolutionary algorithm. First, the individuals having an invalid fitness are evaluated. Then, the evolutionary loop begins by producing *lambda* offsprings from the population, the offsprings are generated by a crossover, a mutation or a reproduction proportionally to the probabilities *cxpb*, *mutpb* and 1 - (cxpb + mutpb). The offsprings are then evaluated and the next generation population is selected **only** from the offsprings. Briefly, the operators are applied as following :: evaluate(population) for i in range(ngen): offsprings = generate_offsprings(population) evaluate(offsprings) population = select(offsprings) .. note:: Both produced individuals from the crossover are put in the offspring pool. """ assert lambda_ >= mu, "lambda must be greater or equal to mu." assert (cxpb + mutpb) <= 1.0, ("The sum of the crossover and mutation" "probabilities must be smaller or equal to 1.0.") _logger.info("Start of evolution") evaluations = 0 # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in population if not ind.fitness.valid] fitnesses = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit _logger.debug("Evaluated %i individuals", len(invalid_ind)) if halloffame is not None: halloffame.update(population) # Begin the generational process for gen in range(ngen): _logger.info("Evolving generation %i", gen) evaluations = 0 offsprings = [] nb_offsprings = 0 while nb_offsprings < lambda_: #for i in xrange(lambda_): op_choice = random.random() if op_choice < cxpb: # Apply crossover ind1, ind2 = random.sample(population, 2) ind1 = toolbox.clone(ind1) ind2 = toolbox.clone(ind2) toolbox.mate(ind1, ind2) del ind1.fitness.values del ind2.fitness.values offsprings.append(ind1) offsprings.append(ind2) nb_offsprings += 2 elif op_choice < cxpb + mutpb: # Apply mutation ind = random.choice(population) # select ind = copy.deepcopy(ind) # clone toolbox.mutate(ind) del ind.fitness.values offsprings.append(ind) nb_offsprings += 1 else: # Apply reproduction offsprings.append(random.choice(population)) nb_offsprings += 1 # Remove the exedant of offsprings if nb_offsprings > lambda_: del offsprings[lambda_:] # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in offsprings if not ind.fitness.valid] fitnesses = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit _logger.debug("Evaluated %i individuals", len(invalid_ind)) if halloffame is not None: halloffame.update(offsprings) # Select the next generation population population[:] = toolbox.select(offsprings, mu) # Gather all the fitnesses in one list and print the stats fits = [ind.fitness.values for ind in population] fits_t = zip(*fits) # Transpose fitnesses for analysis minimums = map(min, fits_t) maximums = map(max, fits_t) length = len(population) sums = map(sum, fits_t) sums2 = [sum(x*x for x in fit) for fit in fits_t] means = [sum_ / length for sum_ in sums] std_devs = [abs(sum2 / length - mean**2)**0.5 for sum2, mean in zip(sums2, means)] #_logger.debug("Min %s", ", ".join(map(str, minimums))) #_logger.debug("Max %s", ", ".join(map(str, maximums))) #_logger.debug("Avg %s", ", ".join(map(str, means))) #_logger.debug("Std %s", ", ".join(map(str, std_devs))) _logger.info("End of (successful) evolution")
# create folder to save results if not os.path.exists(path_results): os.makedirs(path_results) # create initial population population = np.array([toolbox.Chromosome() for i in range(POPULATION_SIZE)]) print("ready to go") # evolutionary algorithm main body for i in range(EPOCHS + 1): # select best individuals to pass to the next generation without any changes # elitism technique. hof = hall of fame - best individuals hof = toolbox.hall_of_fame(population) # select individuals that survive to the next generation offspring = toolbox.select(population, len(population) - HOF_NUMBER) # perform pairwise crossover operator for survived individuals for child1, child2 in zip(offspring[::2], offspring[1::2]): # certain probability to change individuals if np.random.random() < P_CROSSOVER: toolbox.crossover(child1, child2) # set fitness to invalid state - means that we need to recalculate it child1.fitness_value = -1 child2.fitness_value = -1 # mutations for each individual in offspring for mutant in offspring: # perform mutation with certain probability if np.random.random() < P_MUTATION: toolbox.mutate(mutant) # set fitness value to be invalid - need to be recalculated mutant.fitness_value = -1