/** {@inheritDoc} */
  public List<EvaluatedCandidate<T>> evolvePopulation(
      int populationSize,
      int eliteCount,
      Collection<T> seedCandidates,
      TerminationCondition... conditions) {
    if (eliteCount < 0 || eliteCount >= populationSize) {
      throw new IllegalArgumentException(
          "Elite count must be non-negative and less than population size.");
    }
    if (conditions.length == 0) {
      throw new IllegalArgumentException("At least one TerminationCondition must be specified.");
    }

    satisfiedTerminationConditions = null;
    int currentGenerationIndex = 0;
    long startTime = System.currentTimeMillis();

    List<T> population =
        candidateFactory.generateInitialPopulation(populationSize, seedCandidates, rng);

    // Calculate the fitness scores for each member of the initial
    // population.
    List<EvaluatedCandidate<T>> evaluatedPopulation = evaluatePopulation(population);
    EvolutionUtils.sortEvaluatedPopulation(evaluatedPopulation, fitnessEvaluator.isNatural());
    PopulationData<T> data =
        EvolutionUtils.getPopulationData(
            evaluatedPopulation,
            fitnessEvaluator.isNatural(),
            eliteCount,
            currentGenerationIndex,
            startTime);
    // Notify observers of the state of the population.
    notifyPopulationChange(data);

    List<TerminationCondition> satisfiedConditions =
        EvolutionUtils.shouldContinue(data, conditions);
    while (satisfiedConditions == null) {
      ++currentGenerationIndex;
      evaluatedPopulation = nextEvolutionStep(evaluatedPopulation, eliteCount, rng);
      EvolutionUtils.sortEvaluatedPopulation(evaluatedPopulation, fitnessEvaluator.isNatural());
      data =
          EvolutionUtils.getPopulationData(
              evaluatedPopulation,
              fitnessEvaluator.isNatural(),
              eliteCount,
              currentGenerationIndex,
              startTime);
      // Notify observers of the state of the population.
      notifyPopulationChange(data);
      notifyMyPopulationChange(new MyPopulationData<T>(data, evaluatedPopulation));
      satisfiedConditions = EvolutionUtils.shouldContinue(data, conditions);
    }
    this.satisfiedTerminationConditions = satisfiedConditions;
    return evaluatedPopulation;
  }