def _do(self, problem, pop, n_survive, D=None, **kwargs): # attributes to be set after the survival F = pop.get("F") # find or usually update the new ideal point - from feasible solutions self.ideal_point = np.min(np.vstack( (self.ideal_point, F, self.ref_points)), axis=0) self.worst_point = np.max(np.vstack( (self.worst_point, F, self.ref_points)), axis=0) # calculate the fronts of the population fronts, rank = NonDominatedSorting().do(F, return_rank=True, n_stop_if_ranked=n_survive) non_dominated, last_front = fronts[0], fronts[-1] # find the extreme points for normalization self.extreme_points = get_extreme_points_c( np.vstack([F[non_dominated], self.ref_points]), self.ideal_point, extreme_points=self.extreme_points) # find the intercepts for normalization and do backup if gaussian elimination fails worst_of_population = np.max(F, axis=0) worst_of_front = np.max(F[non_dominated, :], axis=0) self.nadir_point = get_nadir_point(self.extreme_points, self.ideal_point, self.worst_point, worst_of_population, worst_of_front) # consider only the population until we come to the splitting front I = np.concatenate(fronts) pop, rank, F = pop[I], rank[I], F[I] # update the front indices for the current population counter = 0 for i in range(len(fronts)): for j in range(len(fronts[i])): fronts[i][j] = counter counter += 1 last_front = fronts[-1] unit_ref_points = (self.ref_points - self.ideal_point) / ( self.nadir_point - self.ideal_point) ref_dirs = get_ref_dirs_from_points(unit_ref_points, self.aspiration_ref_dirs, mu=self.mu) self.ref_dirs = denormalize(ref_dirs, self.ideal_point, self.nadir_point) # associate individuals to niches niche_of_individuals, dist_to_niche, dist_matrix = associate_to_niches( F, ref_dirs, self.ideal_point, self.nadir_point) pop.set('rank', rank, 'niche', niche_of_individuals, 'dist_to_niche', dist_to_niche) # set the optimum, first front and closest to all reference directions closest = np.unique( dist_matrix[:, np.unique(niche_of_individuals)].argmin(axis=0)) self.opt = pop[intersect(fronts[0], closest)] # if we need to select individuals to survive if len(pop) > n_survive: # if there is only one front if len(fronts) == 1: n_remaining = n_survive until_last_front = np.array([], dtype=int) niche_count = np.zeros(len(ref_dirs), dtype=int) # if some individuals already survived else: until_last_front = np.concatenate(fronts[:-1]) niche_count = calc_niche_count( len(ref_dirs), niche_of_individuals[until_last_front]) n_remaining = n_survive - len(until_last_front) S = niching(pop[last_front], n_remaining, niche_count, niche_of_individuals[last_front], dist_to_niche[last_front]) survivors = np.concatenate( (until_last_front, last_front[S].tolist())) pop = pop[survivors] return pop
def _do(self, problem, pop, n_survive, **kwargs): # get the objective space values and objects F = pop.get("F") # the final indices of surviving individuals survivors = [] # do the non-dominated sorting until splitting front fronts = NonDominatedSorting().do(F) if self.normalization == "ever": # find or usually update the new ideal point - from feasible solutions self.ideal_point = np.min(np.vstack((self.ideal_point, F)), axis=0) self.nadir_point = np.max(np.vstack((self.nadir_point, F)), axis=0) elif self.normalization == "front": front = fronts[0] if len(front) > 1: self.ideal_point = np.min(F[front], axis=0) self.nadir_point = np.max(F[front], axis=0) elif self.normalization == "no": self.ideal_point = np.zeros(self.n_obj) self.nadir_point = np.ones(self.n_obj) if self.extreme_points_as_reference_points: self.ref_points = np.row_stack( [self.ref_points, get_extreme_points_c(F, self.ideal_point)]) # calculate the distance matrix from ever solution to all reference point dist_to_ref_points = calc_norm_pref_distance(F, self.ref_points, self.weights, self.ideal_point, self.nadir_point) for k, front in enumerate(fronts): # save rank attributes to the individuals - rank = front here pop[front].set("rank", np.full(len(front), k)) # number of individuals remaining n_remaining = n_survive - len(survivors) # the ranking of each point regarding each reference point (two times argsort is necessary) rank_by_distance = np.argsort(np.argsort(dist_to_ref_points[front], axis=0), axis=0) # the reference point where the best ranking is coming from ref_point_of_best_rank = np.argmin(rank_by_distance, axis=1) # the actual ranking which is used as crowding ranking = rank_by_distance[np.arange(len(front)), ref_point_of_best_rank] if len(front) <= n_remaining: # we can simply copy the crowding to ranking. not epsilon selection here crowding = ranking I = np.arange(len(front)) else: # Distance from solution to every other solution and set distance to itself to infinity dist_to_others = calc_norm_pref_distance( F[front], F[front], self.weights, self.ideal_point, self.nadir_point) np.fill_diagonal(dist_to_others, np.inf) # the crowding that will be used for selection crowding = np.full(len(front), np.nan) # solutions which are not already selected - for not_selected = np.argsort(ranking) # until we have saved a crowding for each solution while len(not_selected) > 0: # select the closest solution idx = not_selected[0] # set crowding for that individual crowding[idx] = ranking[idx] # need to remove myself from not-selected array to_remove = [idx] # Group of close solutions dist = dist_to_others[idx][not_selected] group = not_selected[np.where(dist < self.epsilon)[0]] # if there exists solution with a distance less than epsilon if len(group): # discourage them by giving them a high crowding crowding[group] = ranking[group] + np.round( len(front) / 2) # remove group from not_selected array to_remove.extend(group) not_selected = np.array( [i for i in not_selected if i not in to_remove]) # now sort by the crowding (actually modified rank) ascending and let the best survive I = np.argsort(crowding)[:n_remaining] # 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 _do(self, pop, n_survive, D=None, **kwargs): # attributes to be set after the survival F = pop.get("F") # find or usually update the new ideal point - from feasible solutions self.ideal_point = np.min(np.vstack((self.ideal_point, F)), axis=0) self.worst_point = np.max(np.vstack((self.worst_point, F)), axis=0) # calculate the fronts of the population fronts, rank = NonDominatedSorting().do(F, return_rank=True, n_stop_if_ranked=n_survive) non_dominated, last_front = fronts[0], fronts[-1] # find the extreme points for normalization self.extreme_points = get_extreme_points_c( F[non_dominated, :], self.ideal_point, extreme_points=self.extreme_points) # find the intercepts for normalization and do backup if gaussian elimination fails worst_of_population = np.max(F, axis=0) worst_of_front = np.max(F[non_dominated, :], axis=0) self.nadir_point = get_nadir_point(self.extreme_points, self.ideal_point, self.worst_point, worst_of_population, worst_of_front) # consider only the population until we come to the splitting front I = np.concatenate(fronts) pop, rank, F = pop[I], rank[I], F[I] # update the front indices for the current population counter = 0 for i in range(len(fronts)): for j in range(len(fronts[i])): fronts[i][j] = counter counter += 1 # normalize the whole population by the estimations made N = normalize(F, self.ideal_point, self.nadir_point) # the final indices of surviving individuals survivors = [] for k, front in enumerate(fronts): # calculate the crowding distance of the front crowding_of_front = calc_asf_crowding_distance(N[front, :]) # save rank and crowding in the individual class for j, i in enumerate(front): pop[i].set("rank", k) pop[i].set("crowding", crowding_of_front[j]) # current front sorted by crowding distance if splitting if len(survivors) + len(front) > n_survive: I = randomized_argsort(crowding_of_front, order='descending', method='numpy') I = I[:(n_survive - len(survivors))] # otherwise take the whole front unsorted else: I = np.arange(len(front)) # extend the survivors by all or selected individuals survivors.extend(front[I]) return pop[survivors]
def _do(self, pop, n_survive, D=None, **kwargs): # attributes to be set after the survival X, F = pop.get("X", "F") # find or usually update the new ideal point - from feasible solutions self.ideal_point = np.min(np.vstack((self.ideal_point, F)), axis=0) self.worst_point = np.max(np.vstack((self.worst_point, F)), axis=0) # calculate the fronts of the population fronts, rank = NonDominatedSorting().do(F, return_rank=True, n_stop_if_ranked=n_survive) non_dominated, last_front = fronts[0], fronts[-1] # find the extreme points for normalization self.extreme_points = get_extreme_points_c( F[non_dominated, :], self.ideal_point, extreme_points=self.extreme_points) # find the intercepts for normalization and do backup if gaussian elimination fails worst_of_population = np.max(F, axis=0) worst_of_front = np.max(F[non_dominated, :], axis=0) self.nadir_point = get_nadir_point(self.extreme_points, self.ideal_point, self.worst_point, worst_of_population, worst_of_front) # consider only the population until we come to the splitting front I = np.concatenate(fronts) pop, rank, X, F = pop[I], rank[I], X[I], F[I] # update the front indices for the current population counter = 0 for i in range(len(fronts)): for j in range(len(fronts[i])): fronts[i][j] = counter counter += 1 last_front = fronts[-1] # associate individuals to niches niche_of_individuals, dist_to_niche = associate_to_niches( F, self.ref_dirs, self.ideal_point, self.nadir_point) kktpm, _ = KKTPM(var_bounds_as_constraints=False).calc(X, problem) kktpm = kktpm[:, 0] pop.set('rank', rank, 'niche', niche_of_individuals, 'dist_to_niche', dist_to_niche, 'kktpm', kktpm) # if we need to select individuals to survive if len(pop) > n_survive: # if there is only one front if len(fronts) == 1: n_remaining = n_survive until_last_front = np.array([], dtype=np.int) niche_count = np.zeros(len(self.ref_dirs), dtype=np.int) # if some individuals already survived else: until_last_front = np.concatenate(fronts[:-1]) niche_count = calc_niche_count( len(self.ref_dirs), niche_of_individuals[until_last_front]) n_remaining = n_survive - len(until_last_front) S = niching(F[last_front, :], n_remaining, niche_count, niche_of_individuals[last_front], kktpm[last_front]) survivors = np.concatenate( (until_last_front, last_front[S].tolist())) pop = pop[survivors] return pop