def run(self, seed): """ Trains this classifier. :param seed: seed used to partition training set at every generation. The (sub)sets will be constant throughout all the evolutionary process, allowing a direct comparison between individuals from different generations. :type seed: int :rtype: tuple :return: a tuple containing two individuals.Individual objects, where the first individual is the best solution (according to fitness) found throughout all the evolutionary process, and the second individual the best solution from the last generation. """ # Statistics computation stats = tools.Statistics(lambda ind: ind.fitness) for stat_name, stat_func in PBILLogger.population_operators: stats.register(stat_name, stat_func) # An object that keeps track of the best individual found so far. self._hof = HallOfFame(maxsize=1) # type: HallOfFame best_last, logbook = self.__run__(seed=seed, ngen=self.n_generations, stats=stats, verbose=True) best_overall = self._hof[0] # type: Individual self._hof = None gc.collect() return best_overall, best_last
def _setup(self, refiner, ngen=NGEN, ngen_comm=NGEN_COMM, nswarms=NSWARMS, **kwargs): if not self._has_been_setup: logger.info( "Setting up the DEAP CMA-ES refinement algorithm (ngen=%d)" % ngen) refiner.status.message = "Setting up algorithm..." # Process some general stuff: bounds = np.array(refiner.ranges) #@UndefinedVariable create_individual = self._individual_creator(refiner, bounds) # Setup strategy: #TODO make the others random parents = [None] * nswarms parents[0] = create_individual(refiner.history.initial_solution) for i in range(1, nswarms): parents[i] = create_individual([ random.uniform(bounds[j, 0], bounds[j, 1]) for j in range(len(refiner.history.initial_solution)) ]) strategy = SwarmStrategy( parents=parents, sigma=1.0 / 10.0, ranges=bounds, stop=self._stop, ) # Toolbox setup: toolbox = base.Toolbox() toolbox.register("generate", strategy.generate, create_individual) toolbox.register("update", strategy.update) # Hall of fame & stats: logger.info("Creating hall-off-fame and statistics") halloffame = HallOfFame( 1, similar=lambda a1, a2: np.all(a1 == a2) ) #PyXRDParetoFront(similar=lambda a1, a2: np.all(a1 == a2)) stats = self._create_stats() # Create algorithm self.algorithm = SwarmAlgorithm(toolbox, halloffame, stats, ngen=ngen, ngen_comm=ngen_comm, refiner=refiner, stop=self._stop) self._has_been_setup = True return self.algorithm
def __init__(self, **kwargs): ## TODO: add ability to determine if evolution has stopped ## TODO: add archive ## TODO: add generating and collecting different statistics ## TODO: add logging # create initial populations of all species # taking part in coevolution self.kwargs = deepcopy(kwargs) self.ENV = kwargs["env"] self.SPECIES = kwargs["species"] self.INTERACT_INDIVIDUALS_COUNT = kwargs["interact_individuals_count"] self.GENERATIONS = kwargs["generations"] self.solstat = kwargs.get("solstat", lambda sols: {}) #choose = kwargs["operators"]["choose"] self.build_solutions = kwargs["operators"]["build_solutions"] self.fitness = kwargs["operators"]["fitness"] self.assign_credits = kwargs["operators"]["assign_credits"] self.analyzers = kwargs.get("analyzers", []) self.USE_CREDIT_INHERITANCE = kwargs.get("use_credit_inheritance", False) self.HALL_OF_FAME_SIZE = kwargs.get("hall_of_fame_size", 0) self._result = None self.stat = tools.Statistics(key=lambda x: x.fitness) self.stat.register("best", rounddec(numpy.max)) self.stat.register("min", rounddec(numpy.min)) self.stat.register("avg", rounddec(numpy.average)) self.stat.register("std", rounddec(numpy.std)) self.logbook = tools.Logbook() self.kwargs['logbook'] = self.logbook ## TODO: make processing of population consisting of 1 element uniform ## generate initial population self.pops = {s: self._generate_k(s.initialize(self.kwargs, s.pop_size)) if not s.fixed else self._generate_k([s.representative_individual]) for s in self.SPECIES} ## make a copy for logging. TODO: remake it with logbook later. self.initial_pops = {s.name: deepcopy(pop) for s, pop in self.pops.items()} ## checking correctness for s, pop in self.pops.items(): sm = sum(p.k for p in pop) assert sm == self.INTERACT_INDIVIDUALS_COUNT, \ "For specie {0} count doesn't equal to {1}. Actual value {2}".format(s, self.INTERACT_INDIVIDUALS_COUNT, sm) print("Initialization finished") self.hall = HallOfFame(self.HALL_OF_FAME_SIZE) self.kwargs['gen'] = 0 pass
def _select_best(self, pop): """Select the best individuals of the population. :param pop: The population :type pop: Any iterable type :return: The best individuals found :rtype: :py:class:`~deap.tools.HallOfFame` of individuals """ hof = HallOfFame(self.pop_size) hof.update(pop) return hof
def main(): pop = toolbox.population(n=rd.pop_size) stats_cost = tools.Statistics(lambda ind: ind.fitness.values[0]) mstats = tools.MultiStatistics(cost=stats_cost) mstats.register("min", np.min, axis=0) mstats.register("median", np.median, axis=0) mstats.register("max", np.max, axis=0) hof = HallOfFame(1) pop, logbook = my_ea.ea(pop, toolbox, rd.cxpb, rd.mutpb, rd.elitism, rd.gens, stats=mstats, halloffame=hof, verbose=True) return pop, mstats, hof, logbook
def evolution(env: Environment, number_of_rays: int, ray_distribution: str, angle_lower_bound: int, angle_upper_bound: int, length_lower_bound: int, length_upper_bound: int, no_of_reflective_segments: int, distance_limit: int, length_limit: int, population_size: int, number_of_generations: int, xover_prob: float, mut_angle_prob: float, mut_length_prob: float, shift_segment_prob: float, rotate_segment_prob: float, resize_segment_prob: float): # Initiating evolutionary algorithm creator.create("Fitness", base.Fitness, weights=(1.0, )) creator.create("Individual", Component3D, fitness=creator.Fitness) toolbox = base.Toolbox() toolbox.register("individual", creator.Individual, number_of_rays=number_of_rays, ray_distribution=ray_distribution, base_length=env.road_length, base_width=env.road_width) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("select", tools.selTournament, tournsize=2) # Initiating first population pop = toolbox.population(n=population_size) # Evaluating fitness fitnesses = [] for item in pop: fitnesses.append(evaluate(item, env)) for ind, fit in zip(pop, fitnesses): ind.fitness = fit # Rendering individuals in initial population as images for i in range(len(pop)): draw_road(pop[i], f"{i}") print("Drawing initial population finished") stats_line = f"0, {max(fitnesses)}, {sum(fitnesses)/population_size}" log_stats_init(f"stats", stats_line) # Initiating elitism hof = HallOfFame(1) print("Start of evolution") # Begin the evolution for g in range(number_of_generations): # A new generation print(f"-- Generation {g} --") # Select the next generation individuals 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]): # cross two individuals with probability xover_prob if random.random() < xover_prob: mate(child1, child2) # fitness values of the children must be recalculated later child1.fitness = 0 child2.fitness = 0 for mutant in offspring: if env.configuration == "multiple free": if random.random() < shift_segment_prob: mutant.reflective_segments = shift_one_segment( mutant.reflective_segments, "x") mutant.fitness = 0 if random.random() < shift_segment_prob: mutant.reflective_segments = shift_one_segment( mutant.reflective_segments, "y") mutant.fitness = 0 if random.random() < rotate_segment_prob: mutant.reflective_segments = rotate_one_segment( mutant.reflective_segments) mutant.fitness = 0 if random.random() < resize_segment_prob: mutant.reflective_segments = resize_one_segment( mutant.reflective_segments) mutant.fitness = 0 if env.configuration == "two connected": if random.random() < mut_angle_prob: mutate_angle(mutant) mutant.fitness = 0 if random.random() < mut_length_prob: mutate_length(mutant, length_upper_bound, length_lower_bound) mutant.fitness = 0 # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in offspring if ind.fitness == 0] fitnesses = [] for item in invalid_ind: fitnesses.append(evaluate(item, env)) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness = fit print(f" Evaluated {len(invalid_ind)} individuals") # The population is entirely replaced by the offspring pop[:] = offspring hof.update(pop) # best_ind = tools.selBest(pop, 1)[0] best_ind = hof[0] fitnesses = [] for item in pop: fitnesses.append(evaluate(item, env)) print(fitnesses) stats_line = f"{g+1}, {best_ind.fitness}, {sum(fitnesses) / population_size}" log_stats_append(f"stats", stats_line) print(f"Best individual has fitness: {best_ind.fitness}") draw(best_ind, f"best{g}", env) print("-- End of (successful) evolution --") print("--")
def _genetic_algo(model, initial_pop, exp_ess, base_biomass, toolbox, GA_param, distance, processes, outputs): index = [i for i in initial_pop.index] print('made it to the GA') print(outputs) # Initial population evaluation pop = toolbox.population_guess() if 'history_name' in outputs.keys(): history.update(pop) print('I will evaluate the initial population') fits = toolbox.map(toolbox.evaluate, pop, initial_pop, model, base_biomass, exp_ess, distance, processes) print('Fitnesses that will be attributed to individuals %s' % (fits, )) for ind, fit in zip(pop, fits): ind.fitness.values = fit print('Finished evaluating initial population') # Record outputs if 'hall_of_fame_name' in outputs.keys(): # Hall of fame hof = HallOfFame(maxsize=outputs.get('hall_of_fame_size')) hof.update(pop) if 'logbook_name' in outputs.keys(): multi_level = pd.MultiIndex( levels=[['Fitness', 'Size'], ['Mean', 'Std', 'Max', 'Min', 'Sizes']], labels=[[ 0, 0, 0, 0, 1, ], [0, 1, 2, 3, 4]]) data_logbook = [] #valid_logbook = [] # The GA itself for g in range(GA_param.get('NGEN')): print('Starting generation %s' % (g, )) offspring = toolbox.select(pop, k=len(pop)) offspring = list(map(toolbox.clone, offspring)) for child1, child2 in zip(offspring[::2], offspring[1::2]): # Keep the parents for comparison parent1 = list(map(toolbox.clone, [child1]))[0] parent2 = list(map(toolbox.clone, [child2]))[0] rand_nb = random.random() if rand_nb < GA_param.get('CXPB'): print('doing a crossover') if child1 == child2: print('generating a new individual') l = toolbox.generate_new_individual( initial_pop.index, model, base_biomass) child2 = creator.Individual(l) if child2 == parent2: print('generating new individual didnt work') toolbox.mate(child1, child2) # Assess the efficiency of crossover if child1 == parent1 or child1 == parent2: print('crossover yielded identical individuals') l = toolbox.generate_new_individual( initial_pop.index, model, base_biomass) child2 = creator.Individual(l) toolbox.mate(child1, child2) else: print('crossover actually worked') del child1.fitness.values del child2.fitness.values for mutant in offspring: rand_nb = random.random() if rand_nb < GA_param.get('MUTPB'): toolbox.mutate(mutant) del mutant.fitness.values # The individuals that have been crossed or mutated will have an invalid fitness # and will need to be r-evaluated (saves on computing time) invalid_ind = [ind for ind in offspring if not ind.fitness.valid] print('I will evaluate %s invalid individuals, wish me luck!' % (len(invalid_ind), )) fitnesses = toolbox.map(toolbox.evaluate, invalid_ind, initial_pop, model, base_biomass, exp_ess, distance, processes) print(fitnesses) for ind, fit in zip(invalid_ind, fitnesses): print(sum(ind)) ind.fitness.values = fit print(" Evaluated %s individuals" % (len(invalid_ind), )) pop[:] = offspring # Save stats of the evolution print('Trying to compile stats') if 'logbook_name' in outputs.keys(): current_stats = record_stats(pop, g, multi_level) # Manually update the logbook data_logbook.append(current_stats) if 'hall_of_fame_name' in outputs.keys(): hof.update(pop) if 'history_name' in outputs.keys(): history.update(pop) # Outputs # Saving the logbook if 'logbook_name' in outputs.keys(): final_logbook = pd.concat(data_logbook) final_logbook.to_csv(outputs.get('logbook_name')) # Get the best individuals from the hall of fame (metabolites) if 'hall_of_fame_name' in outputs.keys(): hof_df = get_ind_composition(hof, index) hof_df.to_csv(outputs.get('hall_of_fame_name'))
def mainPart(x_, y_, pset, max_=5, pop_n=100, random_seed=2, cxpb=0.8, mutpb=0.1, ngen=5, tournsize=3, max_value=10, double=False, score=None, cal_dim=True, target_dim=None, inter_add=True, iner_add=True, random_add=False, store=True): """ Parameters ---------- target_dim max_ inter_add iner_add random_add cal_dim score double x_ y_ pset pop_n random_seed cxpb mutpb ngen tournsize max_value Returns ------- """ if score is None: score = [r2_score, explained_variance_score] if cal_dim: assert all([isinstance(i, Dim) for i in pset.dim_list ]), "all import dim of pset should be Dim object" random.seed(random_seed) toolbox = Toolbox() if isinstance(pset, ExpressionSet): PTrees = ExpressionTree Generate = genHalfAndHalf mutate = mutNodeReplacement mate = cxOnePoint elif isinstance(pset, FixedSet): PTrees = FixedTree Generate = generate_index mutate = mutUniForm_index mate = partial(cxOnePoint_index, pset=pset) else: raise NotImplementedError("get wrong pset") if double: Fitness_ = creator.create("Fitness_", Fitness, weights=(1.0, 1.0)) else: Fitness_ = creator.create("Fitness_", Fitness, weights=(1.0, )) PTrees_ = creator.create("PTrees_", PTrees, fitness=Fitness_, dim=dnan, withdim=0) toolbox.register("generate", Generate, pset=pset, min_=1, max_=max_) toolbox.register("individual", initIterate, container=PTrees_, generator=toolbox.generate) toolbox.register('population', initRepeat, container=list, func=toolbox.individual) # def selection toolbox.register("select_gs", selTournament, tournsize=tournsize) toolbox.register("select_kbest_target_dim", selKbestDim, dim_type=target_dim, fuzzy=True) toolbox.register("select_kbest_dimless", selKbestDim, dim_type="integer") toolbox.register("select_kbest", selKbestDim, dim_type='ignore') # def mate toolbox.register("mate", mate) # def mutate toolbox.register("mutate", mutate, pset=pset) if isinstance(pset, ExpressionSet): toolbox.decorate( "mate", staticLimit(key=operator.attrgetter("height"), max_value=max_value)) toolbox.decorate( "mutate", staticLimit(key=operator.attrgetter("height"), max_value=max_value)) # def elaluate toolbox.register("evaluate", calculatePrecision, pset=pset, x=x_, y=y_, scoring=score[0], cal_dim=cal_dim, inter_add=inter_add, iner_add=iner_add, random_add=random_add) toolbox.register("evaluate2", calculatePrecision, pset=pset, x=x_, y=y_, scoring=score[1], cal_dim=cal_dim, inter_add=inter_add, iner_add=iner_add, random_add=random_add) toolbox.register("parallel", parallelize, n_jobs=1, func=toolbox.evaluate, respective=False) toolbox.register("parallel2", parallelize, n_jobs=1, func=toolbox.evaluate2, respective=False) pop = toolbox.population(n=pop_n) haln = 10 hof = HallOfFame(haln) stats1 = Statistics(lambda ind: ind.fitness.values[0] if ind and ind.y_dim in target_dim else 0) stats1.register("max", np.max) stats2 = Statistics(lambda ind: ind.y_dim in target_dim if ind else 0) stats2.register("countable_number", np.sum) stats = MultiStatistics(score1=stats1, score2=stats2) population, logbook = eaSimple(pop, toolbox, cxpb=cxpb, mutpb=mutpb, ngen=ngen, stats=stats, halloffame=hof, pset=pset, store=store) return population, hof
def __init__(self, pset, pop=500, gen=20, mutate_prob=0.5, mate_prob=0.8, hall=1, re_hall=1, re_Tree=None, initial_min=None, initial_max=3, max_value=5, scoring=(r2_score,), score_pen=(1,), filter_warning=True, cv=1, add_coef=True, inter_add=True, inner_add=False, vector_add=False, out_add=False, flat_add=False, cal_dim=False, dim_type=None, fuzzy=False, n_jobs=1, batch_size=40, random_state=None, stats=None, verbose=True, migrate_prob=0, tq=True, store=False, personal_map=False, stop_condition=None, details=False, classification=False, score_object="y", sub_mu_max=1, limit_type="h_bgp", batch_para=False): """ Parameters ---------- pset:SymbolSet the feature x and target y and others should have been added. pop: int number of population. gen: int number of generation. mutate_prob:float probability of mutate. mate_prob:float probability of mate(crossover). initial_max:int max initial size of expression when first producing. initial_min : None,int min initial size of expression when first producing. max_value:int max size of expression. limit_type: "height" or "length",","h_bgp" limitation type for max_value, but don't affect initial_max, initial_min. hall:int,>=1 number of HallOfFame (elite) to maintain. re_hall:None or int>=2 Notes: only valid when hall number of HallOfFame to add to next generation. re_Tree: int number of new features to add to next generation. 0 is false to add. personal_map:bool or "auto" "auto" is using 'premap' and with auto refresh the 'premap' with individual.\n True is just using constant 'premap'.\n False is just use the prob of terminals. scoring: list of Callable, default is [sklearn.metrics.r2_score,] See Also ``sklearn.metrics`` score_pen: tuple of 1, -1 or float but 0. >0 : max problem, best is positive, worse -np.inf. <0 : min problem, best is negative, worse np.inf. Notes: if multiply score method, the scores must be turn to same dimension in prepossessing or weight by score_pen. Because the all the selection are stand on the mean(w_i*score_i) Examples:: scoring = [r2_score,] score_pen= [1,] cv:sklearn.model_selection._split._BaseKFold,int the shuffler must be False, default=1 means no cv. filter_warning:bool filter warning or not. add_coef:bool add coef in expression or not. inter_add:bool add intercept constant or not. inner_add:bool add inner coefficients or not. out_add:bool add out coefficients or not. flat_add:bool add flat coefficients or not. n_jobs:int default 1, advise 6. batch_size:int default 40, depend of machine. random_state:int None,int. cal_dim:bool escape the dim calculation. dim_type:Dim or None or list of Dim "coef": af(x)+b. a,b have dimension,f(x)'s dimension is not dnan. \n "integer": af(x)+b. f(x) is with integer dimension. \n [Dim1,Dim2]: f(x)'s dimension in list. \n Dim: f(x) ~= Dim. (see fuzzy) \n Dim: f(x) == Dim. \n None: f(x) == pset.y_dim fuzzy:bool choose the dim with same base with dim_type, such as m,m^2,m^3. stats:dict details of logbook to show. \n Map:\n values = {"max": np.max, "mean": np.mean, "min": np.mean, "std": np.std, "sum": np.sum} keys = {\n "fitness": just see fitness[0], \n "fitness_dim_max": max problem, see fitness with demand dim,\n "fitness_dim_min": min problem, see fitness with demand dim,\n "dim_is_target": demand dim,\n "coef": dim is True, coef have dim, \n "integer": dim is integer, \n ... } if stats is None, default is: for cal_dim=True: stats = {"fitness_dim_max": ("max",), "dim_is_target": ("sum",)} for cal_dim=False stats = {"fitness": ("max",)} if self-definition, the key is func to get attribute of each ind. Examples:: def func(ind): return ind.fitness[0] stats = {func: ("mean",), "dim_is_target": ("sum",)} verbose:bool print verbose logbook or not. tq:bool print progress bar or not. store:bool or path bool or path. stop_condition:callable stop condition on the best ind of hall, which return bool,the true means stop loop. Examples:: def func(ind): c = ind.fitness.values[0]>=0.90 return c details:bool return expr and predict_y or not. classification: bool classification or not. score_object: score by y or delta y (for implicit function). """ super(BaseLoop, self).__init__() assert initial_max <= max_value, "the initial size of expression should less than max_value limitation" if cal_dim: assert all( [isinstance(i, Dim) for i in pset.dim_ter_con.values()]), \ "all import dim of pset should be Dim object." self.details = details self.max_value = max_value self.pop = pop self.gen = gen self.mutate_prob = mutate_prob self.mate_prob = mate_prob self.migrate_prob = migrate_prob self.verbose = verbose self.cal_dim = cal_dim self.re_hall = re_hall self.re_Tree = re_Tree self.store = store self.limit_type = limit_type self.data_all = [] self.personal_map = personal_map self.stop_condition = stop_condition self.population = [] self.rand_state = None self.random_state = random_state self.sub_mu_max = sub_mu_max self.population_next = [] self.cpset = CalculatePrecisionSet(pset, scoring=scoring, score_pen=score_pen, filter_warning=filter_warning, cal_dim=cal_dim, add_coef=add_coef, inter_add=inter_add, inner_add=inner_add, vector_add=vector_add, out_add=out_add, flat_add=flat_add, cv=cv, n_jobs=n_jobs, batch_size=batch_size, tq=tq, fuzzy=fuzzy, dim_type=dim_type, details=details, classification=classification, score_object=score_object, batch_para=batch_para ) Fitness_ = newclass.create("Fitness_", Fitness, weights=score_pen) self.PTree = newclass.create("PTrees", SymbolTree, fitness=Fitness_) # def produce if initial_min is None: initial_min = 2 self.register("genGrow", genGrow, pset=self.cpset, min_=initial_min, max_=initial_max + 1, personal_map=self.personal_map) self.register("genFull", genFull, pset=self.cpset, min_=initial_min, max_=initial_max + 1, personal_map=self.personal_map) self.register("genHalf", genGrow, pset=self.cpset, min_=initial_min, max_=initial_max + 1, personal_map=self.personal_map) self.register("gen_mu", genGrow, min_=1, max_=self.sub_mu_max + 1, personal_map=self.personal_map) # def selection self.register("select", selTournament, tournsize=2) self.register("selKbestDim", selKbestDim, dim_type=self.cpset.dim_type, fuzzy=self.cpset.fuzzy) self.register("selBest", selBest) self.register("mate", cxOnePoint) # def mutate self.register("mutate", mutUniform, expr=self.gen_mu, pset=self.cpset) self.decorate("mate", staticLimit(key=operator.attrgetter(limit_type), max_value=self.max_value)) self.decorate("mutate", staticLimit(key=operator.attrgetter(limit_type), max_value=self.max_value)) if stats is None: if cal_dim: if score_pen[0] > 0: stats = {"fitness_dim_max": ("max",), "dim_is_target": ("sum",)} else: stats = {"fitness_dim_min": ("min",), "dim_is_target": ("sum",)} else: if score_pen[0] > 0: stats = {"fitness": ("max",)} else: stats = {"fitness": ("min",)} self.stats = Statis_func(stats=stats) logbook = Logbook() logbook.header = ['gen'] + (self.stats.fields if self.stats else []) self.logbook = logbook if hall is None: hall = 1 self.hall = HallOfFame(hall) if re_hall is None: self.re_hall = None else: if re_hall == 1 or re_hall == 0: print("re_hall should more than 1") re_hall = 2 assert re_hall >= hall, "re_hall should more than hall" self.re_hall = HallOfFame(re_hall)
def create_halloffame(maxsize, rel_tol=1e-6): return HallOfFame(maxsize, similar=EqualIndividual(rel_tol))
def __init__(self, traj, optimizee_create_individual, optimizee_fitness_weights, parameters, optimizee_bounding_func=None): super().__init__( traj, optimizee_create_individual=optimizee_create_individual, optimizee_fitness_weights=optimizee_fitness_weights, parameters=parameters, optimizee_bounding_func=optimizee_bounding_func) self.optimizee_bounding_func = optimizee_bounding_func __, self.optimizee_individual_dict_spec = dict_to_list( optimizee_create_individual(), get_dict_spec=True) traj.f_add_parameter('seed', parameters.seed, comment='Seed for RNG') traj.f_add_parameter('popsize', parameters.popsize, comment='Population size') # 185 traj.f_add_parameter('CXPB', parameters.CXPB, comment='Crossover term') traj.f_add_parameter('MUTPB', parameters.MUTPB, comment='Mutation probability') traj.f_add_parameter('n_iteration', parameters.NGEN, comment='Number of generations') traj.f_add_parameter('indpb', parameters.indpb, comment='Mutation parameter') traj.f_add_parameter('tournsize', parameters.tournsize, comment='Selection parameter') # ------- Create and register functions with DEAP ------- # # delay_rate, slope, std_err, max_fraction_active creator.create("FitnessMax", base.Fitness, weights=self.optimizee_fitness_weights) creator.create("Individual", list, fitness=creator.FitnessMax) toolbox = base.Toolbox() # Structure initializers toolbox.register("individual", tools.initIterate, creator.Individual, lambda: dict_to_list(optimizee_create_individual())) toolbox.register("population", tools.initRepeat, list, toolbox.individual) # Operator registering # This complex piece of code is only necessary because we're using the # DEAP framework and would like to decorate the DEAP mutation operator def bounding_decorator(func): def bounding_wrapper(*args, **kwargs): if self.optimizee_bounding_func is None: return func(*args, **kwargs) else: # Deap Functions modify individuals in-place, Hence we must do the same result_individuals_deap = func(*args, **kwargs) result_individuals = [ list_to_dict(x, self.optimizee_individual_dict_spec) for x in result_individuals_deap ] bounded_individuals = [ self.optimizee_bounding_func(x) for x in result_individuals ] for i, deap_indiv in enumerate(result_individuals_deap): deap_indiv[:] = dict_to_list(bounded_individuals[i]) print("Bounded Individual: {}".format(bounded_individuals)) return result_individuals_deap return bounding_wrapper toolbox.register("mate", tools.cxBlend, alpha=parameters.matepar) toolbox.decorate("mate", bounding_decorator) toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=parameters.mutpar, indpb=traj.indpb) toolbox.decorate("mutate", bounding_decorator) toolbox.register("select", tools.selTournament, tournsize=traj.tournsize) # ------- Initialize Population and Trajectory -------- # # NOTE: The Individual object implements the list interface. self.pop = toolbox.population(n=traj.popsize) self.eval_pop_inds = [ind for ind in self.pop if not ind.fitness.valid] self.eval_pop = [ list_to_dict(ind, self.optimizee_individual_dict_spec) for ind in self.eval_pop_inds ] self.g = 0 # the current generation self.toolbox = toolbox # the DEAP toolbox self.hall_of_fame = HallOfFame(20) self._expand_trajectory(traj)
def init_population(self): self.pop = self.toolbox.population(n=self.indi) self.hof = HallOfFame(5, similar=np.array_equal)
def new_hall_of_fame(self) -> HallOfFame: return HallOfFame(maxsize=50)
def mainPart(x_, y_, pset, pop_n=100, random_seed=1, cxpb=0.8, mutpb=0.1, ngen=5, alpha=1, tournsize=3, max_value=10, double=False, score=None, **kargs): """ Parameters ---------- score double x_ y_ pset pop_n random_seed cxpb mutpb ngen alpha tournsize max_value kargs Returns ------- """ max_ = pset.max_ if score is None: score = [r2_score, explained_variance_score] random.seed(random_seed) toolbox = Toolbox() if isinstance(pset, PrimitiveSet): PTrees = ExpressionTree Generate = genHalfAndHalf mutate = mutNodeReplacement mate = cxOnePoint elif isinstance(pset, FixedPrimitiveSet): PTrees = FixedExpressionTree Generate = generate_ mate = partial(cxOnePoint_index, pset=pset) mutate = mutUniForm_index else: raise NotImplementedError("get wrong pset") if double: creator.create("Fitness_", Fitness, weights=(1.0, 1.0)) else: creator.create("Fitness_", Fitness, weights=(1.0,)) creator.create("PTrees_", PTrees, fitness=creator.Fitness_) toolbox.register("generate_", Generate, pset=pset, min_=None, max_=max_) toolbox.register("individual", initIterate, container=creator.PTrees_, generator=toolbox.generate_) toolbox.register('population', initRepeat, container=list, func=toolbox.individual) # def selection toolbox.register("select_gs", selTournament, tournsize=tournsize) # def mate toolbox.register("mate", mate) # def mutate toolbox.register("mutate", mutate, pset=pset) if isinstance(pset, PrimitiveSet): toolbox.decorate("mate", staticLimit(key=operator.attrgetter("height"), max_value=max_value)) toolbox.decorate("mutate", staticLimit(key=operator.attrgetter("height"), max_value=max_value)) # def elaluate toolbox.register("evaluate", calculate, pset=pset, x=x_, y=y_, score_method=score[0], **kargs) toolbox.register("evaluate2", calculate, pset=pset, x=x_, y=y_, score_method=score[1], **kargs) stats1 = Statistics(lambda ind: ind.fitness.values[0]) stats = MultiStatistics(score1=stats1, ) stats.register("avg", np.mean) stats.register("max", np.max) pop = toolbox.population(n=pop_n) haln = 5 hof = HallOfFame(haln) if double: population, logbook = multiEaSimple(pop, toolbox, cxpb=cxpb, mutpb=mutpb, ngen=ngen, stats=stats, alpha=alpha, halloffame=hof, pset=pset) else: population, logbook = eaSimple(pop, toolbox, cxpb=cxpb, mutpb=mutpb, ngen=ngen, stats=stats, halloffame=hof, pset=pset) return population, logbook, hof
def evolution( env: Environment, number_of_rays: int, ray_distribution: str, angle_lower_bound: int, angle_upper_bound: int, length_lower_bound: int, length_upper_bound: int, no_of_reflective_segments: int, distance_limit: int, length_limit: int, population_size: int, number_of_generations: int, xover_prob: float, mut_angle_prob: float, mut_length_prob: float, shift_segment_prob: float, rotate_segment_prob: float, resize_segment_prob: float, tilt_base_prob: float, base_length: int, base_slope: int, base_angle_limit_min: int, base_angle_limit_max: int): # Initiating evolutionary algorithm creator.create("Fitness", base.Fitness, weights=(1.0, )) base.Fitness.weights = (1.0, 10.0, 5.0, -1.0) creator.create("Individual", Component, fitness=creator.Fitness) toolbox = base.Toolbox() toolbox.register("individual", creator.Individual, env=env, number_of_rays=number_of_rays, ray_distribution=ray_distribution, angle_lower_bound=angle_lower_bound, angle_upper_bound=angle_upper_bound, length_lower_bound=length_lower_bound, length_upper_bound=length_upper_bound, no_of_reflective_segments=no_of_reflective_segments, distance_limit=distance_limit, length_limit=length_limit, base_length=base_length, base_slope=base_slope) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("evaluate", evaluate) if env.quality_criterion == "nsgaii": toolbox.register("select", tools.selNSGA2) else: toolbox.register("select", tools.selTournament, tournsize=2) # Initiating first population pop = toolbox.population(n=population_size) # Evaluating fitness fitnesses = [] for item in pop: fitnesses.append(evaluate(item, env)) for ind, fit in zip(pop, fitnesses): ind.fitness = fit if env.quality_criterion != "nsgaii": if env.configuration == "two connected": stats_line = f"generation, best fitness, average fitness, fitness array, left segment angle, " \ f"left segment length, right segment angle, right segment length \n" else: stats_line = f"generation, best fitness, average fitness, fitness array, reflective segments \n" log_stats_init(f"stats", stats_line) # Initiating elitism if env.quality_criterion == "nsgaii": pop = toolbox.select(pop, len(pop)) hof = tools.ParetoFront() hof.update(pop) else: hof = HallOfFame(1) hof.update(pop) print("Start of evolution") # Begin the evolution for g in range(number_of_generations): # A new generation print(f"-- Generation {g} --") # Select the next generation individuals if env.quality_criterion == "nsgaii": offspring = tools.selTournamentDCD(pop, len(pop)) offspring = [toolbox.clone(ind) for ind in offspring] else: offspring = toolbox.select(pop, len(pop)) offspring = list(map(toolbox.clone, offspring)) # Apply crossover and mutation on the offspring for child1, child2 in zip(offspring[::2], offspring[1::2]): # cross two individuals with probability xover_prob if env.configuration == "multiple free": if random.random() < xover_prob: x_over_multiple_segments(child1, child2) # fitness values of the children must be recalculated later child1.fitness = None child2.fitness = None if env.configuration == "two connected": if random.random() < xover_prob: x_over_two_segments(child1, child2) # fitness values of the children must be recalculated later child1.fitness = None child2.fitness = None for mutant in offspring: if env.configuration == "multiple free": if random.random() < shift_segment_prob: mutant.reflective_segments = shift_one_segment( mutant.reflective_segments, "x") mutant.fitness = None if random.random() < shift_segment_prob: mutant.reflective_segments = shift_one_segment( mutant.reflective_segments, "y") mutant.fitness = None if random.random() < rotate_segment_prob: mutant.reflective_segments = rotate_one_segment( mutant.reflective_segments) mutant.fitness = None if random.random() < resize_segment_prob: mutant.reflective_segments = resize_one_segment( mutant.reflective_segments) mutant.fitness = None if random.random() < tilt_base_prob: mutant.base_slope = tilt_base(mutant.base_slope, base_angle_limit_min, base_angle_limit_max) mutant.calculate_base() mutant.original_rays = mutant.sample_rays( number_of_rays, ray_distribution) mutant.fitness = None if env.configuration == "two connected": if random.random() < mut_angle_prob: mutate_angle(mutant) mutant.fitness = None if random.random() < mut_length_prob: mutate_length(mutant, length_upper_bound, length_lower_bound) mutant.fitness = None # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in offspring if ind.fitness is None] fitnesses = [] for item in invalid_ind: fitnesses.append(evaluate(item, env)) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness = fit if env.quality_criterion == "nsgaii": pop = toolbox.select(offspring + pop, population_size) else: pop[:] = offspring hof.update(pop) best_ind = hof[0] fitnesses = [] for item in pop: fitnesses.append(item.fitness) print(fitnesses) if env.configuration == "two connected" and env.quality_criterion != "nsgaii": stats_line = f"{g+1}, {best_ind.fitness}, {sum(fitnesses) / population_size}, {best_ind.fitness_array}, " \ f"left angle: {180-best_ind.left_angle+best_ind.base_slope}, " \ f"left length: {best_ind.left_length_coef*best_ind.base_length}, " \ f"right angle: {best_ind.right_angle-best_ind.base_slope}, " \ f"right length: {best_ind.right_length_coef*best_ind.base_length} " log_stats_append(f"stats", stats_line) if env.configuration == "multiple free" and env.quality_criterion != "nsgaii": stats_line = f"{g + 1}, {best_ind.fitness}, {sum(fitnesses) / population_size}, {best_ind.fitness_array}, " for reflective_segment in best_ind.reflective_segments: dimensions = f" start: {reflective_segment.p1}, end: {reflective_segment.p2}" stats_line = stats_line + dimensions log_stats_append(f"stats", stats_line) print(f"Best individual has fitness: {best_ind.fitness}") draw(best_ind, f"best{g}", env) if env.quality_criterion == "nsgaii": unique = choose_unique(hof, env.configuration) stats_line = f"index, fitness array" log_stats_init(f"stats", stats_line) for index in range(len(unique)): draw(unique[index], f"unique{index}", env) if env.configuration == "two connected": stats_line = f"{index}, {unique[index].fitness}," \ f"left angle: {180-unique[index].left_angle+unique[index].base_slope}, " \ f"left length: {unique[index].left_length_coef*unique[index].base_length}, " \ f"right angle: {unique[index].right_angle-unique[index].base_slope}, " \ f"right length: {unique[index].right_length_coef*unique[index].base_length} " else: stats_line = f"{index}, {unique[index].fitness}, {unique[index].base_slope}" for reflective_segment in unique[index].reflective_segments: dimensions = f" start: {reflective_segment.p1}, end: {reflective_segment.p2}" stats_line = stats_line + dimensions log_stats_append(f"stats", stats_line) print("-- End of (successful) evolution --") print("--")