public Individual[] run(
      StopCondition cond,
      FitnessFunction fitness,
      SelectionAlgorithm[] selector,
      GenerationAlgorithm generator,
      ReplaceAlgorithm replacer,
      int lambda) {

    int t = 0;

    double prob[] = new double[selector.length];

    for (int i = 0; i < prob.length; i++) {
      prob[i] = 1 / prob.length;
    }

    Individual parents[] = fitness.initialize(lambda);

    double mini = minimize ? Double.MAX_VALUE : Double.MIN_VALUE;

    double better = minimize ? Double.MAX_VALUE : Double.MIN_VALUE;

    for (int i = 0; i < parents.length; i++) {
      double fit = fitness.fitness(parents[i]);
      if (minimize) {
        if (better > fit) {
          better = fit;
        }
      } else {
        if (better < fit) {
          better = fit;
        }
      }
    }

    double previous = better;

    boolean first = true;
    boolean second = true;
    ArrayList<Double> values = new ArrayList<Double>();

    ArrayList<Double> minis = new ArrayList<Double>();
    ArrayList<Double> maxis = new ArrayList<Double>();
    ArrayList<Double> promis = new ArrayList<Double>();
    ArrayList<Double> desvis = new ArrayList<Double>();

    while (!cond.stop(parents, fitness, t)) {
      for (int l = 0; l < lambda; l += 2) {
        Individual[] marriage = new Individual[2];
        marriage[0] = parents[StdRandom.uniform(lambda)];
        marriage[1] = parents[StdRandom.uniform(lambda)];
        marriage = generator.generate(marriage, fitness, minimize);
        parents[l] = marriage[0];
        if (l + 1 < lambda) {
          parents[l + 1] = marriage[1];
        }
      }
      double rnd = StdRandom.uniform(0.0, 1.0);
      double sum = 0.0;
      SelectionAlgorithm sel = selector[selector.length - 1];
      int index = selector.length - 1;
      for (int i = 0; i < prob.length; i++) {
        if ((sum += prob[i]) >= rnd) {
          sel = selector[i];
          index = i;
          break;
        }
      }
      parents = sel.selection(parents, fitness, minimize);

      double prom = 0.0;
      better = minimize ? Double.MAX_VALUE : Double.MIN_VALUE;

      for (int i = 0; i < parents.length; i++) {
        double fit = fitness.fitness(parents[i]);
        values.add(fit);
        prom += fit;
        if (minimize) {
          if (better > fit) {
            better = fit;
          }
        } else {
          if (better < fit) {
            better = fit;
          }
        }
      }
      prom /= parents.length;
      if (prom != mini) {

        prob[index] +=
            minimize && prom < mini
                ? (1 - prob[index]) / prob.length
                : (-1 * prob[index]) / prob.length;

        for (int i = 0; i < prob.length; i++) {
          if (i != index) {
            prob[i] +=
                minimize && prom < mini
                    ? -1 * (1 - prob[index]) / (prob.length * (prob.length - 1))
                    : (prob[index]) / (prob.length * (prob.length - 1));
          }
        }

        mini = minimize && prom < mini ? prom : mini;
        mini = !minimize && prom > mini ? prom : mini;
      }

      if (Math.abs(previous - better) < StdRandom.uniform(0.0, 1)) {

        for (int i = 0; i < parents.length; i++) {
          double par[] = parents[i].getParameters();
          par[Individual.DELTA] += StdRandom.uniform(0.5, fitness.getConstraintMax() * 2);
          parents[i].setParameters(par);
        }
      } else if (Math.abs(previous - better) > StdRandom.uniform(100, 10000)) {
        for (int i = 0; i < parents.length; i++) {
          double par[] = parents[i].getParameters();
          if (par[Individual.DELTA] > 0) {
            par[Individual.DELTA] -= StdRandom.uniform(0, par[Individual.DELTA] / 2);
          }

          parents[i].setParameters(par);
        }
      }

      previous = better;

      t++;

      if (fitness.callsNumber() >= 120000 && first) {
        first = false;
        Statistics.run(values, fitness, minimize);
      }
      if (fitness.callsNumber() >= 600000 && second) {
        second = false;
        Statistics.run(values, fitness, minimize);
      }

      double min = Double.MAX_VALUE;
      double max = Double.MIN_VALUE;
      double desEst = 0;
      double prome = 0;

      for (int i = 0; i < parents.length; i++) {
        double fit = fitness.fitness(parents[i]);
        values.add(fit);
        if (fit < min) {
          min = fit;
        }
        if (fit > max) {
          max = fit;
        }
        prome += fit;
      }
      prome /= parents.length;

      for (int i = 0; i < parents.length; i++) {
        double fit = fitness.fitness(parents[i]);
        desEst = (fit - prome) * (fit - prome);
      }
      desEst /= parents.length - 1;

      minis.add(min);
      maxis.add(max);
      promis.add(prome);
      desvis.add(desEst);
      System.out.println(min);
    }
    Statistics.run(values, fitness, minimize);

    System.out.println("ITER;MIN;MAX;PROM;D.EST");
    for (int i = 0; i < minis.size(); i++) {
      System.out.print((i + 1) + ";");
      System.out.print(minis.get(i) + ";");
      System.out.print(maxis.get(i) + ";");
      System.out.print(promis.get(i) + ";");
      System.out.println(desvis.get(i));
    }

    return parents;
  }
  @Override
  public Individual[] run(
      StopCondition T,
      FitnessFunction f,
      SelectionAlgorithm selector,
      GenerationAlgorithm generator,
      ReplaceAlgorithm replacer,
      int lambda) {

    int t = 0;
    Individual[] P = f.initialize(lambda);

    boolean first = true;
    boolean second = true;
    ArrayList<Double> values = new ArrayList<Double>();

    ArrayList<Double> minis = new ArrayList<Double>();
    ArrayList<Double> maxis = new ArrayList<Double>();
    ArrayList<Double> promis = new ArrayList<Double>();
    ArrayList<Double> desvis = new ArrayList<Double>();

    while (!T.stop(P, f, t)) {
      Individual Q[] =
          selector.selection(
              P, f,
              minimize); // lambda-individuos, seleccion por ruleta, torneo, ranqueo o USS ->
                         // repetir lambda veces
      Individual H[] = generator.generate(Q, f, minimize); // generar lambda-individuos:
      // 1. se hacen parejas
      // se hace cruce si cumple probabilidad P=0.6 para cada hijo
      // se hace una mutacion si cumple probabilidad por cada bit P = 1/len(cromosoma) para cada
      // hijo
      // se ponen en H
      P = replacer.replace(P, H);

      double min = Double.MAX_VALUE;
      double max = Double.MIN_VALUE;
      double desEst = 0;
      double prom = 0;

      for (int i = 0; i < P.length; i++) {
        double fit = f.fitness(P[i]);
        values.add(fit);
        if (fit < min) {
          min = fit;
        }
        if (fit > max) {
          max = fit;
        }
        prom += fit;
      }
      prom /= P.length;

      for (int i = 0; i < P.length; i++) {
        double fit = f.fitness(P[i]);
        desEst = (fit - prom) * (fit - prom);
      }
      desEst /= P.length - 1;

      minis.add(min);
      maxis.add(max);
      promis.add(prom);
      desvis.add(desEst);

      System.out.println(min);

      if (f.callsNumber() >= 120000 && first) {
        first = false;
        Statistics.run(values, f, minimize);
      }
      if (f.callsNumber() >= 600000 && second) {
        second = false;
        Statistics.run(values, f, minimize);
      }

      t++;
    }
    Statistics.run(values, f, minimize);
    System.out.println("ITER;MIN;MAX;PROM;D.EST");
    for (int i = 0; i < minis.size(); i++) {
      System.out.print((i + 1) + ";");
      System.out.print(minis.get(i) + ";");
      System.out.print(maxis.get(i) + ";");
      System.out.print(promis.get(i) + ";");
      System.out.println(desvis.get(i));
    }

    return P;
  }