if (this.actualThreadCount == -1) {
preIteration();
}
if (getPopulation().getSpecies().size() == 0) {
throw new AIFHError("Population is empty, there are no species.");
}
this.iteration++;
// Clear new population to just best genome.
this.newPopulation.clear();
this.newPopulation.add(this.bestGenome);
this.oldBestGenome = this.bestGenome;
// execute species in parallel
this.threadList.clear();
for (final Species species : getPopulation().getSpecies()) {
int numToSpawn = species.getOffspringCount();
// Add elite genomes directly
if (species.getMembers().size() > 5) {
final int idealEliteCount = (int) (species.getMembers().size() * getEliteRate());
final int eliteCount = Math.min(numToSpawn, idealEliteCount);
for (int i = 0; i < eliteCount; i++) {
final Genome eliteGenome = species.getMembers().get(i);
if (getOldBestGenome() != eliteGenome) {
numToSpawn--;
if (!addChild(eliteGenome)) {
break;
}
}
}
}
// now add one task for each offspring that each species is allowed
while (numToSpawn-- > 0) {
final EAWorker worker = new EAWorker(this, species);
this.threadList.add(worker);
}
}
// run all threads and wait for them to finish
try {
this.taskExecutor.invokeAll(this.threadList);
} catch (final InterruptedException e) {
e.printStackTrace();
}
// handle any errors that might have happened in the threads
if (this.reportedError != null && !getShouldIgnoreExceptions()) {
throw new AIFHError(this.reportedError);
}
// validate, if requested
if (isValidationMode()) {
if (this.oldBestGenome != null
&& !this.newPopulation.contains(this.oldBestGenome)) {
throw new AIFHError(
"The top genome died, this should never happen!!");
}
if (this.bestGenome != null
&& this.oldBestGenome != null
&& getBestComparator().isBetterThan(this.oldBestGenome,
this.bestGenome)) {
throw new AIFHError(
"The best genome's score got worse, this should never happen!! Went from "
+ this.oldBestGenome.getScore() + " to "
+ this.bestGenome.getScore());
}
}