code: 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 range(N)]
  
      for i, ind_i in enumerate(individuals):
          for j, ind_j in enumerate(individuals[i + 1 :], i + 1):
              if ind_i.fitness.dominates(ind_j.fitness):
                  strength_fits[i] += 1
                  dominating_inds[j].append(i)
              elif ind_j.fitness.dominates(ind_i.fitness):
                  strength_fits[j] += 1
                  dominating_inds[i].append(j)
  
      for i in range(N):
          for j in dominating_inds[i]:
              fits[i] += strength_fits[j]
  
      # Choose all non-dominated individuals
      chosen_indices = [i for i in range(N) if fits[i] < 1]
  
      if len(chosen_indices) < k:  # The archive is too small
          for i in range(N):
              distances = [0.0] * N
              for j in range(i + 1, N):
                  dist = 0.0
                  for k in range(L):
                      val = (
                          individuals[i].fitness.values[k]
                          - individuals[j].fitness.values[k]
                      )
                      dist += val * val
                  distances[j] = dist
              kth_dist = _randomizedSelect(distances, 0, N - 1, K)
              density = 1.0 / (kth_dist + 2.0)
              fits[i] += density
  
          next_indices = [
              (fits[i], i) for i in range(N) if i not 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 range(N)]
          sorted_indices = [[0] * N for i in range(N)]
          for i in range(N):
              for j in range(i + 1, N):
                  dist = 0.0
                  for k in range(L):
                      val = (
                          individuals[chosen_indices[i]].fitness.values[
                              k
                          ]
                          - individuals[
                              chosen_indices[j]
                          ].fitness.values[k]
                      )
                      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 range(N):
              for j in range(1, N):
                  k = j
                  while (
                      k > 0
                      and distances[i][j]
                      < distances[i][sorted_indices[i][k - 1]]
                  ):
                      sorted_indices[i][k] = sorted_indices[i][k - 1]
                      k -= 1
                  sorted_indices[i][k] = j
  
          size = N
          to_remove = []
          while size > k:
              # Search for minimal distance
              min_pos = 0
              for i in range(1, N):
                  for j in range(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 range(N):
                  distances[i][min_pos] = float("inf")
                  distances[min_pos][i] = float("inf")
  
                  for j in range(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]
  
imports: import bisect
  from collections import defaultdict, namedtuple
  from itertools import chain
  import math
  from operator import attrgetter, itemgetter
  import random
  import numpy
label_desc: Use image node_id 21 for calling a global function with example usage: selSPEA2(individuals, k) and returns: unknown