def _exploration_move(self, center, opt=None): if opt is None: opt = center def step(x, delta, k): # copy and add delta to the new point X = np.copy(x) # normalize the delta by the bounds if they are provided by the problem eps = delta[k] # if the problem has bounds normalize the delta if self.problem.has_bounds(): xl, xu = self.problem.bounds() eps *= (xu[k] - xl[k]) # now add to the current solution X[k] = X[k] + eps # repair if out of bounds if necessary X = set_to_bounds_if_outside_by_problem(self.problem, X) # return the new solution as individual mutant = pop_from_array_or_individual(X)[0] 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
def _next(self): # in the beginning of each iteration first do an exploration move self._previous = self.opt[0] self._current = self._exploration_move(self._previous) # one iteration is the combination of this two moves repeatedly until delta needs to be reduced while self._previous != self._current: # use the pattern move to get a new trial vector trial = self._pattern_move(self._previous, self._current) # perform an exploration move around the trial vector - the best known solution is always stored in _current explr = self._exploration_move(trial, opt=self._current) # we can break if we did not improve if not is_better(explr, self._current, eps=1e-6): break # else also check if we are terminating - otherwise this loop might run far too long self._set_optimum() if not self.termination.do_continue(self): break self._previous, self._current = self._current, explr self.explr_delta *= self.explr_rho
def _step(self): pop = self.pop X, F, V = pop.get("X", "F", "V") # get the personal best of each particle pbest = Population.create(*pop.get("pbest")) P_X, P_F = pbest.get("X", "F") # get the GLOBAL best solution - other variants such as local best can be implemented here too best = self.opt.repeat(len(pop)) G_X = best.get("X") # get the inertia weight of the individual inerta = self.w * V # calculate random values for the updates r1 = np.random.random((len(pop), self.problem.n_var)) r2 = np.random.random((len(pop), self.problem.n_var)) cognitive = self.c1 * r1 * (P_X - X) social = self.c2 * r2 * (G_X - X) # calculate the velocity vector _V = inerta + cognitive + social _V = set_to_bounds_if_outside(_V, - self.V_max, self.V_max) # update the values of each particle _X = X + _V _X = InversePenaltyOutOfBoundsRepair().do(self.problem, _X, P=X) # evaluate the offspring population off = Population(len(pop)).set("X", _X, "V", _V, "pbest", pbest) self.evaluator.eval(self.problem, off, algorithm=self) # check whether a solution has improved or not - also consider constraints here has_improved = ImprovementReplacement().do(self.problem, pbest, off, return_indices=True) # replace the personal best of each particle if it has improved off[has_improved].set("pbest", off[has_improved]) off.set("best", best) pop = off # try to improve the current best with a pertubation if self.pertube_best: pbest = Population.create(*pop.get("pbest")) k = FitnessSurvival().do(self.problem, pbest, 1, return_indices=True)[0] eta = int(np.random.uniform(5, 30)) mutant = PolynomialMutation(eta).do(self.problem, pbest[[k]])[0] self.evaluator.eval(self.problem, mutant, algorithm=self) # if the mutant is in fact better - replace the personal best if is_better(mutant, pop[k]): pop[k].set("pbest", mutant) self.pop = pop
def _next(self): # number of variables increased by one - matches equations in the paper xl, xu = self.problem.bounds() pop, n = self.pop, self.problem.n_var - 1 # calculate the centroid centroid = pop[:n + 1].get("X").mean(axis=0) # ------------------------------------------------------------------------------------------- # REFLECT # ------------------------------------------------------------------------------------------- # check the maximum alpha until the bounds are hit max_alpha = max_expansion_factor(centroid, (centroid - pop[n + 1].X), xl, xu) # reflect the point, consider factor if bounds are there, make sure in bounds (floating point) evaluate x_reflect = centroid + min(self.alpha, max_alpha) * (centroid - pop[n + 1].X) x_reflect = set_to_bounds_if_outside_by_problem( self.problem, x_reflect) reflect = self.evaluator.eval(self.problem, Individual(X=x_reflect), algorithm=self) # whether a shrink is necessary or not - decided during this step shrink = False better_than_current_best = is_better(reflect, pop[0]) better_than_second_worst = is_better(reflect, pop[n]) better_than_worst = is_better(reflect, pop[n + 1]) # if better than the current best - check for expansion if better_than_current_best: # ------------------------------------------------------------------------------------------- # EXPAND # ------------------------------------------------------------------------------------------- # the maximum expansion until the bounds are hit max_beta = max_expansion_factor(centroid, (x_reflect - centroid), xl, xu) # expand using the factor, consider bounds, make sure in case of floating point issues x_expand = centroid + min(self.beta, max_beta) * (x_reflect - centroid) x_expand = set_to_bounds_if_outside_by_problem( self.problem, x_expand) # if the expansion is almost equal to reflection (if boundaries were hit) - no evaluation if np.allclose(x_expand, x_reflect, atol=1e-16): expand = reflect else: expand = self.evaluator.eval(self.problem, Individual(X=x_expand), algorithm=self) # if the expansion further improved take it - otherwise use expansion if is_better(expand, reflect): pop[n + 1] = expand else: pop[n + 1] = reflect # if the new point is not better than the best, but better than second worst - just keep it elif not better_than_current_best and better_than_second_worst: pop[n + 1] = reflect # if not worse than the worst - outside contraction elif not better_than_second_worst and better_than_worst: # ------------------------------------------------------------------------------------------- # Outside Contraction # ------------------------------------------------------------------------------------------- x_contract_outside = centroid + self.gamma * (x_reflect - centroid) contract_outside = self.evaluator.eval( self.problem, Individual(X=x_contract_outside), algorithm=self) if is_better(contract_outside, reflect): pop[n + 1] = contract_outside else: shrink = True # if the reflection was worse than the worst - inside contraction else: # ------------------------------------------------------------------------------------------- # Inside Contraction # ------------------------------------------------------------------------------------------- x_contract_inside = centroid - self.gamma * (x_reflect - centroid) contract_inside = self.evaluator.eval( self.problem, Individual(X=x_contract_inside), algorithm=self) if is_better(contract_inside, pop[n + 1]): pop[n + 1] = contract_inside else: shrink = True # ------------------------------------------------------------------------------------------- # Shrink (only if necessary) # ------------------------------------------------------------------------------------------- if shrink: for i in range(1, len(pop)): pop[i].X = pop[0].X + self.delta * (pop[i].X - pop[0].X) pop[1:] = self.evaluator.eval(self.problem, pop[1:], algorithm=self) self.pop = FitnessSurvival().do(self.problem, pop, len(pop))