def test_association(self): problem = C1DTLZ3(n_var=12, n_obj=3) ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'preCA.x')) CA = Population.create(ca_x) self.evaluator.eval(problem, CA) da_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'preDA.x')) DA = Population.create(da_x) self.evaluator.eval(problem, DA) off_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'offspring.x')) off = Population.create(off_x) self.evaluator.eval(problem, off) true_assoc = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'feasible_rank0.txt')) true_niche = true_assoc[:, 1] true_id = true_assoc[:, 0] sorted_id = np.argsort(true_id) survival = CADASurvival(self.ref_dirs) mixed = CA.merge(off) survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0) fronts = NonDominatedSorting().do(mixed.get("F"), n_stop_if_ranked=len(self.ref_dirs)) I = np.concatenate(fronts) niche, _ = survival._associate(mixed[I]) sorted_I = np.argsort(I) assert (niche[sorted_I] == true_niche[sorted_id]).all()
def _next(self): # all the elements in the interval a, left, right, b = self.pop # the golden ratio (precomputed constant) R = self.R # if the left solution is better than the right if left.F[0] < right.F[0]: # make the right to be the new right bound and the left becomes the right a, b = a, right right = left # create a new left individual and evaluate left = Individual(X=b.X - R * (b.X - a.X)) self.evaluator.eval(self.problem, Population.create(left), algorithm=self) # if the right solution is better than the left else: # make the left to be the new left bound and the right becomes the left a, b = left, b left = right # create a new right individual and evaluate right = Individual(X=a.X + R * (b.X - a.X)) self.evaluator.eval(self.problem, Population.create(right), algorithm=self) # update the population with all the four individuals self.pop = Population.create(a, left, right, b)
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 test_restricted_mating_selection(self): np.random.seed(200) selection = RestrictedMating(func_comp=comp_by_cv_dom_then_random) problem = C3DTLZ4(n_var=12, n_obj=3) ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c3dtlz4', 'case2', 'preCA.x')) CA = Population.create(ca_x) self.evaluator.eval(problem, CA) da_x = np.loadtxt(path_to_test_resources('ctaea', 'c3dtlz4', 'case2', 'preDA.x')) DA = Population.create(da_x) self.evaluator.eval(problem, DA) Hm = CA.merge(DA) n_pop = len(CA) _, rank = NonDominatedSorting().do(Hm.get('F'), return_rank=True) Pc = (rank[:n_pop] == 0).sum()/len(Hm) Pd = (rank[n_pop:] == 0).sum()/len(Hm) P = selection.do(Hm, len(CA)) assert P.shape == (91, 2) if Pc > Pd: assert (P[:, 0] < n_pop).all() else: assert (P[:, 0] >= n_pop).all() assert (P[:, 1] >= n_pop).any() assert (P[:, 1] < n_pop).any()
def test_update_da(self): problem = C1DTLZ3(n_var=12, n_obj=3) for i in range(2): ca_x = np.loadtxt( path_to_test_resources('ctaea', 'c1dtlz3', f'case{i+1}', 'preCA.x')) CA = Population.create(ca_x) self.evaluator.eval(problem, CA) da_x = np.loadtxt( path_to_test_resources('ctaea', 'c1dtlz3', f'case{i+1}', 'preDA.x')) DA = Population.create(da_x) self.evaluator.eval(problem, DA) off_x = np.loadtxt( path_to_test_resources('ctaea', 'c1dtlz3', f'case{i+1}', 'offspring.x')) off = Population.create(off_x) self.evaluator.eval(problem, off) survival = CADASurvival(self.ref_dirs) mixed = Population.merge(CA, off) survival.ideal_point = np.min(np.vstack( (DA.get("F"), mixed.get("F"))), axis=0) post_ca_x = np.loadtxt( path_to_test_resources('ctaea', 'c1dtlz3', f'case{i+1}', 'postCA.x')) CA = Population.create(post_ca_x) self.evaluator.eval(problem, CA) Hd = Population.merge(DA, off) pDA = survival._updateDA(CA, Hd, 91) true_S1 = [ 151, 35, 6, 63, 67, 24, 178, 106, 134, 172, 148, 159, 41, 173, 145, 77, 62, 40, 127, 61, 130, 27, 171, 115, 52, 176, 22, 75, 55, 87, 36, 149, 154, 47, 78, 170, 90, 15, 53, 175, 179, 165, 56, 89, 132, 82, 141, 39, 32, 25, 131, 14, 72, 65, 177, 140, 66, 143, 34, 81, 103, 99, 147, 168, 51, 26, 70, 94, 54, 97, 158, 107, 29, 120, 50, 108, 157, 11, 85, 174, 80, 0, 95, 13, 142, 101, 156, 19, 8, 98, 20 ] true_S2 = [ 78, 173, 59, 21, 101, 52, 36, 94, 17, 20, 37, 96, 90, 129, 150, 136, 162, 70, 146, 75, 138, 154, 65, 179, 98, 32, 97, 11, 26, 107, 12, 128, 95, 170, 24, 171, 40, 180, 14, 44, 49, 43, 130, 23, 60, 79, 148, 62, 87, 56, 157, 73, 104, 45, 177, 74, 15, 152, 164, 28, 80, 113, 41, 33, 158, 57, 77, 34, 114, 118, 18, 54, 53, 145, 93, 115, 121, 174, 142, 39, 13, 105, 10, 69, 120, 55, 6, 153, 91, 137, 46 ] if i == 0: assert np.all(pDA == Hd[true_S1]) else: assert np.all(pDA == Hd[true_S2])
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 do(self, problem, *args, **kwargs): if type(args[0]) is Population: pop, parents = args else: pop = Population.create(*args) parents = np.array([np.arange(len(args))]) if self.n_parents != parents.shape[1]: raise ValueError( 'Exception during crossover: Number of parents differs from defined at crossover.' ) # get the design space matrix form the population and parents X = pop.get("X")[parents.T].copy() # now apply the crossover probability do_crossover = np.random.random(len(parents)) < self.prob # execute the crossover _X = self._do(problem, X, **kwargs) X[:, do_crossover, :] = _X[:, do_crossover, :] # flatten the array to become a 2d-array X = X.reshape(-1, X.shape[-1]) # create a population object off = pop.new("X", X) return off
def _do(self, problem, pop, n_offsprings, parents=None, **kwargs): rnd = np.random.random(n_offsprings) n_neighbors = (rnd <= self.bias).sum() other = super()._do(problem, pop, n_offsprings - n_neighbors, parents, **kwargs) N = [] cand = TournamentSelection(comp_by_rank).do(pop, n_neighbors, n_parents=1)[:, 0] for k in cand: 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)
def _next(self): # 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
def _update(self): D = self.D ind = Individual(X=np.copy(D["X"]), F=np.copy(D["F"]), G=np.copy(-D["G"])) pop = Population.merge(self.pop, Population.create(ind)) set_cv(pop) self.pop = 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 best for each solution - could be global or local or something else - (here: Global) best = self._social_best() 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, "best", best) # 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(20, 30)) mutant = PolynomialMutation(eta).do(self.problem, pbest[[k]])[0] off[k].set("X", mutant.X) return off
def do(self, problem, pop, off, return_indices=False, inplace=False, **kwargs): pop = Population.create(pop) if isinstance(pop, Individual) else pop off = Population.create(off) if isinstance(off, Individual) else off I = self._do(problem, pop, off, **kwargs) if return_indices: return I else: if not inplace: pop = pop.copy() pop[I] = off[I] return pop
def test_update(self): problem = C3DTLZ4(n_var=12, n_obj=3) ca_x = np.loadtxt( path_to_test_resources('ctaea', 'c3dtlz4', 'case2', 'preCA.x')) CA = Population.create(ca_x) self.evaluator.eval(problem, CA) da_x = np.loadtxt( path_to_test_resources('ctaea', 'c3dtlz4', 'case2', 'preDA.x')) DA = Population.create(da_x) self.evaluator.eval(problem, DA) off_x = np.loadtxt( path_to_test_resources('ctaea', 'c3dtlz4', 'case2', 'offspring.x')) off = Population.create(off_x) self.evaluator.eval(problem, off) post_ca_x = np.loadtxt( path_to_test_resources('ctaea', 'c3dtlz4', 'case2', 'postCA.x')) true_pCA = Population.create(post_ca_x) self.evaluator.eval(problem, true_pCA) post_da_x = np.loadtxt( path_to_test_resources('ctaea', 'c3dtlz4', 'case2', 'postDA.x')) true_pDA = Population.create(post_da_x) self.evaluator.eval(problem, true_pDA) survival = CADASurvival(self.ref_dirs) mixed = Population.merge(CA, off) survival.ideal_point = np.array([0., 0., 0.]) pCA, pDA = survival.do(problem, mixed, DA, len(self.ref_dirs)) pCA_X = set([tuple(x) for x in pCA.get("X")]) tpCA_X = set([tuple(x) for x in true_pCA.get("X")]) pDA_X = set([tuple(x) for x in pDA.get("X")]) tpDA_X = set([tuple(x) for x in true_pDA.get("X")]) assert pCA_X == tpCA_X assert pDA_X == tpDA_X
def _do(self, problem, evaluator, algorithm): pop = algorithm.pop algorithm.pop = Population.create(*algorithm.pop.get("pbest")) super()._do(problem, evaluator, algorithm) algorithm.pop = pop if algorithm.adaptive: self.output.append("f", algorithm.f if algorithm.f is not None else "-", width=8) self.output.append("S", algorithm.strategy if algorithm.strategy is not None else "-", width=6) self.output.append("w", algorithm.w, width=6) self.output.append("c1", algorithm.c1, width=8) self.output.append("c2", algorithm.c2, width=8)
def _adapt(self): pop = self.pop X, F, best = pop.get("X", "F", "best") best = Population.create(*best) w, c1, c2, = self.w, self.c1, self.c2 # get the average distance from one to another for normalization D = norm_eucl_dist(self.problem, X, X) mD = D.sum(axis=1) / (len(pop) - 1) _min, _max = mD.min(), mD.max() # get the average distance to the global best g_D = norm_euclidean_distance(self.problem)(best.get("X"), X).mean() f = (g_D - _min) / (_max - _min + 1e-32) S = np.array([ S1_exploration(f), S2_exploitation(f), S3_convergence(f), S4_jumping_out(f) ]) strategy = S.argmax() + 1 delta = 0.05 + (np.random.random() * 0.05) if strategy == 1: c1 += delta c2 -= delta elif strategy == 2: c1 += 0.5 * delta c2 -= 0.5 * delta elif strategy == 3: c1 += 0.5 * delta c2 += 0.5 * delta elif strategy == 4: c1 -= delta c2 += delta c1 = max(1.5, min(2.5, c1)) c2 = max(1.5, min(2.5, c2)) if c1 + c2 > 4.0: c1 = 4.0 * (c1 / (c1 + c2)) c2 = 4.0 * (c2 / (c1 + c2)) w = 1 / (1 + 1.5 * np.exp(-2.6 * f)) self.f = f self.strategy = strategy self.c1 = c1 self.c2 = c2 self.w = w
def _next(self): a, left, right, b = self.pop R = self.R if left.F[0] < right.F[0]: a, b = a, right right = left left = Individual(X=b.X - R * (b.X - a.X)) self.evaluator.eval(self.problem, Population.create(left), algorithm=self) else: a, b = left, b left = right right = Individual(X=a.X + R * (b.X - a.X)) self.evaluator.eval(self.problem, Population.create(right), algorithm=self) self.pop = Population.create(a, left, right, b)
def _initialize(self): xl, xu = self.problem.bounds() R = self.R d = R * (xu - xl) a = Individual(X=xl) b = Individual(X=xu) left = Individual(X=xu - d) right = Individual(X=xl + d) pop = Population.create(a, left, right, b) self.evaluator.eval(self.problem, pop, algorithm=self) self.pop = pop
def _next(self): # the offspring population to finally evaluate and attach to the population off = Population() # find the potential optimal solution in the current population potential_optimal = self._potential_optimal() # for each of those solutions execute the division move for current in potential_optimal: # find the largest dimension the solution has not been evaluated yet nxl, nxu = norm_bounds(current, problem) k = np.argmax(nxu - nxl) # the delta value to be used to get left and right - this is one sixth of the range xl, xu = current.get("xl"), current.get("xu") delta = (xu[k] - xl[k]) / 6 # print(current.X, delta, k, xl, xu) # create the left individual left_x = np.copy(current.X) left_x[k] = xl[k] + delta left = Individual(X=left_x) # create the right individual right_x = np.copy(current.X) right_x[k] = xu[k] - delta right = Individual(X=right_x) # update the boundaries for all the points accordingly for ind in [current, left, right]: update_bounds(ind, xl, xu, k, delta) # create the offspring population, evaluate and attach to current population _off = Population.create(left, right) _off.set("depth", current.get("depth") + 1) off = Population.merge(off, _off) # evaluate the offsprings self.evaluator.eval(self.problem, off, algorithm=self) # print(off.get("X")) # add the offsprings to the population self.pop = Population.merge(self.pop, off)
def do(self, problem, algorithm): import matplotlib.pyplot as plt if problem.n_var != 2 or problem.n_obj != 1: raise Exception( "This visualization can only be used for problems with two variables and one objective!") # draw the problem surface FitnessLandscape(problem, _type="contour", kwargs_contour=dict(alpha=0.3), n_samples=self.n_samples_for_surface, close_on_destroy=False).do() # get the population off = algorithm.pop pop = algorithm.pop if self.last_pop is None else self.last_pop pbest = Population.create(*off.get("pbest")) for i in range(len(pop)): plt.plot([off[i].X[0], pop[i].X[0]], [off[i].X[1], pop[i].X[1]], color="blue", alpha=0.5) plt.plot([pbest[i].X[0], pop[i].X[0]], [pbest[i].X[1], pop[i].X[1]], color="red", alpha=0.5) plt.plot([pbest[i].X[0], off[i].X[0]], [pbest[i].X[1], off[i].X[1]], color="red", alpha=0.5) X, F, CV = pbest.get("X", "F", "CV") plt.scatter(X[:, 0], X[:, 1], edgecolors="red", marker="*", s=70, facecolors='none', label="pbest") X, F, CV = off.get("X", "F", "CV") plt.scatter(X[:, 0], X[:, 1], color="blue", marker="o", s=30, 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)
def result(self, only_optimum=True, return_values_of="auto"): if return_values_of == "auto": return_values_of = ["X", "F"] if self.problem.n_constr > 0: return_values_of.append("CV") if only_optimum: self.algorithm.finalize() pop, opt = self.algorithm.pop, self.algorithm.opt res = filter_optimum(pop.copy()) if opt is None else opt.copy() if isinstance(res, Individual): res = Population.create(res) else: res = self.algorithm.pop return res.get(*return_values_of)
def _initialize(self): # the boundaries of the problem for initialization xl, xu = self.problem.bounds() # the golden ratio (precomputed constant) R = self.R # a and b always represents the boundaries a, b = Individual(X=xl), Individual(X=xu) # create the left and right in the interval itself left, right = Individual(X=xu - R * (xu - xl)), Individual(X=xl + R * (xu - xl)) # create a population with all four individuals pop = Population.create(a, left, right, b) # evaluate all the points self.evaluator.eval(self.problem, pop, algorithm=self) self.pop = pop
def do(self, individual, **kwargs): prob = self.problem n_var, n_obj, n_constr = prob.n_var, prob.n_obj, prob.n_constr individual = Individual(X=individual.X) self.evaluator.eval(self.problem, Population.create(individual)) dF = np.zeros((n_obj, n_var)) dG = np.zeros((n_constr, n_var)) for i in range(n_var): x = np.copy(individual.X) x[i] += self.epsilon eps_F, _, eps_G = self.evaluator.eval(prob, x) dF[:, i] = (eps_F - individual.F) / self.epsilon if n_constr > 0 and eps_G is not None: dG[:, i] = (eps_G - individual.G) / self.epsilon return dF, dG
def _next(self): # get the offspring solutions and evaluate them off = self._step() self.evaluator.eval(self.problem, off, algorithm=self) # the the personal bests of the current population pbest = Population.create(*self.pop.get("pbest")) # if an offspring has improved the personal store that index 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]) pop = off self.off = off self.pop = pop if self.adaptive: self._adapt()
def eval(self, problem, X, algorithm=None, **kwargs): pop = pop_from_array_or_individual(X) pop.set("algorithm", [algorithm] * len(pop)) if self.history is None: self.history = pop else: self.history = Population.create(self.history, pop) before = self.n_eval ret = super().eval(problem, X, **kwargs) after = self.n_eval if algorithm is not None: if algorithm not in self.algorithms: self.algorithms[algorithm] = 0 self.algorithms[algorithm] += after - before if self.opt is None or pop.get("F").min() < self.opt[0].F.min(): self.opt = pop[[pop.get("F").argmin()]] return ret
def _next(self): problem, evaluator = self.problem, self.evaluator # add the box constraints defined in the problem bounds = None if self.use_bounds: xl, xu = self.problem.bounds() if self.with_bounds: bounds = np.column_stack([xl, xu]) else: if xl is not None or xu is not None: raise Exception(f"Error: Boundary constraints can not be handled by {self.method}") # define the actual constraints if supported by the algorithm constr = [] if self.use_constr: constr = [LinearConstraint(np.eye(self.problem.n_var), xl, xu)] if problem.has_constraints(): if self.with_constr: def fun_constr(x): g, cv = problem.evaluate(x, return_values_of=["G", "CV"]) return cv[0] non_lin_constr = NonlinearConstraint(fun_constr, -float("inf"), 0) constr.append(non_lin_constr) else: raise Exception(f"Error: Constraint handling is not supported by {self.method}") # the objective function to be optimized and add gradients if available if self.estm_gradients: jac = None def fun_obj(x): f = problem.evaluate(x, return_values_of=["F"])[0] evaluator.n_eval += 1 return f else: jac = True def fun_obj(x): f, df = problem.evaluate(x, return_values_of=["F", "dF"]) if df is None: raise Exception("If the gradient shall not be estimate, please set out['dF'] in _evaluate. ") evaluator.n_eval += 1 return f[0], df[0] # the arguments to be used kwargs = dict(args=(), method=self.method, bounds=bounds, constraints=constr, jac=jac, options=self.options) # the starting solution found by sampling beforehand x0 = self.opt[0].X # actually run the optimization if not self.show_warnings: warnings.simplefilter("ignore") res = scipy_minimize(fun_obj, x0, **kwargs) opt = Population.create(Individual(X=res.x)) self.evaluator.eval(self.problem, opt, algorithm=self) self.pop = opt self.termination.force_termination = True if hasattr("res", "nit"): self.n_gen = res.nit + 1
def test_update_ca(self): problem = C1DTLZ3(n_var=12, n_obj=3) ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'preCA.x')) CA = Population.create(ca_x) self.evaluator.eval(problem, CA) da_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'preDA.x')) DA = Population.create(da_x) self.evaluator.eval(problem, DA) off_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'offspring.x')) off = Population.create(off_x) self.evaluator.eval(problem, off) post_ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz3', 'case3', 'postCA.x')) true_pCA = Population.create(post_ca_x) self.evaluator.eval(problem, true_pCA) survival = CADASurvival(self.ref_dirs) mixed = CA.merge(off) survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0) pCA = survival._updateCA(mixed, len(self.ref_dirs)) pX = set([tuple(x) for x in pCA.get("X")]) tpX = set([tuple(x) for x in true_pCA.get("X")]) assert pX == tpX problem = C1DTLZ1(n_var=9, n_obj=3) ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz1', 'preCA.x')) CA = Population.create(ca_x) self.evaluator.eval(problem, CA) da_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz1', 'preDA.x')) DA = Population.create(da_x) self.evaluator.eval(problem, DA) off_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz1', 'offspring.x')) off = Population.create(off_x) self.evaluator.eval(problem, off) post_ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c1dtlz1', 'postCA.x')) true_pCA = Population.create(post_ca_x) self.evaluator.eval(problem, true_pCA) survival = CADASurvival(self.ref_dirs) mixed = CA.merge(off) survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0) pCA = survival._updateCA(mixed, len(self.ref_dirs)) pX = set([tuple(x) for x in pCA.get("X")]) tpX = set([tuple(x) for x in true_pCA.get("X")]) assert pX == tpX problem = C3DTLZ4(n_var=12, n_obj=3) ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c3dtlz4', 'case1', 'preCA.x')) CA = Population.create(ca_x) self.evaluator.eval(problem, CA) da_x = np.loadtxt(path_to_test_resources('ctaea', 'c3dtlz4', 'case1', 'preDA.x')) DA = Population.create(da_x) self.evaluator.eval(problem, DA) off_x = np.loadtxt(path_to_test_resources('ctaea', 'c3dtlz4', 'case1', 'offspring.x')) off = Population.create(off_x) self.evaluator.eval(problem, off) post_ca_x = np.loadtxt(path_to_test_resources('ctaea', 'c3dtlz4', 'case1', 'postCA.x')) true_pCA = Population.create(post_ca_x) self.evaluator.eval(problem, true_pCA) survival = CADASurvival(self.ref_dirs) mixed = CA.merge(off) survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0) pCA = survival._updateCA(mixed, len(self.ref_dirs)) pX = set([tuple(x) for x in pCA.get("X")]) tpX = set([tuple(x) for x in true_pCA.get("X")]) assert pX == tpX
def _next(self): # initialize all ants to be used in this iteration ants = [] for k in range(self.n_ants): ant = self.ant() ant.initialize(self.problem, self.pheromones) ants.append(ant) active = list(range(self.n_ants)) while len(active) > 0: for k in active: ant = ants[k] if ant.has_next(): ant.next() if self.local_update: e = ant.last() if e is None or e.pheromone is None: raise Exception( "For a local update the ant has to set the pheromones when notified." ) else: self.pheromones.set( e.key, self.pheromones.get(e.key) * ant.alpha + e.pheromone * ant.alpha) # self.pheromones.update(e.key, e.pheromone * ant.alpha) else: ant.finalize() active = [i for i in active if i != k] colony = Population.create(*ants) # this evaluation can be disabled or faked if evaluate_each_ant is false - then the finalize method of the # ant has to set the objective and/or constraint values accordingly self.evaluator.eval(self.problem, colony) set_cv(colony) set_feasibility(colony) # set the current best including the new colony opt = FitnessSurvival().do(problem, Population.merge(colony, self.opt), 1) # do the evaporation after this iteration self.pheromones.evaporate() # select the ants to be used for the global pheromone update if self.global_update == "all": ants_to_update = colony elif self.global_update == "it-best": ants_to_update = FitnessSurvival().do(problem, colony, 1) elif self.global_update == "best": ants_to_update = self.opt else: raise Exception( "Unknown value for global updating the pheromones!") # now spread the pheromones for each ant depending on performance for ant in ants_to_update: 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 _next(self): # all place visited so far _X, _F, _evaluated_by_algorithm = self.evaluator.history.get("X", "F", "algorithm") # collect attributes from each algorithm and determine whether it has to be replaced or not pop, F, n_evals = [], [], [] for k, algorithm in enumerate(self.algorithms): # collect some data from the current algorithms _pop = algorithm.pop # if the algorithm has terminated or not has_finished = algorithm.termination.has_terminated(algorithm) # if the area was already explored before closest_dist_to_others = vectorized_cdist(_pop.get("X"), _X[_evaluated_by_algorithm != algorithm], func_dist=norm_euclidean_distance(self.problem)) too_close_to_others = (closest_dist_to_others.min(axis=1) < 1e-3).all() # whether the algorithm is the current best - if yes it will not be replaced current_best = self.evaluator.opt.get("F") == _pop.get("F").min() # algorithm not really useful anymore if not current_best and (has_finished or too_close_to_others): # find a suitable x0 which is far from other or has good expectations self.sampling.criterion = lambda X: vectorized_cdist(X, _X).min() X = self.sampling.do(self.problem, self.n_initial_samples).get("X") # distance in x space to other existing points x_dist = vectorized_cdist(X, _X, func_dist=norm_euclidean_distance(self.problem)).min(axis=1) f_pred, f_uncert = predict_by_nearest_neighbors(_X, _F, X, 5, self.problem) fronts = NonDominatedSorting().do(np.column_stack([- x_dist, f_pred, f_uncert])) I = np.random.choice(fronts[0]) # I = vectorized_cdist(X, _X, func_dist=norm_euclidean_distance(self.problem)).min(axis=1).argmax() # choose the one with the largest distance to current solutions x0 = X[[I]] # replace the current algorithm algorithm = get_algorithm("nelder-mead", problem=self.problem, x0=x0, termination=NelderAndMeadTermination(x_tol=1e-3, f_tol=1e-3), evaluator=self.evaluator, ) algorithm.initialize() self.algorithms[k] = algorithm pop.append(algorithm.pop) F.append(algorithm.pop.get("F")) n_evals.append(self.evaluator.algorithms[algorithm]) # get the values of all algorithms as arrays F, n_evals = np.array(F), np.array(n_evals) rewards = 1 - normalize(F.min(axis=1))[:, 0] n_evals_total = self.evaluator.n_eval - self.evaluator.algorithms[self] # calculate the upper confidence bound ucb = rewards + 0.95 * np.sqrt(np.log(n_evals_total) / n_evals) I = ucb.argmax() self.algorithms[I].next() # create the population object with all algorithms self.pop = Population.create(*pop) # update the current optimum self.opt = self.evaluator.opt
def _set_optimum(self, force=False): pbest = Population.create(*self.pop.get("pbest")) self.opt = filter_optimum(pbest, least_infeasible=True)
def _update(self): D = self.D ind = Individual(X=np.copy(D["X"]), F=np.copy(D["F"]), G=np.copy(-D["G"])) ind.CV = Problem.calc_constraint_violation(ind.G[None, :])[0] ind.feasible = (ind.CV <= 0) self.pop = Population.merge(self.pop, Population.create(ind))