def update(self, population): """Update the Pareto front hall of fame with the *population* by adding the individuals from the population that are not dominated by the hall of fame. If any individual in the hall of fame is dominated it is removed. :param population: A list of individual with a fitness attribute to update the hall of fame with. """ added = 0 removed = 0 for ind in population: is_dominated = False has_twin = False to_remove = [] for i, hofer in enumerate(self): # hofer = hall of famer if isDominated(ind.fitness.wvalues, hofer.fitness.wvalues): is_dominated = True break elif isDominated(hofer.fitness.wvalues, ind.fitness.wvalues): to_remove.append(i) elif ind.fitness == hofer.fitness and self.similar(ind, hofer): has_twin = True break for i in reversed(to_remove): # Remove the dominated hofer self.remove(i) removed+=1 if not is_dominated and not has_twin: self.insert(ind) added+=1 return added, removed
def selSPEA2(individuals, k): """Apply SPEA-II selection operator on the *individuals*. Usually, the size of *individuals* will be larger than *n* because any individual present in *individuals* will appear in the returned list at most once. Having the size of *individuals* equals to *n* will have no effect other than sorting the population according to a strength Pareto scheme. The list returned contains references to the input *individuals*. For more details on the SPEA-II operator see [Zitzler2001]_. :param individuals: A list of individuals to select from. :param k: The number of individuals to select. :returns: A list of selected individuals. .. [Zitzler2001] Zitzler, Laumanns and Thiele, "SPEA 2: Improving the strength Pareto evolutionary algorithm", 2001. """ N = len(individuals) L = len(individuals[0].fitness.values) K = math.sqrt(N) strength_fits = [0] * N fits = [0] * N dominating_inds = [list() for i in xrange(N)] for i in xrange(N): for j in xrange(i + 1, N): if tools.isDominated(individuals[i].fitness.wvalues, individuals[j].fitness.wvalues): strength_fits[j] += 1 dominating_inds[i].append(j) elif tools.isDominated(individuals[j].fitness.wvalues, individuals[i].fitness.wvalues): strength_fits[i] += 1 dominating_inds[j].append(i) for i in xrange(N): for j in dominating_inds[i]: fits[i] += strength_fits[j] # Choose all non-dominated individuals chosen_indices = [i for i in xrange(N) if fits[i] < 1] if len(chosen_indices) < k: # The archive is too small for i in xrange(N): distances = [0.0] * N for j in xrange(i + 1, N): dist = 0.0 for l in xrange(L): val = individuals[i].fitness.values[l] -\ individuals[j].fitness.values[l] dist += val * val distances[j] = dist kth_dist = tools._randomizedSelect(distances, 0, N - 1, K) density = 1.0 / (kth_dist + 2.0) fits[i] += density next_indices = [(fits[i], i) for i in xrange(N)\ if not i in chosen_indices] next_indices.sort() #print next_indices chosen_indices += [i for _, i in next_indices[:k - len(chosen_indices)]] elif len(chosen_indices) > k: # The archive is too large N = len(chosen_indices) distances = [[0.0] * N for i in xrange(N)] sorted_indices = [[0] * N for i in xrange(N)] for i in xrange(N): for j in xrange(i + 1, N): dist = 0.0 for l in xrange(L): val = individuals[chosen_indices[i]].fitness.values[l] -\ individuals[chosen_indices[j]].fitness.values[l] dist += val * val distances[i][j] = dist distances[j][i] = dist distances[i][i] = -1 # Insert sort is faster than quick sort for short arrays for i in xrange(N): for j in xrange(1, N): l = j while l > 0 and distances[i][j] < distances[i][sorted_indices[i][l - 1]]: sorted_indices[i][l] = sorted_indices[i][l - 1] l -= 1 sorted_indices[i][l] = j size = N to_remove = [] while size > k: # Search for minimal distance min_pos = 0 for i in xrange(1, N): for j in xrange(1, size): dist_i_sorted_j = distances[i][sorted_indices[i][j]] dist_min_sorted_j = distances[min_pos][sorted_indices[min_pos][j]] if dist_i_sorted_j < dist_min_sorted_j: min_pos = i break elif dist_i_sorted_j > dist_min_sorted_j: break # Remove minimal distance from sorted_indices for i in xrange(N): distances[i][min_pos] = float("inf") distances[min_pos][i] = float("inf") for j in xrange(1, size - 1): if sorted_indices[i][j] == min_pos: sorted_indices[i][j] = sorted_indices[i][j + 1] sorted_indices[i][j + 1] = min_pos # Remove corresponding individual from chosen_indices to_remove.append(min_pos) size -= 1 for index in reversed(sorted(to_remove)): del chosen_indices[index] return [individuals[i] for i in chosen_indices],[fits[i] for i in chosen_indices]