weights : np.array normalization : {{'no', 'front', 'ever'}} extreme_points_as_reference_points : bool Returns ------- rnsga2 : :class:`~pymoo.model.algorithm.Algorithm` Returns an RNSGA2 algorithm object. """ rnsga2 = nsga2(**kwargs) rnsga2.epsilon = epsilon rnsga2.weights = weights rnsga2.normalization = normalization rnsga2.selection = RandomSelection() rnsga2.survival = RankAndModifiedCrowdingSurvival( ref_points, epsilon, weights, normalization, extreme_points_as_reference_points) return rnsga2 parse_doc_string(rnsga2)
One strategy to introduce adaptive weights (F) during one run. The option allows the same dither to be used in one iteration ('scalar') or a different one for each individual ('vector). jitter : bool Another strategy for adaptive weights (F). Here, only a very small value is added or substracted to the weight used for the crossover for each individual. Returns ------- de : :class:`~pymoo.model.algorithm.Algorithm` Returns an DifferentialEvolution algorithm object. """ _, _selection, _n, _mutation, = variant.split("/") return DifferentialEvolution( variant, CR, F, dither, jitter, pop_size=pop_size, sampling=sampling, **kwargs) parse_doc_string(de)
self.arrow_style = kwargs["arrow_style"] def _do(self): # initial a figure with a single plot self.init_figure() # equal axis length and no ticks equal_axis(self.ax) no_ticks(self.ax) # determine the overall scale of points _F = np.row_stack([e[0] for e in self.to_plot]) _min, _max = _F.min(axis=0), _F.max(axis=0) V = get_uniform_points_around_circle(self.n_dim) plot_axes_arrow(self.ax, V, extend_factor=self.axis_extension, **{**self.axis_style, **self.arrow_style}) plot_axis_labels(self.ax, V, self.get_labels(), **self.axis_label_style) # normalize in range for this plot - here no implicit normalization as in radviz bounds = parse_bounds(self.bounds, self.n_dim) to_plot_norm = normalize(self.to_plot, bounds) for k, (F, kwargs) in enumerate(to_plot_norm): N = (F[..., None] * V).sum(axis=1) self.ax.scatter(N[:, 0], N[:, 1], **kwargs) parse_doc_string(StarCoordinate.__init__)
denom = nadir_point - utopian_point denom[denom == 0] = 1e-12 # normalize by ideal point and intercepts N = (F - utopian_point) / denom dist_matrix = load_function("calc_perpendicular_distance")(N, niches) niche_of_individuals = np.argmin(dist_matrix, axis=1) dist_to_niche = dist_matrix[np.arange(F.shape[0]), niche_of_individuals] return niche_of_individuals, dist_to_niche, dist_matrix def calc_niche_count(n_niches, niche_of_individuals): niche_count = np.zeros(n_niches, dtype=np.int) index, count = np.unique(niche_of_individuals, return_counts=True) niche_count[index] = count return niche_count # ========================================================================================================= # Interface # ========================================================================================================= def nsga3(*args, **kwargs): return NSGA3(*args, **kwargs) parse_doc_string(NSGA3.__init__)
# make a step and create the offsprings self.off = self._step() # evaluate the offsprings self.evaluator.eval(self.problem, self.off, algorithm=self) survivors = [] for k in range(self.pop_size): parent, off = self.pop[k], self.off[k] rel = get_relation(parent, off) if rel == 0: survivors.extend([parent, off]) elif rel == -1: survivors.append(off) else: survivors.append(parent) survivors = Population.create(*survivors) if len(survivors) > self.pop_size: survivors = RankAndCrowdingSurvival().do(self.problem, survivors, self.pop_size) self.pop = survivors parse_doc_string(GDE3.__init__)
for i in range(len(sections) - 1): t = np.linspace(sections[i], sections[i + 1], 100) v = np.column_stack([np.cos(t), np.sin(t)]) P = np.row_stack([center, F[i] * v]) plot_polygon(ax, P, color=self.colors[i]) # draw the outer circle plot_circle(ax, **self.axis_style) plot_axes_lines(ax, V, **self.axis_style) def _do(self): n_rows = len(self.to_plot) n_cols = max([len(e[0]) for e in self.to_plot]) self.init_figure(n_rows=n_rows, n_cols=n_cols, force_axes_as_matrix=True) # normalize the input bounds = parse_bounds(self.bounds, self.n_dim) to_plot_norm = normalize(self.to_plot, bounds, reverse=self.reverse) for k, (F, kwargs) in enumerate(to_plot_norm): for j, _F in enumerate(F): self._plot(self.ax[k, j], _F) parse_doc_string(Petal.__init__)
Parameters ---------- pop_size : {pop_size} sampling : {sampling} selection : {selection} crossover : {crossover} mutation : {mutation} eliminate_duplicates : {eliminate_duplicates} n_offsprings : {n_offsprings} Returns ------- ga : :class:`~pymoo.model.algorithm.Algorithm` Returns an SingleObjectiveGeneticAlgorithm algorithm object. """ return SingleObjectiveGeneticAlgorithm(pop_size=pop_size, sampling=sampling, selection=selection, crossover=crossover, mutation=mutation, survival=FitnessSurvival(), eliminate_duplicates=eliminate_duplicates, n_offsprings=n_offsprings, **kwargs) parse_doc_string(ga)
self.off = self.crossover.do(self.problem, pop, P, algorithm=self) # then do the mutation (which is actually ) _pop = self.off.new().merge(self.pop).merge(self.off) _P = np.column_stack( [np.arange(len(pop)), np.arange(len(pop)) + len(pop)]) self.off = self.mutation.do(self.problem, _pop, _P, algorithm=self)[:len(self.pop)] # bounds back if something is out of bounds self.off = BoundsBackRepair().do(self.problem, self.off) # evaluate the results self.evaluator.eval(self.problem, self.off, algorithm=self) _F, _CV, _feasible = self.off.get("F", "CV", "feasible") _F = parameter_less(_F, _CV) # find the individuals which are indeed better is_better = np.where((_F <= F)[:, 0])[0] # replace the individuals in the population pop[is_better] = self.off[is_better] # store the population in the algorithm object self.pop = pop parse_doc_string(DE.__init__)
# set the crowding to all individuals pop[front].set("crowding", crowding) # extend the survivors by all or selected individuals survivors.extend(front[I]) # inverse of crowding because nsga2 does maximize it (then tournament selection can stay the same) pop.set("crowding", -pop.get("crowding")) return pop[survivors] def calc_norm_pref_distance(A, B, weights, ideal, nadir): D = np.repeat(A, B.shape[0], axis=0) - np.tile(B, (A.shape[0], 1)) N = ((D / (nadir - ideal))**2) * weights N = np.sqrt(np.sum(N, axis=1) * len(weights)) return np.reshape(N, (A.shape[0], B.shape[0])) # ========================================================================================================= # Interface # ========================================================================================================= def rnsga2(*args, **kwargs): return RNSGA2(*args, **kwargs) parse_doc_string(RNSGA2.__init__)
#Levy Flight #pick the best one from random optimum nests (leas infeasibles or PF members) best = self.opt[np.random.randint(len(self.opt), size=len(X))] G_X = np.array([best_nest.get("X") for best_nest in best]) step_size = self._get_global_step_size(X) _X = X + np.random.rand(*X.shape) * step_size * (G_X - X) _X = set_to_bounds_if_outside_by_problem(self.problem, _X) #Evaluate off = Population(len(_X)).set("X", _X) self.evaluator.eval(self.problem, off, algorithm=self) #Local Random Walk _X = off.get("X") dir_vec = self._get_local_directional_vector(X) _X = _X + dir_vec _X = set_to_bounds_if_outside_by_problem(self.problem, _X) off = Population(len(_X)).set("X", _X) self.evaluator.eval(self.problem, off, algorithm=self) #append offspring to population and then sort for elitism (survival) self.pop = Population.merge(pop, off) self.pop = self.survival.do(self.problem, self.pop, self.pop_size, algorithm=self) parse_doc_string(MOCS.__init__)
# the angle of niche to nearest neighboring niche gamma = self.gamma[k] # the angle from the individuals of this niches to the niche itself theta = acute_angle[assigned_to_niche, k] # the penalty which is applied for the metric penalty = problem.n_obj * ( (n_gen / n_max_gen)**self.alpha) * (theta / gamma) # calculate the angle-penalized penalized (APD) apd = dist_to_ideal[assigned_to_niche] * (1 + penalty) # the individual which survives survivor = assigned_to_niche[apd.argmin()] # set attributes to the individual pop[assigned_to_niche].set(theta=theta, apd=apd, niche=k, best=False) pop[survivor].set("best", True) # select the one with smallest APD value survivors.append(survivor) return pop[survivors] parse_doc_string(RVEA.__init__)
for e in ant.path: if e.pheromone is None: raise Exception( "The ant has to set the pheromone of each entry in the path." ) else: self.pheromones.update(e.key, e.pheromone * pheromones.rho) self.pop, self.off = colony, colony self.opt = opt def _set_optimum(self, **kwargs): pass parse_doc_string(ACO.__init__) # ========================================================================================================= # TSP Example # ========================================================================================================= class GraphAnt(Ant): def __init__(self, **kwargs) -> None: super().__init__(**kwargs) self.not_visited = None self.costs = 0.0 def initialize(self, *args, **kwargs): super().initialize(*args, **kwargs) self.not_visited = np.full(self.problem.n_var, True)
---------- ref_dirs : {ref_dirs} decomposition : {{ 'auto', 'tchebi', 'pbi' }} The decomposition approach that should be used. If set to `auto` for two objectives `tchebi` and for more than two `pbi` will be used. n_neighbors : int Number of neighboring reference lines to be used for selection. prob_neighbor_mating : float Probability of selecting the parents in the neighborhood. Returns ------- moead : :class:`~pymoo.model.algorithm.MOEAD` Returns an MOEAD algorithm object. """ return MOEAD(ref_dirs, n_neighbors=n_neighbors, decomposition=decomposition, prob_neighbor_mating=prob_neighbor_mating, **kwargs) parse_doc_string(moead)
eliminate_duplicates=True, **kwargs) self.n_elites = n_elites self.n_mutants = n_mutants self.bias = bias self.default_termination = SingleObjectiveDefaultTermination() def _next(self): pop = self.pop elites = np.where(pop.get("type") == "elite")[0] # actually do the mating given the elite selection and biased crossover off = self.mating.do(self.problem, pop, n_offsprings=self.n_offsprings, algorithm=self) # create the mutants randomly to fill the population with mutants = FloatRandomSampling().do(self.problem, self.n_mutants, algorithm=self) # evaluate all the new solutions to_evaluate = Population.merge(off, mutants) self.evaluator.eval(self.problem, to_evaluate, algorithm=self) # finally merge everything together and sort by fitness pop = Population.merge(pop[elites], to_evaluate) # the do survival selection - set the elites for the next round self.pop = self.survival.do(self.problem, pop, len(pop), algorithm=self) parse_doc_string(BRKGA.__init__)
return mutant for k in range(self.problem.n_var): # create the the individual and evaluate it mutant = step(center.X, self.explr_delta, k) self.evaluator.eval(self.problem, mutant, algorithm=self) self.pop = Population.merge(self.pop, mutant) if is_better(mutant, opt): center, opt = mutant, mutant else: # inverse the sign of the delta self.explr_delta[k] = -self.explr_delta[k] # now try the other sign if there was no improvement mutant = step(center.X, self.explr_delta, k) self.evaluator.eval(self.problem, mutant, algorithm=self) self.pop = Population.merge(self.pop, mutant) if is_better(mutant, opt): center, opt = mutant, mutant return opt parse_doc_string(PatternSearch.__init__)
N.append(pop[k]) n_cand_neighbors = pop[k].get("neighbors") rnd = np.random.permutation( len(n_cand_neighbors))[:self.crossover.n_parents - 1] [N.append(e) for e in n_cand_neighbors[rnd]] parents = np.reshape(np.arange(len(N)), (-1, self.crossover.n_parents)) N = Population.create(*N) bias = super()._do(problem, N, n_neighbors, parents, **kwargs) return Population.merge(bias, other) parse_doc_string(MMGA.__init__) if __name__ == '__main__': problem = MultiModalSimple2() algorithm = MMGA(pop_size=20, eliminate_duplicates=True) ret = minimize(problem, algorithm, termination=('n_gen', 100), seed=1, save_history=True, verbose=False) def plot(algorithm): pop = algorithm.pop
F, G = pop.get("F", "G") f = F[:, 0] if problem.n_constr == 0: I = f.argsort() else: phi = (np.maximum(0, G) ** 2).sum(axis=1) J = np.arange(len(phi)) I = load_function("stochastic_ranking")(f, phi, self.PR, J) return pop[I][:n_survive] class SRES(ES): def __init__(self, PF=0.45, **kwargs): """ Stochastic Ranking Evolutionary Strategy (SRES) Parameters ---------- PF: float The stochastic ranking weight for choosing a random decision while doing the modified bubble sort. """ super().__init__(survival=StochasticRankingSurvival(PF), **kwargs) self.PF = PF parse_doc_string(SRES.__init__)
("s", 70), ("alpha", 0.3)) def _do(self): # initial a figure with a single plot self.init_figure() # equal axis length and no ticks equal_axis(self.ax) no_ticks(self.ax) V = get_uniform_points_around_circle(self.n_dim) plot_axis_labels(self.ax, V, self.get_labels(), **self.axis_label_style) # draw the outer circle and radar lines plot_circle(self.ax, **self.axis_style) plot_radar_line(self.ax, V, **self.axis_style) # draw the endpoints of each objective if self.endpoint_style: self.ax.scatter(V[:, 0], V[:, 1], **self.endpoint_style) # plot all the points for k, (F, kwargs) in enumerate(self.to_plot): N = (F[..., None] * V).sum(axis=1) / F.sum(axis=1)[:, None] self.ax.scatter(N[:, 0], N[:, 1], **kwargs) parse_doc_string(Radviz.__init__)
return_random_if_equal=True) # otherwise just select random else: S[i] = random.choice([a, b]) return S[:, None].astype(np.int) # ========================================================================================================= # Interface # ========================================================================================================= def unsga3(**kwargs): """ This is an implementation of the Unified NSGA3 algorithm :cite:`unsga3`. The same options as for :class:`pymoo.algorithms.nsga3.nsga3` are available. Returns ------- unsga3 : :class:`~pymoo.model.algorithm.Algorithm` Returns an UNSGA3 algorithm object. """ return NSGA3(selection=TournamentSelection(func_comp=comp_by_rank_and_ref_line_dist), **kwargs) parse_doc_string(unsga3)
X = np.array(X) self.send_array_to_yield = X.ndim > 1 X = np.atleast_2d(X) # evaluate the population self.pop = Population.new("X", X) self.evaluator.eval(self.problem, self.pop, algorithm=self) # set infeasible individual's objective values to np.nan - then CMAES can handle it for ind in self.pop: if not ind.feasible[0]: ind.F[0] = np.nan def _set_optimum(self): val = self.pop if self.opt is not None: val = Population.merge(val, self.opt) self.opt = filter_optimum(val, least_infeasible=True) def __getstate__(self): state = self.__dict__.copy() del state["es"] return state def __setstate__(self, state): self.__dict__.update(state) self.ers = None parse_doc_string(CMAES.__init__)
return self def plot(self, ax, _type, F, **kwargs): is_3d = F.shape[1] == 3 if _type is None: _type = "scatter" if _type == "scatter": if is_3d: ax.scatter(F[:, 0], F[:, 1], F[:, 2], **kwargs) else: ax.scatter(F[:, 0], F[:, 1], **kwargs) else: if is_3d: ax.plot_trisurf(F[:, 0], F[:, 1], F[:, 2], **kwargs) else: ax.plot(F[:, 0], F[:, 1], **kwargs) def set_labels(self, ax, labels, is_3d): # set the labels for each axis ax.set_xlabel(labels[0]) ax.set_ylabel(labels[1]) if is_3d: ax.set_zlabel(labels[2]) parse_doc_string(Scatter.__init__)
Parameters ---------- pop_size : {pop_size} sampling : {sampling} selection : {selection} crossover : {crossover} mutation : {mutation} eliminate_duplicates : {eliminate_duplicates} n_offsprings : {n_offsprings} Returns ------- nsganet : :class:`~pymoo.model.algorithm.Algorithm` Returns an NSGANet algorithm object. """ return NSGANet(pop_size=pop_size, sampling=sampling, selection=selection, crossover=crossover, mutation=mutation, survival=RankAndCrowdingSurvival(), eliminate_duplicates=eliminate_duplicates, n_offsprings=n_offsprings, **kwargs) parse_doc_string(nsganet)
if self.show_bounds: self.ax.text(i - margin_left, bottom, self.func_number_to_text(bounds[0][i])) self.ax.text(i - margin_left, top, self.func_number_to_text(bounds[1][i])) if self.n_ticks is not None: n_length = 0.03 for y in np.linspace(0, 1, self.n_ticks): self.ax.hlines(y, i - n_length, i + n_length, **self.axis_style) # if bounds are shown, then move them to the bottom if self.show_bounds: self.ax.tick_params(axis='x', which='major', pad=25) self.ax.spines['right'].set_visible(False) self.ax.spines['left'].set_visible(False) self.ax.set_yticklabels([]) self.ax.set_yticks([]) self.ax.set_ylim((-0.05, 1.05)) self.ax.set_xticks(np.arange(self.n_dim)) self.ax.set_xticklabels(self.get_labels()) return self parse_doc_string(PCP.__init__)
self.pop = self.pc_pop.copy(deep=True) def _replace(self, i, off): npc_pop = self.npc_pop pop_size = len(self.ref_dirs) nr = math.ceil(pop_size / 100) # calculate the decomposed values for each neighbor N = self.neighbors[i] FV = self.decomp.do(npc_pop[N].get("F"), weights=self.ref_dirs[N, :], ideal_point=self.ideal) off_FV = self.decomp.do(off.get("F"), weights=self.ref_dirs[N, :], ideal_point=self.ideal) # get the absolute index in F where offspring is better than the current F (decomposed space) I = np.where(off_FV < FV)[0] if len(I) > 0: npc_pop[N[I[:nr]]] = off[0] return npc_pop parse_doc_string(BCEMOEAD.__init__)
label="particle") X, F, CV = pop.get("X", "F", "CV") plt.scatter(X[:, 0], X[:, 1], color="blue", marker="o", s=30, alpha=0.5) opt = algorithm.opt X, F, CV = opt.get("X", "F", "CV") plt.scatter(X[:, 0], X[:, 1], color="black", marker="x", s=100, label="gbest") xl, xu = problem.bounds() plt.xlim(xl[0], xu[0]) plt.ylim(xl[1], xu[1]) plt.title(f"Generation: %s \nf: %.5E" % (algorithm.n_gen, opt[0].F[0])) plt.legend() self.last_pop = off.copy(deep=True) parse_doc_string(PSO.__init__)
else: IC = (Ci + 1e-6) / (CV + 1e-6) CVF = np.max(np.maximum(Fi, F) / np.minimum(Fi, F), axis=1) val = np.log(np.maximum(CVF, IC)) indicator[:, i] = val indicator[i, i] = np.inf feas = np.where(CV <= 0)[0] if len(feas) <= self.pop_size: self.archive = pop[np.argsort(CV)[:self.pop_size]] else: feas_F = pop[feas].get("F") - self.norm.ideal( only_feas=True) + 1e-6 I = Selection_Operator_of_PREA(feas_F, indicator[feas][:, feas], self.pop_size) self.archive = pop[feas[I]] I = Indicator_based_CHT(F, indicator, self.ref_dirs, self.pop_size) self.pop = pop[I] self.Ra = 1 - self.n_gen / self.termination.n_max_gen def _set_optimum(self, **kwargs): self.opt = filter_optimum(self.archive, least_infeasible=True) parse_doc_string(ICMA.__init__)
ref_points : {ref_points} pop_per_ref_point : int Size of the population used for each reference point. mu : float Defines the scaling of the reference lines used during survival selection. Increasing mu will result having solutions with a larger spread. Other Parameters ------- n_offsprings : {n_offsprings} sampling : {sampling} selection : {selection} crossover : {crossover} mutation : {mutation} eliminate_duplicates : {eliminate_duplicates} Returns ------- nsga3 : :class:`~pymoo.model.algorithm.Algorithm` Returns an NSGA3 algorithm object. """ return RNSGA3(ref_points, pop_per_ref_point, mu, **kwargs) parse_doc_string(rnsga3)