Esempio n. 1
0
 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
Esempio n. 2
0
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]