/**
   * Prunes the population to the specified size. This is similar to {@link #truncate(int)}, except
   * the crowding distance is recalculated each time a solution is removed.
   *
   * @param size the target population size after pruning
   */
  public void prune(int size) {
    if (modified) {
      update();
    }

    sort(new RankComparator());

    // collect all solutions in the front which must be pruned
    // note the use of super to prevent repeatedly triggering update()
    int maxRank = (Integer) super.get(size - 1).getAttribute(RANK_ATTRIBUTE);
    Population front = new Population();

    for (int i = size() - 1; i >= 0; i--) {
      Solution solution = super.get(i);
      int rank = (Integer) solution.getAttribute(RANK_ATTRIBUTE);

      if (rank >= maxRank) {
        super.remove(i);

        if (rank == maxRank) {
          front.add(solution);
        }
      }
    }

    // prune front until correct size
    while (size() + front.size() > size) {
      nondominatedSorting.updateCrowdingDistance(front);
      front.truncate(front.size() - 1, new CrowdingComparator());
    }

    addAll(front);
  }
 /**
  * Updates the rank and crowding distance of all solutions in this population. This method will in
  * general be called automatically when the population is modified. However, only changes made to
  * this population can be tracked; changes made directly to the contained solutions will not be
  * detected. Therefore, it may be necessary to invoke {@link #update()} manually.
  */
 public void update() {
   modified = false;
   nondominatedSorting.evaluate(this);
 }