docs: protected int[] rankUnfeasibleSolutions(List<S> population){
          int numberOfViolatedConstraintsBySolution1, numberOfViolatedConstraintsBySolution2;
          int indexOfFirstSolution, indexOfSecondSolution, indexOfWeight;
          double overallConstraintViolationSolution1, overallConstraintViolationSolution2;
          double minimumValueFirstSolution, minimumValueSecondSolution, value;
          int[] rank = new int[population.size()];
          Arrays.fill(rank, 0);
  
          //Iteration for each solution
          for (indexOfFirstSolution = 0; indexOfFirstSolution < population.size()-1; indexOfFirstSolution++ ) {
              //The current solution is compared with the following ones
              for (indexOfSecondSolution = indexOfFirstSolution + 1; indexOfSecondSolution < population.size(); indexOfSecondSolution++) {
                  numberOfViolatedConstraintsBySolution1 = numberOfViolatedConstraints.getAttribute(population.get(indexOfFirstSolution));
                  numberOfViolatedConstraintsBySolution2 = numberOfViolatedConstraints.getAttribute(population.get(indexOfSecondSolution));
  
                  //The number of violated constraints is compared.
                  //A solution with higher number of violated constraints has a worse (higher) rank
                  if (numberOfViolatedConstraintsBySolution1 > numberOfViolatedConstraintsBySolution2) {
                      rank[indexOfFirstSolution]++;
                  } else if (numberOfViolatedConstraintsBySolution1 < numberOfViolatedConstraintsBySolution2) {
                      rank[indexOfSecondSolution]++;
                  } else {
                      //Because the solutions have a similar violated number of constraints, the overall constraint
                      //violation values are compared.
                      //Note that overall constraint values are negative in jMetal
                      overallConstraintViolationSolution1 = overallConstraintViolation.getAttribute(population.get(indexOfFirstSolution));
                      overallConstraintViolationSolution2 = overallConstraintViolation.getAttribute(population.get(indexOfSecondSolution));
  
                      //The overall constraint violation values are compared.
                      //Note that overall constraint values are negative in jMetal.
                      //Thus, a solution with higher value has a better (higher) rank
                      if (overallConstraintViolationSolution1 > overallConstraintViolationSolution2) {
                          rank[indexOfSecondSolution]++;
                      } else if (overallConstraintViolationSolution1 < overallConstraintViolationSolution2) {
                          rank[indexOfFirstSolution]++;
                      } else {
                          //Because the solutions have the same overall constraint violation values, we compare the
                          //the value of their utility functions. Lower values are better.
                          minimumValueFirstSolution = minimumValueSecondSolution = Double.POSITIVE_INFINITY;
                          for (indexOfWeight = 0; indexOfWeight < this.utilityFunctionsNadir.getSize(); indexOfWeight++) {
                              value = this.utilityFunctionsNadir.evaluate(population.get(indexOfFirstSolution), indexOfWeight);
                              if (value < minimumValueFirstSolution) {
                                  minimumValueFirstSolution = value;
                              }
  
                              value = this.utilityFunctionsNadir.evaluate(population.get(indexOfSecondSolution), indexOfWeight);
                              if (value < minimumValueSecondSolution) {
                                  minimumValueSecondSolution = value;
                              }
                          }
                          for (indexOfWeight = 0; indexOfWeight < this.utilityFunctionsUtopia.getSize(); indexOfWeight++) {
                              value = this.utilityFunctionsUtopia.evaluate(population.get(indexOfFirstSolution), indexOfWeight);
                              if (value < minimumValueFirstSolution) {
                                  minimumValueFirstSolution = value;
                              }
  
                              value = this.utilityFunctionsUtopia.evaluate(population.get(indexOfSecondSolution), indexOfWeight);
                              if (value < minimumValueSecondSolution) {
                                  minimumValueSecondSolution = value;
                              }
                          }
  
                          if (minimumValueFirstSolution < minimumValueSecondSolution) {
                              rank[indexOfSecondSolution]++;
                          } else {
                              rank[indexOfFirstSolution]++;
                          }
                      }
                  }
              }
          }
  
          return rank;
      }