@Override public GRCandidateProgram[] crossover(final CandidateProgram p1, final CandidateProgram p2) { final GRCandidateProgram child1 = (GRCandidateProgram) p1; final GRCandidateProgram child2 = (GRCandidateProgram) p2; final NonTerminalSymbol parseTree1 = child1.getParseTree(); final NonTerminalSymbol parseTree2 = child2.getParseTree(); final List<NonTerminalSymbol> nonTerminals1 = parseTree1.getNonTerminalSymbols(); final List<NonTerminalSymbol> nonTerminals2 = parseTree2.getNonTerminalSymbols(); final int point1 = rng.nextInt(nonTerminals1.size()); final NonTerminalSymbol subtree1 = nonTerminals1.get(point1); // Generate a list of matching non-terminals from the second program. final List<NonTerminalSymbol> matchingNonTerminals = new ArrayList<NonTerminalSymbol>(); for (final NonTerminalSymbol nt : nonTerminals2) { if (nt.getGrammarRule().equals(subtree1.getGrammarRule())) { matchingNonTerminals.add(nt); } } if (matchingNonTerminals.isEmpty()) { // No valid points in second program, cancel crossover. return null; } else { // Randomly choose a second point out of the matching non-terminals. final int point2 = rng.nextInt(matchingNonTerminals.size()); final NonTerminalSymbol subtree2 = matchingNonTerminals.get(point2); // Add crossover points to the stats manager. Stats.get().addData(XO_POINT1, point1); Stats.get().addData(XO_POINT2, point2); // Swap the non-terminals' children. final List<Symbol> temp = subtree1.getChildren(); subtree1.setChildren(subtree2.getChildren()); subtree2.setChildren(temp); // Add subtrees into the stats manager. Stats.get().addData(XO_SUBTREE1, subtree1); Stats.get().addData(XO_SUBTREE2, subtree2); } return new GRCandidateProgram[] {child1, child2}; }