@Override
  protected void splitProcess(EvolutionState state) {
    splits = 0;
    List<MetaPopulation> created = new ArrayList<MetaPopulation>();
    for (MetaPopulation mp : metaPops) {
      if (mp.populations.size() > 1) {
        // Find the biggest distance between populations of the same MetaPopulation
        int maxI = -1, maxJ = -1;
        for (Integer i : mp.populations) {
          for (Integer j : mp.populations) {
            if (j > i && (maxI == -1 || distanceMatrix[i][j] > distanceMatrix[maxI][maxJ])) {
              maxI = i;
              maxJ = j;
            }
          }
        }

        double threshold =
            Math.max(
                finalThreshold, finalThreshold + thresholdDeviation - mp.age * thresholdChange);

        // Check if it needs to be split
        if (distanceMatrix[maxI][maxJ] > threshold) {
          // Determine which one will leave the metapopulation
          int exitPop = maxJ;
          if (mp.populations.size() > 2) {
            double maxIdist = 0, maxJdist = 0;
            for (Integer k : mp.populations) {
              maxIdist += distanceMatrix[k][maxI];
              maxJdist += distanceMatrix[k][maxJ];
            }
            exitPop = maxIdist > maxJdist ? maxI : maxJ;
          }

          // Do the split -- remove subpop from current metapopulation
          System.out.println(
              "Spliting "
                  + exitPop
                  + " from "
                  + mp.toString()
                  + " D: "
                  + distanceMatrix[maxI][maxJ]
                  + " T: "
                  + threshold);
          mp.populations.remove((Object) exitPop);
          mp.age = 0;

          // Create new metapopulation with subpop and the same individuals as the former metapop
          MetaPopulation mpj = new MetaPopulation();
          mpj.individuals = state.population.subpops[exitPop].individuals;
          mpj.populations.add(exitPop);
          created.add(mpj);
          splits++;
        }
      }
    }
    metaPops.addAll(created);
  }
  @Override
  protected void mergeProcess(EvolutionState state) {
    Iterator<MetaPopulation> iter = metaPops.iterator();
    while (iter.hasNext()) {
      MetaPopulation next = iter.next();
      // The population is alone: candidate to merging
      if (next.populations.size() == 1) {
        // Find the closest metapopulation to merge with
        int subpop = next.populations.get(0); // get the single subpopulation
        MetaPopulation closest = null;
        double distance = Double.POSITIVE_INFINITY;
        for (MetaPopulation mp : metaPops) {
          if (mp != next) { // can not merge with itself
            double d = maxDistance(subpop, mp);
            if (d < distance) {
              distance = d;
              closest = mp;
            }
          }
        }

        // One metapop was found, merge with it
        if (closest != null) {
          double threshold =
              Math.min(
                  finalThreshold,
                  finalThreshold
                      - thresholdDeviation
                      + Math.min(closest.age, next.age) * thresholdChange);
          if (distance < threshold) {
            iter.remove(); // delete current metapop
            // Integrate in the closest
            System.out.println(
                "Merging "
                    + next.toString()
                    + " with "
                    + closest.toString()
                    + " D: "
                    + distance
                    + " T: "
                    + threshold);
            closest.populations.add(subpop);
            closest.waitingIndividuals.add(next.individuals);
            closest.age = 0;
          }
        }
      }
    }
  }