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 best = self.opt.repeat(len(pop)) G_X = best.get("X") # perform the pso equation 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 = repair_out_of_bounds_manually(_V, -self.V_max, self.V_max) # update the values of each particle _X = X + _V _X = repair_out_of_bounds(self.problem, _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: opt = FitnessSurvival().do(self.problem, Population.create(*pop.get("pbest")), 1) eta = int(np.random.uniform(5, 30)) mutant = PolynomialMutation(eta).do(self.problem, opt) self.evaluator.eval(self.problem, mutant, algorithm=self) if ImprovementReplacement().do(self.problem, opt, mutant, return_indices=True)[0]: k = [i for i, e in enumerate(pop.get("pbest")) if e == opt][0] pop[k].set("pbest", mutant) self.pop = pop
def _do(self, problem, X, **kwargs): X = X.astype(np.float) Y = np.full(X.shape, np.inf) if self.prob is None: self.prob = 1.0 / problem.n_var do_mutation = np.random.random(X.shape) < self.prob Y[:, :] = X xl = np.repeat(problem.xl[None, :], X.shape[0], axis=0)[do_mutation] xu = np.repeat(problem.xu[None, :], X.shape[0], axis=0)[do_mutation] X = X[do_mutation] delta1 = (X - xl) / (xu - xl) delta2 = (xu - X) / (xu - xl) mut_pow = 1.0 / (self.eta + 1.0) rand = np.random.random(X.shape) mask = rand <= 0.5 mask_not = np.logical_not(mask) deltaq = np.zeros(X.shape) xy = 1.0 - delta1 val = 2.0 * rand + (1.0 - 2.0 * rand) * (np.power( xy, (self.eta + 1.0))) d = np.power(val, mut_pow) - 1.0 deltaq[mask] = d[mask] xy = 1.0 - delta2 val = 2.0 * (1.0 - rand) + 2.0 * (rand - 0.5) * (np.power( xy, (self.eta + 1.0))) d = 1.0 - (np.power(val, mut_pow)) deltaq[mask_not] = d[mask_not] # mutated values _Y = X + deltaq * (xu - xl) # back in bounds if necessary (floating point issues) _Y[_Y < xl] = xl[_Y < xl] _Y[_Y > xu] = xu[_Y > xu] # set the values for output Y[do_mutation] = _Y # in case out of bounds repair (very unlikely) Y = repair_out_of_bounds(problem, Y) return Y
def _evaluate(self, x, out, *args, **kwargs): out_of_bounds = np.any(repair_out_of_bounds(self, x.copy()) != x) f1 = x[:, 0] g = 1 + 9.0 / (self.n_var - 1) * np.sum((x[:, 1:]) ** 2, axis=1) f2 = g * (1 - np.power((f1 / g), 0.5)) if out_of_bounds: f1 = np.full(x.shape[0], np.inf) f2 = np.full(x.shape[0], np.inf) out["F"] = np.column_stack([f1, f2])
def _next(self): # create a copy from the current values - if restart is necessary _X = np.copy(self.X) # if the gradient was not provided yet evaluate it if self.F is None or self.dX is None: # evaluate the problem and get the information of gradients F, dX, CV = self.problem.evaluate( self.X, return_values_of=["F", "dF", "CV"]) # because we only consider one objective here F = F[:, [self.objective]] dX = dX[:, self.objective] # increase the evaluation count self.evaluator.n_eval += len(self.X) has_improved = self.F is None or np.any(F < self.F) is_gradient_valid = np.all(~np.isnan(dX)) # if the gradient did lead to an improvement if has_improved: self.F, self.dX, self.CV = F, dX, CV # if the gradient is valid and has no nan values if is_gradient_valid: # make the step and check out of bounds for X self.apply() self.X = repair_out_of_bounds(self.problem, self.X) # set the population object for automatic print self.pop = Population(len(self.X)).set("X", self.X, "F", self.F, "CV", self.CV, "feasible", self.CV <= 0) # otherwise end the termination form now on else: print("WARNING: GRADIENT ERROR", self.dX) self.termination.force_termination = True # otherwise do a restart of the algorithm else: self.X = _X self.restart() self.n_restarts += 1 # set the gradient to none to be ready for the next iteration self.dX = None
def _step(self): # number of variables increased by one - matches equations in the paper 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), self.problem.xl, self.problem.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 = repair_out_of_bounds(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 # if the new point is not better than the best, but better than second worst - just take it if pop[0].F <= reflect.F < pop[n].F: pop[n + 1] = reflect # if even better than the best - check for expansion elif reflect.F < pop[0].F: # ------------------------------------------------------------------------------------------- # EXPAND # ------------------------------------------------------------------------------------------- # the maximum expansion until the bounds are hit max_beta = max_expansion_factor(centroid, (x_reflect - centroid), self.problem.xl, self.problem.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 = repair_out_of_bounds(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 expand.F < reflect.F: pop[n + 1] = expand else: pop[n + 1] = reflect # if not worst than the worst - outside contraction elif pop[n].F <= reflect.F < pop[n + 1].F: # ------------------------------------------------------------------------------------------- # 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 contract_outside.F <= reflect.F: 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 contract_inside.F < pop[n + 1].F: 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) # finally sort the population by objective values pop = pop[np.argsort(pop.get("F")[:, 0])] return pop
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 = repair_out_of_bounds_manually(_V, -self.V_max, self.V_max) # update the values of each particle _X = X + _V _X = repair_out_of_bounds(self.problem, _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 _do(self, problem, X, **kwargs): X = X.astype(np.float) _, n_matings, n_var = X.shape # boundaries of the problem xl, xu = problem.xl, problem.xu #if np.any(X < xl) or np.any(X > xu): # raise Exception("Simulated binary crossover requires all variables to be in bounds!") # crossover mask that will be used in the end do_crossover = np.full(X[0].shape, True) # per variable the probability is then 50% do_crossover[np.random.random((n_matings, problem.n_var)) > self.prob_per_variable] = False # also if values are too close no mating is done do_crossover[np.abs(X[0] - X[1]) <= 1.0e-14] = False # assign y1 the smaller and y2 the larger value y1 = np.min(X, axis=0) y2 = np.max(X, axis=0) # random values for each individual rand = np.random.random((n_matings, problem.n_var)) def calc_betaq(beta): alpha = 2.0 - np.power(beta, -(self.eta + 1.0)) mask, mask_not = (rand <= (1.0 / alpha)), (rand > (1.0 / alpha)) betaq = np.zeros(mask.shape) betaq[mask] = np.power((rand * alpha), (1.0 / (self.eta + 1.0)))[mask] betaq[mask_not] = np.power((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta + 1.0)))[mask_not] return betaq # difference between all variables delta = (y2 - y1) # now just be sure not dividing by zero (these cases will be filtered later anyway) # delta[np.logical_or(delta < 1.0e-10, np.logical_not(do_crossover))] = 1.0e-10 delta[delta < 1.0e-10] = 1.0e-10 beta = 1.0 + (2.0 * (y1 - xl) / delta) betaq = calc_betaq(beta) c1 = 0.5 * ((y1 + y2) - betaq * delta) beta = 1.0 + (2.0 * (xu - y2) / delta) betaq = calc_betaq(beta) c2 = 0.5 * ((y1 + y2) + betaq * delta) # do randomly a swap of variables b = np.random.random((n_matings, problem.n_var)) <= 0.5 val = np.copy(c1[b]) c1[b] = c2[b] c2[b] = val # take the parents as _template c = np.copy(X) # copy the positions where the crossover was done c[0, do_crossover] = c1[do_crossover] c[1, do_crossover] = c2[do_crossover] c[0] = repair_out_of_bounds(problem, c[0]) c[1] = repair_out_of_bounds(problem, c[1]) if self.n_offsprings == 1: # Randomly select one offspring c = c[np.random.choice(2, X.shape[1]), np.arange(X.shape[1])] c = c.reshape((1, X.shape[1], X.shape[2])) return c
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 = repair_out_of_bounds(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 = repair_out_of_bounds(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))