@Override
public void performOperation(final Random rnd, final Genome[] parents,
final int parentIndex, final Genome[] offspring,
final int offspringIndex) {
final NEATGenome mom = (NEATGenome) parents[parentIndex + 0];
final NEATGenome dad = (NEATGenome) parents[parentIndex + 1];
final NEATGenome best = favorParent(rnd, mom, dad);
final NEATGenome notBest = (best != mom) ? mom : dad;
final List<NEATLinkGene> selectedLinks = new ArrayList<NEATLinkGene>();
final List<NEATNeuronGene> selectedNeurons = new ArrayList<NEATNeuronGene>();
int curMom = 0; // current gene index from mom
int curDad = 0; // current gene index from dad
NEATLinkGene selectedGene = null;
// add in the input and bias, they should always be here
final int alwaysCount = ((NEATGenome)parents[0]).getInputCount()
+ ((NEATGenome)parents[0]).getOutputCount() + 1;
for (int i = 0; i < alwaysCount; i++) {
addNeuronID(i, selectedNeurons, best, notBest);
}
while ((curMom < mom.getNumGenes()) || (curDad < dad.getNumGenes())) {
NEATLinkGene momGene = null; // the mom gene object
NEATLinkGene dadGene = null; // the dad gene object
long momInnovation = -1;
long dadInnovation = -1;
// grab the actual objects from mom and dad for the specified
// indexes
// if there are none, then null
if (curMom < mom.getNumGenes()) {
momGene = mom.getLinksChromosome().get(curMom);
momInnovation = momGene.getInnovationId();
}
if (curDad < dad.getNumGenes()) {
dadGene = dad.getLinksChromosome().get(curDad);
dadInnovation = dadGene.getInnovationId();
}
// now select a gene for mom or dad. This gene is for the baby
if ((momGene == null) && (dadGene != null)) {
if (best == dad) {
selectedGene = dadGene;
}
curDad++;
} else if ((dadGene == null) && (momGene != null)) {
if (best == mom) {
selectedGene = momGene;
}
curMom++;
} else if (momInnovation < dadInnovation) {
if (best == mom) {
selectedGene = momGene;
}
curMom++;
} else if (dadInnovation < momInnovation) {
if (best == dad) {
selectedGene = dadGene;
}
curDad++;
} else if (dadInnovation == momInnovation) {
if (Math.random() < 0.5f) {
selectedGene = momGene;
}
else {
selectedGene = dadGene;
}
curMom++;
curDad++;
}
if (selectedGene != null) {
if (selectedLinks.size() == 0) {
selectedLinks.add(selectedGene);
} else {
if (selectedLinks.get(selectedLinks.size() - 1)
.getInnovationId() != selectedGene
.getInnovationId()) {
selectedLinks.add(selectedGene);
}
}
// Check if we already have the nodes referred to in
// SelectedGene.
// If not, they need to be added.
addNeuronID(selectedGene.getFromNeuronID(), selectedNeurons,
best, notBest);
addNeuronID(selectedGene.getToNeuronID(), selectedNeurons,
best, notBest);
}
}
// now create the required nodes. First sort them into order
Collections.sort(selectedNeurons);
// finally, create the genome
final NEATGenomeFactory factory = (NEATGenomeFactory) this.owner
.getPopulation().getGenomeFactory();
final NEATGenome babyGenome = factory.factor(selectedNeurons,
selectedLinks, mom.getInputCount(), mom.getOutputCount());
babyGenome.setBirthGeneration(this.owner.getIteration());
babyGenome.setPopulation(this.owner.getPopulation());
babyGenome.sortGenes();
offspring[offspringIndex] = babyGenome;
}