code: import numpy as np
  
  from pymoo.core.survival import Survival
  from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
  from pymoo.util.randomized_argsort import randomized_argsort
  
  # ---------------------------------------------------------------------------------------------------------
  # Survival Selection
  # ---------------------------------------------------------------------------------------------------------
  
  
  class RankAndNoveltySurvival(Survival):
  
      def __init__(self, nds=None) -> None:
          super().__init__(filter_infeasible=True)
          self.nds = nds if nds is not None else NonDominatedSorting()
  
      def _do(self, problem, pop, *args, n_survive=None, **kwargs):
  
          # get the objective space values and objects
          F = pop.get("F").astype(float, copy=False)
  
          # the final indices of surviving individuals
          survivors = []
  
          # do the non-dominated sorting until splitting front
          fronts = self.nds.do(F, n_stop_if_ranked=n_survive)
  
          for k, front in enumerate(fronts):
  
              # calculate the novelty of the front
              novelty_of_front = get_unaligned_novelty(pop[front])
  
              # save rank and crowding in the individual class
              for j, i in enumerate(front):
                  pop[i].set("rank", k)
                  pop[i].set("crowding", novelty_of_front[j])
  
              # current front sorted by crowding distance if splitting
              if len(survivors) + len(front) > n_survive:
                  I = randomized_argsort(novelty_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 get_unaligned_novelty(pop):
      return np.array([x_i.X.unaligned_novelty_metric for x_i in pop])
  
apis: numpy.array