def init_deap_functions(self): creator.create("Fitness", base.Fitness, weights=self.weights) creator.create("Individual", list, fitness=creator.Fitness) toolbox = base.Toolbox() toolbox.register("individual", tools.initIterate, creator.Individual, self.generate_ind) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("evaluate", self.fit_func) if self.penalty != None: toolbox.decorate("evaluate", tools.DeltaPenality(self.feasible, self.inf_val)) #toolbox.register("mate", tools.cxTwoPoint) toolbox.register("mate", tools.cxSimulatedBinaryBounded, low=self.bounds_min, up=self.bounds_max, eta=10.0) #toolbox.register("mutate", tools.mutGaussian, mu=0.0, sigma=0.2, indpb=MUTPB) toolbox.register("mutate", tools.mutPolynomialBounded, eta=10.0, low=self.bounds_min, up=self.bounds_max, indpb=self.mutpb) return toolbox
def results_wavy(tb,D,delta,rounds,global_min,cxp,mup): import pandas as pd m = 50; l = 100; col = {'_cxp':[],'_mup':[],'Delta':[],'Dimensions':[],'Successes':[], 'avg_evals':[],'avg_min':[],'avg_time':[]} df = pd.DataFrame(col) def feasible2( indiv ): if any( indiv < MIN_BOUND) or any( indiv > MAX_BOUND): return False return True def distance2(indiv) : dist = 0.0 for i in range (len( indiv )) : penalty = 0 if(indiv[i] < MIN_BOUND[i]) : penalty = -pi*temp - indiv[i] if(indiv[i] > MAX_BOUND[i]) : penalty = indiv[i] - pi*temp dist = dist + penalty return dist for i in range(0,len(D)): MIN_BOUND = np.array([-pi]*D[i]) MAX_BOUND = np.array([pi]*D[i]) temp = D[i] tb.register( "InitialValue", np.random.uniform, -pi, pi) tb.register( "indiv", tools.initRepeat, creator.IndividualContainer, tb.InitialValue, D[i]) tb.register( "population", tools.initRepeat, list , tb.indiv) tb.register( "evaluate", wavy,D=D[i],k=10) tb.decorate( "evaluate", tools.DeltaPenality (feasible2, 4*pi, distance2)) regfunc(0.02,0.1,5,'Uniform','FlipBit',tb) a,b,c,d,e,f,g=solve(eaMuPlusLamda_with_stats,delta[i],cxp,mup,rounds,m,l,tb,global_min) df.loc[i] = [delta[i],D[i],a,cxp,mup,b,c,d] return df
def setup_ga(self): self.toolbox.register("individual", tools.initIterate, creator.Individual, self.create_individual) self.toolbox.register("population", tools.initRepeat, list, self.toolbox.individual) self.toolbox.register("evaluate", self.fitness) self.toolbox.decorate("evaluate", tools.DeltaPenality (self.feasible, minus_inf, self.distance)) self.toolbox.register("mate", tools.cxTwoPoint) self.toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) self.toolbox.register("select", tools.selTournament, tournsize=4)
def configuracionAlgoritmo(toolbox): # Se seleccionan procedimiento standard para cruce, mutacion y seleccion toolbox.register("mate", tools.cxTwoPoint) toolbox.register("mutate", tools.mutShuffleIndexes, indpb=0.2) toolbox.register("select", tools.selTournament, tournsize=3) # Se define cómo se evaluará cada individuo # En este caso, se hará uso de la función de evaluación que se ha definido en el modulo Evaluacion.py toolbox.register("evaluate", Evaluacion.fitness) toolbox.decorate( "evaluate", tools.DeltaPenality(Evaluacion.esValido, 0, Evaluacion.distancia))
def optimize_route(flow_dic): if 'premium' in flow_dic['_id']: gen = 25 elif 'assured' in flow_dic['_id']: gen = 15 else: gen = 10 flow_obj = Flow(flow_dic) evaluate_individual = get_evaluate_individual(topology, flow_dic) evaluate_SLA = get_evaluate_SLA(flow_obj.SLA, topology, evaluate_individual) penalty = get_penalty(flow_obj.SLA, topology, evaluate_individual) topology.toolbox.register("evaluate", evaluate_individual) topology.toolbox.decorate( "evaluate", tools.DeltaPenality(evaluate_SLA, 20.0, penalty)) topology.toolbox.register("population_fetch", initPopulation, list, \ creator.Individual, flow_obj.starting_node, flow_obj.ending_node, topology) pop = topology.toolbox.population_fetch() if pop == []: print('WARNING - EMPTY POPULATION') print(flow_dic['node1'], flow_dic['node2']) hof = tools.ParetoFront(similar=compare_individuals) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", np.mean, axis=0) stats.register("std", np.std, axis=0) stats.register("min", np.min, axis=0) stats.register("max", np.max, axis=0) algorithms.eaSimple(pop, topology.toolbox, cxpb=0.75, mutpb=0.2, ngen=gen, stats=stats, halloffame=hof, verbose=False) min_attr = 1e15 meta_att = topology.meta_heuristic for p in hof: evaluation = evaluate_individual(p) if evaluation[meta_att] < min_attr: meta_best = p min_attr = evaluation[meta_att] topology.toolbox.unregister("evaluate") topology.toolbox.unregister("population_fetch") return meta_best
def minimize_deap(f, p0, kwargs): # weight is -1 because we want to minimize the error creator.create("FitnessMax", base.Fitness, weights=(-1.0, )) creator.create("Individual", list, fitness=creator.FitnessMax) # See: http://deap.readthedocs.org/en/master/tutorials/basic/part1.html#a-funky-one toolbox = base.Toolbox() toolbox.register("attr", random.uniform, -2, 2) toolbox.register("individual", tools.initCycle, creator.Individual, (toolbox.attr, ), n=len(p0)) toolbox.register("population", tools.initRepeat, list, toolbox.individual) def myfunc(c, **kwarwgs): """ Wrap the objective function so that it returns a tuple for compatibility with deap """ return (f(c, **kwargs), ) toolbox.register("evaluate", myfunc, **kwargs) if 'DeltaPenality' in dir(tools): toolbox.decorate("evaluate", tools.DeltaPenality(feasible, 100000)) # If two individuals mate, interpolate between them, allow for a bit of extrapolation toolbox.register("mate", tools.cxBlend, alpha=0.3) sigma = np.array([0.01] * len(p0)).tolist() toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=sigma, indpb=1.0) toolbox.register( "select", tools.selTournament, tournsize=5 ) # The greater the tournament size, the greater the selection pressure hof = tools.HallOfFame(50) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("min", np.min) pop = toolbox.population(n=500) pop, log = eaSimple( pop, toolbox, cxpb=0.5, # Crossover probability mutpb=0.3, # Mutation probability ngen=20, stats=stats, halloffame=hof, verbose=True) best = max(pop, key=attrgetter("fitness")) print(best, best.fitness) return list(best)
def fit(): creator.create("FitnessMax", base.Fitness, weights=(1.0, )) creator.create("Individual", list, fitness=creator.FitnessMax) toolbox = base.Toolbox() toolbox.register("individual", tools.initIterate, creator.Individual, initialize_individual) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("r", objective) toolbox.register("mate", cxTwoPoint) toolbox.register("mutate", mutation, indpb=indpb) toolbox.register("select", tools.selTournament, tournsize=tournsize) toolbox.decorate("r", tools.DeltaPenality(feasible, 0, distance)) pop = toolbox.population(n=n_population) fitnesses = list(map(toolbox.r, pop)) for ind, fit in zip(pop, fitnesses): ind.fitness.values = fit fits = [ind.fitness.values[0] for ind in pop] for generation in range(n_generation): print("Generation {} :".format(generation)) if (generation == 0): optimal_weight, optimal_fit = [], max(fits) offspring = toolbox.select(pop, len(pop)) # Clone the selected individuals offspring = list(map(toolbox.clone, offspring)) # Apply crossover and mutation on the offspring for child1, child2 in zip(offspring[::2], offspring[1::2]): if random.random() < CXPB: toolbox.mate(child1, child2) del child1.fitness.values del child2.fitness.values for mutant in offspring: if random.random() < MUTPB: toolbox.mutate(mutant) del mutant.fitness.values invalid_ind = [ind for ind in offspring if not ind.fitness.valid] fitnesses = map(toolbox.r, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit pop[:] = offspring fits = [ind.fitness.values[0] for ind in pop] if (display): print("Max objective function: {} \nOptimal weight: {} \n". format(max(fits), pop[fits.index(max(fits))])) if (max(fits) > optimal_fit): optimal_weight = pop[fits.index(max(fits))] return optimal_weight
def init_deap_functions(self): creator.create("Fitness", base.Fitness, weights=self.weights) creator.create("Individual", list, fitness=creator.Fitness) self.toolbox = base.Toolbox() self.toolbox.register("individual", tools.initIterate, creator.Individual, self.generate_ind) self.toolbox.register("population", tools.initRepeat, list, self.toolbox.individual) self.toolbox.register("evaluate", self.fit_func) if self.penalty != None: self.toolbox.decorate( "evaluate", tools.DeltaPenality(self.feasible, self.inf_val))
BOUND_LOW, BOUND_UP = 0.0, 1.0 creator.create("FitnessMulti", base.Fitness, weights=(1.0, 1.0)) # creator.create("FitnessMulti", base.Fitness, weights=(1.0,)) creator.create("Individual", np.ndarray, fitness=creator.FitnessMulti) toolbox = base.Toolbox() toolbox.register("attr_float", random.uniform, BOUND_LOW, BOUND_UP) toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_float, n=IND_SIZE) toolbox.register("evaluate", func) toolbox.decorate("evaluate", tools.DeltaPenality(feasible, 0)) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("mate", tools.cxSimulatedBinaryBounded, low=BOUND_LOW, up=BOUND_UP, eta=20.0) toolbox.register("mutate", tools.mutPolynomialBounded, low=BOUND_LOW, up=BOUND_UP, eta=20.0, indpb=1.0 / IND_SIZE) toolbox.register("select", tools.selNSGA2) stats = tools.Statistics()
def faster_optimize_route(flow_dic): flow_obj = Flow(flow_dic) # number of weights in the tuple -> number of objective functions creator.create("FitnessMultiObj", base.Fitness, weights=( -1.0, -1.0, -1.0, -1.0, )) creator.create("Individual", list, fitness=creator.FitnessMultiObj) toolbox = base.Toolbox() toolbox.register("individual", generate_individual, creator.Individual, flow_obj.starting_node, flow_obj.ending_node, topology) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("mate", crossover_one_point, topology=topology, ind_class=creator.Individual, toolbox=toolbox) toolbox.register("select", tools.selNSGA2) toolbox.register("mutate", mutate_path_faster, topology=topology, indi_class=creator.Individual) evaluate_individual = get_evaluate_individual(topology, flow_dic) toolbox.register("evaluate", evaluate_individual) evaluate_SLA = get_evaluate_SLA(flow_obj.SLA, topology, evaluate_individual) penalty = get_penalty(flow_obj.SLA, topology, evaluate_individual) toolbox.decorate("evaluate", tools.DeltaPenality(evaluate_SLA, 20.0, penalty)) pop = toolbox.population(n=25) hof = tools.ParetoFront(similar=compare_individuals) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", np.mean, axis=0) #stats.register("std", np.std, axis=0) #stats.register("min", np.min, axis=0) #stats.register("max", np.max, axis=0) algorithms.eaSimple(pop, toolbox, cxpb=0.75, mutpb=0.2, ngen=10, stats=stats, halloffame=hof, verbose=False) min_attr = 1e15 meta_att = topology.meta_heuristic for p in hof: evaluation = evaluate_individual(p) if evaluation[meta_att] < min_attr: meta_best = p min_attr = evaluation[meta_att] return meta_best
def deap_solver(design_var_dict, obj_func_list, obj_func_names=None, norm_facts=None, POPSIZE=1000, GENS=50, MUTPB=None, CXPB=None, SURVIVORS=100, CHILDREN=1000, constraints=None): """ This is an optimization solver based on the Distributed Evolutionary Algorithms in Python (DEAP) package. It uses binary representations of design variables in each individual. Given an objective function (or list of objective functions) and constraints, the solver evolves each population of individuals based on the NSGA-II genetic algorithm. :param design_var_dict: dictionary of design variables :param obj_func_list: list of anonymous functions that represents the objective(s) :param obj_func_names: optional, specifies function names :param norm_facts: specify normalization factors for objective function outputs. If problem has multiple objective functions with outputs expected to be on different orders of magnitude, this is very important to include. Choose normalization factors approximately equal to maximum expected output from its associated function :param POPSIZE: size of initial population :param GENS: number of generations to be evaluated :param MUTPB: probability of mutation :param CXPB: probability of crossover :param SURVIVORS: number of individuals selected after initial population is evaluated. This governs the size of all future populations :param CHILDREN: number of offspring to be produced from the current population at each generation :param constraints: list constraints to be applied in evaluating the validity of each individual :return: the solver returns a table of solution points that contains the variable and objective function values for all optimized solutions. A print(results) statement will display the table. For problems with two objective functions, the solver also returns a plot of the Pareto Frontier EXAMPLE SETUP FOR SOLVER: design_var_dict = {'r': {'interval': [0,10],'bits': 10},'h':{'interval':[0,20],'bits':10}} S = lambda r,h: math.pi*r*math.sqrt(r**2+h**2) T = lambda r,h: math.pi*r**2+math.pi*r*math.sqrt(r**2+h**2) obj_func_list = [S,T] obj_func_names = ['Lateral Surface Area','Total Area'] norm_facts = [155,225] constraints = [[V, '>', 200]] --> [[func(r,h),'operator',val],[func(r,h),'operator',val],etc.] gens = 50 popSize = 1000 mutPB = 0.1 cxPB = 0.9 survivors = 100 children = 1000 results = deapSolver(design_vars, func_list, obj_func_names=func_names, norm_facts=norm_facts, POPSIZE=popSize, GENS=gens, MUTPB=mutPB, CXPB=cxPB, SURVIVORS=survivors, CHILDREN=children, constraints=constraint_list) """ # Assign values optional keyword arguments whose length depends on the number of objective functions specified if norm_facts is None: norm_facts = [1 for _ in obj_func_list] if MUTPB is None: maxbits = 0 for var in design_var_dict: if design_var_dict[var]['bits'] > maxbits: maxbits = design_var_dict[var]['bits'] MUTPB = 1 / maxbits if CXPB is None: CXPB = 1 - MUTPB if obj_func_names is None: obj_func_names = [ 'f{}'.format(i + 1) for i in range(len(obj_func_list)) ] def bi2de_ind( individual ): # convert binary individuals to list of decimal variable values deciInd = [] counter = 0 for var in design_var_dict: xL = design_var_dict[var]['interval'][0] xU = design_var_dict[var]['interval'][1] diff = xU - xL bits = design_var_dict[var]['bits'] step = diff / (2**bits - 1) binary = ''.join(map(str, individual[counter:(counter + bits)])) deciVal = int(binary, 2) deciInd.append(xL + deciVal * step) counter += bits return deciInd def func_eval( individual ): # evaluate individual fitness by plugging variables into objective function(s) deciInd = bi2de_ind(individual) outputs = [ func(*deciInd) / norm_fact for func, norm_fact in zip(obj_func_list, norm_facts) ] return tuple(outputs) ops = { '>': operator.gt, '<': operator.lt, '>=': operator.ge, '<=': operator.le, '=': operator.eq } #register operator dictionary for constraint evaluation def feasibility( individual ): # determine if an individual's variables violate any constraints deciInd = bi2de_ind(individual) for constraint in constraints: if ops[constraint[1]](constraint[0](*deciInd), constraint[2]) is False: return False return True def uniform( ): # fill each individual in the initial population with total bits in design_var_dict bits = 0 for var in design_var_dict: bits += design_var_dict[var]['bits'] individual = [random.randint(0, 1) for _ in range(bits)] return individual def cx_list(ind1, ind2): # define crossover strategy for lists cxPt = random.randint(0, len(ind1) - 1) child1 = toolbox.individual() child2 = toolbox.individual() child1[::] = ind1[0:cxPt] + ind2[cxPt::] child2[::] = ind2[0:cxPt] + ind1[cxPt::] return child1, child2 def mut_list(individual): # define mutation strategy for lists mutPoint = random.randint(0, len(individual) - 1) if individual[mutPoint] == 1: individual[mutPoint] = 0 else: individual[mutPoint] = 1 return individual, weights = tuple([-1.0 for _ in obj_func_list ]) # weight for all objectives are defaulted to -1 creator.create( "Fitness", base.Fitness, weights=weights ) # create fitness class inherited from 'base.Fitness' class creator.create("Individual", list, fitness=creator.Fitness ) # create Individual class inherited from 'list' class toolbox = base.Toolbox( ) # initialize toolbox class from 'base', contains all evolutionary operators toolbox.register( "initializer", uniform) # register function 'uniform' to initialize individuals toolbox.register( "individual", tools.initIterate, creator.Individual, toolbox.initializer) # register 'individual' creator in toolbox toolbox.register( "population", tools.initRepeat, list, toolbox.individual) # register 'population' creator in toolbox toolbox.register( "mate", cx_list) # register crossover strategy as function 'cx_list' toolbox.register( "mutate", mut_list) # register mutation strategy as function 'mut_list' toolbox.register( "evaluate", func_eval) # register evaluation strategy as function 'func_eval' if constraints: toolbox.decorate( "evaluate", tools.DeltaPenality(feasibility, 10000) ) # decorate evaluation strategy with constraints if they exist, penalize invalid individuals toolbox.register( "select", tools.selNSGA2 ) # register selection strategy for sorting evaluated individuals as NSGA-II stats = tools.Statistics( lambda ind: ind.fitness.values) # log statistics during evolution stats.register("avg", np.mean, axis=0) stats.register("std", np.std, axis=0) stats.register("min", np.min, axis=0) stats.register("max", np.max, axis=0) pop = toolbox.population(n=POPSIZE) # generate initial population hof = tools.ParetoFront( ) # register criteria for selecting hall of fame individuals (Pareto dominant solutions) output = algorithms.eaMuPlusLambda( pop, toolbox, SURVIVORS, CHILDREN, CXPB, MUTPB, GENS, stats, halloffame=hof) # conduct evolutionary optimization process headerList = ['Solution Point'] for var in design_var_dict: headerList.append(var) for name in obj_func_names: headerList.append(name) results = PrettyTable( headerList) # generate table to store and display results solution = 1 for individual in output[0]: # put optimal solutions into 'results' table solutionList = [solution] deciInd = bi2de_ind(individual) for val in deciInd: solutionList.append(val) for val, norm_fact in zip(individual.fitness.values, norm_facts): solutionList.append(val * norm_fact) results.add_row(solutionList) solution += 1 if len(obj_func_list ) == 2: # if two objective functions provided, plot Pareto Frontier non_dom = tools.sortNondominated(output[0], k=len(output[0]), first_front_only=True)[0] for ind in non_dom: fitvals = [ ind.fitness.value * norm_fact for ind.fitness.value, norm_fact in zip( ind.fitness.values, norm_facts) ] plt.plot(*fitvals, 'bo') plt.title('Pareto Front') plt.xlabel('{}'.format(obj_func_names[0])) plt.ylabel('{}'.format(obj_func_names[1])) plt.show() return results else: return results
size = len(ind1) cxpoint1 = random.randint(1, size) cxpoint2 = random.randint(1, size - 1) if cxpoint2 >= cxpoint1: cxpoint2 += 1 else: # Swap the two cx points cxpoint1, cxpoint2 = cxpoint2, cxpoint1 ind1[cxpoint1:cxpoint2], ind2[cxpoint1:cxpoint2] \ = ind2[cxpoint1:cxpoint2].copy(), ind1[cxpoint1:cxpoint2].copy() return ind1, ind2 toolbox.register("evaluate", evalSchedule) toolbox.decorate("evaluate", tools.DeltaPenality(feasible, 1.0, distance)) toolbox.register("mate", cxTwoPointCopy) toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) toolbox.register("select", tools.selTournament, tournsize=3) def ga_main(): random.seed(64) pop = toolbox.population(n=100) hof = tools.HallOfFame(1, similar=numpy.array_equal) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", numpy.mean) stats.register("std", numpy.std) stats.register("min", numpy.min) stats.register("max", numpy.max) algorithms.eaSimple(pop,
toolbox.register( "select", tools.selTournament,tournsize=tournsize) """Γίνονται register έπειτα η επιθυμία ελαχιστοποίησης της συνάρτησης, το πεδίο ορισμού της, ο πληθυσμός και τελικά η συνάρτηση η οποία γίνεται decorate απο τις feasible και distance που ορίστηκαν προηγουμένως με Δ=2X10=20""" creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) creator.create( "IndividualContainer", list , fitness= creator.FitnessMin) toolbox = base.Toolbox() # Structure initializers toolbox.register( "InitialValue", np.random.uniform, 0, 10) toolbox.register( "indiv", tools.initRepeat, creator.IndividualContainer, toolbox.InitialValue, D) toolbox.register( "population", tools.initRepeat, list , toolbox.indiv) toolbox.register( "evaluate", langerman) toolbox.decorate( "evaluate", tools.DeltaPenality (feasible, 10.0, distance)) """Όρίζονται τώρα οι τρεις στρατηγικές εξέλιξης που θα δοκιμάσουμε, χρησιμοποιώντας 100 γενεές και πληθυσμό 200 για να πετύχουμε τους χρονικούς περιορισμούς που περιγράφονται στην εκφώνηση της άσκησης. Για τους μ+λ και μ,λ αλγορίθμους χρησιμοποιούμε μ=75 , λ=125, αναλογία στην οποία καταλήξαμε βάσει αναζήτησης στο διαδύκτιο και βάσει αποτελεσμάτων στις διάφορες δοκιμές μας.""" def ea_with_stats(cxpb,mutpb,m,l,tb): pop = tb.population(n=m+l) hof = tools.HallOfFame(1) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", np.mean) stats.register("min", np.min) stats.register("max", np.max) pop, logbook = algorithms.eaSimple(pop, tb, cxpb, mutpb, ngen=100, stats=stats, halloffame=hof, verbose=False) return pop, logbook, hof def eaMuPlusLamda_with_stats(cxpb,mutpb,m,l,tb): pop = tb.population(n=m+l)
def ea_func(gens, numVariables, evalFunc, cxAlgo, cxArgs, mutAlgo, mutArgs, selArgs, eaAlgo, eaArgs, popul, cxpb, mutpb): # we want to minimize our function creator.create("FitnessMin", base.Fitness, weights=(-1.0, )) creator.create("IndividualContainer", list, fitness=creator.FitnessMin) toolbox = base.Toolbox() # gonna search in range [-100,100) toolbox.register("InitialValue", np.random.uniform, -10., 10.) toolbox.register("indiv", tools.initRepeat, creator.IndividualContainer, toolbox.InitialValue, numVariables) toolbox.register("population", tools.initRepeat, list, toolbox.indiv) toolbox.register("evaluate", evalFunc) # only our scalable function has domain limitations if (evalFunc.__name__ == 'schwefel2_22'): MIN_BOUND = np.array([-100.] * numVariables) MAX_BOUND = np.array([100.] * numVariables) def feasible(indiv): if any(indiv < MIN_BOUND) or any(indiv > MAX_BOUND): return False return True def distance(indiv): dist = 0.0 for i in range(len(indiv)): penalty = 0 if (indiv[i] < MIN_BOUND[i]): penalty = -100. - indiv[i] if (indiv[i] > MAX_BOUND[i]): penalty = indiv[i] - 100. dist = dist + penalty return dist # we set the function max as constant penalty (here named foul) foul = 100 * numVariables + 100**numVariables toolbox.decorate("evaluate", tools.DeltaPenality(feasible, foul, distance)) toolbox.register("mate", cxAlgo, **cxArgs) toolbox.register("mutate", mutAlgo, **mutArgs) toolbox.register("select", tools.selTournament, **selArgs) pop = toolbox.population(n=popul) hof = tools.HallOfFame(1) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", np.mean) stats.register("min", np.min) stats.register("max", np.max) start = time.time() pop, logbook = eaAlgo(pop, toolbox, ngen=gens, cxpb=cxpb, mutpb=mutpb, stats=stats, halloffame=hof, verbose=False, **eaArgs) end = time.time() ex_time = end - start return logbook, ex_time, hof