class_docstr: Non-dominated ranking of NSGA-II proposed by Deb et al., see [Deb2002]
docstr: Compute ranking of candidates.
  
  :param candidates: List of candidates.
  :param k: Number of individuals.
code: def compute_ranking(
      self, candidates: tp.List[p.Parameter], k: tp.Optional[int] = None
  ) -> tp.List[tp.List[p.Parameter]]:
      """Compute ranking of candidates.
  
      :param candidates: List of candidates.
      :param k: Number of individuals.
      """
      n_cand: int = len(candidates)
      # dominated_by_cnt[i]: number of candidates dominating ith candidate
      dominated_by_cnt: tp.List[int] = [
          0
      ] * n_cand  # [0 for _ in range(len(candidates))]
  
      # candidates_dominated[i]: List of candidates dominated by ith candidate
      candidates_dominated: tp.List[tp.List[int]] = [
          [] for _ in range(n_cand)
      ]
  
      # front[i] contains the list of solutions belonging to front i
      front: tp.List[tp.List[int]] = [[] for _ in range(n_cand + 1)]
  
      uid2candidate = {c.uid: c for c in candidates}
      uids = [c.uid for c in candidates]
      for c1 in range(n_cand - 1):
          uid1 = uids[c1]
          for c2 in range(c1 + 1, n_cand):
              uid2 = uids[c2]
              dominance_test_result = self.compare(
                  uid2candidate[uid1], uid2candidate[uid2]
              )
              # self.number_of_comparisons += 1
              if dominance_test_result == -1:
                  # c1 wins
                  candidates_dominated[c1].append(c2)
                  dominated_by_cnt[c2] += 1
              elif dominance_test_result == 1:
                  # c2 wins
                  candidates_dominated[c2].append(c1)
                  dominated_by_cnt[c1] += 1
  
      # Reset rank
      for cand in candidates:
          cand._meta["non_dominated_rank"] = float("inf")
  
      # Formation of front[0], i.e. candidates that do not dominated by others
      front[0] = [
          c1 for c1 in range(n_cand) if dominated_by_cnt[c1] == 0
      ]
      last_fronts = 0
      while len(front[last_fronts]) != 0:
          last_fronts += 1
          # Number of candidates in a frontier <= Number of candidates that dominate at least 1 candidate
          assert len(front[last_fronts - 1]) <= len(
              candidates_dominated
          )
          for c1 in front[last_fronts - 1]:
              for c2 in candidates_dominated[c1]:
                  dominated_by_cnt[c2] -= 1
                  if dominated_by_cnt[c2] == 0:
                      front[last_fronts].append(c2)
  
      # Convert index to uid
      # Trim to frontiers that contain the k candidates of interest
      ranked_sublists = []
      count = 0
      for front_i in range(last_fronts):
          count += len(front[front_i])
          for cand_i in front[front_i]:
              uid2candidate[uids[cand_i]]._meta[
                  "non_dominated_rank"
              ] = front_i
          ranked_sublists.append(
              [uid2candidate[uids[i]] for i in front[front_i]]
          )
          if (k is not None) and (count >= k):
              break
  
      return ranked_sublists
  
file_path: nevergrad/nevergrad/optimization/multiobjective/nsga2.py
imports: import logging
  import numpy
  import nevergrad.common.typing
  from nevergrad.parametrization import parameter
label_desc: Use image node_id 2 for calling the FastNonDominatedRanking obj's underlying member method code with example usage: obj.compute_ranking(candidates, k) and returns: ranked_sublists