@Override
  public void restart(EvolutionaryAlgorithm algorithm) {

    int curr_pop_size, new_pop_size;

    if (curr_num_restarts < max_num_restarts) {

      curr_num_restarts++;

      curr_pop_size = algorithm.getPopulation().getSize();
      new_pop_size =
          (int) Math.ceil(curr_pop_size * Math.pow(this.incr_factor, this.curr_num_restarts));

      // Re-configure the algorithm:
      algorithm.configure(EAFConfiguration.getInstance());

      algorithm.setPopulationSize(new_pop_size);

      algorithm.setState(EvolutionaryAlgorithm.INIT_STATE);

    } else {
      // Continue with the algorithm:
      algorithm.setState(EvolutionaryAlgorithm.SELECT_STATE);
    }
  }
  @Override
  protected Individual select(EvolutionaryAlgorithm algorithm, List<Individual> individuals) {

    double random;
    double acum;
    int n = individuals.size();
    double min = 2 - this.max;
    double range = this.max - min;
    Individual individual;
    int i;

    // Se ordena la lista de individuos según el comparador en orden inverso:
    Collections.sort(individuals, algorithm.getComparator());
    Collections.reverse(individuals);

    // Ahora la posicion en la lista de cada individuo indica su rank:
    random = EAFRandom.nextDouble();

    acum = 0.0;

    i = 0;
    do {

      i++;
      acum += (1.0 / n) * (this.max - range * ((double) (i - 1.0) / (double) (n - 1.0)));

    } while (acum < random);

    individual = individuals.get(--i);

    return (Individual) individual.clone();
  }
  @Override
  public void update(Observable o, Object arg) {

    EvolutionaryAlgorithm algorithm = (EvolutionaryAlgorithm) o;
    BestIndividualSpecification bestSpec = new BestIndividualSpecification();
    Individual best;

    super.update(o, arg);

    if (algorithm.getState() == EvolutionaryAlgorithm.REPLACE_STATE && arg == null) {
      best = algorithm.getBestEverIndividual();
      super.getLog()
          .println(
              algorithm.getGenerations()
                  + " - "
                  + best.getFitness()
                  + " - "
                  + FitnessUtil.meanFitnessValue(algorithm.getPopulation().getIndividuals()));
    }
  }
  @Override
  public void update(Observable o, Object arg) {

    ParallelEvolutionaryAlgorithm pea = (ParallelEvolutionaryAlgorithm) o;

    if (pea.getCurrentObservable() instanceof EvolutionaryAlgorithm) {
      super.update(o, arg);
      EvolutionaryAlgorithm algorithm = (EvolutionaryAlgorithm) pea.getCurrentObservable();

      BestIndividualSpecification bestSpec = new BestIndividualSpecification();
      Individual best;
      int algorithm_fes;

      best =
          IndividualsProductTrader.get(
                  bestSpec, algorithm.getPopulation().getIndividuals(), 1, pea.getComparator())
              .get(0);

      if (algorithm.getState() == EvolutionaryAlgorithm.REPLACE_STATE) {
        algorithm_fes = algorithm.getFEs();

        if (num_prints < this.fes_prints.size()
            && algorithm_fes >= Integer.parseInt((String) this.fes_prints.get(fes_index))) {
          super.getLog().println(best);
          this.fes_index++;
          num_prints++;
        }
      }

      if (algorithm.getState() == EvolutionaryAlgorithm.FINAL_STATE) {
        while (num_prints < this.fes_prints.size()) {
          super.getLog().println(best);
          num_prints++;
        }
      }
    }
  }
  @Override
  public List<Individual> operate(EvolutionaryAlgorithm algorithm, List<Individual> individuals)
      throws OperatorException {
    MacroevolutionaryAlgorithm alg = (MacroevolutionaryAlgorithm) algorithm;
    FitnessComparator<Individual> comparator = algorithm.getComparator();
    Wxy wxy;
    MaIndividual indA, indB;
    double weight;
    int survivors = 0;

    if (comparator instanceof MaximizingFitnessComparator) {
      wxy = new WxyMaximizing();
    } else {
      if (comparator instanceof MinimizingFitnessComparator) {
        wxy = new WxyMinimizing();
      } else {
        throw new OperatorException("Wrong comparator for Inherit Extintion operator");
      }
    }
    for (int i = 0; i < individuals.size(); i++) {
      indA = (MaIndividual) individuals.get(i);
      if (indA.getBestFitness() != indA.getFitness()) {
        indA.setSurvivor(false);
      } else {
        for (int j = i + 1; j < individuals.size(); j++) {
          indB = (MaIndividual) individuals.get(j);
          if (!indA.isSurvivor() || !indB.isSurvivor()) {
            alg.setWxy(i, j, wxy.get(indA, indB));
          }
        }
        weight = 0;
        for (int j = 0; j < i; j++) {
          weight -= alg.getWxy(j, i);
        }
        for (int j = i + 1; j < individuals.size(); j++) {
          weight += alg.getWxy(i, j);
        }
        if (weight > 0) {
          indA.setSurvivor(true);
          survivors++;
        } else {
          if (weight < 0) {
            indA.setSurvivor(false);
          } else {
            if (EAFRandom.nextDouble() < 0.5) {
              indA.setSurvivor(true);
              survivors++;
            } else {
              indA.setSurvivor(false);
            }
          }
        }
      }
    }

    // We always need at least one survivor
    if (survivors == 0) {
      BestIndividual chooser = new BestIndividual();
      ((MaIndividual) chooser.get(algorithm, individuals, null)).setSurvivor(true);
    }

    return individuals;
  }
  @Override
  public List<Individual> operate(EvolutionaryAlgorithm algorithm, List<Individual> individuals)
      throws OperatorException {

    List<Individual> new_population = new ArrayList<Individual>(individuals.size());
    CMAEvolutionaryAlgorithm alg = (CMAEvolutionaryAlgorithm) algorithm;
    debug = algorithm.isDebug();

    double[] chromosome;

    int N = individuals.get(0).getDimension();

    countCUpdatesSinceEigenupdate = alg.getCountCupdatesSinceEigenupdate();
    // latest possibility to generate B and diagD:
    eidgendecomposition(alg, N, 0);

    // ensure minimal and maximal standard deviation:
    double minsqrtdiagC = Math.sqrt(StatUtils.min(alg.diag(alg.getC())));
    double maxsqrtdiagC = Math.sqrt(StatUtils.max(alg.diag(alg.getC())));

    /*
     * TODO: test if it is necessary *
     */
    for (int i = 0; i < individuals.size(); i++) {
      new_population.add((Individual) individuals.get(i).clone());
    }

    if (lowerStandardDeviation != null && lowerStandardDeviation.length > 0) {

      for (int i = 0; i < N; i++) {

        double d = lowerStandardDeviation[Math.min(i, lowerStandardDeviation.length - 1)];

        if (d > alg.getSigma() * minsqrtdiagC) {
          alg.setSigma(d / minsqrtdiagC);
        }
      }
    }

    if (upperStandardDeviation != null && upperStandardDeviation.length > 0) {

      for (int i = 0; i < N; i++) {

        double d = upperStandardDeviation[Math.min(i, upperStandardDeviation.length - 1)];

        if (d < alg.getSigma() * maxsqrtdiagC) {
          alg.setSigma(d / maxsqrtdiagC);
        }
      }
    }

    testAndCorrectNumerics(alg, N, new_population);

    double[] artmp = new double[N];

    /*
     * Sample the distribution
     */
    for (int iNk = 0; iNk < alg.getLambda(); iNk++) {

      chromosome = new_population.get(iNk).getChromosomeAt(0);

      if (alg.getFlgDiag()) {

        for (int i = 0; i < N; i++) {

          chromosome[i] =
              this.checkBounds(
                  alg,
                  alg.getxMean()[i] + alg.getSigma() * alg.getDiag()[i] * EAFRandom.nextGaussian());
        }

      } else {

        for (int i = 0; i < N; i++) {

          artmp[i] = alg.getDiag()[i] * EAFRandom.nextGaussian();
        }

        /*
         * add mutation (sigma * B * (D*z))
         */
        for (int i = 0; i < N; i++) {

          double sum = 0.0;
          for (int j = 0; j < N; j++) {

            sum += alg.getB()[i][j] * artmp[j];
          }

          chromosome[i] = this.checkBounds(alg, alg.getxMean()[i] + alg.getSigma() * sum);
        }
      }

      new_population.get(iNk).setChromosomeAt(0, chromosome);
    }

    return new_population;
  }